Пример #1
0
        // NOTE: this method replicates the logic that the base ServiceClient uses except that it doesn't insert the RetryDelegatingHandler
        // and it does insert the WatcherDelegatingHandler. we don't want the RetryDelegatingHandler because it has a very broad definition
        // of what requests have failed. it considers everything outside 2xx to be failed, including 1xx (e.g. 101 Switching Protocols) and
        // 3xx. in particular, this prevents upgraded connections and certain generic/custom requests from working.
        private void CreateHttpClient(DelegatingHandler[] handlers)
        {
            FirstMessageHandler = HttpClientHandler = CreateRootHandler();
            if (handlers == null || handlers.Length == 0)
            {
                // ensure we have at least one DelegatingHandler so AppendDelegatingHandler will work
                FirstMessageHandler = new ForwardingHandler(HttpClientHandler);
            }
            else
            {
                for (int i = handlers.Length - 1; i >= 0; i--)
                {
                    DelegatingHandler handler = handlers[i];
                    while (handler.InnerHandler is DelegatingHandler d)
                    {
                        handler = d;
                    }

                    handler.InnerHandler = FirstMessageHandler;
                    FirstMessageHandler  = handlers[i];
                }
            }

            AppendDelegatingHandler <WatcherDelegatingHandler>();
            HttpClient = new HttpClient(FirstMessageHandler, false);
        }
Пример #2
0
        /// <summary>
        /// Initializes a new instance of the ServiceConnection class.
        /// </summary>
        /// <param name="connected">
        /// The socket for the new connection.
        /// </param>
        /// <param name="token">
        /// The token for this client of the gatekeeper service,
        /// or zero if this is the registration connection.
        /// </param>
        /// <param name="handler">
        /// The handler routine to call upon forwarding a connection.
        /// </param>
        public ServiceConnection(
            string serverHost,
            Socket connected,
            uint token,
            ForwardingHandler handler,
            VLogger logger)
        {
            this.useSecureStream = true;

            // -
            // Set up the connection state.
            // -
            this.socket        = connected;
            this.netstream     = new NetworkStream(this.socket, true /*ownSocket*/);
            this.sslServerHost = serverHost;
            if (this.useSecureStream)
            {
                this.sslStream = new SslStream(
                    this.netstream,
                    false /* leaveInnerStreamOpen */,
                    new RemoteCertificateValidationCallback(ValidateServerCertificate),
                    null
                    );
                // The server name must match the name on the server certificate.
                try
                {
                    sslStream.AuthenticateAsClient(this.sslServerHost);
                }
                catch (Exception e)
                {
                    logger.Log("Exception: {0}", e.Message);
                    if (e.InnerException != null)
                    {
                        logger.Log("Inner exception: {0}", e.InnerException.Message);
                    }
                    logger.Log("Authentication failed - closing the connection.");
                    this.ShutdownAndClose();
                    return;
                }
            }
            this.clientToken          = token;
            this.handler              = handler;
            this.forwarding           = false;
            this.identifier           = HomeOS.Shared.Gatekeeper.Settings.HomeId;
            this.simpleAuthentication = HomeOS.Shared.Gatekeeper.Settings.HomePassword;

            this.logger = logger;
//#if false
            //-
            //We use keep-alives on the home <-> cloud service
            //connection in an attempt to prevent NAT/firewall
            //state from timing out and dropping our connection.
            //-
            StaticUtilities.SetKeepAlive(this.socket, 120000, 1000);
//#endif

            // -
            // Prepare our buffer space and asynchronous state holder.
            // This is currently just a simplistic single buffer system.
            // Note that this code assumes that the buffer is larger than
            // the largest possible single message (currently 257 bytes).
            // -
            this.buffer       = new byte[1500];
            this.bufferOffset = 0;

            this.streamBufState = new StreamBufferState();
            this.streamBufState.SetBuffer(this.buffer, 0, this.buffer.Length);

            // -
            // Start the dialog with our peer.
            // -
            this.AppendMessage(
                MessageType.Version,
                ServiceConnection.ProtocolVersion);
            this.SendMessage();
        }
