protected void Arrange()
        {
            _serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);
            _connectionInfo = new ConnectionInfo(
                _serverEndPoint.Address.ToString(),
                _serverEndPoint.Port,
                "user",
                new PasswordAuthenticationMethod("user", "password"));
            _connectionInfo.Timeout = TimeSpan.FromMilliseconds(200);
            _actualException = null;

            _serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);

            _serverListener = new AsyncSocketListener(_serverEndPoint);
            _serverListener.Connected += (socket) =>
                {
                    _serverSocket = socket;

                    socket.Send(Encoding.ASCII.GetBytes("\r\n"));
                    socket.Send(Encoding.ASCII.GetBytes("WELCOME banner\r\n"));
                    socket.Send(Encoding.ASCII.GetBytes("SSH-2.0-SshStub\r\n"));
                };
            _serverListener.BytesReceived += (received, socket) =>
                {
                    var badPacket = new byte[] {0x0a, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05};
                    _serverSocket.Send(badPacket, 0, badPacket.Length, SocketFlags.None);
                    _serverSocket.Shutdown(SocketShutdown.Send);
                };
            _serverListener.Start();
        }
示例#2
0
        public void ConnectShouldSkipLinesBeforeProtocolIdentificationString()
        {
            var serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);
            var connectionInfo = CreateConnectionInfo(serverEndPoint, TimeSpan.FromSeconds(5));

            using (var serverStub = new AsyncSocketListener(serverEndPoint))
            {
                serverStub.Connected += socket =>
                    {
                        socket.Send(Encoding.ASCII.GetBytes("\r\n"));
                        socket.Send(Encoding.ASCII.GetBytes("WELCOME banner\r\n"));
                        socket.Send(Encoding.ASCII.GetBytes("SSH-666-SshStub\r\n"));
                        socket.Shutdown(SocketShutdown.Send);
                    };
                serverStub.Start();

                using (var session = new Session(connectionInfo, _serviceFactoryMock.Object))
                {
                    try
                    {
                        session.Connect();
                        Assert.Fail();
                    }
                    catch (SshConnectionException ex)
                    {
                        Assert.IsNull(ex.InnerException);
                        Assert.AreEqual("Server version '666' is not supported.", ex.Message);

                        Assert.AreEqual("SSH-666-SshStub", connectionInfo.ServerVersion);
                    }
                }
            }
        }
示例#3
0
        public void Start()
        {
            _httpRequestParser = new HttpRequestParser();

            _listener = new AsyncSocketListener(_endPoint);
            _listener.BytesReceived += OnBytesReceived;
            _listener.Start();
        }
