ExampleForm.cs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. using System;
  2. using System.IO;
  3. using System.Linq;
  4. using System.Net;
  5. using System.Net.Sockets;
  6. using System.Security.Cryptography;
  7. using System.Text;
  8. using System.Windows.Forms;
  9. namespace UdPunching.ExampleW
  10. {
  11. public partial class ExampleForm : Form
  12. {
  13. private const int ReceiveBufferSize = 1500;
  14. private static readonly IPEndPoint AnyEndPoint = new IPEndPoint(IPAddress.Any, 0);
  15. private IPEndPoint _serverEndPoint;
  16. private RSACryptoServiceProvider _serverRsa;
  17. private SocketAsyncEventArgs _saeRecv;
  18. private Guid _localId;
  19. private RSACryptoServiceProvider _localRsa;
  20. private Socket _localSocket;
  21. private IPEndPoint _publicEndPoint;
  22. private IPEndPoint _peerEndPoint;
  23. private readonly byte[] _keepAliveBuf = new byte[7];// 1flag,1count,1section,4timestamp
  24. private readonly ExchangeMessage _keepAliveMsg = new ExchangeMessage { Id = ExchangeMessageId.KeepAliveReq };
  25. //------------- ctor -------------
  26. public ExampleForm()
  27. {
  28. InitializeComponent();
  29. //------------- ui event -------------
  30. }
  31. //------------- ui event -------------
  32. private void ExampleForm_Shown(object sender, EventArgs e)
  33. {
  34. _serverRsa = new RSACryptoServiceProvider();
  35. _serverRsa.FromXmlString(File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ServerPublicKey.txt")));
  36. var privateKeys = Directory
  37. .GetFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "PrivateKey"))
  38. .Select(Path.GetFileNameWithoutExtension)
  39. .ToArray();
  40. PeerKetyDropDown.DataSource = privateKeys;
  41. var peerPubKeys = Directory
  42. .GetFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "PeerPublicKey"))
  43. .Select(Path.GetFileNameWithoutExtension)
  44. .ToArray();
  45. PeerToKonckDropDown.DataSource = peerPubKeys;
  46. }
  47. private void StartButton_Click(object sender, EventArgs e)
  48. {
  49. Log("Starting...");
  50. _serverEndPoint = ServerIEndPointTextBox.Text.ParseToIpEndPointV4();
  51. _localId = new Guid(PeerKetyDropDown.Text);
  52. _localRsa = new RSACryptoServiceProvider();
  53. var peerPrivateKeyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "PrivateKey", PeerKetyDropDown.Text + ".txt");
  54. _localRsa.FromXmlString(
  55. File.ReadAllText(
  56. peerPrivateKeyPath
  57. )
  58. );
  59. _localSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
  60. _localSocket.Bind(AnyEndPoint);
  61. _saeRecv = new SocketAsyncEventArgs();
  62. _saeRecv.SetBuffer(new byte[ReceiveBufferSize], 0, ReceiveBufferSize);
  63. _saeRecv.Completed += RecvCompleted;
  64. BeginRecv();
  65. KeepAliveTimer.Start();
  66. KeepAliveTimer_Tick(null, null);
  67. PeerKetyDropDown.Enabled = false;
  68. StartButton.Enabled = false;
  69. StopButton.Enabled = true;
  70. KnockButton.Enabled = true;
  71. Log("Started...");
  72. }
  73. private void StopButton_Click(object sender, EventArgs e)
  74. {
  75. Log("Stopping...");
  76. KeepAliveTimer.Stop();
  77. _localSocket?.Dispose();
  78. _saeRecv?.Dispose();
  79. _localRsa?.Dispose();
  80. _localSocket = null;
  81. _saeRecv = null;
  82. _localRsa = null;
  83. PeerKetyDropDown.Enabled = true;
  84. StartButton.Enabled = true;
  85. StopButton.Enabled = false;
  86. KnockButton.Enabled = false;
  87. SendButton.Enabled = false;
  88. Log("Stopped");
  89. }
  90. private void KeepAliveTimer_Tick(object sender, EventArgs e)
  91. {
  92. _keepAliveMsg.TimeStamp = DateTime.Now;
  93. _keepAliveMsg.WriteToBuffer(_keepAliveBuf);
  94. var encode = TransferCodec.Encode(_serverRsa, _localId, _keepAliveBuf);
  95. _localSocket.SendTo(encode, _serverEndPoint);
  96. }
  97. private void KnockButton_Click(object sender, EventArgs e)
  98. {
  99. //TODO:
  100. SendButton.Enabled = true;
  101. }
  102. private void SendButton_Click(object sender, EventArgs e)
  103. {
  104. //TODO: use datatransfer message
  105. var to = SendToEndPointTextBox.Text.ParseToIpEndPointV4();
  106. var sent = _localSocket.SendTo(Encoding.UTF8.GetBytes(SendContentTextBox.Text), to);
  107. }
  108. //------------- logic -------------
  109. private void ProcessPacket()
  110. {
  111. var peerId = TransferCodec.ReadId(_saeRecv.Buffer);
  112. if (_saeRecv.RemoteEndPoint.IpEndPointEqualsTo(_serverEndPoint))
  113. {
  114. if (BuildInPeerId.Invalid == peerId)
  115. {
  116. Log("ERROR SERVER FAILURE");
  117. }
  118. else if (Guid.Empty == peerId)
  119. {
  120. var msgData = TransferCodec.DecodeData(_localRsa, _saeRecv.Buffer);
  121. var msg = new ExchangeMessage(msgData);
  122. switch (msg.Id)
  123. {
  124. case ExchangeMessageId.KeepAliveAckSessionCreated:
  125. _publicEndPoint = msg.PeerEndPoint;
  126. Log($"Session Created, public endpoint {_publicEndPoint}");
  127. Invoke(new Action(() =>
  128. {
  129. PublicEndPointTextBox.Text = msg.PeerEndPoint.ToString();
  130. }));
  131. break;
  132. case ExchangeMessageId.KeepAliveAckNoChg:
  133. break;
  134. default:
  135. throw new ArgumentOutOfRangeException();
  136. }
  137. }
  138. }
  139. else
  140. {
  141. if (BuildInPeerId.Invalid == peerId || BuildInPeerId.Server == peerId)
  142. {
  143. return; //Ignore invalid message
  144. }
  145. Invoke(new Action(() =>
  146. {
  147. Log($"RECV FROM {_saeRecv.RemoteEndPoint},{Encoding.UTF8.GetString(_saeRecv.Buffer, 0, _saeRecv.BytesTransferred)}");
  148. }));
  149. }
  150. }
  151. private void RecvCompleted(object sender, SocketAsyncEventArgs e)
  152. {
  153. if (e.SocketError == SocketError.Success)
  154. {
  155. try
  156. {
  157. ProcessPacket();
  158. }
  159. catch (Exception exception)
  160. {
  161. Log($"ERROR ProcessPacket:{exception}");
  162. Invoke(new Action(() => { StopButton_Click(null, null); }));
  163. }
  164. }
  165. else
  166. {
  167. Log($"ERROR SOCKET:{e.SocketError}");
  168. }
  169. if (null == _localSocket) return;
  170. if (false == _localSocket.ReceiveFromAsync(_saeRecv)) RecvCompleted(null, null);
  171. }
  172. private void BeginRecv()
  173. {
  174. _saeRecv.RemoteEndPoint = AnyEndPoint;
  175. if (false == _localSocket.ReceiveFromAsync(_saeRecv))
  176. {
  177. RecvCompleted(null, _saeRecv);
  178. }
  179. }
  180. //------------- util -------------
  181. private void Log(string content)
  182. {
  183. if (InvokeRequired)
  184. {
  185. Invoke(new Action<string>(Log), content);
  186. return;
  187. }
  188. RecvTextBox.Text =
  189. $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} {content}"
  190. + $"{Environment.NewLine}"
  191. + RecvTextBox.Text;
  192. RecvTextBox.Refresh();
  193. }
  194. }
  195. }