Пример #3
0
        // NOTE: this method replicates the logic that the base ServiceClient uses except that it doesn't insert the RetryDelegatingHandler
        // and it does insert the WatcherDelegatingHandler. we don't want the RetryDelegatingHandler because it has a very broad definition
        // of what requests have failed. it considers everything outside 2xx to be failed, including 1xx (e.g. 101 Switching Protocols) and
        // 3xx. in particular, this prevents upgraded connections and certain generic/custom requests from working.
        private void CreateHttpClient(DelegatingHandler[] handlers, KubernetesClientConfiguration config)
        {
            FirstMessageHandler = HttpClientHandler = CreateRootHandler();


#if NET5_0
            // https://github.com/kubernetes-client/csharp/issues/587
            // let user control if tcp keep alive until better fix
            if (config.TcpKeepAlive)
            {
                // https://github.com/kubernetes-client/csharp/issues/533
                // net5 only
                // this is a temp fix to attach SocketsHttpHandler to HttpClient in order to set SO_KEEPALIVE
                // https://tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/
                //
                // _underlyingHandler is not a public accessible field
                // src of net5 HttpClientHandler and _underlyingHandler field defined here
                // https://github.com/dotnet/runtime/blob/79ae74f5ca5c8a6fe3a48935e85bd7374959c570/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs#L22
                //
                // Should remove after better solution

                var sh = new SocketsHttpHandler();
                sh.ConnectCallback = async(context, token) =>
                {
                    var socket = new Socket(SocketType.Stream, ProtocolType.Tcp)
                    {
                        NoDelay = true,
                    };

                    socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);

                    var host = context.DnsEndPoint.Host;

                    if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                    {
                        // https://github.com/dotnet/runtime/issues/24917
                        // GetHostAddresses will return {host} if host is an ip
                        var ips = Dns.GetHostAddresses(host);
                        if (ips.Length == 0)
                        {
                            throw new Exception($"{host} DNS lookup failed");
                        }

                        host = ips[new Random().Next(ips.Length)].ToString();
                    }

                    await socket.ConnectAsync(host, context.DnsEndPoint.Port, token).ConfigureAwait(false);

                    return(new NetworkStream(socket, ownsSocket: true));
                };


                // set HttpClientHandler's cert callback before replace _underlyingHandler
                // force HttpClientHandler use our callback
                InitializeFromConfig(config);

                var p = HttpClientHandler.GetType().GetField("_underlyingHandler", BindingFlags.NonPublic | BindingFlags.Instance);
                p.SetValue(HttpClientHandler, (sh));
            }
#endif

            if (handlers == null || handlers.Length == 0)
            {
                // ensure we have at least one DelegatingHandler so AppendDelegatingHandler will work
                FirstMessageHandler = new ForwardingHandler(HttpClientHandler);
            }
            else
            {
                for (int i = handlers.Length - 1; i >= 0; i--)
                {
                    DelegatingHandler handler = handlers[i];
                    while (handler.InnerHandler is DelegatingHandler d)
                    {
                        handler = d;
                    }

                    handler.InnerHandler = FirstMessageHandler;
                    FirstMessageHandler  = handlers[i];
                }
            }

            AppendDelegatingHandler <WatcherDelegatingHandler>();
            HttpClient = new HttpClient(FirstMessageHandler, false);
        }
Пример #4
0
        /// <summary>
        /// Initializes a new instance of the ServiceConnection class.
        /// </summary>
        /// <param name="connected">
        /// The socket for the new connection.
        /// </param>
        /// <param name="token">
        /// The token for this client of the gatekeeper service,
        /// or zero if this is the registration connection.
        /// </param>
        /// <param name="handler">
        /// The handler routine to call upon forwarding a connection.
        /// </param>
        public ServiceConnection(
            string serverHost,
            Socket connected,
            uint token,
            ForwardingHandler handler, 
            VLogger logger)
        {
            this.useSecureStream = true;

            // -
            // Set up the connection state.
            // -
            this.socket = connected;
            this.netstream = new NetworkStream(this.socket, true /*ownSocket*/);
            this.sslServerHost = serverHost;
            if (this.useSecureStream)
            {
                this.sslStream = new SslStream(
                                    this.netstream,
                                    false /* leaveInnerStreamOpen */,
                                    new RemoteCertificateValidationCallback(ValidateServerCertificate),
                                    null
                                    );
                // The server name must match the name on the server certificate.
                try
                {
                    sslStream.AuthenticateAsClient(this.sslServerHost);
                }
                catch (Exception e)
                {
                    logger.Log("Exception: {0}", e.Message);
                    if (e.InnerException != null)
                    {
                        logger.Log("Inner exception: {0}", e.InnerException.Message);
                    }
                    logger.Log("Authentication failed - closing the connection.");
                    this.ShutdownAndClose();
                    return;
                }
            }
            this.clientToken = token;
            this.handler = handler;
            this.forwarding = false;
            this.identifier = HomeOS.Shared.Gatekeeper.Settings.HomeId;
            this.simpleAuthentication = HomeOS.Shared.Gatekeeper.Settings.HomePassword;

            this.logger = logger;
            //#if false
             //-
             //We use keep-alives on the home <-> cloud service
             //connection in an attempt to prevent NAT/firewall
             //state from timing out and dropping our connection.
             //-
            StaticUtilities.SetKeepAlive(this.socket, 120000, 1000);
            //#endif

            // -
            // Prepare our buffer space and asynchronous state holder.
            // This is currently just a simplistic single buffer system.
            // Note that this code assumes that the buffer is larger than
            // the largest possible single message (currently 257 bytes).
            // -
            this.buffer = new byte[1500];
            this.bufferOffset = 0;

            this.streamBufState = new StreamBufferState();
            this.streamBufState.SetBuffer(this.buffer, 0, this.buffer.Length);

            // -
            // Start the dialog with our peer.
            // -
            this.AppendMessage(
                MessageType.Version,
                ServiceConnection.ProtocolVersion);
            this.SendMessage();
        }