Example #1
0
        public GamePlayer(ServerHost context, Socket socket, int bufferSize)
        {
            this.mContext = context;
            this.Socket = socket;
            mBufferSize = bufferSize;
            mMaxBufferSize = bufferSize * 2;
            mLocalBuffer = new byte[mMaxBufferSize]; //<! For now, allow max buffer storage be 2x size of max buffer

            ConnectResponse msg = new ConnectResponse{ success = true };
            DispatchMessage(msg);

            // Temporary
            JoinGameSession();
        }
 protected virtual void Client_FailedToConnectToServer(ConnectResponse response)
 {
     UnityMainThreadDispatcher.Instance().Enqueue(() => {
         SetLeftScreenViewController(null, ViewController.AnimationType.None);
     });
 }
Example #3
0
 private void OnConnect(ConnectResponse connectResponse)
 {
 }
Example #4
0
        /// -----------------------------------------------------------------------------
        /// <summary>
        /// Test du protocole
        /// </summary>
        /// <typeparam name="TP">Le type de protocole</typeparam>
        /// <typeparam name="TC">Le type de canal</typeparam>
        /// <param name="port">le port de base</param>
        /// -----------------------------------------------------------------------------
        private void TestProtocol <TP, TC>(int port)
            where TP : GenericProtocol
            where TC : IChannel
        {
            BdtServer     server;
            BdtClient     client;
            EchoServer    echo;
            GatewayServer gw;

            Initialize <TP>(port, out server, out client, out echo, out gw);
            foreach (IChannel channel in ChannelServices.RegisteredChannels)
            {
                Assert.IsInstanceOfType(channel, typeof(TC));
                Assert.IsTrue(channel.ChannelName == client.ClientConfig.ServiceName || channel.ChannelName == client.ClientConfig.ServiceName + ".Client");
            }

            ConnectResponse conr = client.Tunnel.Connect(new ConnectRequest(client.Sid, "localhost", port + GatewayOffset));

            Assert.IsTrue(conr.Connected);
            Assert.IsTrue(conr.Success);

            int totalread = 0;

            for (int datalength = 0; datalength < 4096; datalength = (datalength == 0) ? 1 : datalength * 2)
            {
                var buffer    = new byte[datalength];
                var outbuffer = new byte[datalength];
                var readcount = 0;

                var rnd = new Random();
                rnd.NextBytes(buffer);

                var wrir = client.Tunnel.Write(new WriteRequest(client.Sid, conr.Cid, buffer));
                Assert.IsTrue(wrir.Connected);
                Assert.IsTrue(wrir.Success);
                while (readcount < datalength)
                {
                    var rear = client.Tunnel.Read(new ConnectionContextRequest(client.Sid, conr.Cid));
                    Assert.IsTrue(rear.Connected);
                    Assert.IsTrue(rear.Success);

                    if (!rear.DataAvailable)
                    {
                        continue;
                    }

                    Array.Copy(rear.Data, 0, outbuffer, readcount, rear.Data.Length);
                    readcount += rear.Data.Length;
                }
                Assert.AreEqual(datalength, readcount);

                for (var i = 0; i < datalength; i++)
                {
                    Assert.AreEqual(buffer[i], outbuffer[i], "Offset " + i);
                }

                totalread += readcount;
            }

            // Test Monitor method
            var monr = client.Tunnel.Monitor(new SessionContextRequest(client.Sid));

            Assert.IsTrue(monr.Success);
            Assert.AreEqual(1, monr.Sessions.Length);
            Assert.IsTrue(monr.Sessions[0].Admin);
            Assert.AreEqual(client.Sid.ToString("x"), monr.Sessions[0].Sid);
            Assert.AreEqual(2, monr.Sessions[0].Connections.Length);

            var connections = (from c in monr.Sessions[0].Connections orderby c.Port select c).ToArray();
            var hostname    = Dns.GetHostEntry(connections[0].Address).HostName;

            Assert.AreEqual(hostname, connections[0].Host);
            Assert.AreEqual("127.0.0.1", connections[0].Address);
            Assert.AreEqual(port + EchoOffset, connections[0].Port);
            Assert.AreEqual(totalread, connections[0].ReadCount);
            Assert.AreEqual(totalread, connections[0].WriteCount);

            Assert.AreEqual(hostname, connections[1].Host);
            Assert.AreEqual("127.0.0.1", connections[1].Address);
            Assert.AreEqual(port + GatewayOffset, connections[1].Port);
            Assert.AreEqual(totalread, connections[1].ReadCount);
            Assert.AreEqual(totalread, connections[1].WriteCount);
            Assert.AreEqual(conr.Cid.ToString("x"), connections[1].Cid);

            // Test Disconnect method
            var disr = client.Tunnel.Disconnect(new ConnectionContextRequest(client.Sid, conr.Cid));

            Assert.IsFalse(disr.Connected);
            Assert.IsTrue(disr.Success);

            TestKill(client, port);
            TestBadValues(client, port);

            Finalize(ref server, ref client, ref echo, ref gw);
        }
