├── .gitignore
├── LICENSE
├── README.md
├── TcpUdpTool.sln
├── TcpUdpTool
├── App.config
├── App.xaml
├── App.xaml.cs
├── Model
│ ├── Data
│ │ ├── Transmission.cs
│ │ └── TransmissionResult.cs
│ ├── EventArg
│ │ └── ReceivedEventArgs.cs
│ ├── Formatter
│ │ ├── HexFormatter.cs
│ │ ├── IFormatter.cs
│ │ └── PlainTextFormatter.cs
│ ├── Parser
│ │ ├── HexParser.cs
│ │ ├── IParser.cs
│ │ └── PlainTextParser.cs
│ ├── RateMonitor.cs
│ ├── TcpClient.cs
│ ├── TcpServer.cs
│ ├── UdpClientServer.cs
│ ├── UdpMulticastClient.cs
│ └── Util
│ │ ├── DialogUtils.cs
│ │ ├── NetworkUtils.cs
│ │ ├── SettingsUtils.cs
│ │ └── StringFormatUtils.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── Resources
│ ├── Icons.xaml
│ ├── Styles.xaml
│ └── icon.ico
├── TcpUdpTool.csproj
├── View
│ ├── HelpView.xaml
│ ├── HelpView.xaml.cs
│ ├── HistoryView.xaml
│ ├── HistoryView.xaml.cs
│ ├── MainWindow.xaml
│ ├── MainWindow.xaml.cs
│ ├── SettingsView.xaml
│ ├── SettingsView.xaml.cs
│ ├── TcpClientView.xaml
│ ├── TcpClientView.xaml.cs
│ ├── TcpServerView.xaml
│ ├── TcpServerView.xaml.cs
│ ├── UdpAsmView.xaml
│ ├── UdpAsmView.xaml.cs
│ ├── UdpSsmView.xaml
│ ├── UdpSsmView.xaml.cs
│ ├── UdpView.xaml
│ └── UdpView.xaml.cs
└── ViewModel
│ ├── Base
│ ├── BatchObservableCollection.cs
│ ├── DelegateCommand.cs
│ └── ObservableObject.cs
│ ├── Extension
│ ├── ListViewExtension.cs
│ └── WindowExtension.cs
│ ├── Helper
│ ├── DispatchHelper.cs
│ └── IContentChangedHelper.cs
│ ├── HistoryViewModel.cs
│ ├── Item
│ ├── ConversationItemViewModel.cs
│ └── InterfaceAddress.cs
│ ├── MainViewModel.cs
│ ├── SendViewModel.cs
│ ├── SettingsViewModel.cs
│ ├── TcpClientViewModel.cs
│ ├── TcpServerViewModel.cs
│ ├── UdpAsmViewModel.cs
│ ├── UdpSsmViewModel.cs
│ └── UdpViewModel.cs
└── icon
├── tcp-udp-tool-icon.ico
├── tcp-udp-tool-icon.png
└── tcp-udp-tool-icon.psd
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 | [Ll]og/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opendb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 | *.VC.db
84 | *.VC.VC.opendb
85 |
86 | # Visual Studio profiler
87 | *.psess
88 | *.vsp
89 | *.vspx
90 | *.sap
91 |
92 | # TFS 2012 Local Workspace
93 | $tf/
94 |
95 | # Guidance Automation Toolkit
96 | *.gpState
97 |
98 | # ReSharper is a .NET coding add-in
99 | _ReSharper*/
100 | *.[Rr]e[Ss]harper
101 | *.DotSettings.user
102 |
103 | # JustCode is a .NET coding add-in
104 | .JustCode
105 |
106 | # TeamCity is a build add-in
107 | _TeamCity*
108 |
109 | # DotCover is a Code Coverage Tool
110 | *.dotCover
111 |
112 | # NCrunch
113 | _NCrunch_*
114 | .*crunch*.local.xml
115 | nCrunchTemp_*
116 |
117 | # MightyMoose
118 | *.mm.*
119 | AutoTest.Net/
120 |
121 | # Web workbench (sass)
122 | .sass-cache/
123 |
124 | # Installshield output folder
125 | [Ee]xpress/
126 |
127 | # DocProject is a documentation generator add-in
128 | DocProject/buildhelp/
129 | DocProject/Help/*.HxT
130 | DocProject/Help/*.HxC
131 | DocProject/Help/*.hhc
132 | DocProject/Help/*.hhk
133 | DocProject/Help/*.hhp
134 | DocProject/Help/Html2
135 | DocProject/Help/html
136 |
137 | # Click-Once directory
138 | publish/
139 |
140 | # Publish Web Output
141 | *.[Pp]ublish.xml
142 | *.azurePubxml
143 | # TODO: Comment the next line if you want to checkin your web deploy settings
144 | # but database connection strings (with potential passwords) will be unencrypted
145 | *.pubxml
146 | *.publishproj
147 |
148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
149 | # checkin your Azure Web App publish settings, but sensitive information contained
150 | # in these scripts will be unencrypted
151 | PublishScripts/
152 |
153 | # NuGet Packages
154 | *.nupkg
155 | # The packages folder can be ignored because of Package Restore
156 | **/packages/*
157 | # except build/, which is used as an MSBuild target.
158 | !**/packages/build/
159 | # Uncomment if necessary however generally it will be regenerated when needed
160 | #!**/packages/repositories.config
161 | # NuGet v3's project.json files produces more ignoreable files
162 | *.nuget.props
163 | *.nuget.targets
164 |
165 | # Microsoft Azure Build Output
166 | csx/
167 | *.build.csdef
168 |
169 | # Microsoft Azure Emulator
170 | ecf/
171 | rcf/
172 |
173 | # Windows Store app package directories and files
174 | AppPackages/
175 | BundleArtifacts/
176 | Package.StoreAssociation.xml
177 | _pkginfo.txt
178 |
179 | # Visual Studio cache files
180 | # files ending in .cache can be ignored
181 | *.[Cc]ache
182 | # but keep track of directories ending in .cache
183 | !*.[Cc]ache/
184 |
185 | # Others
186 | ClientBin/
187 | ~$*
188 | *~
189 | *.dbmdl
190 | *.dbproj.schemaview
191 | *.pfx
192 | *.publishsettings
193 | node_modules/
194 | orleans.codegen.cs
195 |
196 | # Since there are multiple workflows, uncomment next line to ignore bower_components
197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
198 | #bower_components/
199 |
200 | # RIA/Silverlight projects
201 | Generated_Code/
202 |
203 | # Backup & report files from converting an old project file
204 | # to a newer Visual Studio version. Backup files are not needed,
205 | # because we have git ;-)
206 | _UpgradeReport_Files/
207 | Backup*/
208 | UpgradeLog*.XML
209 | UpgradeLog*.htm
210 |
211 | # SQL Server files
212 | *.mdf
213 | *.ldf
214 |
215 | # Business Intelligence projects
216 | *.rdl.data
217 | *.bim.layout
218 | *.bim_*.settings
219 |
220 | # Microsoft Fakes
221 | FakesAssemblies/
222 |
223 | # GhostDoc plugin setting file
224 | *.GhostDoc.xml
225 |
226 | # Node.js Tools for Visual Studio
227 | .ntvs_analysis.dat
228 |
229 | # Visual Studio 6 build log
230 | *.plg
231 |
232 | # Visual Studio 6 workspace options file
233 | *.opt
234 |
235 | # Visual Studio LightSwitch build output
236 | **/*.HTMLClient/GeneratedArtifacts
237 | **/*.DesktopClient/GeneratedArtifacts
238 | **/*.DesktopClient/ModelManifest.xml
239 | **/*.Server/GeneratedArtifacts
240 | **/*.Server/ModelManifest.xml
241 | _Pvt_Extensions
242 |
243 | # Paket dependency manager
244 | .paket/paket.exe
245 | paket-files/
246 |
247 | # FAKE - F# Make
248 | .fake/
249 |
250 | # JetBrains Rider
251 | .idea/
252 | *.sln.iml
253 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # tcp-udp-tool
2 |
3 | 
4 |
--------------------------------------------------------------------------------
/TcpUdpTool.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25123.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TcpUdpTool", "TcpUdpTool\TcpUdpTool.csproj", "{C3FF0B8C-0EAF-41EF-AEF6-C8C597CF0A7F}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {C3FF0B8C-0EAF-41EF-AEF6-C8C597CF0A7F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {C3FF0B8C-0EAF-41EF-AEF6-C8C597CF0A7F}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {C3FF0B8C-0EAF-41EF-AEF6-C8C597CF0A7F}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {C3FF0B8C-0EAF-41EF-AEF6-C8C597CF0A7F}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | EndGlobal
23 |
--------------------------------------------------------------------------------
/TcpUdpTool/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | 65001
15 |
16 |
17 | False
18 |
19 |
20 | 100
21 |
22 |
23 | True
24 |
25 |
26 | True
27 |
28 |
29 | True
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/TcpUdpTool/App.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/TcpUdpTool/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Data;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using System.Windows;
8 |
9 | namespace TcpUdpTool
10 | {
11 | ///
12 | /// Interaction logic for App.xaml
13 | ///
14 | public partial class App : Application
15 | {
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/TcpUdpTool/Model/Data/Transmission.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 |
4 | namespace TcpUdpTool.Model.Data
5 | {
6 | public class Transmission : IEquatable, IComparable
7 | {
8 | private static ulong _counter = 0;
9 | private static object _lock = new object();
10 |
11 |
12 | public enum EType { Sent, Received };
13 |
14 | private ulong _sequenceNr;
15 | private byte[] _data;
16 | private EType _type;
17 | private DateTime _timestamp;
18 | private IPEndPoint _origin;
19 | private IPEndPoint _destination;
20 |
21 |
22 | public ulong SequenceNr
23 | {
24 | get { return _sequenceNr; }
25 | }
26 |
27 | public byte[] Data
28 | {
29 | get { return _data; }
30 | }
31 |
32 | public EType Type
33 | {
34 | get { return _type; }
35 | }
36 |
37 | public IPEndPoint Origin
38 | {
39 | get { return _origin; }
40 | set{ _origin = value; }
41 | }
42 |
43 | public IPEndPoint Destination
44 | {
45 | get { return _destination; }
46 | set { _destination = value; }
47 | }
48 |
49 |
50 | public DateTime Timestamp
51 | {
52 | get { return _timestamp; }
53 | }
54 |
55 | public bool IsReceived
56 | {
57 | get { return _type == EType.Received; }
58 | }
59 |
60 | public bool IsSent
61 | {
62 | get { return _type == EType.Sent; }
63 | }
64 |
65 | public int Length
66 | {
67 | get { return _data.Length; }
68 | }
69 |
70 |
71 | public Transmission(byte[] data, EType type)
72 | {
73 | lock(_lock)
74 | {
75 | _sequenceNr = _counter++;
76 | }
77 |
78 | _data = data;
79 | _type = type;
80 | _timestamp = DateTime.Now;
81 | }
82 |
83 | public bool Equals(Transmission other)
84 | {
85 | if(other != null)
86 | {
87 | return SequenceNr == other.SequenceNr;
88 | }
89 |
90 | return false;
91 | }
92 |
93 | public override bool Equals(object obj)
94 | {
95 | return Equals(obj as Transmission);
96 | }
97 |
98 | public override int GetHashCode()
99 | {
100 | return (int)SequenceNr;
101 | }
102 |
103 | public int CompareTo(Transmission other)
104 | {
105 | if(SequenceNr > other.SequenceNr)
106 | {
107 | return 1;
108 | }
109 | else if(SequenceNr < other.SequenceNr)
110 | {
111 | return -1;
112 | }
113 |
114 | return 0;
115 | }
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/TcpUdpTool/Model/Data/TransmissionResult.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 |
3 | namespace TcpUdpTool.Model.Data
4 | {
5 | public class TransmissionResult
6 | {
7 | public IPEndPoint From { get; set; }
8 | public IPEndPoint To { get; set; }
9 |
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/TcpUdpTool/Model/EventArg/ReceivedEventArgs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using TcpUdpTool.Model.Data;
3 |
4 | namespace TcpUdpTool.Model.EventArg
5 | {
6 | public class ReceivedEventArgs : EventArgs
7 | {
8 |
9 | public Transmission Message { get; private set; }
10 |
11 | public ReceivedEventArgs(Transmission message)
12 | {
13 | Message = message;
14 | }
15 |
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/TcpUdpTool/Model/Formatter/HexFormatter.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using TcpUdpTool.Model.Data;
3 |
4 | namespace TcpUdpTool.Model.Formatter
5 | {
6 | public class HexFormatter : IFormatter
7 | {
8 | private StringBuilder _builder = new StringBuilder();
9 |
10 | public string Format(Transmission msg)
11 | {
12 | _builder.Clear();
13 |
14 | int count = 0;
15 | foreach (byte b in msg.Data)
16 | {
17 | _builder.Append(b.ToString("X2"));
18 |
19 | if (++count % 16 == 0)
20 | {
21 | _builder.AppendLine();
22 | }
23 | else
24 | {
25 | _builder.Append(' ');
26 | }
27 | }
28 |
29 | return _builder.ToString();
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/TcpUdpTool/Model/Formatter/IFormatter.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using TcpUdpTool.Model.Data;
3 |
4 | namespace TcpUdpTool.Model.Formatter
5 | {
6 | public interface IFormatter
7 | {
8 | string Format(Transmission msg);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/TcpUdpTool/Model/Formatter/PlainTextFormatter.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using TcpUdpTool.Model.Data;
3 |
4 | namespace TcpUdpTool.Model.Formatter
5 | {
6 | public class PlainTextFormatter : IFormatter
7 | {
8 | private Encoding _encoding;
9 |
10 | public PlainTextFormatter(Encoding encoding = null)
11 | {
12 | _encoding = encoding;
13 | if (_encoding == null)
14 | {
15 | _encoding = Encoding.Default;
16 | }
17 | }
18 |
19 | public string Format(Transmission msg)
20 | {
21 | return _encoding.GetString(msg.Data);
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/TcpUdpTool/Model/Parser/HexParser.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Text;
4 |
5 | namespace TcpUdpTool.Model.Parser
6 | {
7 | public class HexParser : IParser
8 | {
9 | public byte[] Parse(string text, Encoding encoding = null)
10 | {
11 | string[] parts = text.Split(new char[0], StringSplitOptions.RemoveEmptyEntries);
12 | byte[] data = new byte[parts.Length];
13 |
14 | for(int i = 0; i < parts.Length; i++)
15 | {
16 | try
17 | {
18 | if (parts[i].Length > 2)
19 | throw new FormatException();
20 |
21 | data[i] = (byte)uint.Parse(parts[i], NumberStyles.AllowHexSpecifier);
22 | }
23 | catch(FormatException)
24 | {
25 | throw new FormatException("Incorrect sequence, " + parts[i] + " is not a 8-bit hexadecimal number.");
26 | }
27 | }
28 |
29 | return data;
30 | }
31 |
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/TcpUdpTool/Model/Parser/IParser.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 |
3 | namespace TcpUdpTool.Model.Parser
4 | {
5 | public interface IParser
6 | {
7 | byte[] Parse(string text, Encoding encoding = null);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/TcpUdpTool/Model/Parser/PlainTextParser.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Globalization;
4 | using System.Text;
5 |
6 | namespace TcpUdpTool.Model.Parser
7 | {
8 | public class PlainTextParser : IParser
9 | {
10 |
11 | public byte[] Parse(string text, Encoding encoding = null)
12 | {
13 | if(encoding == null)
14 | {
15 | encoding = Encoding.UTF8;
16 | }
17 |
18 | List res = new List(text.Length * 2);
19 | StringBuilder cache = new StringBuilder();
20 |
21 | bool escape = false;
22 | bool escapeHex = false;
23 | bool escapeUnicode = false;
24 | string hexStr = "";
25 |
26 | foreach (char c in text)
27 | {
28 | if (escape)
29 | {
30 | if (c == '\\')
31 | cache.Append('\\');
32 | else if (c == '0')
33 | cache.Append('\0');
34 | else if (c == 'a')
35 | cache.Append('\a');
36 | else if (c == 'b')
37 | cache.Append('\b');
38 | else if (c == 'f')
39 | cache.Append('\f');
40 | else if (c == 'n')
41 | cache.Append('\n');
42 | else if (c == 'r')
43 | cache.Append('\r');
44 | else if (c == 't')
45 | cache.Append('\t');
46 | else if (c == 'v')
47 | cache.Append('\v');
48 | else if (c == 'x')
49 | escapeHex = true;
50 | else if (c == 'u')
51 | escapeUnicode = true;
52 | else
53 | throw new FormatException("Incorrect escape sequence found, \\"
54 | + c + " is not allowed.");
55 |
56 | escape = false;
57 | }
58 | else if (escapeHex)
59 | {
60 | hexStr += c;
61 |
62 | if (hexStr.Length == 2)
63 | {
64 | try
65 | {
66 | // adding binary data that should not be character encoded,
67 | // encode and move previous data to result and clear cache.
68 | res.AddRange(encoding.GetBytes(cache.ToString()));
69 | cache.Clear();
70 | res.Add((byte)int.Parse(hexStr, NumberStyles.AllowHexSpecifier));
71 | }
72 | catch (FormatException)
73 | {
74 | throw new FormatException("Incorrect escape sequence found, \\x"
75 | + hexStr + " is not a 8-bit hexadecimal number.");
76 | }
77 |
78 | escapeHex = false;
79 | hexStr = "";
80 | }
81 | }
82 | else if (escapeUnicode)
83 | {
84 | hexStr += c;
85 |
86 | if (hexStr.Length == 4)
87 | {
88 | try
89 | {
90 | cache.Append(Convert.ToChar(int.Parse(hexStr, NumberStyles.AllowHexSpecifier)));
91 | }
92 | catch (FormatException)
93 | {
94 | throw new FormatException("Incorrect escape sequence found, \\u"
95 | + hexStr + " is not a 16-bit hexadecimal unicode character code.");
96 | }
97 |
98 | escapeUnicode = false;
99 | hexStr = "";
100 | }
101 | }
102 | else
103 | {
104 | if (c == '\\')
105 | {
106 | // next char is an escape sequence.
107 | escape = true;
108 | }
109 | else
110 | {
111 | cache.Append(c);
112 | }
113 | }
114 | }
115 |
116 | res.AddRange(encoding.GetBytes(cache.ToString()));
117 |
118 | return res.ToArray();
119 | }
120 |
121 | }
122 |
123 | }
124 |
--------------------------------------------------------------------------------
/TcpUdpTool/Model/RateMonitor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Threading;
4 | using TcpUdpTool.Model.Data;
5 |
6 | namespace TcpUdpTool.Model
7 | {
8 | public class RateMonitor : IDisposable
9 | {
10 |
11 | #region private members
12 |
13 | private ulong _recevedBytes;
14 | private ulong _sentBytes;
15 |
16 | private ulong _recvSinceLastUpdate;
17 | private ulong _sentSinceLastUpdate;
18 |
19 | private Timer _updateTimer;
20 | private Stopwatch _stopwatch;
21 |
22 | #endregion
23 |
24 | #region public properties
25 |
26 | public ulong TotalSentBytes { get; set; }
27 | public ulong TotalReceivedBytes { get; set; }
28 | public ulong CurrentSendRate { get; set; }
29 | public ulong CurrentReceiveRate { get; set; }
30 |
31 | #endregion
32 |
33 | #region constructors
34 |
35 | public RateMonitor()
36 | {
37 |
38 | }
39 |
40 | #endregion
41 |
42 | #region public functions
43 |
44 | public void Start()
45 | {
46 | if(_updateTimer == null)
47 | {
48 | Reset();
49 | _stopwatch = new Stopwatch();
50 | _updateTimer = new Timer(OnUpdate, null, 0, 500);
51 | }
52 | }
53 |
54 | public void Stop()
55 | {
56 | if (_updateTimer != null)
57 | {
58 | _updateTimer.Dispose();
59 | _updateTimer = null;
60 | }
61 | Reset();
62 | }
63 |
64 | public void Reset()
65 | {
66 | lock(this)
67 | {
68 | _recevedBytes = 0;
69 | _sentBytes = 0;
70 | _recvSinceLastUpdate = 0;
71 | _sentSinceLastUpdate = 0;
72 | TotalSentBytes = 0;
73 | TotalReceivedBytes = 0;
74 | CurrentReceiveRate = 0;
75 | CurrentSendRate = 0;
76 | }
77 | }
78 |
79 | public void NoteReceived(Transmission data)
80 | {
81 | lock(this)
82 | {
83 | _recevedBytes += (uint)data.Length;
84 | _recvSinceLastUpdate+= (uint)data.Length;
85 | }
86 | }
87 |
88 | public void NoteSent(Transmission data)
89 | {
90 | lock(this)
91 | {
92 | _sentBytes += (uint)data.Length;
93 | _sentSinceLastUpdate += (uint)data.Length;
94 | }
95 | }
96 |
97 | #endregion
98 |
99 | #region private functions
100 |
101 | private void OnUpdate(object state)
102 | {
103 | lock (this)
104 | {
105 | _stopwatch.Stop();
106 | ulong millis = (ulong)_stopwatch.ElapsedMilliseconds;
107 | if (millis > 0)
108 | {
109 | TotalSentBytes = _sentBytes;
110 | TotalReceivedBytes = _recevedBytes;
111 | CurrentSendRate = (_sentSinceLastUpdate * 8 * 1000) / millis;
112 | CurrentReceiveRate = (_recvSinceLastUpdate * 8 * 1000) / millis;
113 | _sentSinceLastUpdate = 0;
114 | _recvSinceLastUpdate = 0;
115 | }
116 | _stopwatch.Reset();
117 | _stopwatch.Start();
118 | }
119 | }
120 |
121 | public void Dispose()
122 | {
123 | _updateTimer?.Dispose();
124 | }
125 |
126 | #endregion
127 |
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/TcpUdpTool/Model/TcpClient.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Threading.Tasks;
4 | using TcpUdpTool.Model.Data;
5 | using TcpUdpTool.Model.EventArg;
6 | using TcpUdpTool.Model.Util;
7 |
8 | namespace TcpUdpTool.Model
9 | {
10 | public class TcpClient : IDisposable
11 | {
12 |
13 | public event EventHandler Received;
14 | public event EventHandler StatusChanged;
15 |
16 | private System.Net.Sockets.TcpClient _tcpClient;
17 | private byte[] _buffer;
18 |
19 |
20 | public TcpClient()
21 | {
22 | _buffer = new byte[8192];
23 | }
24 |
25 |
26 | public async Task ConnectAsync(string host, int port)
27 | {
28 | if (_tcpClient != null && _tcpClient.Connected)
29 | return; // already connected
30 |
31 | OnConnectStatusChanged(TcpClientStatusEventArgs.EConnectStatus.Connecting);
32 |
33 | try
34 | {
35 | // resolve ip address
36 | IPAddress addr = await NetworkUtils.DnsResolveAsync(host);
37 |
38 | _tcpClient = new System.Net.Sockets.TcpClient(addr.AddressFamily);
39 |
40 | await _tcpClient.ConnectAsync(addr, port);
41 | OnConnectStatusChanged(TcpClientStatusEventArgs.EConnectStatus.Connected);
42 |
43 | StartReceive();
44 | }
45 | catch(Exception)
46 | {
47 | Disconnect();
48 | throw;
49 | }
50 | }
51 |
52 | public void Disconnect()
53 | {
54 | if(_tcpClient != null)
55 | {
56 | _tcpClient.Close();
57 | _tcpClient = null;
58 | }
59 |
60 | OnConnectStatusChanged(TcpClientStatusEventArgs.EConnectStatus.Disconnected);
61 | }
62 |
63 | public async Task SendAsync(Transmission msg)
64 | {
65 | if(!_tcpClient.Connected)
66 | {
67 | return null;
68 | }
69 |
70 | IPEndPoint from = _tcpClient.Client.LocalEndPoint as IPEndPoint;
71 | IPEndPoint to = _tcpClient.Client.RemoteEndPoint as IPEndPoint;
72 |
73 | await _tcpClient.GetStream().WriteAsync(msg.Data, 0, msg.Length);
74 |
75 | return new TransmissionResult() { From = from, To = to };
76 | }
77 |
78 |
79 | private void StartReceive()
80 | {
81 | Task.Run(async () =>
82 | {
83 | while(_tcpClient != null)
84 | {
85 | try
86 | {
87 | int read = await _tcpClient.GetStream().ReadAsync(_buffer, 0, _buffer.Length);
88 |
89 | if(read > 0)
90 | {
91 | byte[] data = new byte[read];
92 | Array.Copy(_buffer, data, read);
93 |
94 |
95 | Transmission msg = new Transmission(data, Transmission.EType.Received);
96 | msg.Destination = _tcpClient.Client.LocalEndPoint as IPEndPoint;
97 | msg.Origin = _tcpClient.Client.RemoteEndPoint as IPEndPoint;
98 |
99 | Received?.Invoke(this, new ReceivedEventArgs(msg));
100 | }
101 | else
102 | {
103 | // server closes connection.
104 | Disconnect();
105 | break;
106 | }
107 | }
108 | catch(Exception e)
109 | when(e is ObjectDisposedException || e is InvalidOperationException)
110 | {
111 | Disconnect();
112 | break;
113 | }
114 | }
115 | });
116 | }
117 |
118 | private void OnConnectStatusChanged(TcpClientStatusEventArgs.EConnectStatus status)
119 | {
120 | IPEndPoint ep = status == TcpClientStatusEventArgs.EConnectStatus.Connected ?
121 | _tcpClient.Client.RemoteEndPoint as IPEndPoint : null;
122 |
123 | StatusChanged?.Invoke(false, new TcpClientStatusEventArgs(status, ep));
124 | }
125 |
126 | public void Dispose()
127 | {
128 | _tcpClient?.Close();
129 | _tcpClient = null;
130 | }
131 |
132 | }
133 |
134 | public class TcpClientStatusEventArgs : EventArgs
135 | {
136 | public enum EConnectStatus { Disconnected, Connecting, Connected };
137 |
138 |
139 | public EConnectStatus Status { get; private set; }
140 | public IPEndPoint RemoteEndPoint { get; private set; }
141 |
142 | public TcpClientStatusEventArgs(EConnectStatus status, IPEndPoint remoteEndPoint)
143 | {
144 | Status = status;
145 | RemoteEndPoint = remoteEndPoint;
146 | }
147 |
148 | }
149 |
150 | }
151 |
--------------------------------------------------------------------------------
/TcpUdpTool/Model/TcpServer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Net.Sockets;
6 | using System.Threading.Tasks;
7 | using TcpUdpTool.Model.Data;
8 | using TcpUdpTool.Model.EventArg;
9 |
10 | namespace TcpUdpTool.Model
11 | {
12 |
13 | public class TcpServer : IDisposable
14 | {
15 | public event EventHandler Received;
16 | public event EventHandler StatusChanged;
17 |
18 | private TcpListener _tcpServer;
19 | private List _connectedClients;
20 | private byte[] _buffer;
21 |
22 |
23 | public int NumConnectedClients
24 | {
25 | get
26 | {
27 | int count = 0;
28 | lock(_connectedClients)
29 | {
30 | count = _connectedClients.Count;
31 | }
32 |
33 | return count;
34 | }
35 | }
36 |
37 |
38 | public TcpServer()
39 | {
40 | _connectedClients = new List();
41 | _buffer = new byte[8192];
42 | }
43 |
44 | public void Start(IPAddress ip, int port)
45 | {
46 | if(_tcpServer != null)
47 | return;
48 |
49 | try
50 | {
51 | _tcpServer = new TcpListener(new IPEndPoint(ip, port));
52 | _tcpServer.Start(0);
53 | OnStatusChanged(TcpServerStatusEventArgs.EServerStatus.Started);
54 | }
55 | catch(Exception)
56 | {
57 | Stop();
58 | throw;
59 | }
60 |
61 | StartAcceptClient();
62 | }
63 |
64 | public void Stop()
65 | {
66 | Disconnect();
67 | if(_tcpServer != null)
68 | {
69 | _tcpServer.Stop();
70 | _tcpServer = null;
71 | OnStatusChanged(TcpServerStatusEventArgs.EServerStatus.Stopped);
72 | }
73 | }
74 |
75 | public async Task> SendAsync(Transmission msg)
76 | {
77 | var result = new List();
78 |
79 | List copy;
80 | lock (_connectedClients)
81 | {
82 | copy = _connectedClients.ToList();
83 | }
84 |
85 | foreach (var c in copy)
86 | {
87 | IPEndPoint from = c.Client.LocalEndPoint as IPEndPoint;
88 | IPEndPoint to = c.Client.RemoteEndPoint as IPEndPoint;
89 |
90 | try
91 | {
92 | await c.GetStream().WriteAsync(msg.Data, 0, msg.Length);
93 | result.Add(new TransmissionResult { From = from, To = to });
94 | }
95 | catch(Exception)
96 | {
97 | DisconnectClient(c);
98 | }
99 | }
100 |
101 | return result;
102 | }
103 |
104 | public void Disconnect()
105 | {
106 | // close client connection.
107 |
108 | List copy;
109 | lock(_connectedClients)
110 | {
111 | copy = _connectedClients.ToList();
112 | }
113 |
114 | foreach(var c in copy)
115 | {
116 | OnClientStatusChanged(TcpServerStatusEventArgs.EServerStatus.ClientDisconnected, c);
117 | c.Close();
118 | c.Dispose();
119 | }
120 |
121 | lock(_connectedClients)
122 | {
123 | _connectedClients.Clear();
124 | }
125 | }
126 |
127 |
128 | private void StartAcceptClient()
129 | {
130 | Task.Run(async () =>
131 | {
132 | while(_tcpServer != null)
133 | {
134 | try
135 | {
136 | var client = await _tcpServer.AcceptTcpClientAsync();
137 | lock(_connectedClients)
138 | {
139 | _connectedClients.Add(client);
140 | }
141 | OnClientStatusChanged(TcpServerStatusEventArgs.EServerStatus.ClientConnected, client);
142 | StartReceive(client);
143 | }
144 | catch(Exception ex)
145 | when(ex is SocketException || ex is ObjectDisposedException)
146 | {
147 | Stop();
148 | break;
149 | }
150 | }
151 | });
152 | }
153 |
154 | private void StartReceive(System.Net.Sockets.TcpClient client)
155 | {
156 | Task.Run(async () =>
157 | {
158 | bool stop = false;
159 | while (!stop)
160 | {
161 | try
162 | {
163 | int read = await client.GetStream().ReadAsync(_buffer, 0, _buffer.Length);
164 |
165 | if (read > 0)
166 | {
167 | byte[] data = new byte[read];
168 | Array.Copy(_buffer, data, read);
169 |
170 | Transmission msg = new Transmission(data, Transmission.EType.Received);
171 | msg.Destination = client.Client.LocalEndPoint as IPEndPoint;
172 | msg.Origin = client.Client.RemoteEndPoint as IPEndPoint;
173 |
174 | Received?.Invoke(this, new ReceivedEventArgs(msg));
175 | }
176 | else
177 | {
178 | // server closed connection.
179 | DisconnectClient(client);
180 | stop = true;
181 | }
182 | }
183 | catch (Exception e)
184 | when (e is ObjectDisposedException || e is InvalidOperationException)
185 | {
186 | DisconnectClient(client);
187 | stop = true;
188 | }
189 | }
190 | });
191 | }
192 |
193 | private void OnStatusChanged(TcpServerStatusEventArgs.EServerStatus status)
194 | {
195 | StatusChanged?.Invoke(this, new TcpServerStatusEventArgs(status,
196 | _tcpServer?.LocalEndpoint as IPEndPoint, null));
197 | }
198 |
199 | private void OnClientStatusChanged(TcpServerStatusEventArgs.EServerStatus status, System.Net.Sockets.TcpClient client)
200 | {
201 | StatusChanged?.Invoke(this, new TcpServerStatusEventArgs(status,
202 | _tcpServer?.LocalEndpoint as IPEndPoint, client.Client.RemoteEndPoint as IPEndPoint));
203 | }
204 |
205 | private void DisconnectClient(System.Net.Sockets.TcpClient client)
206 | {
207 | lock(_connectedClients)
208 | {
209 | _connectedClients.Remove(client);
210 | }
211 |
212 | OnClientStatusChanged(TcpServerStatusEventArgs.EServerStatus.ClientDisconnected, client);
213 | client.Close();
214 | client.Dispose();
215 | }
216 |
217 | public void Dispose()
218 | {
219 | lock (_connectedClients)
220 | {
221 | foreach (var c in _connectedClients)
222 | {
223 | c.Close();
224 | c.Dispose();
225 | }
226 |
227 | _connectedClients.Clear();
228 | }
229 |
230 | _tcpServer?.Stop();
231 | _tcpServer = null;
232 | }
233 | }
234 |
235 | public class TcpServerStatusEventArgs : EventArgs
236 | {
237 | public enum EServerStatus { Started, Stopped, ClientConnected, ClientDisconnected }
238 |
239 | public EServerStatus Status { get; private set; }
240 | public IPEndPoint ServerInfo { get; private set; }
241 | public IPEndPoint ClientInfo { get; private set; }
242 |
243 |
244 | public TcpServerStatusEventArgs(EServerStatus status, IPEndPoint serverInfo, IPEndPoint clientInfo = null)
245 | {
246 | Status = status;
247 | ServerInfo = serverInfo;
248 | ClientInfo = clientInfo;
249 | }
250 | }
251 |
252 | }
253 |
--------------------------------------------------------------------------------
/TcpUdpTool/Model/UdpClientServer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Net.Sockets;
4 | using System.Threading.Tasks;
5 | using TcpUdpTool.Model.Data;
6 | using TcpUdpTool.Model.EventArg;
7 | using TcpUdpTool.Model.Util;
8 |
9 | namespace TcpUdpTool.Model
10 | {
11 | public class UdpClientServer : IDisposable
12 | {
13 | private UdpClient _udpClient;
14 |
15 | public event EventHandler Received;
16 | public event EventHandler StatusChanged;
17 |
18 |
19 | public UdpClientServer()
20 | {
21 |
22 | }
23 |
24 | public void Start(IPAddress ip, int port)
25 | {
26 | if (_udpClient != null)
27 | return;
28 |
29 | _udpClient = new UdpClient(ip.AddressFamily);
30 | _udpClient.EnableBroadcast = true;
31 |
32 | _udpClient.Client.SetSocketOption(
33 | SocketOptionLevel.Socket,
34 | SocketOptionName.ReuseAddress,
35 | true
36 | );
37 |
38 | _udpClient.Client.Bind(new IPEndPoint(ip, port));
39 |
40 | StatusChanged?.Invoke(this, new UdpClientServerStatusEventArgs(
41 | UdpClientServerStatusEventArgs.EServerStatus.Started,
42 | _udpClient.Client.LocalEndPoint as IPEndPoint));
43 |
44 | StartReceive();
45 | }
46 |
47 | public void Stop()
48 | {
49 | if(_udpClient != null)
50 | {
51 | _udpClient.Close();
52 | _udpClient = null;
53 |
54 | StatusChanged?.Invoke(this, new UdpClientServerStatusEventArgs(
55 | UdpClientServerStatusEventArgs.EServerStatus.Stopped));
56 | }
57 | }
58 |
59 | public async Task SendAsync(string host, int port, Transmission msg)
60 | {
61 | // resolve, prefer ipv6 if currently in use.
62 | IPAddress addr = await NetworkUtils.DnsResolveAsync(host, _udpClient != null &&
63 | _udpClient.Client.LocalEndPoint.AddressFamily == AddressFamily.InterNetworkV6);
64 |
65 | IPEndPoint from = null;
66 | IPEndPoint to = new IPEndPoint(addr, port);
67 |
68 | if(_udpClient != null)
69 | {
70 | if(_udpClient.Client.AddressFamily != addr.AddressFamily)
71 | {
72 | Func IpvToString = (family) =>
73 | {
74 | return family == AddressFamily.InterNetworkV6 ? "IPv6" : "IPv4";
75 | };
76 |
77 | throw new InvalidOperationException(
78 | "Cannot send UDP packet using " + IpvToString(addr.AddressFamily) +
79 | " when bound to an " + IpvToString(_udpClient.Client.AddressFamily) + " interface.");
80 | }
81 |
82 | from = _udpClient.Client.LocalEndPoint as IPEndPoint;
83 | await _udpClient.SendAsync(msg.Data, msg.Data.Length, to);
84 | }
85 | else
86 | {
87 | // send from new udp client, don't care about any response
88 | // since we are not listening.
89 | using (UdpClient tmpClient = new UdpClient(addr.AddressFamily))
90 | {
91 | from = tmpClient.Client.LocalEndPoint as IPEndPoint;
92 | tmpClient.EnableBroadcast = true;
93 | await tmpClient.SendAsync(msg.Data, msg.Data.Length, to);
94 | }
95 | }
96 |
97 | return new TransmissionResult() { From = from, To = to };
98 | }
99 |
100 |
101 | private void StartReceive()
102 | {
103 | Task.Run(async () =>
104 | {
105 | while (_udpClient != null)
106 | {
107 | try
108 | {
109 | UdpReceiveResult res = await _udpClient.ReceiveAsync();
110 |
111 | Transmission msg = new Transmission(res.Buffer, Transmission.EType.Received);
112 | msg.Origin = res.RemoteEndPoint;
113 | msg.Destination = _udpClient.Client.LocalEndPoint as IPEndPoint;
114 |
115 | Received?.Invoke(this, new ReceivedEventArgs(msg));
116 | }
117 | catch (SocketException ex)
118 | {
119 | // Ignore this error, triggered after sending
120 | // a packet to an unreachable port. UDP is not
121 | // reliable anyway, this can safetly be ignored.
122 | if(ex.ErrorCode != 10054)
123 | {
124 | Stop();
125 | break;
126 | }
127 | }
128 | catch(Exception)
129 | {
130 | Stop();
131 | break; // end receive;
132 | }
133 | }
134 | });
135 | }
136 |
137 | public void Dispose()
138 | {
139 | _udpClient?.Close();
140 | _udpClient = null;
141 | }
142 | }
143 |
144 | public class UdpClientServerStatusEventArgs : EventArgs
145 | {
146 | public enum EServerStatus { Started, Stopped };
147 |
148 | public EServerStatus ServerStatus { get; private set; }
149 | public IPEndPoint ServerInfo { get; private set; }
150 |
151 | public UdpClientServerStatusEventArgs(EServerStatus status, IPEndPoint info = null)
152 | {
153 | ServerStatus = status;
154 | ServerInfo = info;
155 | }
156 | }
157 |
158 | }
159 |
--------------------------------------------------------------------------------
/TcpUdpTool/Model/Util/DialogUtils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 |
8 | namespace TcpUdpTool.Model.Util
9 | {
10 | public class DialogUtils
11 | {
12 |
13 | public static void ShowErrorDialog(string message)
14 | {
15 | MessageBox.Show(message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
16 | }
17 |
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/TcpUdpTool/Model/Util/NetworkUtils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Net.NetworkInformation;
6 | using System.Net.Sockets;
7 | using System.Threading.Tasks;
8 |
9 | namespace TcpUdpTool.Model.Util
10 | {
11 |
12 | public static class NetworkUtils
13 | {
14 |
15 | public static event Action NetworkInterfaceChange;
16 |
17 | static NetworkUtils()
18 | {
19 | NetworkChange.NetworkAddressChanged += (s, e) => NetworkInterfaceChange?.Invoke();
20 | NetworkChange.NetworkAvailabilityChanged += (s, e) => NetworkInterfaceChange?.Invoke();
21 | }
22 |
23 | public static List GetActiveInterfaces()
24 | {
25 | var result = new List();
26 |
27 | foreach (var adapter in System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces())
28 | {
29 | if ((!adapter.Supports(NetworkInterfaceComponent.IPv4) &&
30 | !adapter.Supports(NetworkInterfaceComponent.IPv6)) ||
31 | adapter.OperationalStatus != OperationalStatus.Up)
32 | {
33 | continue;
34 | }
35 |
36 | var ni = new NetworkInterface();
37 | ni.Id = adapter.Id;
38 | ni.Name = adapter.Name;
39 | ni.Description = adapter.Description;
40 |
41 | var aip = adapter.GetIPProperties();
42 |
43 | if (adapter.Supports(NetworkInterfaceComponent.IPv4))
44 | {
45 | ni.IPv4.Index = aip.GetIPv4Properties().Index;
46 | }
47 |
48 | if (adapter.Supports(NetworkInterfaceComponent.IPv6))
49 | {
50 | ni.IPv6.Index = aip.GetIPv6Properties().Index;
51 | }
52 |
53 | foreach (var uip in aip.UnicastAddresses)
54 | {
55 | if (uip.Address.AddressFamily == AddressFamily.InterNetwork)
56 | {
57 | ni.IPv4.Addresses.Add(uip.Address);
58 | }
59 | else if (uip.Address.AddressFamily == AddressFamily.InterNetworkV6)
60 | {
61 | ni.IPv6.Addresses.Add(uip.Address);
62 | }
63 | }
64 |
65 | result.Add(ni);
66 | }
67 |
68 | return result;
69 | }
70 |
71 | public static int GetBestMulticastInterfaceIndex(IPAddress localInterface)
72 | {
73 | var interfaces = GetActiveInterfaces();
74 | foreach(var intf in interfaces)
75 | {
76 | if (localInterface.AddressFamily == AddressFamily.InterNetwork)
77 | {
78 | if (intf.IPv4.Addresses.Contains(localInterface))
79 | {
80 | return intf.IPv4.Index;
81 | }
82 | }
83 | else if (localInterface.AddressFamily == AddressFamily.InterNetworkV6)
84 | {
85 | if (intf.IPv6.Addresses.Contains(localInterface))
86 | {
87 | return intf.IPv6.Index;
88 | }
89 | }
90 | }
91 |
92 | return -1;
93 | }
94 |
95 | public static bool IsMulticast(IPAddress ipAddress)
96 | {
97 | bool isMulticast = false;
98 |
99 | if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
100 | {
101 | // In IPv6 Multicast addresses first byte is 0xFF
102 | byte[] bytes = ipAddress.GetAddressBytes();
103 | isMulticast = (bytes[0] == 0xff);
104 | }
105 | else if (ipAddress.AddressFamily == AddressFamily.InterNetwork)
106 | {
107 | // In IPv4 Multicast addresses first byte is between 224 and 239
108 | byte[] bytes = ipAddress.GetAddressBytes();
109 | isMulticast = (bytes[0] >= 224) && (bytes[0] <= 239);
110 | }
111 |
112 | return isMulticast;
113 | }
114 |
115 | public static bool IsSourceSpecificMulticast(IPAddress ipAddress)
116 | {
117 | bool isSSM = false;
118 |
119 | if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
120 | {
121 | // In IPv6 SSM first byte is 0xFF and second byte is 0x3X
122 | byte[] bytes = ipAddress.GetAddressBytes();
123 | isSSM = (bytes[0] == 0xff && (bytes[1] >> 4) == 0x03);
124 | }
125 | else if (ipAddress.AddressFamily == AddressFamily.InterNetwork)
126 | {
127 | // In IPv4 SSM first byte is 232
128 | byte[] addressBytes = ipAddress.GetAddressBytes();
129 | isSSM = addressBytes[0] == 232;
130 | }
131 |
132 | return isSSM;
133 | }
134 |
135 | public static bool IsValidPort(int port, bool allowZero = false)
136 | {
137 | return (port >= (allowZero ? 0 : 1)) && port < 65536;
138 | }
139 |
140 | public static async Task DnsResolveAsync(string hostOrAddress, bool favorIpV6 = false)
141 | {
142 | var favoredFamily = favorIpV6 ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork;
143 | var addrs = await Dns.GetHostAddressesAsync(hostOrAddress);
144 | return addrs.FirstOrDefault(addr => addr.AddressFamily == favoredFamily)
145 | ?? addrs.FirstOrDefault();
146 | }
147 |
148 | }
149 |
150 | public class NetworkInterface
151 | {
152 | public class IPInterface
153 | {
154 | public IPInterface()
155 | {
156 | Index = -1;
157 | Addresses = new List();
158 | }
159 |
160 | public int Index { get; set; }
161 | public List Addresses { get; }
162 | }
163 |
164 | public NetworkInterface()
165 | {
166 | IPv4 = new IPInterface();
167 | IPv6 = new IPInterface();
168 | }
169 |
170 | public string Id { get; set; }
171 |
172 | public string Name { get; set; }
173 |
174 | public string Description { get; set; }
175 |
176 | public IPInterface IPv4 { get; private set; }
177 |
178 | public IPInterface IPv6 { get; private set; }
179 |
180 | }
181 |
182 | }
183 |
--------------------------------------------------------------------------------
/TcpUdpTool/Model/Util/SettingsUtils.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 |
3 | namespace TcpUdpTool.Model.Util
4 | {
5 | class SettingsUtils
6 | {
7 | public static Encoding GetEncoding()
8 | {
9 | int codePage = Properties.Settings.Default.Encoding;
10 | if(codePage == 0)
11 | {
12 | return Encoding.Default;
13 | }
14 |
15 | return Encoding.GetEncoding(codePage);
16 | }
17 |
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/TcpUdpTool/Model/Util/StringFormatUtils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | namespace TcpUdpTool.Model.Util
3 | {
4 | public class StringFormatUtils
5 | {
6 |
7 | public static string GetSizeAsString(ulong bytes)
8 | {
9 | ulong B = 0, KB = 1024, MB = KB * 1024, GB = MB * 1024, TB = GB * 1024;
10 | double size = bytes;
11 | string suffix = nameof(B);
12 |
13 | if (bytes >= TB)
14 | {
15 | size = Math.Round((double)bytes / TB, 2);
16 | suffix = nameof(TB);
17 | }
18 | else if (bytes >= GB)
19 | {
20 | size = Math.Round((double)bytes / GB, 2);
21 | suffix = nameof(GB);
22 | }
23 | else if (bytes >= MB)
24 | {
25 | size = Math.Round((double)bytes / MB, 2);
26 | suffix = nameof(MB);
27 | }
28 | else if (bytes >= KB)
29 | {
30 | size = Math.Round((double)bytes / KB, 2);
31 | suffix = nameof(KB);
32 | }
33 |
34 | return $"{size} {suffix}";
35 | }
36 |
37 | public static string GetRateAsString(ulong bitsPerSecond)
38 | {
39 | ulong b = 0, Kb = 1000, Mb = Kb * 1000, Gb = Mb * 1000, Tb = Gb * 1000;
40 | double rate = bitsPerSecond;
41 | string suffix = nameof(b);
42 |
43 | if (bitsPerSecond >= Tb)
44 | {
45 | rate = Math.Round((double)bitsPerSecond / Tb, 2);
46 | suffix = nameof(Tb);
47 | }
48 | else if (bitsPerSecond >= Gb)
49 | {
50 | rate = Math.Round((double)bitsPerSecond / Gb, 2);
51 | suffix = nameof(Gb);
52 | }
53 | else if (bitsPerSecond >= Mb)
54 | {
55 | rate = Math.Round((double)bitsPerSecond / Mb, 2);
56 | suffix = nameof(Mb);
57 | }
58 | else if (bitsPerSecond >= Kb)
59 | {
60 | rate = Math.Round((double)bitsPerSecond / Kb, 2);
61 | suffix = nameof(Kb);
62 | }
63 |
64 | return $"{rate} {suffix}ps";
65 | }
66 |
67 |
68 |
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/TcpUdpTool/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Resources;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using System.Windows;
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | [assembly: AssemblyTitle("TcpUdpTool")]
11 | [assembly: AssemblyDescription("")]
12 | [assembly: AssemblyConfiguration("")]
13 | [assembly: AssemblyCompany("Daniel Nilsson")]
14 | [assembly: AssemblyProduct("TcpUdpTool")]
15 | [assembly: AssemblyCopyright("Copyright © 2022 Daniel Nilsson")]
16 | [assembly: AssemblyTrademark("")]
17 | [assembly: AssemblyCulture("")]
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | [assembly: ComVisible(false)]
23 |
24 | //In order to begin building localizable applications, set
25 | //CultureYouAreCodingWith in your .csproj file
26 | //inside a . For example, if you are using US english
27 | //in your source files, set the to en-US. Then uncomment
28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in
29 | //the line below to match the UICulture setting in the project file.
30 |
31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
32 |
33 |
34 | [assembly: ThemeInfo(
35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
36 | //(used if a resource is not found in the page,
37 | // or application resource dictionaries)
38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
39 | //(used if a resource is not found in the page,
40 | // app, or any theme specific resource dictionaries)
41 | )]
42 |
43 |
44 | // Version information for an assembly consists of the following four values:
45 | //
46 | // Major Version
47 | // Minor Version
48 | // Build Number
49 | // Revision
50 | //
51 | // You can specify all the values or you can default the Build and Revision Numbers
52 | // by using the '*' as shown below:
53 | // [assembly: AssemblyVersion("1.0.*")]
54 | [assembly: AssemblyVersion("1.1.0.0")]
55 | [assembly: AssemblyFileVersion("1.1.0.0")]
56 | [assembly: NeutralResourcesLanguage("en")]
57 |
58 |
--------------------------------------------------------------------------------
/TcpUdpTool/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace TcpUdpTool.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("TcpUdpTool.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/TcpUdpTool/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 |
--------------------------------------------------------------------------------
/TcpUdpTool/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace TcpUdpTool.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.10.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 |
26 | [global::System.Configuration.UserScopedSettingAttribute()]
27 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
28 | [global::System.Configuration.DefaultSettingValueAttribute("65001")]
29 | public int Encoding {
30 | get {
31 | return ((int)(this["Encoding"]));
32 | }
33 | set {
34 | this["Encoding"] = value;
35 | }
36 | }
37 |
38 | [global::System.Configuration.UserScopedSettingAttribute()]
39 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
40 | [global::System.Configuration.DefaultSettingValueAttribute("False")]
41 | public bool IPv6Support {
42 | get {
43 | return ((bool)(this["IPv6Support"]));
44 | }
45 | set {
46 | this["IPv6Support"] = value;
47 | }
48 | }
49 |
50 | [global::System.Configuration.UserScopedSettingAttribute()]
51 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
52 | [global::System.Configuration.DefaultSettingValueAttribute("100")]
53 | public int HistoryEntries {
54 | get {
55 | return ((int)(this["HistoryEntries"]));
56 | }
57 | set {
58 | this["HistoryEntries"] = value;
59 | }
60 | }
61 |
62 | [global::System.Configuration.UserScopedSettingAttribute()]
63 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
64 | [global::System.Configuration.DefaultSettingValueAttribute("True")]
65 | public bool HistoryInfoTimestamp {
66 | get {
67 | return ((bool)(this["HistoryInfoTimestamp"]));
68 | }
69 | set {
70 | this["HistoryInfoTimestamp"] = value;
71 | }
72 | }
73 |
74 | [global::System.Configuration.UserScopedSettingAttribute()]
75 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
76 | [global::System.Configuration.DefaultSettingValueAttribute("True")]
77 | public bool HistoryInfoIpAdress {
78 | get {
79 | return ((bool)(this["HistoryInfoIpAdress"]));
80 | }
81 | set {
82 | this["HistoryInfoIpAdress"] = value;
83 | }
84 | }
85 |
86 | [global::System.Configuration.UserScopedSettingAttribute()]
87 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
88 | [global::System.Configuration.DefaultSettingValueAttribute("True")]
89 | public bool ScrollToEnd {
90 | get {
91 | return ((bool)(this["ScrollToEnd"]));
92 | }
93 | set {
94 | this["ScrollToEnd"] = value;
95 | }
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/TcpUdpTool/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 65001
7 |
8 |
9 | False
10 |
11 |
12 | 100
13 |
14 |
15 | True
16 |
17 |
18 | True
19 |
20 |
21 | True
22 |
23 |
24 |
--------------------------------------------------------------------------------
/TcpUdpTool/Resources/Icons.xaml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
21 |
22 |
38 |
39 |
55 |
56 |
--------------------------------------------------------------------------------
/TcpUdpTool/Resources/Styles.xaml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
54 |
55 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/TcpUdpTool/Resources/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danielnilsson9/tcp-udp-tool/1a115ad0c43b9d908118f85b9748b075753cb52d/TcpUdpTool/Resources/icon.ico
--------------------------------------------------------------------------------
/TcpUdpTool/TcpUdpTool.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {C3FF0B8C-0EAF-41EF-AEF6-C8C597CF0A7F}
8 | WinExe
9 | Properties
10 | TcpUdpTool
11 | TcpUdpTool
12 | v4.8
13 | 512
14 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
15 | 4
16 | true
17 | publish\
18 | true
19 | Disk
20 | false
21 | Foreground
22 | 7
23 | Days
24 | false
25 | false
26 | true
27 | 0
28 | 1.0.0.%2a
29 | false
30 | false
31 | true
32 |
33 |
34 |
35 | AnyCPU
36 | true
37 | full
38 | false
39 | bin\Debug\
40 | DEBUG;TRACE
41 | prompt
42 | 4
43 |
44 |
45 | AnyCPU
46 | pdbonly
47 | true
48 | bin\Release\
49 | TRACE
50 | prompt
51 | 4
52 |
53 |
54 | Resources\icon.ico
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | 4.0
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | MSBuild:Compile
75 | Designer
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 | HelpView.xaml
115 |
116 |
117 | HistoryView.xaml
118 |
119 |
120 | SettingsView.xaml
121 |
122 |
123 | TcpClientView.xaml
124 |
125 |
126 | TcpServerView.xaml
127 |
128 |
129 | UdpSsmView.xaml
130 |
131 |
132 | UdpAsmView.xaml
133 |
134 |
135 | UdpView.xaml
136 |
137 |
138 | Designer
139 | MSBuild:Compile
140 |
141 |
142 | Designer
143 | MSBuild:Compile
144 |
145 |
146 | Designer
147 | MSBuild:Compile
148 |
149 |
150 | MSBuild:Compile
151 | Designer
152 |
153 |
154 | App.xaml
155 | Code
156 |
157 |
158 | MainWindow.xaml
159 | Code
160 |
161 |
162 | Designer
163 | MSBuild:Compile
164 |
165 |
166 | Designer
167 | MSBuild:Compile
168 |
169 |
170 | Designer
171 | MSBuild:Compile
172 |
173 |
174 | Designer
175 | MSBuild:Compile
176 |
177 |
178 | MSBuild:Compile
179 | Designer
180 |
181 |
182 | Designer
183 | MSBuild:Compile
184 |
185 |
186 | Designer
187 | MSBuild:Compile
188 |
189 |
190 |
191 |
192 | Code
193 |
194 |
195 | True
196 | True
197 | Resources.resx
198 |
199 |
200 | True
201 | Settings.settings
202 | True
203 |
204 |
205 | ResXFileCodeGenerator
206 | Resources.Designer.cs
207 | Designer
208 |
209 |
210 | SettingsSingleFileGenerator
211 | Settings.Designer.cs
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 | False
221 | Microsoft .NET Framework 4.5.2 %28x86 and x64%29
222 | true
223 |
224 |
225 | False
226 | .NET Framework 3.5 SP1
227 | false
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
242 |
--------------------------------------------------------------------------------
/TcpUdpTool/View/HelpView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Controls;
2 |
3 | namespace TcpUdpTool.View
4 | {
5 | ///
6 | /// Interaction logic for HelpView.xaml
7 | ///
8 | public partial class HelpView : UserControl
9 | {
10 | public HelpView()
11 | {
12 | InitializeComponent();
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/TcpUdpTool/View/HistoryView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Controls;
2 |
3 | namespace TcpUdpTool.View
4 | {
5 | ///
6 | /// Interaction logic for TcpClientView.xaml
7 | ///
8 | public partial class HistoryView : UserControl
9 | {
10 | public HistoryView()
11 | {
12 | InitializeComponent();
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/TcpUdpTool/View/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
24 |
25 |
26 |
27 |
29 |
30 |
31 |
32 |
34 |
35 |
36 |
37 |
39 |
40 |
41 |
42 |
44 |
45 |
46 |
47 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/TcpUdpTool/View/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace TcpUdpTool.View
4 | {
5 | ///
6 | /// Interaction logic for MainWindow.xaml
7 | ///
8 | public partial class MainWindow : Window
9 | {
10 |
11 | public MainWindow()
12 | {
13 | InitializeComponent();
14 | }
15 |
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/TcpUdpTool/View/SettingsView.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
39 |
40 |
47 |
48 |
51 |
52 |
57 |
58 |
60 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
90 |
91 |
94 |
101 |
102 |
103 |
104 |
105 |
108 |
109 |
114 |
115 |
117 |
120 |
121 |
122 |
126 |
127 |
133 |
134 |
137 |
138 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
--------------------------------------------------------------------------------
/TcpUdpTool/View/SettingsView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Navigation;
14 | using System.Windows.Shapes;
15 |
16 | namespace TcpUdpTool.View
17 | {
18 | ///
19 | /// Interaction logic for SettingsView.xaml
20 | ///
21 | public partial class SettingsView : UserControl
22 | {
23 | public SettingsView()
24 | {
25 | InitializeComponent();
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/TcpUdpTool/View/TcpClientView.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
37 |
38 |
46 |
47 |
52 |
53 |
60 |
61 |
84 |
85 |
86 |
87 |
91 |
92 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
116 |
117 |
118 |
126 |
127 |
128 |
129 |
139 |
140 |
160 |
161 |
170 |
171 |
178 |
179 |
185 |
186 |
190 |
191 |
195 |
196 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
--------------------------------------------------------------------------------
/TcpUdpTool/View/TcpClientView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Controls;
2 |
3 | namespace TcpUdpTool.View
4 | {
5 | ///
6 | /// Interaction logic for TcpClientView.xaml
7 | ///
8 | public partial class TcpClientView : UserControl
9 | {
10 | public TcpClientView()
11 | {
12 | InitializeComponent();
13 | }
14 |
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/TcpUdpTool/View/TcpServerView.xaml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
50 |
51 |
61 |
62 |
63 |
66 |
67 |
68 |
69 |
74 |
75 |
82 |
83 |
103 |
104 |
105 |
106 |
107 |
108 |
112 |
113 |
114 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
138 |
139 |
147 |
148 |
149 |
150 |
159 |
160 |
180 |
181 |
189 |
190 |
197 |
198 |
203 |
204 |
208 |
209 |
213 |
214 |
218 |
219 |
220 |
221 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
--------------------------------------------------------------------------------
/TcpUdpTool/View/TcpServerView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Navigation;
14 | using System.Windows.Shapes;
15 |
16 | namespace TcpUdpTool.View
17 | {
18 | ///
19 | /// Interaction logic for TcpServerView.xaml
20 | ///
21 | public partial class TcpServerView : UserControl
22 | {
23 | public TcpServerView()
24 | {
25 | InitializeComponent();
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/TcpUdpTool/View/UdpAsmView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Controls;
2 |
3 | namespace TcpUdpTool.View
4 | {
5 | ///
6 | /// Interaction logic for UdpMulticastView.xaml
7 | ///
8 | public partial class UdpAsmView : UserControl
9 | {
10 | public UdpAsmView()
11 | {
12 | InitializeComponent();
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/TcpUdpTool/View/UdpSsmView.xaml:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
63 |
64 |
72 |
73 |
80 |
81 |
90 |
91 |
97 |
98 |
107 |
108 |
115 |
116 |
126 |
127 |
128 |
131 |
132 |
133 |
134 |
154 |
155 |
156 |
157 |
162 |
163 |
164 |
165 |
--------------------------------------------------------------------------------
/TcpUdpTool/View/UdpSsmView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Controls;
2 |
3 | namespace TcpUdpTool.View
4 | {
5 | ///
6 | /// Interaction logic for UdpMulticastView.xaml
7 | ///
8 | public partial class UdpSsmView : UserControl
9 | {
10 | public UdpSsmView()
11 | {
12 | InitializeComponent();
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/TcpUdpTool/View/UdpView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Navigation;
14 | using System.Windows.Shapes;
15 |
16 | namespace TcpUdpTool.View
17 | {
18 | ///
19 | /// Interaction logic for UdpView.xaml
20 | ///
21 | public partial class UdpView : UserControl
22 | {
23 | public UdpView()
24 | {
25 | InitializeComponent();
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/TcpUdpTool/ViewModel/Base/BatchObservableCollection.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Collections.ObjectModel;
4 | using System.Collections.Specialized;
5 | using System.ComponentModel;
6 |
7 | namespace TcpUdpTool.ViewModel.Base
8 | {
9 | public class BatchObservableCollection : Collection, INotifyCollectionChanged, INotifyPropertyChanged
10 | {
11 | private int _batchOperationCount;
12 | private bool _changedDuringBatchOperation;
13 |
14 | public event NotifyCollectionChangedEventHandler CollectionChanged;
15 | public event PropertyChangedEventHandler PropertyChanged;
16 |
17 |
18 | public void BeginBatch()
19 | {
20 | _batchOperationCount++;
21 | }
22 |
23 | public void EndBatch()
24 | {
25 | if (_batchOperationCount == 0)
26 | {
27 | throw new InvalidOperationException("EndBatch() called without a matching call to BeginBatch().");
28 | }
29 |
30 | _batchOperationCount--;
31 |
32 | if (_batchOperationCount == 0 && _changedDuringBatchOperation)
33 | {
34 | OnCollectionReset();
35 | _changedDuringBatchOperation = false;
36 | }
37 | }
38 |
39 | public void AddRange(IEnumerable items)
40 | {
41 | if (items == null)
42 | {
43 | return;
44 | }
45 |
46 | BeginBatch();
47 | try
48 | {
49 | var list = items as IList;
50 | if (list != null)
51 | {
52 | for (var i = 0; i < list.Count; i++)
53 | {
54 | Add(list[i]);
55 | }
56 | }
57 | else
58 | {
59 | {
60 | foreach (var item in items)
61 | {
62 | Add(item);
63 | }
64 | }
65 | }
66 | }
67 | finally
68 | {
69 | EndBatch();
70 | }
71 | }
72 |
73 | protected override void ClearItems()
74 | {
75 | var hadItems = Count != 0;
76 |
77 | base.ClearItems();
78 |
79 | if (hadItems)
80 | {
81 | if (_batchOperationCount == 0)
82 | {
83 | OnCollectionReset();
84 | }
85 | else
86 | {
87 | _changedDuringBatchOperation = true;
88 | }
89 | }
90 | }
91 |
92 | protected override void InsertItem(int index, T item)
93 | {
94 | base.InsertItem(index, item);
95 |
96 | if (_batchOperationCount == 0)
97 | {
98 | OnCountChanged();
99 | OnCollectionChanged(NotifyCollectionChangedAction.Add, item, index);
100 | }
101 | else
102 | {
103 | _changedDuringBatchOperation = true;
104 | }
105 | }
106 |
107 | protected override void RemoveItem(int index)
108 | {
109 | var item = this[index];
110 | base.RemoveItem(index);
111 |
112 | if (_batchOperationCount == 0)
113 | {
114 | OnCountChanged();
115 | OnCollectionChanged(NotifyCollectionChangedAction.Remove, item, index);
116 | }
117 | else
118 | {
119 | _changedDuringBatchOperation = true;
120 | }
121 | }
122 |
123 | protected override void SetItem(int index, T item)
124 | {
125 | var oldItem = this[index];
126 | base.SetItem(index, item);
127 |
128 | if (_batchOperationCount == 0)
129 | {
130 | OnItemsChanged();
131 | OnCollectionChanged(NotifyCollectionChangedAction.Replace, item, oldItem, index);
132 | }
133 | else
134 | {
135 | _changedDuringBatchOperation = true;
136 | }
137 | }
138 |
139 | protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
140 | {
141 | CollectionChanged?.Invoke(this, e);
142 | }
143 |
144 | protected virtual void OnPropertyChanged(string name)
145 | {
146 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
147 | }
148 |
149 | private void OnCollectionChanged(NotifyCollectionChangedAction action, T item, int index)
150 | {
151 | OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item, index));
152 | }
153 |
154 | private void OnCollectionChanged(NotifyCollectionChangedAction action, T item, T oldItem, int index)
155 | {
156 | OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item, oldItem, index));
157 | }
158 |
159 | private void OnCollectionReset()
160 | {
161 | OnCountChanged();
162 | OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
163 | }
164 |
165 | private void OnCountChanged()
166 | {
167 | OnPropertyChanged("Count");
168 | OnItemsChanged();
169 | }
170 |
171 | private void OnItemsChanged()
172 | {
173 | OnPropertyChanged("Items[]");
174 | }
175 |
176 | }
177 | }
178 |
--------------------------------------------------------------------------------
/TcpUdpTool/ViewModel/Base/DelegateCommand.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Input;
3 |
4 | namespace TcpUdpTool.ViewModel.Base
5 | {
6 | public class DelegateCommand : ICommand
7 | {
8 | private readonly Action _action;
9 | private readonly Action