示例#4
0
        public void Start()
        {
            _httpRequestParser = new HttpRequestParser();

            _listener = new AsyncSocketListener(_endPoint);
            _listener.BytesReceived += OnBytesReceived;
            _listener.Start();
        }
        public void CleanUp()
        {
            if (_client != null)
            {
                _client.Dispose();
                _client = null;
            }

            if (_listener != null)
            {
                _listener.Stop();
                _listener = null;
            }
        }
        public void CleanUp()
        {
            if (_remoteListener != null)
            {
                _remoteListener.Stop();
                _remoteListener = null;
            }

            if (_channelThread != null)
            {
                if (_channelThread.IsAlive)
                    _channelThread.Abort();
            }
        }
        public void SocketShouldBeClosedAndBindShouldEndWhenForwardedPortSignalsClosingEvent()
        {
            _sessionMock.Setup(p => p.IsConnected).Returns(true);
            _sessionMock.Setup(p => p.SendMessage(It.IsAny<ChannelOpenMessage>()))
                .Callback<Message>(m => _sessionMock.Raise(p => p.ChannelOpenConfirmationReceived += null,
                    new MessageEventArgs<ChannelOpenConfirmationMessage>(
                        new ChannelOpenConfirmationMessage(((ChannelOpenMessage)m).LocalChannelNumber, _remoteWindowSize, _remotePacketSize, _remoteChannelNumber))));
            _sessionMock.Setup(p => p.WaitOnHandle(It.IsAny<EventWaitHandle>()))
                .Callback<WaitHandle>(p => p.WaitOne(Session.Infinite));

            var localPortEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);
            using (var localPortListener = new AsyncSocketListener(localPortEndPoint))
            {
                localPortListener.Start();

                localPortListener.Connected += socket =>
                    {
                        var channel = new ChannelDirectTcpip(_sessionMock.Object, _localChannelNumber, _localWindowSize,
                            _localPacketSize);
                        channel.Open(_remoteHost, _port, _forwardedPortMock.Object, socket);

                        var closeForwardedPortThread =
                            new Thread(() =>
                                {
                                    // sleep for a short period to allow channel to actually start receiving from socket
                                    Thread.Sleep(100);
                                    // raise Closing event on forwarded port
                                    _forwardedPortMock.Raise(p => p.Closing += null, EventArgs.Empty);
                                });
                        closeForwardedPortThread.Start();

                        channel.Bind();

                        closeForwardedPortThread.Join();
                    };

                var client = new Socket(localPortEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                client.Connect(localPortEndPoint);

                // attempt to receive from socket to verify it was shut down by channel
                var buffer = new byte[16];
                var bytesReceived = client.Receive(buffer, 0, buffer.Length, SocketFlags.None);
                Assert.AreEqual(0, bytesReceived);
                Assert.IsTrue(client.Connected);
                // signal to server that we also shut down the socket at our end
                client.Shutdown(SocketShutdown.Send);
            }
        }
        public void SocketShouldBeClosedAndEofShouldBeSentToServerWhenClientShutsDownSocket()
        {
            _sessionMock.Setup(p => p.IsConnected).Returns(true);
            _sessionMock.Setup(p => p.SendMessage(It.IsAny<ChannelOpenMessage>()))
                .Callback<Message>(m => _sessionMock.Raise(p => p.ChannelOpenConfirmationReceived += null,
                    new MessageEventArgs<ChannelOpenConfirmationMessage>(
                        new ChannelOpenConfirmationMessage(((ChannelOpenMessage) m).LocalChannelNumber,
                            _remoteWindowSize, _remotePacketSize, _remoteChannelNumber))));
            _sessionMock.Setup(p => p.WaitOnHandle(It.IsAny<EventWaitHandle>()))
                .Callback<WaitHandle>(p => p.WaitOne(Session.Infinite));
            _sessionMock.Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object);
            _connectionInfoMock.Setup(p => p.Timeout).Returns(TimeSpan.FromSeconds(60));
            _sessionMock.Setup(p => p.TrySendMessage(It.IsAny<ChannelEofMessage>()))
                .Returns(true)
                .Callback<Message>(
                    m => new Thread(() =>
                        {
                            Thread.Sleep(50);
                            _sessionMock.Raise(s => s.ChannelEofReceived += null,
                                new MessageEventArgs<ChannelEofMessage>(new ChannelEofMessage(_localChannelNumber)));
                        }).Start());
            _sessionMock.Setup(p => p.TrySendMessage(It.IsAny<ChannelCloseMessage>()))
                .Returns(true)
                .Callback<Message>(
                    m => new Thread(() =>
                        {
                            Thread.Sleep(50);
                            _sessionMock.Raise(s => s.ChannelCloseReceived += null,
                                new MessageEventArgs<ChannelCloseMessage>(new ChannelCloseMessage(_localChannelNumber)));
                        }).Start());
            var channelBindFinishedWaitHandle = new ManualResetEvent(false);
            Socket handler = null;
            ChannelDirectTcpip channel = null;

            var localPortEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);
            using (var localPortListener = new AsyncSocketListener(localPortEndPoint))
            {
                localPortListener.Start();

                localPortListener.Connected += socket =>
                    {
                        channel = new ChannelDirectTcpip(_sessionMock.Object, _localChannelNumber, _localWindowSize,
                            _localPacketSize);
                        channel.Open(_remoteHost, _port, _forwardedPortMock.Object, socket);
                        channel.Bind();
                        channel.Close();

                        handler = socket;

                        channelBindFinishedWaitHandle.Set();
                    };

                var client = new Socket(localPortEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                client.Connect(localPortEndPoint);
                client.Shutdown(SocketShutdown.Send);
                Assert.IsFalse(client.Connected);

                channelBindFinishedWaitHandle.WaitOne();

                Assert.IsNotNull(handler);
                Assert.IsFalse(handler.Connected);

                _sessionMock.Verify(p => p.TrySendMessage(It.IsAny<ChannelEofMessage>()), Times.Once);
                _sessionMock.Verify(p => p.TrySendMessage(It.IsAny<ChannelCloseMessage>()), Times.Once);

                channel.Close();

                _sessionMock.Verify(p => p.TrySendMessage(It.IsAny<ChannelEofMessage>()), Times.Once);
                _sessionMock.Verify(p => p.TrySendMessage(It.IsAny<ChannelCloseMessage>()), Times.Once);
            }
        }
        protected virtual void Arrange()
        {
            Random = new Random();

            _serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);
            ConnectionInfo = new ConnectionInfo(
                _serverEndPoint.Address.ToString(),
                _serverEndPoint.Port,
                "user",
                new PasswordAuthenticationMethod("user", "password"));
            ConnectionInfo.Timeout = TimeSpan.FromSeconds(20);
            _keyExchangeAlgorithm = Random.Next().ToString(CultureInfo.InvariantCulture);
            SessionId = new byte[10];
            Random.NextBytes(SessionId);
            DisconnectedRegister = new List<EventArgs>();
            DisconnectReceivedRegister = new List<MessageEventArgs<DisconnectMessage>>();
            ErrorOccurredRegister = new List<ExceptionEventArgs>();
            ServerBytesReceivedRegister = new List<byte[]>();

            _serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
            _keyExchangeMock = new Mock<IKeyExchange>(MockBehavior.Strict);
            _clientAuthenticationMock = new Mock<IClientAuthentication>(MockBehavior.Strict);

            Session = new Session(ConnectionInfo, _serviceFactoryMock.Object);
            Session.Disconnected += (sender, args) => DisconnectedRegister.Add(args);
            Session.DisconnectReceived += (sender, args) => DisconnectReceivedRegister.Add(args);
            Session.ErrorOccured += (sender, args) => ErrorOccurredRegister.Add(args);
            Session.KeyExchangeInitReceived += (sender, args) =>
                {
                    var newKeysMessage = new NewKeysMessage();
                    var newKeys = newKeysMessage.GetPacket(8, null);
                    ServerSocket.Send(newKeys, 4, newKeys.Length - 4, SocketFlags.None);
                };

            _serviceFactoryMock.Setup(p => p.CreateKeyExchange(ConnectionInfo.KeyExchangeAlgorithms, new[] { _keyExchangeAlgorithm })).Returns(_keyExchangeMock.Object);
            _keyExchangeMock.Setup(p => p.Name).Returns(_keyExchangeAlgorithm);
            _keyExchangeMock.Setup(p => p.Start(Session, It.IsAny<KeyExchangeInitMessage>()));
            _keyExchangeMock.Setup(p => p.ExchangeHash).Returns(SessionId);
            _keyExchangeMock.Setup(p => p.CreateServerCipher()).Returns((Cipher) null);
            _keyExchangeMock.Setup(p => p.CreateClientCipher()).Returns((Cipher) null);
            _keyExchangeMock.Setup(p => p.CreateServerHash()).Returns((HashAlgorithm) null);
            _keyExchangeMock.Setup(p => p.CreateClientHash()).Returns((HashAlgorithm) null);
            _keyExchangeMock.Setup(p => p.CreateCompressor()).Returns((Compressor) null);
            _keyExchangeMock.Setup(p => p.CreateDecompressor()).Returns((Compressor) null);
            _keyExchangeMock.Setup(p => p.Dispose());
            _serviceFactoryMock.Setup(p => p.CreateClientAuthentication()).Returns(_clientAuthenticationMock.Object);
            _clientAuthenticationMock.Setup(p => p.Authenticate(ConnectionInfo, Session));

            ServerListener = new AsyncSocketListener(_serverEndPoint);
            ServerListener.Connected += socket =>
                {
                    ServerSocket = socket;

                    socket.Send(Encoding.ASCII.GetBytes("\r\n"));
                    socket.Send(Encoding.ASCII.GetBytes("WELCOME banner\r\n"));
                    socket.Send(Encoding.ASCII.GetBytes("SSH-2.0-SshStub\r\n"));
                };

            var counter = 0;
            ServerListener.BytesReceived += (received, socket) =>
                {
                    ServerBytesReceivedRegister.Add(received);

                    switch (counter++)
                    {
                        case 0:
                            var keyExchangeInitMessage = new KeyExchangeInitMessage
                                {
                                    CompressionAlgorithmsClientToServer = new string[0],
                                    CompressionAlgorithmsServerToClient = new string[0],
                                    EncryptionAlgorithmsClientToServer = new string[0],
                                    EncryptionAlgorithmsServerToClient = new string[0],
                                    KeyExchangeAlgorithms = new[] {_keyExchangeAlgorithm},
                                    LanguagesClientToServer = new string[0],
                                    LanguagesServerToClient = new string[0],
                                    MacAlgorithmsClientToServer = new string[0],
                                    MacAlgorithmsServerToClient = new string[0],
                                    ServerHostKeyAlgorithms = new string[0]
                                };
                            var keyExchangeInit = keyExchangeInitMessage.GetPacket(8, null);
                            ServerSocket.Send(keyExchangeInit, 4, keyExchangeInit.Length - 4, SocketFlags.None);
                            break;
                        case 1:
                            var serviceAcceptMessage =
                                ServiceAcceptMessageBuilder.Create(ServiceName.UserAuthentication)
                                    .Build();
                            ServerSocket.Send(serviceAcceptMessage, 0, serviceAcceptMessage.Length, SocketFlags.None);
                            break;
                    }
                };
            ServerListener.Start();

            Session.Connect();
        }
        protected virtual void SetupData()
        {
            Random = new Random();

            _serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);
            ConnectionInfo = new ConnectionInfo(
                _serverEndPoint.Address.ToString(),
                _serverEndPoint.Port,
                "user",
                new PasswordAuthenticationMethod("user", "password"))
            { Timeout = TimeSpan.FromSeconds(20) };
            _keyExchangeAlgorithm = Random.Next().ToString(CultureInfo.InvariantCulture);
            SessionId = new byte[10];
            Random.NextBytes(SessionId);
            DisconnectedRegister = new List<EventArgs>();
            DisconnectReceivedRegister = new List<MessageEventArgs<DisconnectMessage>>();
            ErrorOccurredRegister = new List<ExceptionEventArgs>();
            ServerBytesReceivedRegister = new List<byte[]>();
            _disconnectMessage = new DisconnectMessage(DisconnectReason.ServiceNotAvailable, "Not today!");

            Session = new Session(ConnectionInfo, _serviceFactoryMock.Object);
            Session.Disconnected += (sender, args) => DisconnectedRegister.Add(args);
            Session.DisconnectReceived += (sender, args) => DisconnectReceivedRegister.Add(args);
            Session.ErrorOccured += (sender, args) => ErrorOccurredRegister.Add(args);
            Session.KeyExchangeInitReceived += (sender, args) =>
            {
                var newKeysMessage = new NewKeysMessage();
                var newKeys = newKeysMessage.GetPacket(8, null);
                ServerSocket.Send(newKeys, 4, newKeys.Length - 4, SocketFlags.None);
            };

            ServerListener = new AsyncSocketListener(_serverEndPoint);
            ServerListener.Connected += socket =>
            {
                ServerSocket = socket;

                socket.Send(Encoding.ASCII.GetBytes("\r\n"));
                socket.Send(Encoding.ASCII.GetBytes("WELCOME banner\r\n"));
                socket.Send(Encoding.ASCII.GetBytes("SSH-2.0-SshStub\r\n"));
            };

            var counter = 0;

            ServerListener.BytesReceived += (received, socket) =>
            {
                ServerBytesReceivedRegister.Add(received);

                switch (counter++)
                {
                    case 0:
                        var keyExchangeInitMessage = new KeyExchangeInitMessage
                        {
                            CompressionAlgorithmsClientToServer = new string[0],
                            CompressionAlgorithmsServerToClient = new string[0],
                            EncryptionAlgorithmsClientToServer = new string[0],
                            EncryptionAlgorithmsServerToClient = new string[0],
                            KeyExchangeAlgorithms = new[] { _keyExchangeAlgorithm },
                            LanguagesClientToServer = new string[0],
                            LanguagesServerToClient = new string[0],
                            MacAlgorithmsClientToServer = new string[0],
                            MacAlgorithmsServerToClient = new string[0],
                            ServerHostKeyAlgorithms = new string[0]
                        };
                        var keyExchangeInit = keyExchangeInitMessage.GetPacket(8, null);
                        ServerSocket.Send(keyExchangeInit, 4, keyExchangeInit.Length - 4, SocketFlags.None);
                        break;
                    case 1:
                        var serviceAcceptMessage =ServiceAcceptMessageBuilder.Create(ServiceName.UserAuthentication).Build();
                        ServerSocket.Send(serviceAcceptMessage, 0, serviceAcceptMessage.Length, SocketFlags.None);
                        break;
                }
            };
        }
