public GameProxy(ServerInfo info, ObjectPool <SocketAsyncEventArgs> pool, PacketProcessor processor, int backlog, TimeSpan timeout) { if (backlog < 0) { throw new ArgumentOutOfRangeException(nameof(backlog)); } Info = info ?? throw new ArgumentNullException(nameof(info)); ArgsPool = pool ?? throw new ArgumentNullException(nameof(pool)); Processor = processor ?? throw new ArgumentNullException(nameof(processor)); Timeout = timeout; _serverSocket = new Socket(info.ProxyEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp) { ExclusiveAddressUse = true, NoDelay = true, }; _backlog = backlog; }
void Receive(Direction direction, byte[] headerBuffer, byte[] payloadBuffer) { headerBuffer ??= new byte[PacketHeader.HeaderSize]; payloadBuffer ??= new byte[PacketHeader.MaxPayloadSize]; Socket from; Socket to; GameEncryptionSession fromEnc; GameEncryptionSession toEnc; if (direction == Direction.ClientToServer) { from = _clientSocket; to = _serverSocket; fromEnc = _clientEncryption; toEnc = _serverEncryption; } else { from = _serverSocket; to = _clientSocket; fromEnc = _serverEncryption; toEnc = _clientEncryption; } var toServer = to == _serverSocket; var fromServer = to == _serverSocket; bool DoReceive() { try { ReceiveInternal(headerBuffer, PacketHeader.HeaderSize, from, fromEnc, fromServer); var header = PacketProcessor.ReadHeader(headerBuffer); if (header.Length > PacketHeader.MaxPayloadSize) { DisconnectInternal(); _log.Error("Disconnected client {0} from {1} due to invalid packet length: {2}", EndPoint, Proxy.Info.Name, header.Length); return(false); } ReceiveInternal(payloadBuffer, header.Length, from, fromEnc, fromServer); // Can be set to a new array. var payload = payloadBuffer; if (Proxy.Processor.Process(this, direction, ref header, ref payload)) { PacketProcessor.WriteHeader(header, headerBuffer); SendInternal(headerBuffer, headerBuffer.Length, true, to, toEnc, toServer); SendInternal(payload, header.Length, true, to, toEnc, toServer); } } catch (SocketDisconnectedException) { // Normal disconnection. Disconnect(); return(false); } catch (Exception e) when(IsSocketException(e)) { // The client is already disconnected. return(false); } return(true); } // If we don't expect a large number of clients, just use dedicated // tasks to receive data instead of spawning a new one per receive. if (Proxy.MaxClients <= Environment.ProcessorCount) { Task.Factory.StartNew(() => { while (DoReceive()) { } }, TaskCreationOptions.LongRunning); } else { Task.Run(() => { DoReceive(); Receive(direction, headerBuffer, payloadBuffer); }); } }