/// <summary> /// Callback method invoked when the given messages have failed to be sent /// because of an unexpected Bayeux server exception was thrown. /// </summary> /// <param name="info">Bayeux server error message.</param> /// <param name="ex">The exception that caused the failure.</param> /// <param name="messages">The messages being sent.</param> public virtual void OnProtocolError(string info, Exception ex, IMessage[] messages) { Exception pex = new ProtocolViolationException(info); if (ex != null) { FieldInfo f = pex.GetType().GetField("_innerException", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.NonPublic); if (f != null) { f.SetValue(pex, ex); } } this.OnFailure(pex, messages); }
private void InitWith(ExceptionManager ownerFeed, ProtocolViolationException e) { this.InitWith(ownerFeed, e, SR.ProtocolViolationExceptionCategory); }
public override void Write(byte[] buffer, int offset, int count) { #if DEBUG if (HttpTraceHelper.Api.TraceVerbose) { HttpTraceHelper.WriteLine("ListenerResponseStream#" + HttpTraceHelper.HashString(this) + "::Write() count:" + count); } #endif if (_contentLength != -1 && _sentContentLength + count > _contentLength) { Exception exception = new ProtocolViolationException(); #if DEBUG if (HttpTraceHelper.ExceptionThrown.TraceVerbose) { HttpTraceHelper.WriteLine("ListenerResponseStream#" + HttpTraceHelper.HashString(this) + "::Write() throwing: " + exception); } #endif throw exception; } Socket checkSocket; if (!_httpListenerWebResponse.SentHeaders) { // // we didn't send the headers yet, do so now. // // we null out the Socket when we cleanup // make a local copy to avoid null reference exceptions checkSocket = _httpListenerWebResponse.Request.ConnectionState.ConnectionSocket; if (checkSocket != null) { #if DEBUG if (HttpTraceHelper.Socket.TraceVerbose) { HttpTraceHelper.WriteLine("ListenerResponseStream#" + HttpTraceHelper.HashString(this) + "::GetResponseStream() calling Socket.Send() Length:" + _httpListenerWebResponse.HeadersBuffer.Length); } #endif checkSocket.Send(_httpListenerWebResponse.HeadersBuffer); _httpListenerWebResponse.SentHeaders = true; } } var DataToWrite = count; if (_writeChunked) { var ChunkHeader = "0x" + Convert.ToString(count, 16); DataToWrite += ChunkHeader.Length + 4; var newBuffer = new byte[DataToWrite]; for (var index = 0; index < ChunkHeader.Length; index++) { newBuffer[index] = (byte)ChunkHeader[index]; } newBuffer[ChunkHeader.Length] = 0x0D; newBuffer[ChunkHeader.Length + 1] = 0x0A; Buffer.BlockCopy(buffer, offset, newBuffer, ChunkHeader.Length + 2, count); newBuffer[DataToWrite - 2] = 0x0D; newBuffer[DataToWrite - 1] = 0x0A; buffer = newBuffer; offset = 0; } #if DEBUG if (HttpTraceHelper.Socket.TraceVerbose) { HttpTraceHelper.WriteLine("ListenerResponseStream#" + HttpTraceHelper.HashString(this) + "::GetResponseStream() calling Socket.Send() Length:" + DataToWrite); } #endif // we null out the Socket when we cleanup // make a local copy to avoid null reference exceptions checkSocket = _httpListenerWebResponse.Request.ConnectionState.ConnectionSocket; if (checkSocket != null) { checkSocket.Send(buffer, offset, DataToWrite, SocketFlags.None); } if (_contentLength != -1) { // // keep track of the data transferred // _sentContentLength -= count; } }
private async Task HandleClientAsync(TcpClient client, int clientIndex) { var clientEndPoint = (IPEndPoint)client.Client.RemoteEndPoint; var ev = new ServerEventArgs() { ClientEndPoint = clientEndPoint }; logger.DebugFormat("client{0}<{1}:{2}> connected", clientIndex, clientEndPoint.Address, clientEndPoint.Port); var stage = ConnectionStage.New; using (var stream = client.GetStream()) { try { OnClientConnected(ev); if (ev.DropClient) { throw new SystemException("an OnClientConnected event handler requires dropping client"); } var bytesRead = 0; var bytesParsed = 0; var ivlen = _algorithm.IV.Length; var iv = new byte[ivlen]; var clientBuffer = new byte[ivlen + 280]; // IV + AddressType(1) + Address(<=256) + Port(2) + HMAC(10) var invalidClientStage = stage; Exception invalidClientException = null; try { bytesRead += await PromisedReadAsync(stream, clientBuffer, bytesRead, ivlen - bytesRead, _serverCt).ConfigureAwait(false); } catch (IOException) { throw new InvalidDataException("Can't read entire IV."); } Buffer.BlockCopy(clientBuffer, 0, iv, 0, ivlen); bytesParsed += ivlen; var iv2 = new byte[ivlen]; _rng.GetBytes(iv2); stage = ConnectionStage.IVReceived; using (var decryptor = _algorithm.CreateDecryptor(_algorithm.Key, iv)) // we don't use CryptoStream because it won't return until it get full-length data using (var encryptor = _algorithm.CreateEncryptor(_algorithm.Key, iv2)) { bytesRead += await PromisedReadAsync(stream, clientBuffer, bytesRead, 1, _serverCt).ConfigureAwait(false); decryptor.TransformBlock(clientBuffer, bytesParsed, 1, clientBuffer, bytesParsed); var atyp = clientBuffer[bytesParsed]; bytesParsed++; #if (YASS_ENABLE_EXTENSIONS) const byte atypMask = 0xC0; // 0b11000000 #else const byte atypMask = 0xE0; // 0b11100000 #endif if ((atyp & atypMask) != 0) { invalidClientException = new ProtocolViolationException("Invalid ATYP value."); } var flaggedAtyp = (AtypFlags)atyp; var hmacClient = flaggedAtyp.HasFlag(AtypFlags.HMACEnabled); #if (YASS_ENABLE_EXTENSIONS) var timestampEnabled = flaggedAtyp.HasFlag(AtypFlags.TimestampEnabled); #endif var clientAddressType = (AddressType)(atyp & 0x0F); stage = ConnectionStage.AddressTypeReceived; if (hmacClient && HmacPolicy == ServerHmacPolicy.Disabled && invalidClientException == null) { invalidClientException = new ProtocolViolationException("Received an HMAC-enabled request but HMAC is disabled."); } if (!hmacClient && HmacPolicy == ServerHmacPolicy.Mandatory && invalidClientException == null) { invalidClientException = new ProtocolViolationException("Received a non-HMAC-enabled request but HMAC is mandatory."); } int addressLength; switch (clientAddressType) { case AddressType.IPv4: addressLength = 4; break; case AddressType.IPv6: addressLength = 16; break; case AddressType.Hostname: await PromisedReadAsync(stream, clientBuffer, bytesRead, 1, _serverCt).ConfigureAwait(false); bytesRead++; decryptor.TransformBlock(clientBuffer, bytesParsed, 1, clientBuffer, bytesParsed); addressLength = clientBuffer[bytesParsed]; bytesParsed++; break; default: if (invalidClientException == null) { invalidClientException = new ProtocolViolationException("Invalid address type."); } var fakeAddressLength = new byte[1]; _rng.GetNonZeroBytes(fakeAddressLength); addressLength = fakeAddressLength[0]; break; } if (invalidClientException != null) { invalidClientStage = stage; } bytesRead += await PromisedReadAsync(stream, clientBuffer, bytesRead, addressLength + 2, _serverCt).ConfigureAwait(false); decryptor.TransformBlock(clientBuffer, bytesParsed, addressLength + 2, clientBuffer, bytesParsed); var remoteAddress = new ArraySegment <byte>(clientBuffer, bytesParsed, addressLength); var port = Util.UInt16FromNetworkOrder(clientBuffer, bytesParsed + addressLength); bytesParsed += addressLength + 2; stage = ConnectionStage.AddressReceived; if (hmacClient) { var headerHmacKey = new byte[_algorithm.KeySize / 8 + ivlen]; iv.CopyTo(headerHmacKey, 0); _algorithm.Key.CopyTo(headerHmacKey, ivlen); var localHash = Util.ComputeHMACSHA1Hash(headerHmacKey, clientBuffer, ivlen, bytesParsed - ivlen); bytesRead += await PromisedReadAsync(stream, clientBuffer, bytesRead, 10, _serverCt).ConfigureAwait(false); decryptor.TransformBlock(clientBuffer, bytesParsed, 10, clientBuffer, bytesParsed); var clientHash = new ArraySegment <byte>(clientBuffer, bytesParsed, 10); bytesParsed += 10; if (!localHash.Take(10).SequenceEqual(clientHash) && invalidClientException == null) { invalidClientException = new InvalidDataException("HMAC mismatch."); invalidClientStage = stage; } } #if (YASS_ENABLE_EXTENSIONS) if (timestampEnabled) { bytesRead += await PromisedReadAsync(stream, clientBuffer, bytesRead, 8, _serverCt).ConfigureAwait(false); decryptor.TransformBlock(clientBuffer, bytesParsed, 8, clientBuffer, bytesParsed); var timestamp = new ArraySegment <byte>(clientBuffer, bytesParsed, 8); bytesParsed += 8; var clientTime = Util.UInt64FromNetworkOrder(timestamp.ToArray(), 0); var localTime = Util.GetUtcTime(); if (Math.Abs((double)(clientTime - localTime)) > 120) { invalidClientException = new InvalidDataException("Timestamp error."); invalidClientStage = stage; } } #endif if (invalidClientException != null) { stage = invalidClientStage; throw invalidClientException; } ev.IsHmacClient = hmacClient; ev.RemoteAddressType = clientAddressType; if (clientAddressType == AddressType.Hostname) { ev.RemoteHostname = Encoding.UTF8.GetString(remoteAddress.ToArray()); } else { ev.RemoteAddress = new IPAddress(remoteAddress.Take(addressLength).ToArray()); } ev.RemotePort = port; OnRemoteAddressReceived(ev); if (ev.DropClient) { throw new SystemException("An OnRemoteAddressReceived event handler requires dropping client."); } using (var remote = new TcpClient()) { var address = clientAddressType == AddressType.Hostname ? (await Dns.GetHostAddressesAsync(ev.RemoteHostname).ConfigureAwait(false))[0] : ev.RemoteAddress; var logAddress = clientAddressType == AddressType.Hostname ? Encoding.UTF8.GetString(remoteAddress.ToArray()) : address.ToString(); logger.InfoFormat("client{0}<{1}:{2}> connecting to {3}:{4}", clientIndex, clientEndPoint.Address, clientEndPoint.Port, logAddress, port); remote.ReceiveTimeout = remote.SendTimeout = _timeout; remote.Client.NoDelay = true; await remote.ConnectAsync(address, port).ConfigureAwait(false); stage = ConnectionStage.RemoteConnected; using (var remoteStream = remote.GetStream()) using (var clientCts = new CancellationTokenSource()) using (var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(_serverCt, clientCts.Token)) { var ct = linkedCts.Token; var clientTask = hmacClient ? StartHmacEnabledClientRelayAsync(stream, remoteStream, iv, decryptor, ct) : StartRelayAsync(stream, remoteStream, decryptor, ct); var remoteTask = StartRelayAsync(remoteStream, stream, encryptor, iv2, 0, ivlen, ct); stage = ConnectionStage.Streaming; await Task.WhenAny(clientTask, remoteTask); clientCts.Cancel(); client.Close(); remote.Close(); //await Task.WhenAll(clientTask, remoteTask); } OnClientDisconnected(ev); } } } catch (Exception e) { logger.ErrorFormat("Client{0}<{1}:{2}> failed in stage {3}: {4} - {5}", clientIndex, clientEndPoint.Address, clientEndPoint.Port, stage, e.GetType().Name, e.Message); OnClientFailed(ev); // reset the connection client.Client.LingerState = new LingerOption(true, 0); client.Client.Dispose(); } } lock (_clientTasks) _clientTasks.Remove(client); logger.DebugFormat("Client{0}<{1}:{2}> disconnected", clientIndex, clientEndPoint.Address, clientEndPoint.Port); }