public async Task <byte[]> ProcessRequestAsync(byte[] rawRequest, string clientInformation)
        {
            byte[]    response;
            CommandId commandId = CommandId.Zero;

            try
            {
                if (rawRequest == null)
                {
                    throw new ArgumentNullException(nameof(rawRequest));
                }
                if (rawRequest.Length == 0)
                {
                    throw new ArgumentException(@"Length must not be zero.", nameof(rawRequest));
                }

                var tlsEnvelope = new NOTLSEnvelope(rawRequest);
                var request     = this.ratchet.DecryptRequest(tlsEnvelope);

                Command command = request.ParseCommand();
                commandId = command.CommandId;
                response  = await this.commandProcessor.ExecuteAuthenticatedRequestAsync(command);
            }
            catch (Exception e)
            {
                // Always return a properly formatted response, never null, otherwise the client will simply hang.
                var error = $"{clientInformation}: Command {commandId} threw an Exception: {e.Message}";
                this.logger.LogError(error, nameof(NoTLSRequestHandler));
                response = new RequestCommand(CommandId.ServerException, error).Serialize(CommandHeader.Yes);
            }

            byte[] reply = this.ratchet.EncryptRequest(response).Serialize();
            this.logger.LogInformation($"{clientInformation}: {commandId}, I/O {rawRequest?.Length}/{reply.Length} bytes.");
            return(reply);
        }
        // This method is invoked when an asynchronous receive operation (by the socket) completes.
        // If the remote host already closed the connection, then the socket is already closed and we just decrement the counter.
        // If SocketError.Success, we process the client command and reply immediately (we always send an 'ack').
        void ProcessReceive(SocketAsyncEventArgs e)
        {
            AsyncUserToken token = (AsyncUserToken)e.UserToken;

            if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
            {
                try
                {
                    NOTLSEnvelopeExtensions.UpdatePayload(e.BytesTransferred, token);

                    do
                    {
                        NOTLSEnvelope packet = NOTLSEnvelopeExtensions.TryTakeOnePacket(ref token.Payload);
                        if (packet == null)                         // null -> not yet complete
                        {
                            if (!token.Socket.ReceiveAsync(e))
                            {
                                ProcessReceive(e);
                            }
                            return;
                        }

                        var    clientInformation = token.Socket.RemoteEndPoint.ToString();
                        byte[] reply             = this.requestHandler.ProcessRequestAsync(packet.Serialize(), clientInformation).Result;


                        if (reply != null)
                        {
                            SocketAsyncEventArgs sendArgs = CreateArgs();
                            ((AsyncUserToken)sendArgs.UserToken).Socket = token.Socket;
                            sendArgs.SetBuffer(reply, 0, reply.Length);
                            if (!token.Socket.SendAsync(sendArgs))
                            {
                                ProcessSend(sendArgs);
                            }
                        }
                    } while (token.Payload != null);
                }
                catch (Exception ex)
                {
                    this.logger.LogError($"ProcessReceive - {ex}");
                }
            }
            else
            {
                CloseClientSocket(e);
            }
        }
Beispiel #3
0
        public async Task <string> Receive(byte[] rawRequest, Transport transport)
        {
            Debug.Assert(transport == Transport.UDP);

            try
            {
                if (rawRequest == null || rawRequest.Length == 0)
                {
                    throw new Exception("TLSClient received null or empty packet");
                }

                var tlsEnvelope = new NOTLSEnvelope(rawRequest);

                int actualCrc32;
                if (!NOTLSEnvelopeExtensions.ValidateCrc32(rawRequest, out actualCrc32))
                {
                    throw new Exception($"TLSEnvelope CRC32 Error: Expected: {tlsEnvelope.Crc32}, actual: {actualCrc32}");
                }

                var request = await this.Ratchet.DecryptRequest(tlsEnvelope);


                var command = request.ParseCommand();

                if (!command.CommandId.IsCommandDefined())
                {
                    throw new Exception($"TLSClient: The command {command.CommandId} is not defined.");
                }

                await ProcessCommand(command);
            }
            catch (Exception e)
            {
                this.logger.LogError(e.Message);
            }
            return(null); // this goes back to the IUdpConnection and is not used there.
        }