bool SendRawPacketInternal(RawPacket packet, byte[] buffer, Socket socket, GameEncryptionSession encryption, bool server) { if (packet == null) { throw new ArgumentNullException(nameof(packet)); } if (packet.Payload.Length > PacketHeader.MaxPayloadSize) { throw new ArgumentException("Packet is too big.", nameof(packet)); } var header = new PacketHeader((ushort)packet.Payload.Length, Proxy.Processor.Serializer.GameMessages.NameToCode[packet.Name]); lock (socket) { PacketProcessor.WriteHeader(header, buffer); Buffer.BlockCopy(packet.Payload, 0, buffer, PacketHeader.HeaderSize, header.Length); try { return(SendInternal(buffer, header.FullLength, false, socket, encryption, server)); } catch (SocketDisconnectedException) { // Normal disconnection. return(false); } } }
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); }); } }