Example #5
0
        public ConnectResponse Connect()
        {
            ConnectResponse connectResponse = new ConnectResponse();

            try
            {
                Connect(out connectResponse.ErrorInfo);
                if (base.IsConnected)
                {
                    if (isRs485)
                    {
                        RS485Item[] rS485Items = RS485Items;
                        foreach (RS485Item rS485Item in rS485Items)
                        {
                            MsgRfidStatusQuery msgRfidStatusQuery = new MsgRfidStatusQuery();
                            if (rS485Item.Send(msgRfidStatusQuery))
                            {
                                rS485Item.UhfBand = msgRfidStatusQuery.ReceivedMessage.UhfBand;
                            }
                            Msg6CTagFieldConfig msg6CTagFieldConfig = new Msg6CTagFieldConfig();
                            if (rS485Item.Send(msg6CTagFieldConfig))
                            {
                                rS485Item.isEnableAntenna = msg6CTagFieldConfig.ReceivedMessage.IsEnableAntenna;
                                rS485Item.isEnableRSSI    = msg6CTagFieldConfig.ReceivedMessage.IsEnableRSSI;
                            }
                            MsgReaderVersionQuery msgReaderVersionQuery = new MsgReaderVersionQuery();
                            if (rS485Item.Send(msgReaderVersionQuery))
                            {
                                rS485Item.modelNumber = msgReaderVersionQuery.ReceivedMessage.ModelNumber;
                            }
                        }
                    }
                    else if (!(base.CommPort is UdpPort))
                    {
                        MsgRfidStatusQuery msgRfidStatusQuery2 = new MsgRfidStatusQuery();
                        if (Send(msgRfidStatusQuery2))
                        {
                            UhfBand = msgRfidStatusQuery2.ReceivedMessage.UhfBand;
                        }
                        Msg6CTagFieldConfig msg6CTagFieldConfig2 = new Msg6CTagFieldConfig();
                        if (Send(msg6CTagFieldConfig2))
                        {
                            isEnableAntenna = msg6CTagFieldConfig2.ReceivedMessage.IsEnableAntenna;
                            isEnableRSSI    = msg6CTagFieldConfig2.ReceivedMessage.IsEnableRSSI;
                        }
                        MsgReaderVersionQuery msgReaderVersionQuery2 = new MsgReaderVersionQuery();
                        if (Send(msgReaderVersionQuery2))
                        {
                            modelNumber = msgReaderVersionQuery2.ReceivedMessage.ModelNumber;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                connectResponse.ErrorInfo = new ErrInfo("FF01", ex.Message);
                Log.Error(ex.Message);
            }
            connectResponse.IsSucessed = base.IsConnected;
            return(connectResponse);
        }
        private void ProcessFirstResponse(ConnectResponse response)
        {
            var isMasterResponse = response.IsMasterResult.Response;

            // first response has to match replica set name in settings (if any)
            var replicaSetName = isMasterResponse["setName"].AsString;
            if (_server.Settings.ReplicaSetName != null && replicaSetName != _server.Settings.ReplicaSetName)
            {
                var message = string.Format(
                    "Server at address '{0}' is a member of replica set '{1}' and not '{2}'.",
                    response.ServerInstance.Address, replicaSetName, _server.Settings.ReplicaSetName);
                throw new MongoConnectionException(message);
            }
            _server.ReplicaSetName = replicaSetName;

            // find all valid addresses
            var validAddresses = new HashSet<MongoServerAddress>();
            if (isMasterResponse.Contains("hosts"))
            {
                foreach (string address in isMasterResponse["hosts"].AsBsonArray)
                {
                    validAddresses.Add(MongoServerAddress.Parse(address));
                }
            }
            if (isMasterResponse.Contains("passives"))
            {
                foreach (string address in isMasterResponse["passives"].AsBsonArray)
                {
                    validAddresses.Add(MongoServerAddress.Parse(address));
                }
            }
            if (isMasterResponse.Contains("arbiters"))
            {
                foreach (string address in isMasterResponse["arbiters"].AsBsonArray)
                {
                    validAddresses.Add(MongoServerAddress.Parse(address));
                }
            }

            // remove server instances created from the seed list that turn out to be invalid
            var invalidInstances = _server.Instances.Where(i => !validAddresses.Contains(i.Address)).ToArray(); // force evaluation
            foreach (var invalidInstance in invalidInstances)
            {
                _server.RemoveInstance(invalidInstance);
            }

            // add any server instances that were missing from the seed list
            foreach (var address in validAddresses)
            {
                if (!_server.Instances.Any(i => i.Address == address))
                {
                    var missingInstance = new MongoServerInstance(_server, address);
                    _server.AddInstance(missingInstance);
                    QueueConnect(missingInstance);
                }
            }
        }
        // private methods
        // note: this method will run on a thread from the ThreadPool
        private void ConnectWorkItem(object argsObject)
        {
            var args = (ConnectArgs)argsObject;
            var serverInstance = args.ServerInstance;

            var response = new ConnectResponse { ServerInstance = serverInstance };
            try
            {
                serverInstance.Connect(true); // slaveOk
                response.IsMasterResult = serverInstance.IsMasterResult;
            }
            catch (Exception ex)
            {
                response.Exception = ex;
            }

            args.ResponseQueue.Enqueue(response);
        }
        private void ProcessResponse(
            ConnectResponse response
        ) {
            responses.Add(response);
            if (response.ServerInstance.ConnectException != null) {
                return;
            }

            try {
                if (!response.IsMasterResult.Response.Contains("setName")) {
                    var message = string.Format("Server at address '{0}' does not have a replica set name.", response.ServerInstance.Address);
                    throw new MongoConnectionException(message);
                }
                if (!response.IsMasterResult.Response.Contains("hosts")) {
                    var message = string.Format("Server at address '{0}' does not have a hosts list.", response.ServerInstance.Address);
                    throw new MongoConnectionException(message);
                }

                if (firstResponseHasBeenProcessed) {
                    ProcessAdditionalResponse(response);
                } else {
                    ProcessFirstResponse(response);
                    firstResponseHasBeenProcessed = true; // remains false if ProcessFirstResponse throws an exception
                }
            } catch (Exception ex) {
                response.ServerInstance.ConnectException = ex;
                try { response.ServerInstance.Disconnect(); } catch { } // ignore exceptions
            }
        }
        /// <summary>
        /// This is called when client is aware of proxy
        /// So for HTTPS requests client would send CONNECT header to negotiate a secure tcp tunnel via proxy
        /// </summary>
        /// <param name="endPoint"></param>
        /// <param name="tcpClient"></param>
        /// <returns></returns>
        private async Task HandleClient(ExplicitProxyEndPoint endPoint, TcpClient tcpClient)
        {
            var clientStream = new CustomBufferedStream(tcpClient.GetStream(), BufferSize);

            var clientStreamReader = new CustomBinaryReader(clientStream, BufferSize);
            var clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize);

            try
            {
                string connectHostname = null;

                ConnectRequest connectRequest = null;

                //Client wants to create a secure tcp tunnel (probably its a HTTPS or Websocket request)
                if (await HttpHelper.IsConnectMethod(clientStream) == 1)
                {
                    //read the first line HTTP command
                    string httpCmd = await clientStreamReader.ReadLineAsync();

                    if (string.IsNullOrEmpty(httpCmd))
                    {
                        return;
                    }

                    Request.ParseRequestLine(httpCmd, out string _, out string httpUrl, out var version);

                    var httpRemoteUri = new Uri("http://" + httpUrl);
                    connectHostname = httpRemoteUri.Host;

                    //filter out excluded host names
                    bool excluded = false;

                    if (endPoint.BeforeTunnelConnect != null)
                    {
                        excluded = await endPoint.BeforeTunnelConnect(connectHostname);
                    }

                    connectRequest = new ConnectRequest
                    {
                        RequestUri  = httpRemoteUri,
                        OriginalUrl = httpUrl,
                        HttpVersion = version,
                    };

                    await HeaderParser.ReadHeaders(clientStreamReader, connectRequest.Headers);

                    var connectArgs = new TunnelConnectSessionEventArgs(BufferSize, endPoint, connectRequest, ExceptionFunc);
                    connectArgs.ProxyClient.TcpClient    = tcpClient;
                    connectArgs.ProxyClient.ClientStream = clientStream;

                    await endPoint.InvokeTunnectConnectRequest(this, connectArgs, ExceptionFunc);


                    if (await CheckAuthorization(clientStreamWriter, connectArgs) == false)
                    {
                        await endPoint.InvokeTunnectConnectResponse(this, connectArgs, ExceptionFunc);

                        return;
                    }

                    //write back successfull CONNECT response
                    var response = ConnectResponse.CreateSuccessfullConnectResponse(version);
                    response.Headers.FixProxyHeaders();
                    connectArgs.WebSession.Response = response;

                    await clientStreamWriter.WriteResponseAsync(response);

                    var clientHelloInfo = await SslTools.PeekClientHello(clientStream);

                    bool isClientHello = clientHelloInfo != null;
                    if (isClientHello)
                    {
                        connectRequest.ClientHelloInfo = clientHelloInfo;
                    }

                    await endPoint.InvokeTunnectConnectResponse(this, connectArgs, ExceptionFunc, isClientHello);

                    if (!excluded && isClientHello)
                    {
                        connectRequest.RequestUri = new Uri("https://" + httpUrl);

                        SslStream sslStream = null;

                        try
                        {
                            sslStream = new SslStream(clientStream);

                            string certName = HttpHelper.GetWildCardDomainName(connectHostname);

                            var certificate = endPoint.GenericCertificate ?? await CertificateManager.CreateCertificateAsync(certName);

                            //Successfully managed to authenticate the client using the fake certificate
                            await sslStream.AuthenticateAsServerAsync(certificate, false, SupportedSslProtocols, false);

                            //HTTPS server created - we can now decrypt the client's traffic
                            clientStream = new CustomBufferedStream(sslStream, BufferSize);

                            clientStreamReader.Dispose();
                            clientStreamReader = new CustomBinaryReader(clientStream, BufferSize);
                            clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize);
                        }
                        catch
                        {
                            sslStream?.Dispose();
                            return;
                        }

                        if (await HttpHelper.IsConnectMethod(clientStream) == -1)
                        {
                            // It can be for example some Google (Cloude Messaging for Chrome) magic
                            excluded = true;
                        }
                    }

                    //Hostname is excluded or it is not an HTTPS connect
                    if (excluded || !isClientHello)
                    {
                        //create new connection
                        using (var connection = await GetServerConnection(connectArgs, true))
                        {
                            if (isClientHello)
                            {
                                int available = clientStream.Available;
                                if (available > 0)
                                {
                                    //send the buffered data
                                    var data = BufferPool.GetBuffer(BufferSize);

                                    try
                                    {
                                        // clientStream.Available sbould be at most BufferSize because it is using the same buffer size
                                        await clientStream.ReadAsync(data, 0, available);

                                        await connection.StreamWriter.WriteAsync(data, 0, available, true);
                                    }
                                    finally
                                    {
                                        BufferPool.ReturnBuffer(data);
                                    }
                                }

                                var serverHelloInfo = await SslTools.PeekServerHello(connection.Stream);

                                ((ConnectResponse)connectArgs.WebSession.Response).ServerHelloInfo = serverHelloInfo;
                            }

                            await TcpHelper.SendRaw(clientStream, connection.Stream, BufferSize,
                                                    (buffer, offset, count) => { connectArgs.OnDataSent(buffer, offset, count); },
                                                    (buffer, offset, count) => { connectArgs.OnDataReceived(buffer, offset, count); },
                                                    ExceptionFunc);
                        }

                        return;
                    }
                }

                //Now create the request
                await HandleHttpSessionRequest(tcpClient, clientStream, clientStreamReader, clientStreamWriter, connectHostname, endPoint, connectRequest);
            }
            catch (ProxyHttpException e)
            {
                ExceptionFunc(e);
            }
            catch (IOException e)
            {
                ExceptionFunc(new Exception("Connection was aborted", e));
            }
            catch (SocketException e)
            {
                ExceptionFunc(new Exception("Could not connect", e));
            }
            catch (Exception e)
            {
                ExceptionFunc(new Exception("Error occured in whilst handling the client", e));
            }
            finally
            {
                clientStreamReader.Dispose();
                clientStream.Dispose();
            }
        }
Example #10
0
        /// <summary>
        /// This is called when client is aware of proxy
        /// So for HTTPS requests client would send CONNECT header to negotiate a secure tcp tunnel via proxy
        /// </summary>
        /// <param name="endPoint"></param>
        /// <param name="tcpClient"></param>
        /// <returns></returns>
        private async Task HandleClient(ExplicitProxyEndPoint endPoint, TcpClient tcpClient)
        {
            bool disposed = false;

            var clientStream = new CustomBufferedStream(tcpClient.GetStream(), BufferSize);

            var clientStreamReader = new CustomBinaryReader(clientStream, BufferSize);
            var clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize);

            Uri httpRemoteUri;

            try
            {
                //read the first line HTTP command
                string httpCmd = await clientStreamReader.ReadLineAsync();

                if (string.IsNullOrEmpty(httpCmd))
                {
                    return;
                }

                string  httpMethod;
                string  httpUrl;
                Version version;
                Request.ParseRequestLine(httpCmd, out httpMethod, out httpUrl, out version);

                httpRemoteUri = httpMethod == "CONNECT" ? new Uri("http://" + httpUrl) : new Uri(httpUrl);

                //filter out excluded host names
                bool excluded = false;

                if (endPoint.ExcludedHttpsHostNameRegex != null)
                {
                    excluded = endPoint.ExcludedHttpsHostNameRegexList.Any(x => x.IsMatch(httpRemoteUri.Host));
                }

                if (endPoint.IncludedHttpsHostNameRegex != null)
                {
                    excluded = !endPoint.IncludedHttpsHostNameRegexList.Any(x => x.IsMatch(httpRemoteUri.Host));
                }

                ConnectRequest connectRequest = null;

                //Client wants to create a secure tcp tunnel (probably its a HTTPS or Websocket request)
                if (httpMethod == "CONNECT")
                {
                    connectRequest = new ConnectRequest
                    {
                        RequestUri  = httpRemoteUri,
                        OriginalUrl = httpUrl,
                        HttpVersion = version,
                    };

                    await HeaderParser.ReadHeaders(clientStreamReader, connectRequest.Headers);

                    var connectArgs = new TunnelConnectSessionEventArgs(BufferSize, endPoint, connectRequest);
                    connectArgs.ProxyClient.TcpClient    = tcpClient;
                    connectArgs.ProxyClient.ClientStream = clientStream;

                    if (TunnelConnectRequest != null)
                    {
                        await TunnelConnectRequest.InvokeParallelAsync(this, connectArgs, ExceptionFunc);
                    }

                    if (!excluded && await CheckAuthorization(clientStreamWriter, connectArgs) == false)
                    {
                        if (TunnelConnectResponse != null)
                        {
                            await TunnelConnectResponse.InvokeParallelAsync(this, connectArgs, ExceptionFunc);
                        }

                        return;
                    }

                    //write back successfull CONNECT response
                    connectArgs.WebSession.Response = ConnectResponse.CreateSuccessfullConnectResponse(version);
                    await clientStreamWriter.WriteResponseAsync(connectArgs.WebSession.Response);

                    var clientHelloInfo = await SslTools.PeekClientHello(clientStream);

                    bool isClientHello = clientHelloInfo != null;
                    if (isClientHello)
                    {
                        connectRequest.ClientHelloInfo = clientHelloInfo;
                    }

                    if (TunnelConnectResponse != null)
                    {
                        connectArgs.IsHttpsConnect = isClientHello;
                        await TunnelConnectResponse.InvokeParallelAsync(this, connectArgs, ExceptionFunc);
                    }

                    if (!excluded && isClientHello)
                    {
                        httpRemoteUri             = new Uri("https://" + httpUrl);
                        connectRequest.RequestUri = httpRemoteUri;

                        SslStream sslStream = null;

                        try
                        {
                            sslStream = new SslStream(clientStream);

                            string certName = HttpHelper.GetWildCardDomainName(httpRemoteUri.Host);

                            var certificate = endPoint.GenericCertificate ?? CertificateManager.CreateCertificate(certName, false);

                            //Successfully managed to authenticate the client using the fake certificate
                            await sslStream.AuthenticateAsServerAsync(certificate, false, SupportedSslProtocols, false);

                            //HTTPS server created - we can now decrypt the client's traffic
                            clientStream = new CustomBufferedStream(sslStream, BufferSize);

                            clientStreamReader.Dispose();
                            clientStreamReader = new CustomBinaryReader(clientStream, BufferSize);
                            clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize);
                        }
                        catch
                        {
                            sslStream?.Dispose();
                            return;
                        }

                        //Now read the actual HTTPS request line
                        httpCmd = await clientStreamReader.ReadLineAsync();
                    }
                    //Hostname is excluded or it is not an HTTPS connect
                    else
                    {
                        //create new connection
                        using (var connection = await GetServerConnection(connectArgs, true))
                        {
                            try
                            {
                                if (isClientHello)
                                {
                                    if (clientStream.Available > 0)
                                    {
                                        //send the buffered data
                                        var data = new byte[clientStream.Available];
                                        await clientStream.ReadAsync(data, 0, data.Length);

                                        await connection.Stream.WriteAsync(data, 0, data.Length);

                                        await connection.Stream.FlushAsync();
                                    }

                                    var serverHelloInfo = await SslTools.PeekServerHello(connection.Stream);

                                    ((ConnectResponse)connectArgs.WebSession.Response).ServerHelloInfo = serverHelloInfo;
                                }

                                await TcpHelper.SendRaw(clientStream, connection.Stream, BufferSize,
                                                        (buffer, offset, count) => { connectArgs.OnDataSent(buffer, offset, count); }, (buffer, offset, count) => { connectArgs.OnDataReceived(buffer, offset, count); });
                            }
                            finally
                            {
                                UpdateServerConnectionCount(false);
                            }
                        }

                        return;
                    }
                }

                //Now create the request
                disposed = await HandleHttpSessionRequest(tcpClient, httpCmd, clientStream, clientStreamReader, clientStreamWriter,
                                                          httpRemoteUri.Scheme == UriSchemeHttps?httpRemoteUri.Host : null, endPoint, connectRequest);
            }
            catch (Exception e)
            {
                ExceptionFunc(new Exception("Error whilst authorizing request", e));
            }
            finally
            {
                if (!disposed)
                {
                    Dispose(clientStream, clientStreamReader, clientStreamWriter, null);
                }
            }
        }
