< Summary

Information
Class: Renci.SshNet.Channels.ChannelForwardedTcpip
Assembly: Renci.SshNet
File(s): \home\appveyor\projects\ssh-net\src\Renci.SshNet\Channels\ChannelForwardedTcpip.cs
Line coverage
80%
Covered lines: 70
Uncovered lines: 17
Coverable lines: 87
Total lines: 208
Line coverage: 80.4%
Branch coverage
75%
Covered branches: 12
Total branches: 16
Branch coverage: 75%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
.ctor(...)100%1100%
get_ChannelType()100%10%
Bind(...)50%264.7%
OnErrorOccured(...)100%10%
ForwardedPort_Closing(...)100%1100%
ShutdownSocket(...)50%668.42%
CloseSocket()100%4100%
Close()100%2100%
OnData(...)100%2100%

File(s)

\home\appveyor\projects\ssh-net\src\Renci.SshNet\Channels\ChannelForwardedTcpip.cs

#LineLine coverage
 1using System;
 2using System.Net;
 3using System.Net.Sockets;
 4using Renci.SshNet.Abstractions;
 5using Renci.SshNet.Common;
 6using Renci.SshNet.Messages.Connection;
 7
 8namespace Renci.SshNet.Channels
 9{
 10    /// <summary>
 11    /// Implements "forwarded-tcpip" SSH channel.
 12    /// </summary>
 13    internal sealed class ChannelForwardedTcpip : ServerChannel, IChannelForwardedTcpip
 14    {
 1715        private readonly object _socketShutdownAndCloseLock = new object();
 16        private Socket _socket;
 17        private IForwardedPort _forwardedPort;
 18
 19        /// <summary>
 20        /// Initializes a new instance of the <see cref="ChannelForwardedTcpip"/> class.
 21        /// </summary>
 22        /// <param name="session">The session.</param>
 23        /// <param name="localChannelNumber">The local channel number.</param>
 24        /// <param name="localWindowSize">Size of the window.</param>
 25        /// <param name="localPacketSize">Size of the packet.</param>
 26        /// <param name="remoteChannelNumber">The remote channel number.</param>
 27        /// <param name="remoteWindowSize">The window size of the remote party.</param>
 28        /// <param name="remotePacketSize">The maximum size of a data packet that we can send to the remote party.</para
 29        internal ChannelForwardedTcpip(ISession session,
 30                                       uint localChannelNumber,
 31                                       uint localWindowSize,
 32                                       uint localPacketSize,
 33                                       uint remoteChannelNumber,
 34                                       uint remoteWindowSize,
 35                                       uint remotePacketSize)
 1736            : base(session,
 1737                   localChannelNumber,
 1738                   localWindowSize,
 1739                   localPacketSize,
 1740                   remoteChannelNumber,
 1741                   remoteWindowSize,
 1742                   remotePacketSize)
 1743        {
 1744        }
 45
 46        /// <summary>
 47        /// Gets the type of the channel.
 48        /// </summary>
 49        /// <value>
 50        /// The type of the channel.
 51        /// </value>
 52        public override ChannelTypes ChannelType
 53        {
 054            get { return ChannelTypes.ForwardedTcpip; }
 55        }
 56
 57        /// <summary>
 58        /// Binds the channel to the specified endpoint.
 59        /// </summary>
 60        /// <param name="remoteEndpoint">The endpoint to connect to.</param>
 61        /// <param name="forwardedPort">The forwarded port for which the channel is opened.</param>
 62        public void Bind(IPEndPoint remoteEndpoint, IForwardedPort forwardedPort)
 1763        {
 1764            if (!IsConnected)
 065            {
 066                throw new SshException("Session is not connected.");
 67            }
 68
 1769            _forwardedPort = forwardedPort;
 1770            _forwardedPort.Closing += ForwardedPort_Closing;
 71
 72            // Try to connect to the socket
 73            try
 1774            {
 1775                _socket = SocketAbstraction.Connect(remoteEndpoint, ConnectionInfo.Timeout);
 76
 77                // Send channel open confirmation message
 1778                SendMessage(new ChannelOpenConfirmationMessage(RemoteChannelNumber, LocalWindowSize, LocalPacketSize, Lo
 1779            }
 080            catch (Exception exp)
 081            {
 82                // Send channel open failure message
 083                SendMessage(new ChannelOpenFailureMessage(RemoteChannelNumber, exp.ToString(), ChannelOpenFailureMessage
 84
 085                throw;
 86            }
 87
 1788            var buffer = new byte[RemotePacketSize];
 89
 1790            SocketAbstraction.ReadContinuous(_socket, buffer, 0, buffer.Length, SendData);
 1791        }
 92
 93        protected override void OnErrorOccured(Exception exp)
 094        {
 095            base.OnErrorOccured(exp);
 96
 97            // signal to the server that we will not send anything anymore; this will also interrupt the
 98            // blocking receive in Bind if the server sends FIN/ACK in time
 99            //
 100            // if the FIN/ACK is not sent in time, the socket will be closed in Close(bool)
 0101            ShutdownSocket(SocketShutdown.Send);
 0102        }
 103
 104        /// <summary>
 105        /// Occurs as the forwarded port is being stopped.
 106        /// </summary>
 107        private void ForwardedPort_Closing(object sender, EventArgs eventArgs)
 2108        {
 109            // signal to the server that we will not send anything anymore; this will also interrupt the
 110            // blocking receive in Bind if the server sends FIN/ACK in time
 111            //
 112            // if the FIN/ACK is not sent in time, the socket will be closed in Close(bool)
 2113            ShutdownSocket(SocketShutdown.Send);
 2114        }
 115
 116        /// <summary>
 117        /// Shuts down the socket.
 118        /// </summary>
 119        /// <param name="how">One of the <see cref="SocketShutdown"/> values that specifies the operation that will no l
 120        private void ShutdownSocket(SocketShutdown how)
 36121        {
 36122            if (_socket is null)
 0123            {
 0124                return;
 125            }
 126
 36127            lock (_socketShutdownAndCloseLock)
 36128            {
 36129                var socket = _socket;
 36130                if (!socket.IsConnected())
 19131                {
 19132                    return;
 133                }
 134
 135                try
 17136                {
 17137                    socket.Shutdown(how);
 17138                }
 0139                catch (SocketException ex)
 0140                {
 141                    // TODO: log as warning
 0142                    DiagnosticAbstraction.Log("Failure shutting down socket: " + ex);
 0143                }
 17144            }
 36145        }
 146
 147        /// <summary>
 148        /// Closes the socket, hereby interrupting the blocking receive in <see cref="Bind(IPEndPoint,IForwardedPort)"/>
 149        /// </summary>
 150        private void CloseSocket()
 34151        {
 34152            if (_socket is null)
 17153            {
 17154                return;
 155            }
 156
 17157            lock (_socketShutdownAndCloseLock)
 17158            {
 17159                var socket = _socket;
 17160                if (socket != null)
 17161                {
 17162                    _socket = null;
 17163                    socket.Dispose();
 17164                }
 17165            }
 34166        }
 167
 168        /// <summary>
 169        /// Closes the channel waiting for the SSH_MSG_CHANNEL_CLOSE message to be received from the server.
 170        /// </summary>
 171        protected override void Close()
 34172        {
 34173            var forwardedPort = _forwardedPort;
 34174            if (forwardedPort != null)
 17175            {
 17176                forwardedPort.Closing -= ForwardedPort_Closing;
 17177                _forwardedPort = null;
 17178            }
 179
 180            // signal to the server that we will not send anything anymore; this will also interrupt the
 181            // blocking receive in Bind if the server sends FIN/ACK in time
 182            //
 183            // if the FIN/ACK is not sent in time, the socket will be closed after the channel is closed
 34184            ShutdownSocket(SocketShutdown.Send);
 185
 186            // close the SSH channel, and mark the channel closed
 34187            base.Close();
 188
 189            // close the socket
 34190            CloseSocket();
 34191        }
 192
 193        /// <summary>
 194        /// Called when channel data is received.
 195        /// </summary>
 196        /// <param name="data">The data.</param>
 197        protected override void OnData(byte[] data)
 2198        {
 2199            base.OnData(data);
 200
 2201            var socket = _socket;
 2202            if (socket.IsConnected())
 2203            {
 2204                SocketAbstraction.Send(socket, data, 0, data.Length);
 2205            }
 2206        }
 207    }
 208}