Esempio n. 1
0
        public async Task <EpoxyConnection> ConnectToAsync(Endpoint endpoint, CancellationToken ct)
        {
            logger.Site().Information("Connecting to {0}.", endpoint);

            EpoxyClientTlsConfig tlsConfig = endpoint.UseTls ? clientTlsConfig : null;

            try
            {
                EpoxyNetworkStream epoxyStream =
                    await EpoxyNetworkStream.MakeAsync(
                        socketFunc : () => ConnectClientSocketAsync(endpoint),
                        streamFunc : socket => EpoxyNetworkStream.MakeClientStreamAsync(endpoint.Host, socket, tlsConfig, logger),
                        timeoutConfig : timeoutConfig,
                        logger : logger);

                // TODO: keep these in some master collection for shutdown
                var connection = EpoxyConnection.MakeClientConnection(this, epoxyStream, logger, metrics);
                await connection.StartAsync();

                return(connection);
            }
            catch (Exception ex)
            {
                logger.Site().Error(ex, "Failed to start Epoxy client connection to '{0}'", endpoint);
                throw;
            }
        }
Esempio n. 2
0
        async Task StartClientConnectionAsync(Task <Socket> socketTask)
        {
            // If this throws, it will have cleaned up before getting here, so we don't need to
            // handle cleanup.
            EpoxyNetworkStream epoxyStream = await EpoxyNetworkStream.MakeAsync(
                socketFunc : () => socketTask,
                streamFunc : socket => EpoxyNetworkStream.MakeServerStreamAsync(socket, tlsConfig, logger),
                timeoutConfig : timeoutConfig,
                logger : logger);

            // We now have a completely established EpoxyNetworkStream that will eventually need to
            // be shutdown. None of the code between here and adding the connection to our collection
            // will throw (for network I/O reasons), so we'll safely save the connection. (The
            // intervening code may throw for things like OOM. If it does, we've got bigger problems
            // that we likely won't be able to recover from anyway. Ignoring that contingency for
            // now.)
            var connection = EpoxyConnection.MakeServerConnection(
                parentTransport,
                this,
                serviceHost,
                epoxyStream,
                logger,
                metrics);

            lock (connectionsLock)
            {
                connections.Add(connection);
            }

            logger.Site().Debug("Setup server-side connection for {0}. Starting Epoxy handshake.", connection.RemoteEndPoint);
            await connection.StartAsync();
        }
Esempio n. 3
0
        private async Task AcceptAsync(CancellationToken t)
        {
            logger.Site().Information("Accepting connections on {0}", ListenEndpoint);
            while (!t.IsCancellationRequested)
            {
                Socket             socket      = null;
                EpoxyNetworkStream epoxyStream = null;

                try
                {
                    socket = await listener.AcceptSocketAsync();

                    logger.Site().Debug("Accepted connection from {0}.", socket.RemoteEndPoint);

                    EpoxyTransport.ConfigureSocketKeepAlive(socket, timeoutConfig, logger);

                    epoxyStream = await EpoxyNetworkStream.MakeServerStreamAsync(socket, tlsConfig, logger);

                    socket = null; // epoxyStream now owns the socket

                    var connection = EpoxyConnection.MakeServerConnection(
                        parentTransport,
                        this,
                        serviceHost,
                        epoxyStream,
                        logger,
                        metrics);

                    // connection now owns the EpoxyNetworkStream
                    epoxyStream = null;

                    lock (connectionsLock)
                    {
                        connections.Add(connection);
                    }

                    await connection.StartAsync();

                    logger.Site().Debug("Started server-side connection for {0}", connection.RemoteEndPoint);
                }
                catch (AuthenticationException ex)
                {
                    logger.Site().Error(ex, "Failed to authenticate remote connection from {0}", socket?.RemoteEndPoint);
                    ShutdownSocketSafe(socket, epoxyStream);
                }
                catch (SocketException ex)
                {
                    logger.Site().Error(ex, "Accept failed with error {0}.", ex.SocketErrorCode);
                    ShutdownSocketSafe(socket, epoxyStream);
                }
                catch (ObjectDisposedException)
                {
                    ShutdownSocketSafe(socket, epoxyStream);
                }
            }

            logger.Site().Information("Shutting down connection on {0}", ListenEndpoint);
        }
Esempio n. 4
0
        public async Task <EpoxyConnection> ConnectToAsync(Endpoint endpoint, CancellationToken ct)
        {
            logger.Site().Information("Connecting to {0}.", endpoint);

            Socket socket = await ConnectClientSocketAsync(endpoint);

            // For MakeClientStreamAsync, null TLS config means insecure
            EpoxyClientTlsConfig tlsConfig = endpoint.UseTls ? clientTlsConfig : null;
            var epoxyStream = await EpoxyNetworkStream.MakeClientStreamAsync(endpoint.Host, socket, tlsConfig, logger);

            // TODO: keep these in some master collection for shutdown
            var connection = EpoxyConnection.MakeClientConnection(this, epoxyStream, logger, metrics);
            await connection.StartAsync();

            return(connection);
        }