示例#11
0
        public void ConnectShouldSshConnectionExceptionWhenServerResponseDoesNotContainProtocolIdentificationString()
        {
            var serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);

            // response ends with CRLF
            using (var serverStub = new AsyncSocketListener(serverEndPoint))
            {
                serverStub.Connected += socket =>
                    {
                        socket.Send(Encoding.ASCII.GetBytes("\r\n"));
                        socket.Send(Encoding.ASCII.GetBytes("WELCOME banner\r\n"));
                        socket.Shutdown(SocketShutdown.Send);
                    };
                serverStub.Start();

                using (var session = new Session(CreateConnectionInfo(serverEndPoint, TimeSpan.FromSeconds(5)), _serviceFactoryMock.Object))
                {
                    try
                    {
                        session.Connect();
                        Assert.Fail();
                    }
                    catch (SshConnectionException ex)
                    {
                        Assert.IsNull(ex.InnerException);
                        Assert.AreEqual("Server response does not contain SSH protocol identification.", ex.Message);
                    }
                }
            }

            // response does not end with CRLF
            using (var serverStub = new AsyncSocketListener(serverEndPoint))
            {
                serverStub.Connected += socket =>
                    {
                        socket.Send(Encoding.ASCII.GetBytes("\r\n"));
                        socket.Send(Encoding.ASCII.GetBytes("WELCOME banner"));
                        socket.Shutdown(SocketShutdown.Send);
                    };
                serverStub.Start();

                using (var session = new Session(CreateConnectionInfo(serverEndPoint, TimeSpan.FromSeconds(5)), _serviceFactoryMock.Object))
                {
                    try
                    {
                        session.Connect();
                        Assert.Fail();
                    }
                    catch (SshConnectionException ex)
                    {
                        Assert.IsNull(ex.InnerException);
                        Assert.AreEqual("Server response does not contain SSH protocol identification.", ex.Message);
                    }
                }
            }

            // last line is empty
            using (var serverStub = new AsyncSocketListener(serverEndPoint))
            {
                serverStub.Connected += socket =>
                    {
                        socket.Send(Encoding.ASCII.GetBytes("\r\n"));
                        socket.Send(Encoding.ASCII.GetBytes("WELCOME banner\r\n"));
                        socket.Send(Encoding.ASCII.GetBytes("\r\n"));
                        socket.Shutdown(SocketShutdown.Send);
                    };
                serverStub.Start();

                using (var session = new Session(CreateConnectionInfo(serverEndPoint, TimeSpan.FromSeconds(5)), _serviceFactoryMock.Object))
                {
                    try
                    {
                        session.Connect();
                        Assert.Fail();
                    }
                    catch (SshConnectionException ex)
                    {
                        Assert.IsNull(ex.InnerException);
                        Assert.AreEqual("Server response does not contain SSH protocol identification.", ex.Message);
                    }
                }
            }
        }