Example #11
0
        /// <summary>
        ///     This is called when client is aware of proxy
        ///     So for HTTPS requests client would send CONNECT header to negotiate a secure tcp tunnel via proxy
        /// </summary>
        /// <param name="endPoint">The explicit endpoint.</param>
        /// <param name="clientConnection">The client connection.</param>
        /// <returns>The task.</returns>
        internal async Task handleClient(ExplicitProxyEndPoint endPoint, RequestStateBase state)
        {
            TcpClientConnection clientConnection = state.ClientConnection;
            var cancellationTokenSource          = new CancellationTokenSource();
            var cancellationToken = cancellationTokenSource.Token;

            var clientStream = new HttpClientStream(clientConnection, clientConnection.GetStream(), BufferPool);

            Task <TcpServerConnection>?prefetchConnectionTask = null;
            bool closeServerConnection = false;
            bool calledRequestHandler  = false;

            SslStream?sslStream = null;

            try
            {
                TunnelConnectSessionEventArgs?connectArgs = null;

                var method = await HttpHelper.GetMethod(clientStream, BufferPool, cancellationToken);

                if (clientStream.IsClosed)
                {
                    return;
                }

                // Client wants to create a secure tcp tunnel (probably its a HTTPS or Websocket request)
                if (method == KnownMethod.Connect)
                {
                    // read the first line HTTP command
                    var requestLine = await clientStream.ReadRequestLine(cancellationToken);

                    if (requestLine.IsEmpty())
                    {
                        return;
                    }

                    var connectRequest = new ConnectRequest(requestLine.RequestUri)
                    {
                        RequestUriString8 = requestLine.RequestUri,
                        HttpVersion       = requestLine.Version
                    };

                    await HeaderParser.ReadHeaders(clientStream, connectRequest.Headers, cancellationToken);

                    connectArgs = new TunnelConnectSessionEventArgs(state, endPoint, connectRequest,
                                                                    clientConnection, clientStream, cancellationTokenSource);
                    clientStream.DataRead  += (o, args) => connectArgs.OnDataSent(args.Buffer, args.Offset, args.Count);
                    clientStream.DataWrite += (o, args) => connectArgs.OnDataReceived(args.Buffer, args.Offset, args.Count);

                    await endPoint.InvokeBeforeTunnelConnectRequest(this, connectArgs, ExceptionFunc);

                    // filter out excluded host names
                    bool decryptSsl  = endPoint.DecryptSsl && connectArgs.DecryptSsl;
                    bool sendRawData = !decryptSsl;

                    if (connectArgs.DenyConnect)
                    {
                        if (connectArgs.HttpClient.Response.StatusCode == 0)
                        {
                            connectArgs.HttpClient.Response = new Response
                            {
                                HttpVersion       = HttpHeader.Version11,
                                StatusCode        = (int)HttpStatusCode.Forbidden,
                                StatusDescription = "Forbidden"
                            };
                        }

                        // send the response
                        await clientStream.WriteResponseAsync(connectArgs.HttpClient.Response, cancellationToken);

                        return;
                    }

                    if (await checkAuthorization(connectArgs) == false)
                    {
                        await endPoint.InvokeBeforeTunnelConnectResponse(this, connectArgs, ExceptionFunc);

                        // send the response
                        await clientStream.WriteResponseAsync(connectArgs.HttpClient.Response, cancellationToken);

                        return;
                    }

                    // write back successful CONNECT response
                    var response = ConnectResponse.CreateSuccessfulConnectResponse(requestLine.Version);

                    // Set ContentLength explicitly to properly handle HTTP 1.0
                    response.ContentLength = 0;
                    response.Headers.FixProxyHeaders();
                    connectArgs.HttpClient.Response = response;

                    await clientStream.WriteResponseAsync(response, cancellationToken);

                    var clientHelloInfo = await SslTools.PeekClientHello(clientStream, BufferPool, cancellationToken);

                    if (clientStream.IsClosed)
                    {
                        return;
                    }

                    bool isClientHello = clientHelloInfo != null;
                    if (clientHelloInfo != null)
                    {
                        connectRequest.TunnelType      = TunnelType.Https;
                        connectRequest.ClientHelloInfo = clientHelloInfo;
                    }

                    await endPoint.InvokeBeforeTunnelConnectResponse(this, connectArgs, ExceptionFunc, isClientHello);

                    if (decryptSsl && clientHelloInfo != null)
                    {
                        connectRequest.IsHttps = true; // todo: move this line to the previous "if"
                        clientStream.Connection.SslProtocol = clientHelloInfo.SslProtocol;

                        bool http2Supported = false;

                        if (EnableHttp2)
                        {
                            var alpn = clientHelloInfo.GetAlpn();
                            if (alpn != null && alpn.Contains(SslApplicationProtocol.Http2))
                            {
                                // test server HTTP/2 support
                                try
                                {
                                    // todo: this is a hack, because Titanium does not support HTTP protocol changing currently
                                    var connection = await tcpConnectionFactory.GetServerConnection(state,
                                                                                                    true, SslExtensions.Http2ProtocolAsList,
                                                                                                    true, cancellationToken);

                                    http2Supported = connection.NegotiatedApplicationProtocol ==
                                                     SslApplicationProtocol.Http2;

                                    // release connection back to pool instead of closing when connection pool is enabled.
                                    await tcpConnectionFactory.Release(connection, true);
                                }
                                catch (Exception)
                                {
                                    // ignore
                                }
                            }
                        }

                        if (EnableTcpServerConnectionPrefetch)
                        {
                            IPAddress[]? ipAddresses = null;
                            try
                            {
                                // make sure the host can be resolved before creating the prefetch task
                                ipAddresses = await Dns.GetHostAddressesAsync(connectArgs.HttpClient.Request.RequestUri.Host);
                            }
                            catch (SocketException) { }

                            if (ipAddresses != null && ipAddresses.Length > 0)
                            {
                                // don't pass cancellation token here
                                // it could cause floating server connections when client exits
                                prefetchConnectionTask = tcpConnectionFactory.GetServerConnection(state,
                                                                                                  true, null, false,
                                                                                                  CancellationToken.None);
                            }
                        }

                        string connectHostname = requestLine.RequestUri.GetString();
                        int    idx             = connectHostname.IndexOf(":");
                        if (idx >= 0)
                        {
                            connectHostname = connectHostname.Substring(0, idx);
                        }

                        X509Certificate2?certificate = null;
                        try
                        {
                            sslStream = new SslStream(clientStream, false);

                            string certName = HttpHelper.GetWildCardDomainName(connectHostname);
                            certificate = endPoint.GenericCertificate ??
                                          await CertificateManager.CreateServerCertificate(certName);

                            // Successfully managed to authenticate the client using the fake certificate
                            var options = new SslServerAuthenticationOptions();
                            if (EnableHttp2 && http2Supported)
                            {
                                options.ApplicationProtocols = clientHelloInfo.GetAlpn();
                                if (options.ApplicationProtocols == null || options.ApplicationProtocols.Count == 0)
                                {
                                    options.ApplicationProtocols = SslExtensions.Http11ProtocolAsList;
                                }
                            }

                            options.ServerCertificate              = certificate;
                            options.ClientCertificateRequired      = false;
                            options.EnabledSslProtocols            = SupportedSslProtocols;
                            options.CertificateRevocationCheckMode = X509RevocationMode.NoCheck;
                            await sslStream.AuthenticateAsServerAsync(options, cancellationToken);

#if NETSTANDARD2_1
                            clientStream.Connection.NegotiatedApplicationProtocol = sslStream.NegotiatedApplicationProtocol;
#endif

                            // HTTPS server created - we can now decrypt the client's traffic
                            clientStream = new HttpClientStream(clientStream.Connection, sslStream, BufferPool);
                            sslStream    = null; // clientStream was created, no need to keep SSL stream reference

                            clientStream.DataRead  += (o, args) => connectArgs.OnDecryptedDataSent(args.Buffer, args.Offset, args.Count);
                            clientStream.DataWrite += (o, args) => connectArgs.OnDecryptedDataReceived(args.Buffer, args.Offset, args.Count);
                        }
                        catch (Exception e)
                        {
                            var certName = certificate?.GetNameInfo(X509NameType.SimpleName, false);
                            throw new ProxyConnectException(
                                      $"Couldn't authenticate host '{connectHostname}' with certificate '{certName}'.", e, connectArgs);
                        }

                        method = await HttpHelper.GetMethod(clientStream, BufferPool, cancellationToken);

                        if (clientStream.IsClosed)
                        {
                            return;
                        }

                        if (method == KnownMethod.Invalid)
                        {
                            sendRawData = true;
                            await tcpConnectionFactory.Release(prefetchConnectionTask, true);

                            prefetchConnectionTask = null;
                        }
                    }
                    else if (clientHelloInfo == null)
                    {
                        method = await HttpHelper.GetMethod(clientStream, BufferPool, cancellationToken);

                        if (clientStream.IsClosed)
                        {
                            return;
                        }
                    }

                    if (cancellationTokenSource.IsCancellationRequested)
                    {
                        throw new Exception("Session was terminated by user.");
                    }

                    if (method == KnownMethod.Invalid)
                    {
                        sendRawData = true;
                    }

                    // Hostname is excluded or it is not an HTTPS connect
                    if (sendRawData)
                    {
                        // create new connection to server.
                        // If we detected that client tunnel CONNECTs without SSL by checking for empty client hello then
                        // this connection should not be HTTPS.
                        var connection = await tcpConnectionFactory.GetServerConnection(state,
                                                                                        true, SslExtensions.Http2ProtocolAsList,
                                                                                        true, cancellationToken);

                        try
                        {
                            if (isClientHello)
                            {
                                int available = clientStream.Available;
                                if (available > 0)
                                {
                                    // send the buffered data
                                    var data = BufferPool.GetBuffer();

                                    try
                                    {
                                        // clientStream.Available should be at most BufferSize because it is using the same buffer size
                                        int read = await clientStream.ReadAsync(data, 0, available, cancellationToken);

                                        if (read != available)
                                        {
                                            throw new Exception("Internal error.");
                                        }

                                        await connection.Stream.WriteAsync(data, 0, available, true, cancellationToken);
                                    }
                                    finally
                                    {
                                        BufferPool.ReturnBuffer(data);
                                    }
                                }

                                var serverHelloInfo = await SslTools.PeekServerHello(connection.Stream, BufferPool, cancellationToken);

                                ((ConnectResponse)connectArgs.HttpClient.Response).ServerHelloInfo = serverHelloInfo;
                            }

                            if (!clientStream.IsClosed && !connection.Stream.IsClosed)
                            {
                                await TcpHelper.SendRaw(clientStream, connection.Stream, BufferPool,
                                                        null, null, connectArgs.CancellationTokenSource, ExceptionFunc);
                            }
                        }
                        finally
                        {
                            await tcpConnectionFactory.Release(connection, true);
                        }

                        return;
                    }
                }

                if (connectArgs != null && method == KnownMethod.Pri)
                {
                    // todo
                    string?httpCmd = await clientStream.ReadLineAsync(cancellationToken);

                    if (httpCmd == "PRI * HTTP/2.0")
                    {
                        connectArgs.HttpClient.ConnectRequest !.TunnelType = TunnelType.Http2;

                        // HTTP/2 Connection Preface
                        string?line = await clientStream.ReadLineAsync(cancellationToken);

                        if (line != string.Empty)
                        {
                            throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received");
                        }

                        line = await clientStream.ReadLineAsync(cancellationToken);

                        if (line != "SM")
                        {
                            throw new Exception($"HTTP/2 Protocol violation. 'SM' expected, '{line}' received");
                        }

                        line = await clientStream.ReadLineAsync(cancellationToken);

                        if (line != string.Empty)
                        {
                            throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received");
                        }

                        var connection = await tcpConnectionFactory.GetServerConnection(state,
                                                                                        true, SslExtensions.Http2ProtocolAsList,
                                                                                        true, cancellationToken);

                        try
                        {
#if NETSTANDARD2_1
                            var connectionPreface = new ReadOnlyMemory <byte>(Http2Helper.ConnectionPreface);
                            await connection.Stream.WriteAsync(connectionPreface, cancellationToken);

                            await Http2Helper.SendHttp2(clientStream, connection.Stream,
                                                        () => new SessionEventArgs(state, endPoint, clientStream, connectArgs?.HttpClient.ConnectRequest, cancellationTokenSource)
                            {
                                UserData = connectArgs?.UserData
                            },
                                                        async args => { await onBeforeRequest(args); },
                                                        async args => { await onBeforeResponse(args); },
                                                        connectArgs.CancellationTokenSource, clientStream.Connection.Id, ExceptionFunc);
#endif
                        }
                        finally
                        {
                            await tcpConnectionFactory.Release(connection, true);
                        }
                    }
                }

                calledRequestHandler = true;

                // Now create the request
                await handleHttpSessionRequest(endPoint, state, clientStream, cancellationTokenSource, connectArgs, prefetchConnectionTask);
            }
            catch (ProxyException e)
            {
                closeServerConnection = true;
                onException(clientStream, e);
            }
            catch (IOException e)
            {
                closeServerConnection = true;
                onException(clientStream, new Exception("Connection was aborted", e));
            }
            catch (SocketException e)
            {
                closeServerConnection = true;
                onException(clientStream, new Exception("Could not connect", e));
            }
            catch (Exception e)
            {
                closeServerConnection = true;
                onException(clientStream, new Exception("Error occured in whilst handling the client", e));
            }
            finally
            {
                if (!calledRequestHandler)
                {
                    await tcpConnectionFactory.Release(prefetchConnectionTask, closeServerConnection);
                }

                sslStream?.Dispose();
                clientStream.Dispose();
            }
        }
 private void ReadConnectResult(byte[] content)
 {
     using (var reader = new EndianBinaryReader(EndianBitConverter.Big, new MemoryStream(content), Encoding.UTF8))
     {
         BinaryInputArchive bbia = BinaryInputArchive.GetArchive(reader);
         ConnectResponse conRsp = new ConnectResponse();
         conRsp.Deserialize(bbia, "connect");
         negotiatedSessionTimeout = conRsp.TimeOut;
         if (negotiatedSessionTimeout <= 0)
         {
             zooKeeper.State = ZooKeeper.States.CLOSED;
             conn.consumer.QueueEvent(new WatchedEvent(KeeperState.Expired, EventType.None, null));
             throw new SessionExpiredException(new StringBuilder().AppendFormat("Unable to reconnect to ZooKeeper service, session 0x{0:X} has expired", conn.SessionId).ToString());
         }
         conn.readTimeout = new TimeSpan(0, 0, 0, 0, negotiatedSessionTimeout * 2 / 3);
         // commented...we haven't need this information yet...
         //conn.connectTimeout = new TimeSpan(0, 0, 0, negotiatedSessionTimeout / conn.serverAddrs.Count);
         conn.SessionId = conRsp.SessionId;
         conn.SessionPassword = conRsp.Passwd;
         zooKeeper.State = ZooKeeper.States.CONNECTED;
     #if !NET_CORE
         LOG.InfoFormat("Session establishment complete on server {0:X}, negotiated timeout = {1}", conn.SessionId, negotiatedSessionTimeout);
     #endif
         conn.consumer.QueueEvent(new WatchedEvent(KeeperState.SyncConnected, EventType.None, null));
     }
 }
