123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- using System;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- 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 readonly ConcurrentDictionary<Guid, OnlineSession> OnlineSessions = new ConcurrentDictionary<Guid, OnlineSession>();
- private static RSACryptoServiceProvider _serverRsaCryptoServiceProvider;
- private static IReadOnlyDictionary<Guid, RSACryptoServiceProvider> _peerRsaDict;
- private static volatile 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;
- var peerId = TransferCodec.ReadId(sae.Buffer);
- _peerRsaDict.TryGetValue(peerId, out var peerRsa);
- if (null == peerRsa)
- {
- Console.WriteLine($"pacet #{_packetSeq} peer id {peerId} no registered");
- _svrSocket.SendTo(BuildInPeerId.Invalid.ToByteArray(), sae.RemoteEndPoint);
- return;
- }
- ExchangeMessage requestMessage;
- try
- {
- var msgData = TransferCodec.DecodeData(_serverRsaCryptoServiceProvider, sae.Buffer);
- requestMessage = new ExchangeMessage(msgData);
- }
- catch (Exception exception)
- {
- Console.WriteLine($"pacet #{_packetSeq} decode fail:{exception}");
- _svrSocket.SendTo(BuildInPeerId.Invalid.ToByteArray(), sae.RemoteEndPoint);
- return;
- }
- var responseMessage = new ExchangeMessage();
- if (false == requestMessage.TimeStamp.HasValue || Math.Abs((DateTime.Now - requestMessage.TimeStamp.Value).TotalSeconds) > 10)
- {
- responseMessage.Id = ExchangeMessageId.ErrTimeStamp;
- }
- else
- {
- OnlineSessions.TryGetValue(peerId, out var session);
- if (null == session)
- {
- if (ExchangeMessageId.KeepAliveReq == requestMessage.Id)
- {
- session = new OnlineSession(peerId, sae.RemoteEndPoint);
- OnlineSessions[peerId] = session;
- responseMessage.Id = ExchangeMessageId.KeepAliveAckSessionCreated;
- responseMessage.PeerEndPoint = (IPEndPoint)sae.RemoteEndPoint;
- Console.WriteLine($"Session created: {peerId} from {sae.RemoteEndPoint}");
- }
- else
- {
- responseMessage.Id = ExchangeMessageId.ErrSessionNoCreated;
- }
- }
- else
- {
- session.Actively();
- switch (requestMessage.Id)
- {
- case ExchangeMessageId.KeepAliveReq:
- if (false == session.RemoteEndPoint.IpEndPointEqualsTo(sae.RemoteEndPoint))
- {
- session = new OnlineSession(peerId, sae.RemoteEndPoint);
- OnlineSessions[peerId] = session;
- responseMessage.Id = ExchangeMessageId.KeepAliveAckSessionCreated;
- responseMessage.PeerEndPoint = (IPEndPoint)sae.RemoteEndPoint;
- Console.WriteLine($"Session created: {peerId} from {sae.RemoteEndPoint}");
- }
- else
- {
- responseMessage.Id = ExchangeMessageId.KeepAliveAckNoChg;
- }
- break;
- //case ExchangeMessageId.PeerKnockReq:
- // break;
- //case ExchangeMessageId.PeerKnockReqAck:
- // break;
- //case ExchangeMessageId.PeerKnockReqDenied:
- // break;
- //case ExchangeMessageId.PeerKnockConnectionReq:
- // break;
- //case ExchangeMessageId.PeerKnockConnectionAck:
- // break;
- //case ExchangeMessageId.ErrSessionNoCreated:
- // break;
- default:
- throw new ArgumentOutOfRangeException();
- }
- }
- }
- responseMessage.TimeStamp = DateTime.Now;
- var replyBytes = TransferCodec.Encode(peerRsa, BuildInPeerId.Server, responseMessage.ToBytes());
- _svrSocket.SendTo(replyBytes, sae.RemoteEndPoint);
- }
- 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 OnlineSession(Guid id, EndPoint remoteEndPoint)
- {
- Id = id;
- RemoteEndPoint = remoteEndPoint;
- Actively();
- }
- public void Actively() => LastActively = DateTime.Now;
- }
- private static void Main()
- {
- Console.WriteLine("Init...");
- _serverRsaCryptoServiceProvider = new RSACryptoServiceProvider();
- _serverRsaCryptoServiceProvider.FromXmlString(File.ReadAllText("ServerPrivateKey.txt"));
- _peerRsaDict = Directory.GetFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "PeerPublicKey"))
- .ToDictionary(
- s => new Guid(Path.GetFileNameWithoutExtension(s)),
- p =>
- {
- var rsa = new RSACryptoServiceProvider();
- rsa.FromXmlString(File.ReadAllText(p));
- return rsa;
- }
- );
- _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 (sae.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();
- }
- }
- }
|