示例#12
0
        public void ConnectShouldThrowSshOperationExceptionWhenServerDoesNotRespondWithinConnectionTimeout()
        {
            var serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122);
            var timeout = TimeSpan.FromMilliseconds(500);
            Socket clientSocket = null;

            using (var serverStub = new AsyncSocketListener(serverEndPoint))
            {
                serverStub.Connected += socket =>
                    {
                        socket.Send(Encoding.ASCII.GetBytes("\r\n"));
                        socket.Send(Encoding.ASCII.GetBytes("WELCOME banner\r\n"));
                        clientSocket = socket;
                    };
                serverStub.Start();

                using (var session = new Session(CreateConnectionInfo(serverEndPoint, TimeSpan.FromMilliseconds(500)), _serviceFactoryMock.Object))
                {
                    try
                    {
                        session.Connect();
                        Assert.Fail();
                    }
                    catch (SshOperationTimeoutException ex)
                    {
                        Assert.IsNull(ex.InnerException);
                        Assert.AreEqual(string.Format(CultureInfo.InvariantCulture, "Socket read operation has timed out after {0:F0} milliseconds.", timeout.TotalMilliseconds), ex.Message);

                        Assert.IsNotNull(clientSocket);
                        Assert.IsTrue(clientSocket.Connected);

                        // shut down socket
                        clientSocket.Shutdown(SocketShutdown.Send);
                    }
                }
            }
        }
        private void Arrange()
        {
            var random = new Random();
            _localChannelNumber = (uint) random.Next(0, int.MaxValue);
            _localWindowSize = (uint) random.Next(2000, 3000);
            _localPacketSize = (uint) random.Next(1000, 2000);
            _remoteHost = random.Next().ToString(CultureInfo.InvariantCulture);
            _port = (uint) random.Next(IPEndPoint.MinPort, IPEndPoint.MaxPort);
            _channelBindFinishedWaitHandle = new ManualResetEvent(false);
            _clientReceivedFinishedWaitHandle = new ManualResetEvent(false);
            _channelException = null;

            _remoteChannelNumber = (uint)random.Next(0, int.MaxValue);
            _remoteWindowSize = (uint)random.Next(0, int.MaxValue);
            _remotePacketSize = (uint)random.Next(100, 200);

            _sessionMock = new Mock<ISession>(MockBehavior.Strict);
            _forwardedPortMock = new Mock<IForwardedPort>(MockBehavior.Strict);

            var sequence = new MockSequence();
            _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true);
            _sessionMock.InSequence(sequence)
                .Setup(p => p.SendMessage(It.Is<ChannelOpenMessage>(m => AssertExpectedMessage(m))));
            _sessionMock.InSequence(sequence)
                .Setup(p => p.WaitOnHandle(It.IsNotNull<WaitHandle>()))
                .Callback<WaitHandle>(
                    w =>
                    {
                        _sessionMock.Raise(
                            s => s.ChannelOpenConfirmationReceived += null,
                            new MessageEventArgs<ChannelOpenConfirmationMessage>(
                                new ChannelOpenConfirmationMessage(
                                    _localChannelNumber,
                                    _remoteWindowSize,
                                    _remotePacketSize,
                                    _remoteChannelNumber)));
                        w.WaitOne();
                    });
            _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true);
            _sessionMock.InSequence(sequence)
                .Setup(
                    p => p.TrySendMessage(It.Is<ChannelEofMessage>(m => m.LocalChannelNumber == _remoteChannelNumber)))
                .Returns(true);
            _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true);
            _sessionMock.InSequence(sequence)
                .Setup(
                    p => p.TrySendMessage(It.Is<ChannelCloseMessage>(m => m.LocalChannelNumber == _remoteChannelNumber)))
                .Returns(true);
            _sessionMock.InSequence(sequence)
                .Setup(p => p.WaitOnHandle(It.IsNotNull<WaitHandle>()))
                .Callback<WaitHandle>(
                    w =>
                    {
                        _sessionMock.Raise(
                            s => s.ChannelCloseReceived += null,
                            new MessageEventArgs<ChannelCloseMessage>(new ChannelCloseMessage(_localChannelNumber)));
                        w.WaitOne();
                    });

            var localEndpoint = new IPEndPoint(IPAddress.Loopback, 8122);
            _listener = new AsyncSocketListener(localEndpoint);
            _listener.Connected += socket =>
                {
                    try
                    {
                        _channel = new ChannelDirectTcpip(
                            _sessionMock.Object,
                            _localChannelNumber,
                            _localWindowSize,
                            _localPacketSize);
                        _channel.Open(_remoteHost, _port, _forwardedPortMock.Object, socket);
                        _channel.Bind();
                    }
                    catch (Exception ex)
                    {
                        _channelException = ex;
                    }
                    finally
                    {
                        _channelBindFinishedWaitHandle.Set();
                    }
                };
            _listener.Start();

            _client = new Socket(localEndpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            _client.Connect(localEndpoint);

            var clientReceiveThread = new Thread(
                () =>
                    {
                        var buffer = new byte[16];
                        var bytesReceived = _client.Receive(buffer, 0, buffer.Length, SocketFlags.None);
                        if (bytesReceived == 0)
                        {
                            _client.Shutdown(SocketShutdown.Send);
                            _clientReceivedFinishedWaitHandle.Set();
                        }
                    }
                );
            clientReceiveThread.Start();

            // give channel time to bind to socket
            Thread.Sleep(200);
        }
        private void Arrange()
        {
            var random = new Random();
            _localChannelNumber = (uint) random.Next(0, int.MaxValue);
            _localWindowSize = (uint) random.Next(2000, 3000);
            _localPacketSize = (uint) random.Next(1000, 2000);
            _remoteChannelNumber = (uint) random.Next(0, int.MaxValue);
            _remoteWindowSize = (uint) random.Next(0, int.MaxValue);
            _remotePacketSize = (uint) random.Next(100, 200);
            _channelBindFinishedWaitHandle = new ManualResetEvent(false);
            _channelException = null;
            _connectedRegister = new List<Socket>();
            _disconnectedRegister = new List<Socket>();
            _connectionInfoTimeout = TimeSpan.FromSeconds(5);

            _remoteEndpoint = new IPEndPoint(IPAddress.Loopback, 8122);

            _sessionMock = new Mock<ISession>(MockBehavior.Strict);
            _connectionInfoMock = new Mock<IConnectionInfo>(MockBehavior.Strict);
            _forwardedPortMock = new Mock<IForwardedPort>(MockBehavior.Strict);

            var sequence = new MockSequence();
            _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true);
            _sessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object);
            _connectionInfoMock.InSequence(sequence).Setup(p => p.Timeout).Returns(_connectionInfoTimeout);
            _sessionMock.InSequence(sequence).Setup(
                p => p.SendMessage(
                    It.Is<ChannelOpenConfirmationMessage>(
                        m => m.LocalChannelNumber == _remoteChannelNumber
                             &&
                             m.InitialWindowSize == _localWindowSize
                             &&
                             m.MaximumPacketSize == _localPacketSize
                             &&
                             m.RemoteChannelNumber == _localChannelNumber)
                    ));
            _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true);
            _sessionMock.InSequence(sequence)
                .Setup(
                    p => p.TrySendMessage(It.Is<ChannelEofMessage>(m => m.LocalChannelNumber == _remoteChannelNumber)))
                .Returns(true);
            _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true);
            _sessionMock.InSequence(sequence)
                .Setup(
                    p => p.TrySendMessage(It.Is<ChannelCloseMessage>(m => m.LocalChannelNumber == _remoteChannelNumber)))
                .Returns(true);
            _sessionMock.InSequence(sequence)
                .Setup(p => p.WaitOnHandle(It.IsNotNull<WaitHandle>()))
                .Callback<WaitHandle>(
                    w =>
                        {
                            _sessionMock.Raise(
                                s => s.ChannelCloseReceived += null,
                                new MessageEventArgs<ChannelCloseMessage>(new ChannelCloseMessage(_localChannelNumber)));
                            w.WaitOne();
                        });

            _remoteListener = new AsyncSocketListener(_remoteEndpoint);
            _remoteListener.Connected += socket => _connectedRegister.Add(socket);
            _remoteListener.Disconnected += socket => _disconnectedRegister.Add(socket);
            _remoteListener.Start();

            _channel = new ChannelForwardedTcpip(
                _sessionMock.Object,
                _localChannelNumber,
                _localWindowSize,
                _localPacketSize,
                _remoteChannelNumber,
                _remoteWindowSize,
                _remotePacketSize);

            _channelThread = new Thread(() =>
                {
                    try
                    {
                        _channel.Bind(_remoteEndpoint, _forwardedPortMock.Object);
                    }
                    catch (Exception ex)
                    {
                        _channelException = ex;
                    }
                    finally
                    {
                        _channelBindFinishedWaitHandle.Set();
                    }
                });
            _channelThread.Start();

            // give channel time to bind to remote endpoint
            Thread.Sleep(100);
        }