Example #1
0
        static void ConfigureSocketKeepAlive(
            Socket socket,
            EpoxyTransport.TimeoutConfig timeoutConfig,
            Logger logger)
        {
            if (timeoutConfig.KeepAliveTime != TimeSpan.Zero && timeoutConfig.KeepAliveInterval != TimeSpan.Zero)
            {
                // Socket.IOControl for IOControlCode.KeepAliveValues is expecting a structure like
                // the following on Windows:
                //
                // struct tcp_keepalive
                // {
                //     u_long onoff; // 0 for off, non-zero for on
                //     u_long keepalivetime; // milliseconds
                //     u_long keepaliveinterval; // milliseconds
                // };
                //
                // On some platforms this gets mapped to the relevant OS structures, but on other
                // platforms, this may fail with a PlatformNotSupportedException.
                UInt32 keepAliveTimeMillis     = checked ((UInt32)timeoutConfig.KeepAliveTime.TotalMilliseconds);
                UInt32 keepAliveIntervalMillis = checked ((UInt32)timeoutConfig.KeepAliveInterval.TotalMilliseconds);

                var keepAliveVals = new byte[sizeof(UInt32) * 3];
                keepAliveVals[0] = 1;

                keepAliveVals[4] = (byte)(keepAliveTimeMillis & 0xff);
                keepAliveVals[5] = (byte)((keepAliveTimeMillis >> 8) & 0xff);
                keepAliveVals[6] = (byte)((keepAliveTimeMillis >> 16) & 0xff);
                keepAliveVals[7] = (byte)((keepAliveTimeMillis >> 24) & 0xff);

                keepAliveVals[8]  = (byte)(keepAliveIntervalMillis & 0xff);
                keepAliveVals[9]  = (byte)((keepAliveIntervalMillis >> 8) & 0xff);
                keepAliveVals[10] = (byte)((keepAliveIntervalMillis >> 16) & 0xff);
                keepAliveVals[11] = (byte)((keepAliveIntervalMillis >> 24) & 0xff);

                try
                {
                    socket.IOControl(IOControlCode.KeepAliveValues, keepAliveVals, null);
                }
                catch (ObjectDisposedException)
                {
                    // Oh well: the connection went down before we could configure it. Nothing to be
                    // done, except to wait for the next socket operation to fail and let normal
                    // clean up take over.
                }
                catch (Exception ex) when(ex is SocketException || ex is PlatformNotSupportedException)
                {
                    logger.Site().Warning(ex, "Socket keep-alive could not be configured");
                }
            }
        }
Example #2
0
        /// <summary>
        /// Creates an EpoxyNetworkStream from a TCP socket, handling failures that may occur during
        /// TCP/TLS connection establishment.
        /// </summary>
        /// <remarks>
        /// This is a helper function that centralizes error handling during connection creation.
        /// </remarks>
        /// <param name="socketFunc">A function to invoke to acquire a socket.</param>
        /// <param name="streamFunc">
        /// A function to invoke to wrap a socket in a network stream.
        /// </param>
        /// <param name="timeoutConfig">The timeout config to use for this stream.</param>
        /// <param name="logger">The logger.</param>
        /// <returns>A connected EpoxyNetworkStream.</returns>
        public static async Task <EpoxyNetworkStream> MakeAsync(
            Func <Task <Socket> > socketFunc,
            Func <Socket, Task <EpoxyNetworkStream> > streamFunc,
            EpoxyTransport.TimeoutConfig timeoutConfig,
            Logger logger)
        {
            Socket socket = null;

            try
            {
                socket = await socketFunc();

                ConfigureSocketKeepAlive(socket, timeoutConfig, logger);

                return(await streamFunc(socket));
            }
            catch (Exception)
            {
                SafeShutdownSocket(socket, logger);
                throw;
            }
        }
Example #3
0
        public EpoxyListener(
            EpoxyTransport parentTransport,
            IPEndPoint listenEndpoint,
            EpoxyServerTlsConfig tlsConfig,
            EpoxyTransport.TimeoutConfig timeoutConfig,
            Logger logger, Metrics metrics) : base(logger, metrics)
        {
            Debug.Assert(parentTransport != null);
            Debug.Assert(listenEndpoint != null);

            this.parentTransport = parentTransport;

            // will be null if not using TLS
            this.tlsConfig     = tlsConfig;
            this.timeoutConfig = timeoutConfig;

            listener            = new TcpListener(listenEndpoint);
            serviceHost         = new ServiceHost(logger);
            connections         = new HashSet <EpoxyConnection>();
            shutdownTokenSource = new CancellationTokenSource();

            ListenEndpoint = listenEndpoint;
        }