< Summary

Information
Class: Renci.SshNet.Channels.Channel
Assembly: Renci.SshNet
File(s): \home\appveyor\projects\ssh-net\src\Renci.SshNet\Channels\Channel.cs
Line coverage
95%
Covered lines: 360
Uncovered lines: 16
Coverable lines: 376
Total lines: 875
Line coverage: 95.7%
Branch coverage
88%
Covered branches: 78
Total branches: 88
Branch coverage: 88.6%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
.ctor(...)100%1100%
get_Session()100%1100%
get_LocalChannelNumber()100%1100%
get_LocalPacketSize()100%1100%
get_LocalWindowSize()100%1100%
get_RemoteChannelNumber()50%266.66%
set_RemoteChannelNumber(...)100%1100%
get_RemotePacketSize()50%266.66%
set_RemotePacketSize(...)100%1100%
get_RemoteWindowSize()50%266.66%
set_RemoteWindowSize(...)100%1100%
get_IsOpen()100%1100%
get_IsConnected()100%1100%
get_ConnectionInfo()100%1100%
get_SessionSemaphore()100%1100%
InitializeRemoteInfo(...)100%1100%
SendData(...)100%1100%
SendData(...)100%4100%
OnWindowAdjust(...)100%1100%
OnData(...)100%2100%
OnExtendedData(...)50%2100%
OnEof()100%2100%
OnClose()100%2100%
OnRequest(...)100%2100%
OnSuccess()50%2100%
OnFailure()50%2100%
RaiseExceptionEvent(...)50%2100%
TrySendMessage(...)100%1100%
SendMessage(...)50%266.66%
SendEof()100%2100%
WaitOnHandle(...)100%1100%
Close()100%28100%
OnDisconnected()100%1100%
OnErrorOccured(...)100%1100%
Session_Disconnected(...)100%1100%
OnChannelException(...)100%1100%
Session_ErrorOccured(...)100%1100%
OnChannelWindowAdjust(...)100%291.66%
OnChannelData(...)100%291.66%
OnChannelExtendedData(...)100%291.66%
OnChannelEof(...)100%2100%
OnChannelClose(...)100%2100%
OnChannelRequest(...)75%477.77%
OnChannelSuccess(...)100%291.66%
OnChannelFailure(...)100%291.66%
AdjustDataWindow(...)50%250%
GetDataLengthThatCanBeSentInMessage(...)100%2100%
CreateRemoteChannelInfoNotAvailableException()100%10%
CreateChannelClosedException()100%1100%
Dispose()100%1100%
Dispose(...)100%8100%
Finalize()100%1100%

File(s)

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