Example #13
0
        public override void CallServerMethod(uint token, uint methodId, CodedInputStream stream)
        {
            switch (methodId)
            {
            case 1:
            {
                ConnectRequest  request  = ConnectRequest.Parser.ParseFrom(stream);
                ConnectResponse response = new ConnectResponse();

                BattlenetRpcErrorCode status = HandleConnect(request, response);
                Log.outDebug(LogFilter.ServiceProtobuf, "{0} Client called server method ConnectionService.Connect(bgs.protocol.connection.v1.ConnectRequest: {1}) returned bgs.protocol.connection.v1.ConnectResponse: {2} status: {3}.",
                             GetCallerInfo(), request.ToString(), response.ToString(), status);
                if (status == 0)
                {
                    SendResponse(token, response);
                }
                else
                {
                    SendResponse(token, status);
                }
                break;
            }

            case 2:
            {
                BindRequest request = new BindRequest();
                request.MergeFrom(stream);

                BindResponse          response = new BindResponse();
                BattlenetRpcErrorCode status   = HandleBind(request, response);
                Log.outDebug(LogFilter.ServiceProtobuf, "{0} Client called server method ConnectionService.Bind(bgs.protocol.connection.v1.BindRequest: {1}) returned bgs.protocol.connection.v1.BindResponse: {2} status: {3}.",
                             GetCallerInfo(), request.ToString(), response.ToString(), status);
                if (status == 0)
                {
                    SendResponse(token, response);
                }
                else
                {
                    SendResponse(token, status);
                }
                break;
            }

            case 3:
            {
                EchoRequest request = new EchoRequest();
                request.MergeFrom(stream);

                EchoResponse          response = new EchoResponse();
                BattlenetRpcErrorCode status   = HandleEcho(request, response);
                Log.outDebug(LogFilter.ServiceProtobuf, "{0} Client called server method ConnectionService.Echo(bgs.protocol.connection.v1.EchoRequest: {1}) returned bgs.protocol.connection.v1.EchoResponse: {2} status: {3}.",
                             GetCallerInfo(), request.ToString(), response.ToString(), status);
                if (status == 0)
                {
                    SendResponse(token, response);
                }
                else
                {
                    SendResponse(token, status);
                }
                break;
            }

            case 4:
            {
                DisconnectNotification request = DisconnectNotification.Parser.ParseFrom(stream);

                BattlenetRpcErrorCode status = HandleForceDisconnect(request);
                Log.outDebug(LogFilter.ServiceProtobuf, "{0} Client called server method ConnectionService.ForceDisconnect(bgs.protocol.connection.v1.DisconnectNotification: {1}) status: {2}.",
                             GetCallerInfo(), request.ToString(), status);
                if (status != 0)
                {
                    SendResponse(token, status);
                }
                break;
            }

            case 5:
            {
                NoData request = NoData.Parser.ParseFrom(stream);

                BattlenetRpcErrorCode status = HandleKeepAlive(request);
                Log.outDebug(LogFilter.ServiceProtobuf, "{0} Client called server method ConnectionService.KeepAlive(bgs.protocol.NoData: {1}) status: {2}.",
                             GetCallerInfo(), request.ToString(), status);
                if (status != 0)
                {
                    SendResponse(token, status);
                }
                break;
            }

            case 6:
            {
                EncryptRequest request = EncryptRequest.Parser.ParseFrom(stream);

                NoData response = new NoData();
                BattlenetRpcErrorCode status = HandleEncrypt(request, response);
                Log.outDebug(LogFilter.ServiceProtobuf, "{0} Client called server method ConnectionService.Encrypt(bgs.protocol.connection.v1.EncryptRequest: {1}) returned bgs.protocol.NoData: {2} status: {3}.",
                             GetCallerInfo(), request.ToString(), response.ToString(), status);
                if (status == 0)
                {
                    SendResponse(token, response);
                }
                else
                {
                    SendResponse(token, status);
                }
                break;
            }

            case 7:
            {
                DisconnectRequest request = DisconnectRequest.Parser.ParseFrom(stream);

                BattlenetRpcErrorCode status = HandleRequestDisconnect(request);
                Log.outDebug(LogFilter.ServiceProtobuf, "{0} Client called server method ConnectionService.RequestDisconnect(bgs.protocol.connection.v1.DisconnectRequest: {1}) status: {2}.",
                             GetCallerInfo(), request.ToString(), status);
                if (status != 0)
                {
                    SendResponse(token, status);
                }
                break;
            }

            default:
                Log.outError(LogFilter.ServiceProtobuf, "Bad method id {0}.", methodId);
                SendResponse(token, BattlenetRpcErrorCode.RpcInvalidMethod);
                break;
            }
        }
