123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- using System;
- using System.Collections.Concurrent;
- using System.Diagnostics;
- using System.IO;
- using System.Linq;
- using System.Net;
- using System.Net.Sockets;
- using System.Security.Cryptography;
- using System.Threading;
- namespace UdPunching.Serv
- {
- internal static class ServProgram
- {
- private static RSACryptoServiceProvider _serverRsaCryptoServiceProvider;
- private static readonly ConcurrentDictionary<Guid, OnlineSession> OnlineSessions = new ConcurrentDictionary<Guid, OnlineSession>();
- private static int packetSeq;
- private static Socket _svrSocket;
- private static void ProcessPacket(SocketAsyncEventArgs sae)
- {
- //KeepAlive 1s -------- add endpoint to list if no exist, return list
- //Logout -------- remove from list
- //Knock -------- PeerID
- ++packetSeq;
- Console.WriteLine($"Incoming packet#{packetSeq:0,000,000} from {sae.RemoteEndPoint}, len {sae.BytesTransferred}");
- var peerId = TransferCodec.ReadId(sae.Buffer);
- Console.WriteLine($"Incoming packet#{packetSeq:0,000,000} peer id {peerId}");
- var rspMsg = new ExchangeMessage();
- var isSessionCreateNew = false;
- var isSessionValidated = false;
- if (OnlineSessions.TryGetValue(peerId, out var session)
- && session.RemoteEndPoint.IpEndPointEqualsTo(sae.RemoteEndPoint))
- {
- session.Actively();
- isSessionValidated = true;
- }
- else
- {
- var peerRsa = LoadPeerRsa(peerId);
- if (null == peerRsa)
- {
- Console.WriteLine($"Incoming packet#{packetSeq:0,000,000} peer NOT FOUND");
- rspMsg.Flags = ExchangeMessageFlags.PeerNoRegistered;
- }
- else
- {
- session = new OnlineSession(peerId, sae.RemoteEndPoint, peerRsa);
- OnlineSessions[peerId] = session;
- isSessionCreateNew = true;
- isSessionValidated = true;
- }
- }
- byte[] msgData = null;
- if (isSessionValidated)
- {
- try
- {
- msgData = TransferCodec.DecodeData(_serverRsaCryptoServiceProvider, sae.Buffer);
- Console.WriteLine($"Incoming packet#{packetSeq:0,000,000} MsgLength: {msgData.Length}");
- }
- catch (Exception ex)
- {
- Console.WriteLine(ex);
- isSessionValidated = false;
- }
- }
- if (isSessionValidated)
- {
- var reqMsg = new ExchangeMessage(msgData);
- Console.WriteLine($"Incoming packet#{packetSeq:0,000,000} Flags: {reqMsg.Flags}");
- if (isSessionCreateNew) rspMsg.Flags |= ExchangeMessageFlags.ServerSessionCreateNew;
- if (reqMsg.Flags.HasFlag(ExchangeMessageFlags.PeerKeepAlive))
- {
- rspMsg.Flags |= ExchangeMessageFlags.EchoEndPoint;
- rspMsg.PeerEndPoint = (IPEndPoint)sae.RemoteEndPoint;
- }
- //TODO: handle request
- // Exchange request
- // Exchange relay
- var replyBytes = TransferCodec.Encode(session.PeerRsa, Guid.Empty, rspMsg.ToBytes());
- _svrSocket.SendTo(replyBytes, sae.RemoteEndPoint);
- }
- else
- {
- _svrSocket.SendTo(TransferCodec.InvalidPeerId.ToByteArray(), sae.RemoteEndPoint);
- }
- }
- private static RSACryptoServiceProvider LoadPeerRsa(Guid id)
- {
- var peerKeyPath = Path.Combine("Peers", $"{id}.txt");
- if (false == File.Exists(peerKeyPath)) return null;
- var peerRsa = new RSACryptoServiceProvider();
- peerRsa.FromXmlString(File.ReadAllText(peerKeyPath));
- return peerRsa;
- }
- private static void DeadLoopTimeOutKiller()
- {
- while (true)
- {
- //TimeOutKiller
- const int timeOutSeconds = 10;
- foreach (var session in OnlineSessions.Values.ToArray())
- {
- if ((DateTime.Now - session.LastActively).TotalSeconds > timeOutSeconds)
- {
- OnlineSessions.TryRemove(session.Id, out _);
- Console.WriteLine($"Session removed by TimeOutKiller: {session.Id}");
- }
- }
- Thread.Sleep(timeOutSeconds * 1000);
- }
- // ReSharper disable once FunctionNeverReturns
- }
- private class OnlineSession
- {
- public Guid Id { get; }
- public DateTime LastActively { get; private set; }
- public EndPoint RemoteEndPoint { get; }
- public RSACryptoServiceProvider PeerRsa { get; }
- public OnlineSession(Guid id, EndPoint remoteEndPoint, RSACryptoServiceProvider peerRsa)
- {
- Id = id;
- RemoteEndPoint = remoteEndPoint;
- PeerRsa = peerRsa;
- Actively();
- }
- public void Actively() => LastActively = DateTime.Now;
- }
- private static void Main()
- {
- Console.WriteLine("Init...");
- _serverRsaCryptoServiceProvider = new RSACryptoServiceProvider();
- _serverRsaCryptoServiceProvider.FromXmlString(File.ReadAllText("ServerPrivateKey.txt"));
- _svrSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
- _svrSocket.Bind(new IPEndPoint(IPAddress.Any, Properties.Settings.Default.ListenPort));
- Console.WriteLine($"Server Bind on {_svrSocket.LocalEndPoint}");
- const int receiveBufferSize = 1500;
- var sae = new SocketAsyncEventArgs();
- sae.SetBuffer(new byte[receiveBufferSize], 0, receiveBufferSize);
- sae.RemoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
- Console.WriteLine($"Receive buffer:{receiveBufferSize}");
- void SaeOnCompleted(object sender, SocketAsyncEventArgs e)
- {
- if (e.SocketError == SocketError.Success)
- {
- try
- {
- ProcessPacket(sae);
- }
- catch (Exception exception)
- {
- Console.WriteLine(exception);
- }
- }
- sae.RemoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
- if (false == _svrSocket.ReceiveFromAsync(sae)) SaeOnCompleted(null, null);
- }
- sae.Completed += SaeOnCompleted;
- if (false == _svrSocket.ReceiveFromAsync(sae))
- {
- SaeOnCompleted(null, null);
- }
- Console.WriteLine($"Main thread enter dead sleep loop... to exit, kill me, pid:{Process.GetCurrentProcess().Id}");
- DeadLoopTimeOutKiller();
- }
- }
- }
|