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); } }
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. }