public void connection_should_be_closed_by_remote_party(string endpointProperty, bool secure)
        {
            IPEndPoint     endpoint       = (IPEndPoint)_nodes[0].GetType().GetProperty(endpointProperty).GetValue(_nodes[0], null);
            var            connectedEvent = new ManualResetEvent(false);
            var            closedEvent    = new ManualResetEvent(false);
            ITcpConnection connection;

            if (!secure)
            {
                connection = TcpConnection.CreateConnectingTcpConnection(
                    Guid.NewGuid(),
                    endpoint,
                    new TcpClientConnector(),
                    TimeSpan.FromSeconds(5),
                    (conn) => connectedEvent.Set(),
                    (conn, error) => {
                    Assert.Fail($"Connection failed: {error}");
                },
                    false);
            }
            else
            {
                connection = TcpConnectionSsl.CreateConnectingConnection(
                    Guid.NewGuid(),
                    endpoint.GetHost(),
                    endpoint,
                    delegate { return(true, null); },
        public async Task connection_should_be_closed_by_remote_party(string endpointProperty, bool secure)
        {
            IPEndPoint endpoint    = (IPEndPoint)_nodes[0].GetType().GetProperty(endpointProperty).GetValue(_nodes[0], null);
            var        closedEvent = new ManualResetEventSlim();
            TaskCompletionSource <SocketError> connectionResult = new (TaskCreationOptions.RunContinuationsAsynchronously);

            ITcpConnection connection;

            if (!secure)
            {
                connection = TcpConnection.CreateConnectingTcpConnection(
                    Guid.NewGuid(),
                    endpoint,
                    new TcpClientConnector(),
                    TimeSpan.FromSeconds(5),
                    (conn) => connectionResult.TrySetResult(SocketError.Success),
                    (conn, error) => connectionResult.TrySetResult(error),
                    false);
            }
            else
            {
                connection = TcpConnectionSsl.CreateConnectingConnection(
                    Guid.NewGuid(),
                    endpoint.GetHost(),
                    endpoint,
                    delegate { return(true, null); },
        [TestCase(false, false, false, false, true)]     //do not require valid client or server certificate
        public void should_connect_to_each_other_and_send_data_depending_on_certificate_validity_and_settings(
            bool useValidServerCertificate,
            bool useValidClientCertificate,
            bool validateServerCertificate,
            bool validateClientCertificate,
            bool shouldConnectSuccessfully
            )
        {
            var serverEndPoint    = new IPEndPoint(_ip, _port);
            var serverCertificate = useValidServerCertificate
                                ? ssl_connections.GetServerCertificate()
                                : ssl_connections.GetUntrustedCertificate();
            var clientCertificate = useValidClientCertificate
                                ? ssl_connections.GetClientCertificate()
                                : ssl_connections.GetUntrustedCertificate();
            var rootCertificates = new X509Certificate2Collection(ssl_connections.GetRootCertificate());


            var sent = new byte[1000];

            new Random().NextBytes(sent);

            var received = new MemoryStream();

            var done = new ManualResetEventSlim();

            var listener = new TcpServerListener(serverEndPoint);

            listener.StartListening((endPoint, socket) => {
                var ssl = TcpConnectionSsl.CreateServerFromSocket(Guid.NewGuid(), endPoint, socket, serverCertificate,
                                                                  (cert, chain, err) => validateClientCertificate ? ClusterVNode.ValidateClientCertificateWithTrustedRootCerts(cert, chain, err, rootCertificates) : (true, null),
                                                                  verbose: true);
                ssl.ConnectionClosed += (x, y) => done.Set();
                if (ssl.IsClosed)
                {
                    done.Set();
                }

                Action <ITcpConnection, IEnumerable <ArraySegment <byte> > > callback = null;
                callback = (x, y) => {
                    foreach (var arraySegment in y)
                    {
                        received.Write(arraySegment.Array, arraySegment.Offset, arraySegment.Count);
                        Log.Information("Received: {0} bytes, total: {1}.", arraySegment.Count, received.Length);
                    }

                    if (received.Length >= sent.Length)
                    {
                        Log.Information("Done receiving...");
                        done.Set();
                    }
                    else
                    {
                        Log.Information("Receiving...");
                        ssl.ReceiveAsync(callback);
                    }
                };
                Log.Information("Receiving...");
                ssl.ReceiveAsync(callback);
            }, "Secure");

            var clientSsl = TcpConnectionSsl.CreateConnectingConnection(
                Guid.NewGuid(),
                serverEndPoint.GetHost(),
                serverEndPoint,
                (cert, chain, err) => validateServerCertificate ? ClusterVNode.ValidateServerCertificateWithTrustedRootCerts(cert, chain, err, rootCertificates) : (true, null),
                new X509CertificateCollection {
                clientCertificate
            },
        [TestCase(false, false, false, false, true)]     //do not require valid client or server certificate
        public void should_connect_to_each_other_and_send_data_depending_on_certificate_validity_and_settings(
            bool useValidServerCertificate,
            bool useValidClientCertificate,
            bool validateServerCertificate,
            bool validateClientCertificate,
            bool shouldConnectSuccessfully
            )
        {
            var serverEndPoint    = new IPEndPoint(_ip, _port);
            var serverCertificate = useValidServerCertificate
                                ? ssl_connections.GetServerCertificate()
                                : ssl_connections.GetUntrustedCertificate();
            var clientCertificate = useValidClientCertificate
                                ? ssl_connections.GetOtherServerCertificate()
                                : ssl_connections.GetUntrustedCertificate();
            var rootCertificates = new X509Certificate2Collection(ssl_connections.GetRootCertificate());


            var sent = new byte[1000];

            new Random().NextBytes(sent);

            var received = new MemoryStream();

            var done = new ManualResetEventSlim();

            var listener = new TcpServerListener(serverEndPoint);

            listener.StartListening((endPoint, socket) => {
                var ssl = TcpConnectionSsl.CreateServerFromSocket(Guid.NewGuid(), endPoint, socket, () => serverCertificate,
                                                                  (cert, chain, err) => validateClientCertificate ? ClusterVNode <string> .ValidateClientCertificate(cert, chain, err, () => null, () => rootCertificates) : (true, null),
                                                                  verbose: true);
                ssl.ConnectionClosed += (x, y) => done.Set();
                if (ssl.IsClosed)
                {
                    done.Set();
                }

                Action <ITcpConnection, IEnumerable <ArraySegment <byte> > > callback = null;
                callback = (x, y) => {
                    foreach (var arraySegment in y)
                    {
                        received.Write(arraySegment.Array, arraySegment.Offset, arraySegment.Count);
                        Log.Information("Received: {0} bytes, total: {1}.", arraySegment.Count, received.Length);
                    }

                    if (received.Length >= sent.Length)
                    {
                        Log.Information("Done receiving...");
                        done.Set();
                    }
                    else
                    {
                        Log.Information("Receiving...");
                        ssl.ReceiveAsync(callback);
                    }
                };
                Log.Information("Receiving...");
                ssl.ReceiveAsync(callback);
            }, "Secure");

            var clientSsl = TcpConnectionSsl.CreateConnectingConnection(
                Guid.NewGuid(),
                serverEndPoint.GetHost(),
                serverEndPoint,
                (cert, chain, err) => validateServerCertificate ? ClusterVNode <string> .ValidateServerCertificate(cert, chain, err, () => null, () => rootCertificates) : (true, null),
                () => new X509CertificateCollection {
                clientCertificate
            },
                new TcpClientConnector(),
                TcpConnectionManager.ConnectionTimeout,
                conn => {
                Log.Information("Sending bytes...");
                conn.EnqueueSend(new[] { new ArraySegment <byte>(sent) });
            },
                (conn, err) => {
                Log.Error("Connecting failed: {0}.", err);
                done.Set();
            },
                verbose: true);

            Assert.IsTrue(done.Wait(20000), "Took too long to receive completion.");

            Log.Information("Stopping listener...");
            listener.Stop();
            Log.Information("Closing client TLS connection...");
            clientSsl.Close("Normal close.");
            Log.Information("Checking received data...");

            if (shouldConnectSuccessfully)
            {
                Assert.AreEqual(sent, received.ToArray());
            }
            else
            {
                Assert.AreEqual(new byte[0], received.ToArray());
            }
        }