Example #14
0
 public void Handle(ConnectResponse message)
 {
     OnConnect?.Invoke(message);
 }
Example #15
0
        internal Connection(string stanClusterID, string clientID, StanOptions options)
        {
            this.clientID = clientID;
            connID        = Google.Protobuf.ByteString.CopyFrom(System.Text.Encoding.UTF8.GetBytes(pubNUID.Next));

            opts = (options != null) ? new StanOptions(options) : new StanOptions();

            if (opts.natsConn == null)
            {
                ncOwned = true;
                try
                {
                    var nopts = ConnectionFactory.GetDefaultOptions();
                    nopts.MaxReconnect = Options.ReconnectForever;
                    nopts.Url          = opts.NatsURL;
                    // TODO:  disable buffering.
                    nc = new ConnectionFactory().CreateConnection(nopts);
                }
                catch (Exception ex)
                {
                    throw new StanConnectionException(ex);
                }
            }
            else
            {
                nc      = opts.natsConn;
                ncOwned = false;
            }

            // Prepare a subscription on ping responses, even if we are not
            // going to need it, so that if that fails, it fails before initiating
            // a connection.
            pingSubscription = nc.SubscribeAsync(newInbox(), processPingResponse);

            // create a heartbeat inbox
            string hbInbox = newInbox();

            hbSubscription = nc.SubscribeAsync(hbInbox, processHeartBeat);

            string discoverSubject = opts.discoverPrefix + "." + stanClusterID;

            // The streaming server expects seconds, but can handle millis
            // millis are denoted by negative numbers.
            int pi;

            if (opts.PingInterval < 1000)
            {
                pi = opts.pingInterval * -1;
            }
            else
            {
                pi = opts.pingInterval / 1000;
            }

            ConnectRequest req = new ConnectRequest
            {
                ClientID       = clientID,
                HeartbeatInbox = hbInbox,
                ConnID         = (Google.Protobuf.ByteString)connID,
                Protocol       = StanConsts.protocolOne,
                PingMaxOut     = opts.PingMaxOutstanding,
                PingInterval   = pi
            };

            Msg cr;

            try
            {
                cr = nc.Request(discoverSubject,
                                ProtocolSerializer.marshal(req),
                                opts.ConnectTimeout);
            }
            catch (NATSTimeoutException)
            {
                protoUnsubscribe();
                throw new StanConnectRequestTimeoutException(
                          string.Format("No response from a streaming server with a cluster ID of '{0}'", stanClusterID));
            }

            ConnectResponse response = new ConnectResponse();

            try
            {
                ProtocolSerializer.unmarshal(cr.Data, response);
            }
            catch (Exception e)
            {
                protoUnsubscribe();
                throw new StanConnectRequestException(e);
            }

            if (!string.IsNullOrEmpty(response.Error))
            {
                protoUnsubscribe();
                throw new StanConnectRequestException(response.Error);
            }

            // capture cluster configuration endpoints to publish and subscribe/unsubscribe
            pubPrefix        = response.PubPrefix;
            subRequests      = response.SubRequests;
            unsubRequests    = response.UnsubRequests;
            subCloseRequests = response.SubCloseRequests;
            closeRequests    = response.CloseRequests;

            // setup the Ack subscription
            ackSubject      = StanConsts.DefaultACKPrefix + "." + newGUID();
            ackSubscription = nc.SubscribeAsync(ackSubject, processAck);

            // TODO:  hardcode or options?
            ackSubscription.SetPendingLimits(1024 * 1024, 32 * 1024 * 1024);

            pubAckMap = new BlockingDictionary <string, PublishAck>(opts.maxPubAcksInflight);

            // TODO - check out sub map and chans

            bool unsubPing = true;

            // Do this with servers which are at least at protcolOne.
            if (response.Protocol >= StanConsts.protocolOne)
            {
                // Note that in the future server may override client ping
                // interval value sent in ConnectRequest, so use the
                // value in ConnectResponse to decide if we send PINGs
                // and at what interval.
                // In tests, the interval could be negative to indicate
                // milliseconds.
                if (response.PingInterval != 0)
                {
                    unsubPing = false;

                    // These will be immutable
                    pingRequests = response.PingRequests;
                    pingInbox    = pingSubscription.Subject;

                    // negative values returned from the server are ms
                    if (response.PingInterval < 0)
                    {
                        pingInterval = response.PingInterval * -1;
                    }
                    else
                    {
                        // if positive, the result is in seconds, but
                        // in the .NET clients we always use millis.
                        pingInterval = response.PingInterval * 1000;
                    }

                    pingMaxOut = response.PingMaxOut;
                    pingBytes  = ProtocolSerializer.createPing(connID);

                    pingTimer = new Timer(pingServer, null, pingInterval, Timeout.Infinite);
                }
            }
            if (unsubPing)
            {
                pingSubscription.Unsubscribe();
                pingSubscription = null;
            }
        }
