123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- using System;
- using System.IO;
- using System.Linq;
- using System.Net;
- using System.Net.Sockets;
- using System.Security.Cryptography;
- using System.Text;
- using System.Windows.Forms;
- namespace UdPunching.ExampleW
- {
- public partial class ExampleForm : Form
- {
- private const int ReceiveBufferSize = 1500;
- private static readonly IPEndPoint AnyEndPoint = new IPEndPoint(IPAddress.Any, 0);
- private IPEndPoint _serverEndPoint;
- private RSACryptoServiceProvider _serverRsa;
- private SocketAsyncEventArgs _saeRecv;
- private Guid _localId;
- private RSACryptoServiceProvider _localRsa;
- private Socket _localSocket;
- private IPEndPoint _publicEndPoint;
- private IPEndPoint _peerEndPoint;
- private readonly byte[] _keepAliveBuf = new byte[7];// 1flag,1count,1section,4timestamp
- private readonly ExchangeMessage _keepAliveMsg = new ExchangeMessage { Id = ExchangeMessageId.KeepAliveReq };
- //------------- ctor -------------
- public ExampleForm()
- {
- InitializeComponent();
- //------------- ui event -------------
- }
- //------------- ui event -------------
- private void ExampleForm_Shown(object sender, EventArgs e)
- {
- _serverRsa = new RSACryptoServiceProvider();
- _serverRsa.FromXmlString(File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ServerPublicKey.txt")));
- var privateKeys = Directory
- .GetFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "PrivateKey"))
- .Select(Path.GetFileNameWithoutExtension)
- .ToArray();
- PeerKetyDropDown.DataSource = privateKeys;
- var peerPubKeys = Directory
- .GetFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "PeerPublicKey"))
- .Select(Path.GetFileNameWithoutExtension)
- .ToArray();
- PeerToKonckDropDown.DataSource = peerPubKeys;
- }
- private void StartButton_Click(object sender, EventArgs e)
- {
- Log("Starting...");
- _serverEndPoint = ServerIEndPointTextBox.Text.ParseToIpEndPointV4();
- _localId = new Guid(PeerKetyDropDown.Text);
- _localRsa = new RSACryptoServiceProvider();
- var peerPrivateKeyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "PrivateKey", PeerKetyDropDown.Text + ".txt");
- _localRsa.FromXmlString(
- File.ReadAllText(
- peerPrivateKeyPath
- )
- );
- _localSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
- _localSocket.Bind(AnyEndPoint);
- _saeRecv = new SocketAsyncEventArgs();
- _saeRecv.SetBuffer(new byte[ReceiveBufferSize], 0, ReceiveBufferSize);
- _saeRecv.Completed += RecvCompleted;
- BeginRecv();
- KeepAliveTimer.Start();
- KeepAliveTimer_Tick(null, null);
- PeerKetyDropDown.Enabled = false;
- StartButton.Enabled = false;
- StopButton.Enabled = true;
- KnockButton.Enabled = true;
- Log("Started...");
- }
- private void StopButton_Click(object sender, EventArgs e)
- {
- Log("Stopping...");
- KeepAliveTimer.Stop();
- _localSocket?.Dispose();
- _saeRecv?.Dispose();
- _localRsa?.Dispose();
- _localSocket = null;
- _saeRecv = null;
- _localRsa = null;
- PeerKetyDropDown.Enabled = true;
- StartButton.Enabled = true;
- StopButton.Enabled = false;
- KnockButton.Enabled = false;
- SendButton.Enabled = false;
- Log("Stopped");
- }
- private void KeepAliveTimer_Tick(object sender, EventArgs e)
- {
- _keepAliveMsg.TimeStamp = DateTime.Now;
- _keepAliveMsg.WriteToBuffer(_keepAliveBuf);
- var encode = TransferCodec.Encode(_serverRsa, _localId, _keepAliveBuf);
- _localSocket.SendTo(encode, _serverEndPoint);
- }
- private void KnockButton_Click(object sender, EventArgs e)
- {
- //TODO:
- SendButton.Enabled = true;
- }
- private void SendButton_Click(object sender, EventArgs e)
- {
- //TODO: use datatransfer message
- var to = SendToEndPointTextBox.Text.ParseToIpEndPointV4();
- var sent = _localSocket.SendTo(Encoding.UTF8.GetBytes(SendContentTextBox.Text), to);
- }
- //------------- logic -------------
- private void ProcessPacket()
- {
- var peerId = TransferCodec.ReadId(_saeRecv.Buffer);
- if (_saeRecv.RemoteEndPoint.IpEndPointEqualsTo(_serverEndPoint))
- {
- if (BuildInPeerId.Invalid == peerId)
- {
- Log("ERROR SERVER FAILURE");
- }
- else if (Guid.Empty == peerId)
- {
- var msgData = TransferCodec.DecodeData(_localRsa, _saeRecv.Buffer);
- var msg = new ExchangeMessage(msgData);
- switch (msg.Id)
- {
- case ExchangeMessageId.KeepAliveAckSessionCreated:
- _publicEndPoint = msg.PeerEndPoint;
- Log($"Session Created, public endpoint {_publicEndPoint}");
- Invoke(new Action(() =>
- {
- PublicEndPointTextBox.Text = msg.PeerEndPoint.ToString();
- }));
- break;
- case ExchangeMessageId.KeepAliveAckNoChg:
- break;
- default:
- throw new ArgumentOutOfRangeException();
- }
- }
- }
- else
- {
- if (BuildInPeerId.Invalid == peerId || BuildInPeerId.Server == peerId)
- {
- return; //Ignore invalid message
- }
- Invoke(new Action(() =>
- {
- Log($"RECV FROM {_saeRecv.RemoteEndPoint},{Encoding.UTF8.GetString(_saeRecv.Buffer, 0, _saeRecv.BytesTransferred)}");
- }));
- }
- }
- private void RecvCompleted(object sender, SocketAsyncEventArgs e)
- {
- if (e.SocketError == SocketError.Success)
- {
- try
- {
- ProcessPacket();
- }
- catch (Exception exception)
- {
- Log($"ERROR ProcessPacket:{exception}");
- Invoke(new Action(() => { StopButton_Click(null, null); }));
- }
- }
- else
- {
- Log($"ERROR SOCKET:{e.SocketError}");
- }
- if (null == _localSocket) return;
- if (false == _localSocket.ReceiveFromAsync(_saeRecv)) RecvCompleted(null, null);
- }
- private void BeginRecv()
- {
- _saeRecv.RemoteEndPoint = AnyEndPoint;
- if (false == _localSocket.ReceiveFromAsync(_saeRecv))
- {
- RecvCompleted(null, _saeRecv);
- }
- }
- //------------- util -------------
- private void Log(string content)
- {
- if (InvokeRequired)
- {
- Invoke(new Action<string>(Log), content);
- return;
- }
- RecvTextBox.Text =
- $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} {content}"
- + $"{Environment.NewLine}"
- + RecvTextBox.Text;
- RecvTextBox.Refresh();
- }
- }
- }
|