Пример #1
0
        /// <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);
        }
Пример #2
0
 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;
            }
        }
Пример #4
0
        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);
        }