예제 #1
0
        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;
        }
예제 #2
0
        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);
                });
            }
        }