#LineLine coverage
 1using System;
 2using System.Globalization;
 3using System.Net.Sockets;
 4using System.Threading;
 5
 6using Renci.SshNet.Abstractions;
 7using Renci.SshNet.Common;
 8using Renci.SshNet.Messages;
 9using Renci.SshNet.Messages.Connection;
 10
 11namespace Renci.SshNet.Channels
 12{
 13    /// <summary>
 14    /// Represents base class for SSH channel implementations.
 15    /// </summary>
 16    internal abstract class Channel : IChannel
 17    {
 228818        private readonly object _serverWindowSizeLock = new object();
 228819        private readonly object _messagingLock = new object();
 20        private readonly uint _initialWindowSize;
 21        private readonly ISession _session;
 228822        private EventWaitHandle _channelClosedWaitHandle = new ManualResetEvent(initialState: false);
 228823        private EventWaitHandle _channelServerWindowAdjustWaitHandle = new ManualResetEvent(initialState: false);
 24        private uint? _remoteWindowSize;
 25        private uint? _remoteChannelNumber;
 26        private uint? _remotePacketSize;
 27        private bool _isDisposed;
 28
 29        /// <summary>
 30        /// Holds a value indicating whether the SSH_MSG_CHANNEL_CLOSE has been sent to the remote party.
 31        /// </summary>
 32        /// <value>
 33        /// <see langword="true"/> when a SSH_MSG_CHANNEL_CLOSE message has been sent to the other party;
 34        /// otherwise, <see langword="false"/>.
 35        /// </value>
 36        private bool _closeMessageSent;
 37
 38        /// <summary>
 39        /// Holds a value indicating whether a SSH_MSG_CHANNEL_CLOSE has been received from the other
 40        /// party.
 41        /// </summary>
 42        /// <value>
 43        /// <see langword="true"/> when a SSH_MSG_CHANNEL_CLOSE message has been received from the other party;
 44        /// otherwise, <see langword="false"/>.
 45        /// </value>
 46        private bool _closeMessageReceived;
 47
 48        /// <summary>
 49        /// Holds a value indicating whether the SSH_MSG_CHANNEL_EOF has been received from the other party.
 50        /// </summary>
 51        /// <value>
 52        /// <see langword="true"/> when a SSH_MSG_CHANNEL_EOF message has been received from the other party;
 53        /// otherwise, <see langword="false"/>.
 54        /// </value>
 55        private bool _eofMessageReceived;
 56
 57        /// <summary>
 58        /// Holds a value indicating whether the SSH_MSG_CHANNEL_EOF has been sent to the remote party.
 59        /// </summary>
 60        /// <value>
 61        /// <see langword="true"/> when a SSH_MSG_CHANNEL_EOF message has been sent to the remote party;
 62        /// otherwise, <see langword="false"/>.
 63        /// </value>
 64        private bool _eofMessageSent;
 65
 66        /// <summary>
 67        /// Occurs when an exception is thrown when processing channel messages.
 68        /// </summary>
 69        public event EventHandler<ExceptionEventArgs> Exception;
 70
 71        /// <summary>
 72        /// Initializes a new instance of the <see cref="Channel"/> class.
 73        /// </summary>
 74        /// <param name="session">The session.</param>
 75        /// <param name="localChannelNumber">The local channel number.</param>
 76        /// <param name="localWindowSize">Size of the window.</param>
 77        /// <param name="localPacketSize">Size of the packet.</param>
 228878        protected Channel(ISession session, uint localChannelNumber, uint localWindowSize, uint localPacketSize)
 228879        {
 228880            _session = session;
 228881            _initialWindowSize = localWindowSize;
 228882            LocalChannelNumber = localChannelNumber;
 228883            LocalPacketSize = localPacketSize;
 228884            LocalWindowSize = localWindowSize;
 85
 228886            session.ChannelWindowAdjustReceived += OnChannelWindowAdjust;
 228887            session.ChannelDataReceived += OnChannelData;
 228888            session.ChannelExtendedDataReceived += OnChannelExtendedData;
 228889            session.ChannelEofReceived += OnChannelEof;
 228890            session.ChannelCloseReceived += OnChannelClose;
 228891            session.ChannelRequestReceived += OnChannelRequest;
 228892            session.ChannelSuccessReceived += OnChannelSuccess;
 228893            session.ChannelFailureReceived += OnChannelFailure;
 228894            session.ErrorOccured += Session_ErrorOccured;
 228895            session.Disconnected += Session_Disconnected;
 228896        }
 97
 98        /// <summary>
 99        /// Gets the session.
 100        /// </summary>
 101        /// <value>
 102        ///  Thhe session.
 103        /// </value>
 104        protected ISession Session
 105        {
 12186106            get { return _session; }
 107        }
 108
 109        /// <summary>
 110        /// Gets the type of the channel.
 111        /// </summary>
 112        /// <value>
 113        /// The type of the channel.
 114        /// </value>
 115        public abstract ChannelTypes ChannelType { get; }
 116
 117        /// <summary>
 118        /// Gets the local channel number.
 119        /// </summary>
 120        /// <value>
 121        /// The local channel number.
 122        /// </value>
 97254123        public uint LocalChannelNumber { get; private set; }
 124
 125        /// <summary>
 126        /// Gets the maximum size of a data packet that we can receive using the channel.
 127        /// </summary>
 128        /// <value>
 129        /// The maximum size of a packet.
 130        /// </value>
 131        /// <remarks>
 132        /// <para>
 133        /// This is the maximum size (in bytes) we support for the data (payload) of a
 134        /// <c>SSH_MSG_CHANNEL_DATA</c> message we receive.
 135        /// </para>
 136        /// <para>
 137        /// We currently do not enforce this limit.
 138        /// </para>
 139        /// </remarks>
 39454140        public uint LocalPacketSize { get; private set; }
 141
 142        /// <summary>
 143        /// Gets the size of the local window.
 144        /// </summary>
 145        /// <value>
 146        /// The size of the local window.
 147        /// </value>
 108757148        public uint LocalWindowSize { get; private set; }
 149
 150        /// <summary>
 151        /// Gets the remote channel number.
 152        /// </summary>
 153        /// <value>
 154        /// The remote channel number.
 155        /// </value>
 156        public uint RemoteChannelNumber
 157        {
 158            get
 41801159            {
 41801160                if (!_remoteChannelNumber.HasValue)
 0161                {
 0162                    throw CreateRemoteChannelInfoNotAvailableException();
 163                }
 164
 41801165                return _remoteChannelNumber.Value;
 41801166            }
 167            private set
 2153168            {
 2153169                _remoteChannelNumber = value;
 2153170            }
 171        }
 172
 173        /// <summary>
 174        /// Gets the maximum size of a data packet that we can send using the channel.
 175        /// </summary>
 176        /// <value>
 177        /// The maximum size of data that can be sent using a <see cref="ChannelDataMessage"/>
 178        /// on the current channel.
 179        /// </value>
 180        /// <exception cref="InvalidOperationException">The channel has not been opened, or the open has not yet been co
 181        public uint RemotePacketSize
 182        {
 183            get
 37276184            {
 37276185                if (!_remotePacketSize.HasValue)
 0186                {
 0187                    throw CreateRemoteChannelInfoNotAvailableException();
 188                }
 189
 37276190                return _remotePacketSize.Value;
 37276191            }
 192            private set
 2153193            {
 2153194                _remotePacketSize = value;
 2153195            }
 196        }
 197
 198        /// <summary>
 199        /// Gets the window size of the remote server.
 200        /// </summary>
 201        /// <value>
 202        /// The size of the server window.
 203        /// </value>
 204        public uint RemoteWindowSize
 205        {
 206            get
 77214207            {
 77214208                if (!_remoteWindowSize.HasValue)
 0209                {
 0210                    throw CreateRemoteChannelInfoNotAvailableException();
 211                }
 212
 77214213                return _remoteWindowSize.Value;
 77214214            }
 215            private set
 42346216            {
 42346217                _remoteWindowSize = value;
 42346218            }
 219        }
 220
 221        /// <summary>
 222        /// Gets or sets a value indicating whether this channel is open.
 223        /// </summary>
 224        /// <value>
 225        /// <see langword="true"/> if this channel is open; otherwise, <see langword="false"/>.
 226        /// </value>
 103744227        public bool IsOpen { get; protected set; }
 228
 229        /// <summary>
 230        /// Occurs when <see cref="ChannelDataMessage"/> is received.
 231        /// </summary>
 232        public event EventHandler<ChannelDataEventArgs> DataReceived;
 233
 234        /// <summary>
 235        /// Occurs when <see cref="ChannelExtendedDataMessage"/> is received.
 236        /// </summary>
 237        public event EventHandler<ChannelExtendedDataEventArgs> ExtendedDataReceived;
 238
 239        /// <summary>
 240        /// Occurs when <see cref="ChannelEofMessage"/> is received.
 241        /// </summary>
 242        public event EventHandler<ChannelEventArgs> EndOfData;
 243
 244        /// <summary>
 245        /// Occurs when <see cref="ChannelCloseMessage"/> is received.
 246        /// </summary>
 247        public event EventHandler<ChannelEventArgs> Closed;
 248
 249        /// <summary>
 250        /// Occurs when <see cref="ChannelRequestMessage"/> is received.
 251        /// </summary>
 252        public event EventHandler<ChannelRequestEventArgs> RequestReceived;
 253
 254        /// <summary>
 255        /// Occurs when <see cref="ChannelSuccessMessage"/> is received.
 256        /// </summary>
 257        public event EventHandler<ChannelEventArgs> RequestSucceeded;
 258
 259        /// <summary>
 260        /// Occurs when <see cref="ChannelFailureMessage"/> is received.
 261        /// </summary>
 262        public event EventHandler<ChannelEventArgs> RequestFailed;
 263
 264        /// <summary>
 265        /// Gets a value indicating whether the session is connected.
 266        /// </summary>
 267        /// <value>
 268        /// <see langword="true"/> if the session is connected; otherwise, <see langword="false"/>.
 269        /// </value>
 270        protected bool IsConnected
 271        {
 9852272            get { return _session.IsConnected; }
 273        }
 274
 275        /// <summary>
 276        /// Gets the connection info.
 277        /// </summary>
 278        /// <value>The connection info.</value>
 279        protected IConnectionInfo ConnectionInfo
 280        {
 15381281            get { return _session.ConnectionInfo; }
 282        }
 283
 284        /// <summary>
 285        /// Gets the session semaphore to control number of session channels.
 286        /// </summary>
 287        /// <value>The session semaphore.</value>
 288        protected SemaphoreLight SessionSemaphore
 289        {
 11979290            get { return _session.SessionSemaphore; }
 291        }
 292
 293        /// <summary>
 294        /// Initializes the information on the remote channel.
 295        /// </summary>
 296        /// <param name="remoteChannelNumber">The remote channel number.</param>
 297        /// <param name="remoteWindowSize">The remote window size.</param>
 298        /// <param name="remotePacketSize">The remote packet size.</param>
 299        protected void InitializeRemoteInfo(uint remoteChannelNumber, uint remoteWindowSize, uint remotePacketSize)
 2153300        {
 2153301            RemoteChannelNumber = remoteChannelNumber;
 2153302            RemoteWindowSize = remoteWindowSize;
 2153303            RemotePacketSize = remotePacketSize;
 2153304        }
 305
 306        /// <summary>
 307        /// Sends a SSH_MSG_CHANNEL_DATA message with the specified payload.
 308        /// </summary>
 309        /// <param name="data">The payload to send.</param>
 310        public void SendData(byte[] data)
 33076311        {
 33076312            SendData(data, 0, data.Length);
 33074313        }
 314
 315        /// <summary>
 316        /// Sends a SSH_MSG_CHANNEL_DATA message with the specified payload.
 317        /// </summary>
 318        /// <param name="data">An array of <see cref="byte"/> containing the payload to send.</param>
 319        /// <param name="offset">The zero-based offset in <paramref name="data"/> at which to begin taking data from.</p
 320        /// <param name="size">The number of bytes of <paramref name="data"/> to send.</param>
 321        /// <remarks>
 322        /// <para>
 323        /// When the size of the data to send exceeds the maximum packet size or the remote window
 324        /// size does not allow the full data to be sent, then this method will send the data in
 325        /// multiple chunks and will wait for the remote window size to be adjusted when it's zero.
 326        /// </para>
 327        /// <para>
 328        /// This is done to support SSH servers will a small window size that do not agressively
 329        /// increase their window size. We need to take into account that there may be SSH servers
 330        /// that only increase their window size when it has reached zero.
 331        /// </para>
 332        /// </remarks>
 333        public void SendData(byte[] data, int offset, int size)
 44058334        {
 335            // send channel messages only while channel is open
 44058336            if (!IsOpen)
 1337            {
 1338                return;
 339            }
 340
 44057341            var totalBytesToSend = size;
 80968342            while (totalBytesToSend > 0)
 36913343            {
 36913344                var sizeOfCurrentMessage = GetDataLengthThatCanBeSentInMessage(totalBytesToSend);
 345
 36913346                var channelDataMessage = new ChannelDataMessage(RemoteChannelNumber,
 36913347                                                                data,
 36913348                                                                offset,
 36913349                                                                sizeOfCurrentMessage);
 36913350                _session.SendMessage(channelDataMessage);
 351
 36911352                totalBytesToSend -= sizeOfCurrentMessage;
 36911353                offset += sizeOfCurrentMessage;
 36911354            }
 44056355        }
 356
 357        /// <summary>
 358        /// Called when channel window need to be adjust.
 359        /// </summary>
 360        /// <param name="bytesToAdd">The bytes to add.</param>
 361        protected virtual void OnWindowAdjust(uint bytesToAdd)
 3280362        {
 3280363            lock (_serverWindowSizeLock)
 3280364            {
 3280365                RemoteWindowSize += bytesToAdd;
 3280366            }
 367
 3280368            _ = _channelServerWindowAdjustWaitHandle.Set();
 3280369        }
 370
 371        /// <summary>
 372        /// Called when channel data is received.
 373        /// </summary>
 374        /// <param name="data">The data.</param>
 375        protected virtual void OnData(byte[] data)
 34760376        {
 34760377            AdjustDataWindow(data);
 378
 34760379            DataReceived?.Invoke(this, new ChannelDataEventArgs(LocalChannelNumber, data));
 34760380        }
 381
 382        /// <summary>
 383        /// Called when channel extended data is received.
 384        /// </summary>
 385        /// <param name="data">The data.</param>
 386        /// <param name="dataTypeCode">The data type code.</param>
 387        protected virtual void OnExtendedData(byte[] data, uint dataTypeCode)
 46388        {
 46389            AdjustDataWindow(data);
 390
 46391            ExtendedDataReceived?.Invoke(this, new ChannelExtendedDataEventArgs(LocalChannelNumber, data, dataTypeCode))
 46392        }
 393
 394        /// <summary>
 395        /// Called when channel has no more data to receive.
 396        /// </summary>
 397        protected virtual void OnEof()
 1115398        {
 1115399            _eofMessageReceived = true;
 400
 1115401            EndOfData?.Invoke(this, new ChannelEventArgs(LocalChannelNumber));
 1115402        }
 403
 404        /// <summary>
 405        /// Called when channel is closed by the server.
 406        /// </summary>
 407        protected virtual void OnClose()
 2029408        {
 2029409            _closeMessageReceived = true;
 410
 411            // Signal that SSH_MSG_CHANNEL_CLOSE message was received from server.
 412            // We need to signal this before invoking Close() as it may very well
 413            // be blocked waiting for this signal.
 2029414            var channelClosedWaitHandle = _channelClosedWaitHandle;
 2029415            if (channelClosedWaitHandle != null)
 2029416            {
 2029417                _ = channelClosedWaitHandle.Set();
 2029418            }
 419
 420            // close the channel
 2029421            Close();
 2029422        }
 423
 424        /// <summary>
 425        /// Called when channel request received.
 426        /// </summary>
 427        /// <param name="info">Channel request information.</param>
 428        protected virtual void OnRequest(RequestInfo info)
 1698429        {
 1698430            RequestReceived?.Invoke(this, new ChannelRequestEventArgs(info));
 1698431        }
 432
 433        /// <summary>
 434        /// Called when channel request was successful.
 435        /// </summary>
 436        protected virtual void OnSuccess()
 1712437        {
 1712438            RequestSucceeded?.Invoke(this, new ChannelEventArgs(LocalChannelNumber));
 1712439        }
 440
 441        /// <summary>
 442        /// Called when channel request failed.
 443        /// </summary>
 444        protected virtual void OnFailure()
 7445        {
 7446            RequestFailed?.Invoke(this, new ChannelEventArgs(LocalChannelNumber));
 7447        }
 448
 449        /// <summary>
 450        /// Raises <see cref="Exception"/> event.
 451        /// </summary>
 452        /// <param name="exception">The exception.</param>
 453        private void RaiseExceptionEvent(Exception exception)
 72454        {
 72455            Exception?.Invoke(this, new ExceptionEventArgs(exception));
 72456        }
 457
 458        /// <summary>
 459        /// Sends a message to the server.
 460        /// </summary>
 461        /// <param name="message">The message to send.</param>
 462        /// <returns>
 463        /// <see langword="true"/> if the message was sent to the server; otherwise, <see langword="false"/>.
 464        /// </returns>
 465        /// <exception cref="InvalidOperationException">The size of the packet exceeds the maximum size defined by the p
 466        /// <remarks>
 467        /// This methods returns <see langword="false"/> when the attempt to send the message results in a
 468        /// <see cref="SocketException"/> or a <see cref="SshException"/>.
 469        /// </remarks>
 470        private bool TrySendMessage(Message message)
 3152471        {
 3152472            return _session.TrySendMessage(message);
 3152473        }
 474
 475        /// <summary>
 476        /// Sends SSH message to the server.
 477        /// </summary>
 478        /// <param name="message">The message.</param>
 479        protected void SendMessage(Message message)
 1707480        {
 481            // Send channel messages only while channel is open
 1707482            if (!IsOpen)
 0483            {
 0484                return;
 485            }
 486
 1707487            _session.SendMessage(message);
 1707488        }
 489
 490        /// <summary>
 491        /// Sends a SSH_MSG_CHANNEL_EOF message to the remote server.
 492        /// </summary>
 493        /// <exception cref="InvalidOperationException">The channel is closed.</exception>
 494        public void SendEof()
 27495        {
 27496            if (!IsOpen)
 15497            {
 15498                throw CreateChannelClosedException();
 499            }
 500
 12501            lock (_messagingLock)
 12502            {
 12503                _session.SendMessage(new ChannelEofMessage(RemoteChannelNumber));
 12504                _eofMessageSent = true;
 12505            }
 12506        }
 507
 508        /// <summary>
 509        /// Waits for the handle to be signaled or for an error to occurs.
 510        /// </summary>
 511        /// <param name="waitHandle">The wait handle.</param>
 512        protected void WaitOnHandle(WaitHandle waitHandle)
 3849513        {
 3849514            _session.WaitOnHandle(waitHandle);
 3834515        }
 516
 517        /// <summary>
 518        /// Closes the channel, waiting for the SSH_MSG_CHANNEL_CLOSE message to be received from the server.
 519        /// </summary>
 520        protected virtual void Close()
 4107521        {
 522            /*
 523             * Synchronize sending SSH_MSG_CHANNEL_EOF and SSH_MSG_CHANNEL_CLOSE to ensure that these messages
 524             * are sent in that other; when both the client and the server attempt to close the channel at the
 525             * same time we would otherwise risk sending the SSH_MSG_CHANNEL_EOF after the SSH_MSG_CHANNEL_CLOSE
 526             * message causing the server to disconnect the session.
 527             */
 528
 4107529            lock (_messagingLock)
 4107530            {
 531                // Send EOF message first the following conditions are met:
 532                // * we have not sent a SSH_MSG_CHANNEL_EOF message
 533                // * remote party has not already sent a SSH_MSG_CHANNEL_EOF message
 534                // * remote party has not already sent a SSH_MSG_CHANNEL_CLOSE message
 535                // * the channel is open
 536                // * the session is connected
 4107537                if (!_eofMessageSent && !_closeMessageReceived && !_eofMessageReceived && IsOpen && IsConnected)
 1099538                {
 1099539                    if (TrySendMessage(new ChannelEofMessage(RemoteChannelNumber)))
 1084540                    {
 1084541                        _eofMessageSent = true;
 1084542                    }
 1099543                }
 544
 545                // send message to close the channel on the server when it has not already been sent
 546                // and the channel is open and the session is connected
 4107547                if (!_closeMessageSent && IsOpen && IsConnected)
 2053548                {
 2053549                    if (TrySendMessage(new ChannelCloseMessage(RemoteChannelNumber)))
 2017550                    {
 2017551                        _closeMessageSent = true;
 552
 553                        // only wait for the channel to be closed by the server if we didn't send a
 554                        // SSH_MSG_CHANNEL_CLOSE as response to a SSH_MSG_CHANNEL_CLOSE sent by the
 555                        // server
 2017556                        var closeWaitResult = _session.TryWait(_channelClosedWaitHandle, ConnectionInfo.ChannelCloseTime
 2017557                        if (closeWaitResult != WaitResult.Success)
 42558                        {
 42559                            DiagnosticAbstraction.Log(string.Format("Wait for channel close not successful: {0:G}.", clo
 42560                        }
 2017561                    }
 2053562                }
 563
 4107564                if (IsOpen)
 2107565                {
 566                    // mark sure the channel is marked closed before we raise the Closed event
 567                    // this also ensures don't raise the Closed event more than once
 2107568                    IsOpen = false;
 569
 2107570                    if (_closeMessageReceived)
 2023571                    {
 572                        // raise event signaling that both ends of the channel have been closed
 2023573                        Closed?.Invoke(this, new ChannelEventArgs(LocalChannelNumber));
 2023574                    }
 2107575                }
 4107576            }
 4107577        }
 578
 579        protected virtual void OnDisconnected()
 15580        {
 15581        }
 582
 583        protected virtual void OnErrorOccured(Exception exp)
 9584        {
 9585        }
 586
 587        private void Session_Disconnected(object sender, EventArgs e)
 15588        {
 15589            IsOpen = false;
 590
 591            try
 15592            {
 15593                OnDisconnected();
 9594            }
 6595            catch (Exception ex)
 6596            {
 6597                OnChannelException(ex);
 6598            }
 15599        }
 600
 601        /// <summary>
 602        /// Called when an <see cref="Exception"/> occurs while processing a channel message.
 603        /// </summary>
 604        /// <param name="ex">The <see cref="Exception"/>.</param>
 605        /// <remarks>
 606        /// This method will in turn invoke <see cref="OnErrorOccured(System.Exception)"/>, and
 607        /// raise the <see cref="Exception"/> event.
 608        /// </remarks>
 609        protected void OnChannelException(Exception ex)
 66610        {
 66611            OnErrorOccured(ex);
 66612            RaiseExceptionEvent(ex);
 66613        }
 614
 615        private void Session_ErrorOccured(object sender, ExceptionEventArgs e)
 15616        {
 617            try
 15618            {
 15619                OnErrorOccured(e.Exception);
 9620            }
 6621            catch (Exception ex)
 6622            {
 6623                RaiseExceptionEvent(ex);
 6624            }
 15625        }
 626
 627        private void OnChannelWindowAdjust(object sender, MessageEventArgs<ChannelWindowAdjustMessage> e)
 4826628        {
 4826629            if (e.Message.LocalChannelNumber == LocalChannelNumber)
 3280630            {
 631                try
 3280632                {
 3280633                    OnWindowAdjust(e.Message.BytesToAdd);
 3274634                }
 6635                catch (Exception ex)
 6636                {
 6637                    OnChannelException(ex);
 6638                }
 3280639            }
 4826640        }
 641
 642        private void OnChannelData(object sender, MessageEventArgs<ChannelDataMessage> e)
 38864643        {
 38864644            if (e.Message.LocalChannelNumber == LocalChannelNumber)
 34760645            {
 646                try
 34760647                {
 34760648                    OnData(e.Message.Data);
 34754649                }
 6650                catch (Exception ex)
 6651                {
 6652                    OnChannelException(ex);
 6653                }
 34760654            }
 38864655        }
 656
 657        private void OnChannelExtendedData(object sender, MessageEventArgs<ChannelExtendedDataMessage> e)
 46658        {
 46659            if (e.Message.LocalChannelNumber == LocalChannelNumber)
 46660            {
 661                try
 46662                {
 46663                    OnExtendedData(e.Message.Data, e.Message.DataTypeCode);
 40664                }
 6665                catch (Exception ex)
 6666                {
 6667                    OnChannelException(ex);
 6668                }
 46669            }
 46670        }
 671
 672        private void OnChannelEof(object sender, MessageEventArgs<ChannelEofMessage> e)
 1907673        {
 1907674            if (e.Message.LocalChannelNumber == LocalChannelNumber)
 1115675            {
 676                try
 1115677                {
 1115678                    OnEof();
 1109679                }
 6680                catch (Exception ex)
 6681                {
 6682                    OnChannelException(ex);
 6683                }
 1115684            }
 1907685        }
 686
 687        private void OnChannelClose(object sender, MessageEventArgs<ChannelCloseMessage> e)
 2848688        {
 2848689            if (e.Message.LocalChannelNumber == LocalChannelNumber)
 2029690            {
 691                try
 2029692                {
 2029693                    OnClose();
 2023694                }
 6695                catch (Exception ex)
 6696                {
 6697                    OnChannelException(ex);
 6698                }
 2029699            }
 2848700        }
 701
 702        private void OnChannelRequest(object sender, MessageEventArgs<ChannelRequestMessage> e)
 2554703        {
 2554704            if (e.Message.LocalChannelNumber == LocalChannelNumber)
 1698705            {
 706                try
 1698707                {
 1698708                    if (_session.ConnectionInfo.ChannelRequests.TryGetValue(e.Message.RequestName, out var requestInfo))
 1698709                    {
 710                        // Load request specific data
 1698711                        requestInfo.Load(e.Message.RequestData);
 712
 713                        // Raise request specific event
 1698714                        OnRequest(requestInfo);
 1692715                    }
 716                    else
 0717                    {
 718                        // TODO: we should also send a SSH_MSG_CHANNEL_FAILURE message
 0719                        throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Request '{0}' is not 
 720                    }
 1692721                }
 6722                catch (Exception ex)
 6723                {
 6724                    OnChannelException(ex);
 6725                }
 1698726            }
 2554727        }
 728
 729        private void OnChannelSuccess(object sender, MessageEventArgs<ChannelSuccessMessage> e)
 2589730        {
 2589731            if (e.Message.LocalChannelNumber == LocalChannelNumber)
 1712732            {
 733                try
 1712734                {
 1712735                    OnSuccess();
 1706736                }
 6737                catch (Exception ex)
 6738                {
 6739                    OnChannelException(ex);
 6740                }
 1712741            }
 2589742        }
 743
 744        private void OnChannelFailure(object sender, MessageEventArgs<ChannelFailureMessage> e)
 7745        {
 7746            if (e.Message.LocalChannelNumber == LocalChannelNumber)
 7747            {
 748                try
 7749                {
 7750                    OnFailure();
 1751                }
 6752                catch (Exception ex)
 6753                {
 6754                    OnChannelException(ex);
 6755                }
 7756            }
 7757        }
 758
 759        private void AdjustDataWindow(byte[] messageData)
 34806760        {
 34806761            LocalWindowSize -= (uint) messageData.Length;
 762
 763            // Adjust window if window size is too low
 34806764            if (LocalWindowSize < LocalPacketSize)
 0765            {
 0766                SendMessage(new ChannelWindowAdjustMessage(RemoteChannelNumber, _initialWindowSize - LocalWindowSize));
 0767                LocalWindowSize = _initialWindowSize;
 0768            }
 34806769        }
 770
 771        /// <summary>
 772        /// Determines the length of data that currently can be sent in a single message.
 773        /// </summary>
 774        /// <param name="messageLength">The length of the message that must be sent.</param>
 775        /// <returns>
 776        /// The actual data length that currently can be sent.
 777        /// </returns>
 778        private int GetDataLengthThatCanBeSentInMessage(int messageLength)
 36913779        {
 780            do
 37021781            {
 37021782                lock (_serverWindowSizeLock)
 37021783                {
 37021784                    var serverWindowSize = RemoteWindowSize;
 37021785                    if (serverWindowSize == 0U)
 108786                    {
 787                        // Allow us to be signal when remote window size is adjusted
 108788                        _ = _channelServerWindowAdjustWaitHandle.Reset();
 108789                    }
 790                    else
 36913791                    {
 36913792                        var bytesThatCanBeSent = Math.Min(Math.Min(RemotePacketSize, (uint) messageLength),
 36913793                            serverWindowSize);
 36913794                        RemoteWindowSize -= bytesThatCanBeSent;
 36913795                        return (int) bytesThatCanBeSent;
 796                    }
 108797                }
 798
 799                // Wait for remote window size to change
 108800                WaitOnHandle(_channelServerWindowAdjustWaitHandle);
 108801            }
 108802            while (true);
 36913803        }
 804
 805        private static InvalidOperationException CreateRemoteChannelInfoNotAvailableException()
 0806        {
 0807            throw new InvalidOperationException("The channel has not been opened, or the open has not yet been confirmed
 808        }
 809
 810        private static InvalidOperationException CreateChannelClosedException()
 15811        {
 15812            throw new InvalidOperationException("The channel is closed.");
 813        }
 814
 815        /// <summary>
 816        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
 817        /// </summary>
 818        public void Dispose()
 2138819        {
 2138820            Dispose(disposing: true);
 2138821            GC.SuppressFinalize(this);
 2138822        }
 823
 824        /// <summary>
 825        /// Releases unmanaged and - optionally - managed resources.
 826        /// </summary>
 827        /// <param name="disposing"><see langword="true"/> to release both managed and unmanaged resources; <see langwor
 828        protected virtual void Dispose(bool disposing)
 2239829        {
 2239830            if (!_isDisposed && disposing)
 2078831            {
 2078832                Close();
 833
 2078834                var session = _session;
 2078835                if (session is not null)
 2078836                {
 2078837                    session.ChannelWindowAdjustReceived -= OnChannelWindowAdjust;
 2078838                    session.ChannelDataReceived -= OnChannelData;
 2078839                    session.ChannelExtendedDataReceived -= OnChannelExtendedData;
 2078840                    session.ChannelEofReceived -= OnChannelEof;
 2078841                    session.ChannelCloseReceived -= OnChannelClose;
 2078842                    session.ChannelRequestReceived -= OnChannelRequest;
 2078843                    session.ChannelSuccessReceived -= OnChannelSuccess;
 2078844                    session.ChannelFailureReceived -= OnChannelFailure;
 2078845                    session.ErrorOccured -= Session_ErrorOccured;
 2078846                    session.Disconnected -= Session_Disconnected;
 2078847                }
 848
 2078849                var channelClosedWaitHandle = _channelClosedWaitHandle;
 2078850                if (channelClosedWaitHandle is not null)
 2077851                {
 2077852                    _channelClosedWaitHandle = null;
 2077853                    channelClosedWaitHandle.Dispose();
 2077854                }
 855
 2078856                var channelServerWindowAdjustWaitHandle = _channelServerWindowAdjustWaitHandle;
 2078857                if (channelServerWindowAdjustWaitHandle is not null)
 2077858                {
 2077859                    _channelServerWindowAdjustWaitHandle = null;
 2077860                    channelServerWindowAdjustWaitHandle.Dispose();
 2077861                }
 862
 2078863                _isDisposed = true;
 2078864            }
 2239865        }
 866
 867        /// <summary>
 868        /// Finalizes an instance of the <see cref="Channel"/> class.
 869        /// </summary>
 870        ~Channel()
 202871        {
 101872            Dispose(disposing: false);
 202873        }
 874    }
 875}

Methods/Properties

.ctor(Renci.SshNet.ISession,System.UInt32,System.UInt32,System.UInt32)
get_Session()
get_LocalChannelNumber()
get_LocalPacketSize()
get_LocalWindowSize()
get_RemoteChannelNumber()
set_RemoteChannelNumber(System.UInt32)
get_RemotePacketSize()
set_RemotePacketSize(System.UInt32)
get_RemoteWindowSize()
set_RemoteWindowSize(System.UInt32)
get_IsOpen()
get_IsConnected()
get_ConnectionInfo()
get_SessionSemaphore()
InitializeRemoteInfo(System.UInt32,System.UInt32,System.UInt32)
SendData(System.Byte[])
SendData(System.Byte[],System.Int32,System.Int32)
OnWindowAdjust(System.UInt32)
OnData(System.Byte[])
OnExtendedData(System.Byte[],System.UInt32)
OnEof()
OnClose()
OnRequest(Renci.SshNet.Messages.Connection.RequestInfo)
OnSuccess()
OnFailure()
RaiseExceptionEvent(System.Exception)
TrySendMessage(Renci.SshNet.Messages.Message)
SendMessage(Renci.SshNet.Messages.Message)
SendEof()
WaitOnHandle(System.Threading.WaitHandle)
Close()
OnDisconnected()
OnErrorOccured(System.Exception)
Session_Disconnected(System.Object,System.EventArgs)
OnChannelException(System.Exception)
Session_ErrorOccured(System.Object,Renci.SshNet.Common.ExceptionEventArgs)
OnChannelWindowAdjust(System.Object,Renci.SshNet.MessageEventArgs`1<Renci.SshNet.Messages.Connection.ChannelWindowAdjustMessage>)
OnChannelData(System.Object,Renci.SshNet.MessageEventArgs`1<Renci.SshNet.Messages.Connection.ChannelDataMessage>)
OnChannelExtendedData(System.Object,Renci.SshNet.MessageEventArgs`1<Renci.SshNet.Messages.Connection.ChannelExtendedDataMessage>)
OnChannelEof(System.Object,Renci.SshNet.MessageEventArgs`1<Renci.SshNet.Messages.Connection.ChannelEofMessage>)
OnChannelClose(System.Object,Renci.SshNet.MessageEventArgs`1<Renci.SshNet.Messages.Connection.ChannelCloseMessage>)
OnChannelRequest(System.Object,Renci.SshNet.MessageEventArgs`1<Renci.SshNet.Messages.Connection.ChannelRequestMessage>)
OnChannelSuccess(System.Object,Renci.SshNet.MessageEventArgs`1<Renci.SshNet.Messages.Connection.ChannelSuccessMessage>)
OnChannelFailure(System.Object,Renci.SshNet.MessageEventArgs`1<Renci.SshNet.Messages.Connection.ChannelFailureMessage>)
AdjustDataWindow(System.Byte[])
GetDataLengthThatCanBeSentInMessage(System.Int32)
CreateRemoteChannelInfoNotAvailableException()
CreateChannelClosedException()
Dispose()
Dispose(System.Boolean)
Finalize()