Example #16
0
        /// <summary>
        ///     This is called when client is aware of proxy
        ///     So for HTTPS requests client would send CONNECT header to negotiate a secure tcp tunnel via proxy
        /// </summary>
        /// <param name="endPoint">The explicit endpoint.</param>
        /// <param name="clientConnection">The client connection.</param>
        /// <returns>The task.</returns>
        private async Task handleClient(ExplicitProxyEndPoint endPoint, TcpClientConnection clientConnection)
        {
            var cancellationTokenSource = new CancellationTokenSource();
            var cancellationToken       = cancellationTokenSource.Token;

            var clientStream       = new CustomBufferedStream(clientConnection.GetStream(), BufferPool, BufferSize);
            var clientStreamWriter = new HttpResponseWriter(clientStream, BufferPool, BufferSize);

            Task <TcpServerConnection> prefetchConnectionTask = null;
            bool closeServerConnection = false;
            bool calledRequestHandler  = false;

            SslStream sslStream = null;

            try
            {
                string connectHostname = null;
                TunnelConnectSessionEventArgs connectArgs = null;

                // Client wants to create a secure tcp tunnel (probably its a HTTPS or Websocket request)
                if (await HttpHelper.IsConnectMethod(clientStream, BufferPool, BufferSize, cancellationToken) == 1)
                {
                    // read the first line HTTP command
                    string httpCmd = await clientStream.ReadLineAsync(cancellationToken);

                    if (string.IsNullOrEmpty(httpCmd))
                    {
                        return;
                    }

                    Request.ParseRequestLine(httpCmd, out string _, out string httpUrl, out var version);

                    var httpRemoteUri = new Uri("http://" + httpUrl);
                    connectHostname = httpRemoteUri.Host;

                    var connectRequest = new ConnectRequest
                    {
                        RequestUri  = httpRemoteUri,
                        OriginalUrl = httpUrl,
                        HttpVersion = version
                    };

                    await HeaderParser.ReadHeaders(clientStream, connectRequest.Headers, cancellationToken);

                    connectArgs = new TunnelConnectSessionEventArgs(this, endPoint, connectRequest,
                                                                    cancellationTokenSource);
                    connectArgs.ProxyClient.Connection   = clientConnection;
                    connectArgs.ProxyClient.ClientStream = clientStream;

                    await endPoint.InvokeBeforeTunnelConnectRequest(this, connectArgs, ExceptionFunc);

                    // filter out excluded host names
                    bool decryptSsl = endPoint.DecryptSsl && connectArgs.DecryptSsl;

                    if (connectArgs.DenyConnect)
                    {
                        if (connectArgs.HttpClient.Response.StatusCode == 0)
                        {
                            connectArgs.HttpClient.Response = new Response
                            {
                                HttpVersion       = HttpHeader.Version11,
                                StatusCode        = (int)HttpStatusCode.Forbidden,
                                StatusDescription = "Forbidden"
                            };
                        }

                        // send the response
                        await clientStreamWriter.WriteResponseAsync(connectArgs.HttpClient.Response,
                                                                    cancellationToken : cancellationToken);

                        return;
                    }

                    if (await checkAuthorization(connectArgs) == false)
                    {
                        await endPoint.InvokeBeforeTunnelConnectResponse(this, connectArgs, ExceptionFunc);

                        // send the response
                        await clientStreamWriter.WriteResponseAsync(connectArgs.HttpClient.Response,
                                                                    cancellationToken : cancellationToken);

                        return;
                    }

                    // write back successful CONNECT response
                    var response = ConnectResponse.CreateSuccessfulConnectResponse(version);

                    // Set ContentLength explicitly to properly handle HTTP 1.0
                    response.ContentLength = 0;
                    response.Headers.FixProxyHeaders();
                    connectArgs.HttpClient.Response = response;

                    await clientStreamWriter.WriteResponseAsync(response, cancellationToken : cancellationToken);

                    var clientHelloInfo = await SslTools.PeekClientHello(clientStream, BufferPool, cancellationToken);

                    bool isClientHello = clientHelloInfo != null;
                    if (isClientHello)
                    {
                        connectRequest.TunnelType      = TunnelType.Https;
                        connectRequest.ClientHelloInfo = clientHelloInfo;
                    }

                    await endPoint.InvokeBeforeTunnelConnectResponse(this, connectArgs, ExceptionFunc, isClientHello);

                    if (decryptSsl && isClientHello)
                    {
                        connectRequest.RequestUri = new Uri("https://" + httpUrl);

                        bool http2Supported = false;

                        var alpn = clientHelloInfo.GetAlpn();
                        if (alpn != null && alpn.Contains(SslApplicationProtocol.Http2))
                        {
                            // test server HTTP/2 support
                            try
                            {
                                // todo: this is a hack, because Titanium does not support HTTP protocol changing currently
                                var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs,
                                                                                                isConnect : true, applicationProtocols : SslExtensions.Http2ProtocolAsList,
                                                                                                noCache : true, cancellationToken : cancellationToken);

                                http2Supported = connection.NegotiatedApplicationProtocol ==
                                                 SslApplicationProtocol.Http2;
                                //release connection back to pool instead of closing when connection pool is enabled.
                                await tcpConnectionFactory.Release(connection, true);
                            }
                            catch (Exception)
                            {
                                // ignore
                            }
                        }

                        if (EnableTcpServerConnectionPrefetch)
                        {
                            IPAddress[] ipAddresses = null;
                            try
                            {
                                //make sure the host can be resolved before creating the prefetch task
                                ipAddresses = await Dns.GetHostAddressesAsync(connectArgs.HttpClient.Request.RequestUri.Host);
                            }
                            catch (SocketException) { }

                            if (ipAddresses != null && ipAddresses.Length > 0)
                            {
                                //don't pass cancellation token here
                                //it could cause floating server connections when client exits
                                prefetchConnectionTask = tcpConnectionFactory.GetServerConnection(this, connectArgs,
                                                                                                  isConnect: true, applicationProtocols: null, noCache: false,
                                                                                                  cancellationToken: CancellationToken.None);
                            }
                        }

                        X509Certificate2 certificate = null;
                        try
                        {
                            sslStream = new MySslStream(clientStream, false);

                            string certName = HttpHelper.GetWildCardDomainName(connectHostname);
                            certificate = endPoint.GenericCertificate ??
                                          await CertificateManager.CreateServerCertificate(certName);

                            // Successfully managed to authenticate the client using the fake certificate
                            var options = new SslServerAuthenticationOptions();
                            if (EnableHttp2 && http2Supported)
                            {
                                options.ApplicationProtocols = clientHelloInfo.GetAlpn();
                                if (options.ApplicationProtocols == null || options.ApplicationProtocols.Count == 0)
                                {
                                    options.ApplicationProtocols = SslExtensions.Http11ProtocolAsList;
                                }
                            }

                            options.ServerCertificate              = certificate;
                            options.ClientCertificateRequired      = false;
                            options.EnabledSslProtocols            = SupportedSslProtocols;
                            options.CertificateRevocationCheckMode = X509RevocationMode.NoCheck;
                            await sslStream.AuthenticateAsServerAsync(options, cancellationToken);

#if NETCOREAPP2_1
                            clientConnection.NegotiatedApplicationProtocol = sslStream.NegotiatedApplicationProtocol;
#endif

                            // HTTPS server created - we can now decrypt the client's traffic
                            clientStream       = new CustomBufferedStream(new StreamWrapper(sslStream), BufferPool, BufferSize);
                            clientStreamWriter = new HttpResponseWriter(clientStream, BufferPool, BufferSize);
                        }
                        catch (Exception e)
                        {
                            var certName = certificate?.GetNameInfo(X509NameType.SimpleName, false);
                            throw new ProxyConnectException(
                                      $"Couldn't authenticate host '{connectHostname}' with certificate '{certName}'.", e, connectArgs);
                        }

                        if (await HttpHelper.IsConnectMethod(clientStream, BufferPool, BufferSize, cancellationToken) == -1)
                        {
                            decryptSsl = false;
                        }

                        if (!decryptSsl)
                        {
                            await tcpConnectionFactory.Release(prefetchConnectionTask, true);

                            prefetchConnectionTask = null;
                        }
                    }

                    if (cancellationTokenSource.IsCancellationRequested)
                    {
                        throw new Exception("Session was terminated by user.");
                    }

                    // Hostname is excluded or it is not an HTTPS connect
                    if (!decryptSsl || !isClientHello)
                    {
                        if (!isClientHello)
                        {
                            connectRequest.TunnelType = TunnelType.Websocket;
                        }

                        // create new connection to server.
                        // If we detected that client tunnel CONNECTs without SSL by checking for empty client hello then
                        // this connection should not be HTTPS.
                        var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs,
                                                                                        isConnect : true, applicationProtocols : SslExtensions.Http2ProtocolAsList,
                                                                                        noCache : true, cancellationToken : cancellationToken);

                        try
                        {
                            if (isClientHello)
                            {
                                int available = clientStream.Available;
                                if (available > 0)
                                {
                                    // send the buffered data
                                    var data = BufferPool.GetBuffer(BufferSize);

                                    try
                                    {
                                        // clientStream.Available should be at most BufferSize because it is using the same buffer size
                                        await clientStream.ReadAsync(data, 0, available, cancellationToken);

                                        await connection.StreamWriter.WriteAsync(data, 0, available, true, cancellationToken);
                                    }
                                    finally
                                    {
                                        BufferPool.ReturnBuffer(data);
                                    }
                                }

                                var serverHelloInfo = await SslTools.PeekServerHello(connection.Stream, BufferPool, cancellationToken);

                                ((ConnectResponse)connectArgs.HttpClient.Response).ServerHelloInfo = serverHelloInfo;
                            }

                            if (!clientStream.IsClosed && !connection.Stream.IsClosed)
                            {
                                await TcpHelper.SendRaw(clientStream, connection.Stream, BufferPool, BufferSize,
                                                        (buffer, offset, count) => { connectArgs.OnDataSent(buffer, offset, count); },
                                                        (buffer, offset, count) => { connectArgs.OnDataReceived(buffer, offset, count); },
                                                        connectArgs.CancellationTokenSource, ExceptionFunc);
                            }
                        }
                        finally
                        {
                            await tcpConnectionFactory.Release(connection, true);
                        }

                        return;
                    }
                }

                if (connectArgs != null && await HttpHelper.IsPriMethod(clientStream, BufferPool, BufferSize, cancellationToken) == 1)
                {
                    // todo
                    string httpCmd = await clientStream.ReadLineAsync(cancellationToken);

                    if (httpCmd == "PRI * HTTP/2.0")
                    {
                        connectArgs.HttpClient.ConnectRequest.TunnelType = TunnelType.Http2;

                        // HTTP/2 Connection Preface
                        string line = await clientStream.ReadLineAsync(cancellationToken);

                        if (line != string.Empty)
                        {
                            throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received");
                        }

                        line = await clientStream.ReadLineAsync(cancellationToken);

                        if (line != "SM")
                        {
                            throw new Exception($"HTTP/2 Protocol violation. 'SM' expected, '{line}' received");
                        }

                        line = await clientStream.ReadLineAsync(cancellationToken);

                        if (line != string.Empty)
                        {
                            throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received");
                        }

                        var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs,
                                                                                        isConnect : true, applicationProtocols : SslExtensions.Http2ProtocolAsList,
                                                                                        noCache : true, cancellationToken : cancellationToken);

                        try
                        {
                            await connection.StreamWriter.WriteLineAsync("PRI * HTTP/2.0", cancellationToken);

                            await connection.StreamWriter.WriteLineAsync(cancellationToken);

                            await connection.StreamWriter.WriteLineAsync("SM", cancellationToken);

                            await connection.StreamWriter.WriteLineAsync(cancellationToken);

#if NETCOREAPP2_1
                            await Http2Helper.SendHttp2(clientStream, connection.Stream, BufferSize,
                                                        (buffer, offset, count) => { connectArgs.OnDataSent(buffer, offset, count); },
                                                        (buffer, offset, count) => { connectArgs.OnDataReceived(buffer, offset, count); },
                                                        () => new SessionEventArgs(this, endPoint, cancellationTokenSource)
                            {
                                ProxyClient = { Connection = clientConnection },
                                HttpClient  = { ConnectRequest = connectArgs?.HttpClient.ConnectRequest },
                                UserData    = connectArgs?.UserData
                            },
                                                        async args => { await invokeBeforeRequest(args); },
                                                        async args => { await invokeBeforeResponse(args); },
                                                        connectArgs.CancellationTokenSource, clientConnection.Id, ExceptionFunc);
#endif
                        }
                        finally
                        {
                            await tcpConnectionFactory.Release(connection, true);
                        }
                    }
                }

                calledRequestHandler = true;
                // Now create the request
                await handleHttpSessionRequest(endPoint, clientConnection, clientStream, clientStreamWriter,
                                               cancellationTokenSource, connectHostname, connectArgs, prefetchConnectionTask);
            }
            catch (ProxyException e)
            {
                closeServerConnection = true;
                onException(clientStream, e);
            }
            catch (IOException e)
            {
                closeServerConnection = true;
                onException(clientStream, new Exception("Connection was aborted", e));
            }
            catch (SocketException e)
            {
                closeServerConnection = true;
                onException(clientStream, new Exception("Could not connect", e));
            }
            catch (Exception e)
            {
                closeServerConnection = true;
                onException(clientStream, new Exception("Error occured in whilst handling the client", e));
            }
            finally
            {
                if (!calledRequestHandler)
                {
                    await tcpConnectionFactory.Release(prefetchConnectionTask, closeServerConnection);
                }

                sslStream?.Dispose();
                clientStream.Dispose();

                if (!cancellationTokenSource.IsCancellationRequested)
                {
                    cancellationTokenSource.Cancel();
                }
            }
        }
