MainWindowViewModel.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. using DynamicData;
  2. using DynamicData.Binding;
  3. using ReactiveUI;
  4. using ReactiveUI.Fody.Helpers;
  5. using STUN.Client;
  6. using STUN.Enums;
  7. using STUN.Proxy;
  8. using STUN.StunResult;
  9. using STUN.Utils;
  10. using System;
  11. using System.Collections.Generic;
  12. using System.IO;
  13. using System.Linq;
  14. using System.Net;
  15. using System.Reactive;
  16. using System.Reactive.Linq;
  17. using System.Threading;
  18. using System.Threading.Tasks;
  19. namespace NatTypeTester.ViewModels
  20. {
  21. public class MainWindowViewModel : ReactiveObject
  22. {
  23. #region RFC3489
  24. [Reactive]
  25. public ClassicStunResult Result3489 { get; set; }
  26. public ReactiveCommand<Unit, Unit> TestClassicNatType { get; }
  27. #endregion
  28. #region RFC5780
  29. [Reactive]
  30. public StunResult5389 Result5389 { get; set; }
  31. public ReactiveCommand<Unit, Unit> DiscoveryNatType { get; }
  32. #endregion
  33. #region Servers
  34. [Reactive]
  35. public string StunServer { get; set; } = @"stun.syncthing.net";
  36. private readonly IEnumerable<string> _defaultServers = new HashSet<string>
  37. {
  38. @"stun.syncthing.net",
  39. @"stun.qq.com",
  40. @"stun.miwifi.com",
  41. @"stun.bige0.com",
  42. @"stun.stunprotocol.org"
  43. };
  44. private SourceList<string> List { get; } = new();
  45. public readonly IObservableCollection<string> StunServers = new ObservableCollectionExtended<string>();
  46. #endregion
  47. #region Proxy
  48. [Reactive]
  49. public ProxyType ProxyType { get; set; } = ProxyType.Socks5;
  50. [Reactive]
  51. public string ProxyServer { get; set; } = @"127.0.0.1:1080";
  52. [Reactive]
  53. public string? ProxyUser { get; set; }
  54. [Reactive]
  55. public string? ProxyPassword { get; set; }
  56. #endregion
  57. public MainWindowViewModel()
  58. {
  59. Result3489 = new ClassicStunResult
  60. {
  61. LocalEndPoint = new IPEndPoint(IPAddress.Any, 0)
  62. };
  63. Result5389 = new StunResult5389
  64. {
  65. LocalEndPoint = new IPEndPoint(IPAddress.Any, 0)
  66. };
  67. LoadStunServer();
  68. List.Connect()
  69. .DistinctValues(x => x)
  70. .ObserveOnDispatcher()
  71. .Bind(StunServers)
  72. .Subscribe();
  73. TestClassicNatType = ReactiveCommand.CreateFromTask(TestClassicNatTypeImpl);
  74. DiscoveryNatType = ReactiveCommand.CreateFromTask(DiscoveryNatTypeImpl);
  75. }
  76. private async void LoadStunServer()
  77. {
  78. foreach (var server in _defaultServers)
  79. {
  80. List.Add(server);
  81. }
  82. StunServer = _defaultServers.First();
  83. const string path = @"stun.txt";
  84. if (!File.Exists(path))
  85. {
  86. return;
  87. }
  88. using var sw = new StreamReader(path);
  89. string line;
  90. var stun = new StunServer();
  91. while ((line = await sw.ReadLineAsync()) != null)
  92. {
  93. if (!string.IsNullOrWhiteSpace(line) && stun.Parse(line))
  94. {
  95. List.Add(stun.ToString());
  96. }
  97. }
  98. }
  99. private async Task TestClassicNatTypeImpl(CancellationToken token)
  100. {
  101. try
  102. {
  103. var server = new StunServer();
  104. if (server.Parse(StunServer))
  105. {
  106. using var proxy = ProxyFactory.CreateProxy(
  107. ProxyType,
  108. Result3489.LocalEndPoint,
  109. NetUtils.ParseEndpoint(ProxyServer),
  110. ProxyUser, ProxyPassword
  111. );
  112. using var client = new StunClient3489(server.Hostname, server.Port, Result3489.LocalEndPoint, proxy);
  113. Result3489 = client.Status;
  114. await client.Query3489Async();
  115. Result3489.LocalEndPoint = client.LocalEndPoint;
  116. }
  117. else
  118. {
  119. throw new Exception(@"Wrong STUN Server!");
  120. }
  121. }
  122. catch (Exception ex)
  123. {
  124. //TODO MessageBox.Show(ex.Message, nameof(NatTypeTester), MessageBoxButton.OK, MessageBoxImage.Error);
  125. }
  126. }
  127. private async Task DiscoveryNatTypeImpl(CancellationToken token)
  128. {
  129. try
  130. {
  131. var server = new StunServer();
  132. if (server.Parse(StunServer))
  133. {
  134. using var proxy = ProxyFactory.CreateProxy(
  135. ProxyType,
  136. Result5389.LocalEndPoint,
  137. NetUtils.ParseEndpoint(ProxyServer),
  138. ProxyUser, ProxyPassword
  139. );
  140. using var client = new StunClient5389UDP(server.Hostname, server.Port, Result5389.LocalEndPoint, proxy);
  141. Result5389 = client.Status;
  142. await client.QueryAsync();
  143. var cache = new StunResult5389();
  144. cache.Clone(client.Status);
  145. cache.LocalEndPoint = client.LocalEndPoint;
  146. Result5389 = cache;
  147. }
  148. else
  149. {
  150. throw new Exception(@"Wrong STUN Server!");
  151. }
  152. }
  153. catch (Exception ex)
  154. {
  155. //TODO MessageBox.Show(ex.Message, nameof(NatTypeTester), MessageBoxButton.OK, MessageBoxImage.Error);
  156. }
  157. }
  158. }
  159. }