Esempio n. 5
0
 internal static EpoxyConnection MakeServerConnection(
     EpoxyTransport parentTransport,
     EpoxyListener parentListener,
     ServiceHost serviceHost,
     EpoxyNetworkStream networkStream,
     Logger logger,
     Metrics metrics)
 {
     return(new EpoxyConnection(
                ConnectionType.Server,
                parentTransport,
                parentListener,
                serviceHost,
                networkStream,
                logger,
                metrics));
 }
Esempio n. 6
0
        internal static EpoxyConnection MakeClientConnection(
            EpoxyTransport parentTransport,
            EpoxyNetworkStream networkStream,
            Logger logger,
            Metrics metrics)
        {
            const EpoxyListener parentListener = null;

            return(new EpoxyConnection(
                       ConnectionType.Client,
                       parentTransport,
                       parentListener,
                       new ServiceHost(logger),
                       networkStream,
                       logger,
                       metrics));
        }
Esempio n. 7
0
        private void ShutdownSocketSafe(Socket socket, EpoxyNetworkStream epoxyStream)
        {
            if (epoxyStream != null)
            {
                epoxyStream.Shutdown();
                // epoxyStream owns the socket, so we shouldn't try to shutdown
                socket = null;
            }

            try
            {
                socket?.Shutdown(SocketShutdown.Both);
                socket?.Close();
            }
            catch (SocketException ex)
            {
                // We tried to cleanly shutdown the socket, oh well.
                logger.Site().Debug(ex, "Exception encountered when shutting down a socket.");
            }
        }
        public async Task <EpoxyConnection> ConnectToAsync(Endpoint endpoint, CancellationToken ct)
        {
            logger.Site().Information("Connecting to {0}.", endpoint);

            EpoxyClientTlsConfig tlsConfig = endpoint.UseTls ? clientTlsConfig : null;

            try
            {
                EpoxyNetworkStream epoxyStream =
                    await EpoxyNetworkStream.MakeAsync(
                        socketFunc : () => ConnectClientSocketAsync(endpoint),
                        streamFunc : socket => EpoxyNetworkStream.MakeClientStreamAsync(endpoint.Host, socket, tlsConfig, logger),
                        timeoutConfig : timeoutConfig,
                        logger : logger);

                var connection = EpoxyConnection.MakeClientConnection(this, epoxyStream, logger, metrics);

                try
                {
                    connections.Add(connection);
                }
                catch (InvalidOperationException)
                {
                    await connection.StopAsync();

                    throw new InvalidOperationException("This EpoxyTransport has been stopped already.");
                }

                await connection.StartAsync();

                return(connection);
            }
            catch (Exception ex)
            {
                logger.Site().Error(ex, "Failed to start Epoxy client connection to '{0}'", endpoint);
                throw;
            }
        }
Esempio n. 9
0
        private EpoxyConnection(
            ConnectionType connectionType,
            EpoxyTransport parentTransport,
            EpoxyListener parentListener,
            ServiceHost serviceHost,
            EpoxyNetworkStream networkStream,
            Logger logger,
            Metrics metrics)
        {
            Debug.Assert(parentTransport != null);
            Debug.Assert(connectionType != ConnectionType.Server || parentListener != null, "Server connections must have a listener");
            Debug.Assert(serviceHost != null);
            Debug.Assert(networkStream != null);

            this.connectionType = connectionType;

            this.parentTransport = parentTransport;
            this.parentListener  = parentListener;
            this.serviceHost     = serviceHost;

            this.networkStream = networkStream;

            responseMap = new ResponseMap();

            state               = State.Created;
            startTask           = new TaskCompletionSource <bool>();
            stopTask            = new TaskCompletionSource <bool>();
            shutdownTokenSource = new CancellationTokenSource();

            // start at -1 or 0 so the first conversation ID is 1 or 2.
            prevConversationId = (connectionType == ConnectionType.Client) ? -1 : 0;

            ConnectionMetrics.local_endpoint  = LocalEndPoint.ToString();
            ConnectionMetrics.remote_endpoint = RemoteEndPoint.ToString();

            this.logger  = logger;
            this.metrics = metrics;
        }
Esempio n. 10
0
        async Task StartClientConnectionAsync(Socket socket)
        {
            EpoxyNetworkStream epoxyStream = null;

            try
            {
                EpoxyTransport.ConfigureSocketKeepAlive(socket, timeoutConfig, logger);

                epoxyStream = await EpoxyNetworkStream.MakeServerStreamAsync(socket, tlsConfig, logger);

                socket = null; // epoxyStream now owns the socket

                var connection = EpoxyConnection.MakeServerConnection(
                    parentTransport,
                    this,
                    serviceHost,
                    epoxyStream,
                    logger,
                    metrics);

                // connection now owns the EpoxyNetworkStream
                epoxyStream = null;

                lock (connectionsLock)
                {
                    connections.Add(connection);
                }

                logger.Site().Debug("Setup server-side connection for {0}. Starting Epoxy handshake.", connection.RemoteEndPoint);
                await connection.StartAsync();
            }
            catch (Exception)
            {
                ShutdownSocketSafe(socket, epoxyStream);
                throw;
            }
        }