Example #17
0
 public void Answer(Reject reject, B1Protocol b1, B2Protocol b2, B3Protocol b3) {
     Debug.Assert(_status == ConnectionStatus.D_ConnectPending);
     if (_connectIndication == null || _status != ConnectionStatus.D_ConnectPending) {
         throw new NotSupportedException("Connection is not in the right state.");
     }
     ConnectResponse response = new ConnectResponse(_connectIndication);
     _connectIndication = null;
     response.Reject = reject;
     response.BPtotocol.B1 = b1;
     response.BPtotocol.B2 = b2;
     response.BPtotocol.B3 = b3;
     _application.SendMessage(response);
 }
        // note: this method will run on a thread from the ThreadPool
        private void ConnectWorkItem(
            object argsObject
        ) {
            var args = (ConnectArgs) argsObject;
            var serverInstance = args.ServerInstance;

            var response = new ConnectResponse { ServerInstance = serverInstance };
            try {
                serverInstance.Connect(true); // slaveOk
                response.IsMasterResult = serverInstance.IsMasterResult;
            } catch {
                // exception is already stored in serverInstance.ConnectException and will be handled later
            }

            args.ResponseQueue.Enqueue(response);
        }
Example #19
0
 public void Handle(ConnectResponse message)
 {
     Console.WriteLine("Connected!");
     Console.WriteLine(message.Message);
 }
 private void ProcessAdditionalResponse(ConnectResponse response)
 {
     // additional responses have to be for the same replica set name as the first response
     var replicaSetName = response.IsMasterResult.Response["setName"].AsString;
     if (replicaSetName != _server.ReplicaSetName)
     {
         var message = string.Format(
             "Server at address '{0}' is a member of replica set '{1}' and not '{2}'.",
             response.ServerInstance.Address, replicaSetName, _server.ReplicaSetName);
         throw new MongoConnectionException(message);
     }
 }
        internal Connection(string stanClusterID, string clientID, StanOptions options)
        {
            this.clientID = clientID;

            if (options != null)
            {
                opts = new StanOptions(options);
            }
            else
            {
                opts = new StanOptions();
            }

            if (opts.natsConn == null)
            {
                ncOwned = true;
                try
                {
                    nc = new ConnectionFactory().CreateConnection(opts.NatsURL);
                }
                catch (Exception ex)
                {
                    throw new StanConnectionException(ex);
                }
            }
            else
            {
                nc      = opts.natsConn;
                ncOwned = false;
            }

            // create a heartbeat inbox
            string hbInbox = newInbox();

            hbSubscription = nc.SubscribeAsync(hbInbox, processHeartBeat);

            string discoverSubject = opts.discoverPrefix + "." + stanClusterID;

            ConnectRequest req = new ConnectRequest();

            req.ClientID       = this.clientID;
            req.HeartbeatInbox = hbInbox;

            Msg cr;

            try
            {
                cr = nc.Request(discoverSubject,
                                ProtocolSerializer.marshal(req),
                                opts.ConnectTimeout);
            }
            catch (NATSTimeoutException)
            {
                throw new StanConnectRequestTimeoutException();
            }

            ConnectResponse response = new ConnectResponse();

            try
            {
                ProtocolSerializer.unmarshal(cr.Data, response);
            }
            catch (Exception e)
            {
                throw new StanConnectRequestException(e);
            }

            if (!string.IsNullOrEmpty(response.Error))
            {
                throw new StanConnectRequestException(response.Error);
            }

            // capture cluster configuration endpoints to publish and subscribe/unsubscribe
            pubPrefix        = response.PubPrefix;
            subRequests      = response.SubRequests;
            unsubRequests    = response.UnsubRequests;
            subCloseRequests = response.SubCloseRequests;
            closeRequests    = response.CloseRequests;

            // setup the Ack subscription
            ackSubject      = StanConsts.DefaultACKPrefix + "." + newGUID();
            ackSubscription = nc.SubscribeAsync(ackSubject, processAck);

            // TODO:  hardcode or options?
            ackSubscription.SetPendingLimits(1024 * 1024, 32 * 1024 * 1024);

            pubAckMap = new BlockingDictionary <string, PublishAck>(opts.maxPubAcksInflight);
        }
        private void ProcessResponse(ConnectResponse response)
        {
            _responses.Add(response);

            // don't process response if it threw an exception
            if (response.Exception != null)
            {
                return;
            }

            // don't process response if Disconnect was called before the response was received
            if (_server.State == MongoServerState.Disconnected || _server.State == MongoServerState.Disconnecting)
            {
                return;
            }

            // don't process response if it was for a previous connection attempt
            if (_connectionAttempt != _server.ConnectionAttempt)
            {
                return;
            }

            try
            {
                if (!response.IsMasterResult.Response.Contains("setName"))
                {
                    var message = string.Format("Server at address '{0}' does not have a replica set name.", response.ServerInstance.Address);
                    throw new MongoConnectionException(message);
                }
                if (!response.IsMasterResult.Response.Contains("hosts"))
                {
                    var message = string.Format("Server at address '{0}' does not have a hosts list.", response.ServerInstance.Address);
                    throw new MongoConnectionException(message);
                }

                if (_firstResponseHasBeenProcessed)
                {
                    ProcessAdditionalResponse(response);
                }
                else
                {
                    ProcessFirstResponse(response);
                    _firstResponseHasBeenProcessed = true; // remains false if ProcessFirstResponse throws an exception
                }
            }
            catch (Exception ex)
            {
                response.ServerInstance.ConnectException = ex;
                try { response.ServerInstance.Disconnect(); }
                catch { } // ignore exceptions
            }
        }
