// 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); }
/// <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(); }
// 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); }