Example #23
0
        public void ReceivedData(UdpReceiveResult res, UdpClient client)
        {
            var receivedData    = res.Buffer;
            var endPointAddress = res.RemoteEndPoint.Address;
            var addressString   = endPointAddress.ToString();

            if (receivedData.Length > 12)
            {
                var action = Unpack.UInt32(receivedData, 8); //connect,announce,scrape
                switch (action)
                {
                case 0:
                    var connectRequest = new ConnectRequest(receivedData);
                    Console.WriteLine("[Connect] from " + addressString + ":" + res.RemoteEndPoint.Port);

                    var connectResponse = new ConnectResponse(0, connectRequest.TransactionID, (long)13376969);
                    SendDataAsync(client, connectResponse.Data, res.RemoteEndPoint);
                    break;


                case 1:
                    var announceRequest = new AnnounceRequest(receivedData);
                    Console.WriteLine("[Announce] from " + addressString + ":" + announceRequest.Port + ", " + (TorrentEvent)announceRequest.TorrentEvent);

                    var peer = new TorrentPeer(addressString, announceRequest.Port);

                    if ((TorrentEvent)announceRequest.TorrentEvent != TorrentEvent.Stopped)
                    {
                        RedisBacking.AddPeer(peer, announceRequest.InfoHash);
                    }
                    else
                    {
                        RedisBacking.RemovePeer(peer, announceRequest.InfoHash);
                    }

                    var peers       = RedisBacking.GetPeers(announceRequest.InfoHash);
                    var torrentInfo = RedisBacking.ScrapeHashes(new List <byte[]>()
                    {
                        announceRequest.InfoHash
                    });
                    var announceResponse = new AnnounceResponse(announceRequest.TransactionID, AnnounceInterval, torrentInfo.First().Leechers, torrentInfo.First().Seeders, peers);
                    SendDataAsync(client, announceResponse.Data, res.RemoteEndPoint);
                    break;


                case 2:
                    var scrapeRequest = new ScrapeRequest(receivedData);
                    Console.WriteLine(string.Format("[Scrape] from {0} for {1} torrents", addressString, scrapeRequest.InfoHashes.Count));

                    var scrapedTorrents = RedisBacking.ScrapeHashes(scrapeRequest.InfoHashes);
                    var scrapeResponse  = new ScrapeResponse(scrapeRequest.TransactionID, scrapedTorrents);

                    SendDataAsync(client, scrapeResponse.Data, res.RemoteEndPoint);

                    break;

                default:
                    Console.WriteLine(Encoding.UTF8.GetString(receivedData));
                    break;
                }
            }
            else
            {
                Console.WriteLine(Encoding.UTF8.GetString(receivedData));
            }
        }