|  | @@ -1,4 +1,5 @@
 | 
	
		
			
				|  |  |  using System;
 | 
	
		
			
				|  |  | +using System.Net.Sockets;
 | 
	
		
			
				|  |  |  using System.Threading;
 | 
	
		
			
				|  |  |  using Renci.SshNet.Common;
 | 
	
		
			
				|  |  |  using Renci.SshNet.Messages;
 | 
	
	
		
			
				|  | @@ -12,6 +13,10 @@ namespace Renci.SshNet.Channels
 | 
	
		
			
				|  |  |      /// </summary>
 | 
	
		
			
				|  |  |      internal abstract class Channel : IChannel
 | 
	
		
			
				|  |  |      {
 | 
	
		
			
				|  |  | +        private const int Initial = 0;
 | 
	
		
			
				|  |  | +        private const int Considered = 1;
 | 
	
		
			
				|  |  | +        private const int Sent = 2;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          private EventWaitHandle _channelClosedWaitHandle = new ManualResetEvent(false);
 | 
	
		
			
				|  |  |          private EventWaitHandle _channelServerWindowAdjustWaitHandle = new ManualResetEvent(false);
 | 
	
		
			
				|  |  |          private EventWaitHandle _errorOccuredWaitHandle = new ManualResetEvent(false);
 | 
	
	
		
			
				|  | @@ -23,13 +28,14 @@ namespace Renci.SshNet.Channels
 | 
	
		
			
				|  |  |          private ISession _session;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          /// <summary>
 | 
	
		
			
				|  |  | -        /// Holds a value indicating whether a SSH_MSG_CHANNEL_CLOSE has been sent to the other party.
 | 
	
		
			
				|  |  | +        /// Holds a value indicating whether the SSH_MSG_CHANNEL_CLOSE has been sent to the remote party.
 | 
	
		
			
				|  |  |          /// </summary>
 | 
	
		
			
				|  |  |          /// <value>
 | 
	
		
			
				|  |  | -        /// <c>true</c> when a SSH_MSG_CHANNEL_CLOSE message has been sent to the other party;
 | 
	
		
			
				|  |  | -        /// otherwise, <c>false</c>.
 | 
	
		
			
				|  |  | +        /// <c>0</c> when the SSH_MSG_CHANNEL_CLOSE message has not been sent or considered
 | 
	
		
			
				|  |  | +        /// <c>1</c> when sending a SSH_MSG_CHANNEL_CLOSE message to the remote party is under consideration
 | 
	
		
			
				|  |  | +        /// <c>2</c> when this message has been sent to the remote party
 | 
	
		
			
				|  |  |          /// </value>
 | 
	
		
			
				|  |  | -        private bool _closeMessageSent;
 | 
	
		
			
				|  |  | +        private int _closeMessageSent;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          /// <summary>
 | 
	
		
			
				|  |  |          /// Holds a value indicating whether a SSH_MSG_CHANNEL_CLOSE has been received from the other
 | 
	
	
		
			
				|  | @@ -51,11 +57,12 @@ namespace Renci.SshNet.Channels
 | 
	
		
			
				|  |  |          private bool _eofMessageReceived;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          /// <summary>
 | 
	
		
			
				|  |  | -        /// Holds a value indicating whether the SSH_MSG_CHANNEL_EOF has been sent to the other party.
 | 
	
		
			
				|  |  | +        /// Holds a value indicating whether the SSH_MSG_CHANNEL_EOF has been sent to the remote party.
 | 
	
		
			
				|  |  |          /// </summary>
 | 
	
		
			
				|  |  |          /// <value>
 | 
	
		
			
				|  |  | -        /// <c>0</c> when the SSH_MSG_CHANNEL_EOF message has not been sent to the other party, and
 | 
	
		
			
				|  |  | -        /// <c>1</c> when this message was already sent.
 | 
	
		
			
				|  |  | +        /// <c>0</c> when the SSH_MSG_CHANNEL_EOF message has not been sent or considered
 | 
	
		
			
				|  |  | +        /// <c>1</c> when sending a SSH_MSG_CHANNEL_EOF message to the remote party is under consideration
 | 
	
		
			
				|  |  | +        /// <c>2</c> when this message has been sent to the remote party
 | 
	
		
			
				|  |  |          /// </value>
 | 
	
		
			
				|  |  |          private int _eofMessageSent;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -411,6 +418,23 @@ namespace Renci.SshNet.Channels
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +        /// <summary>
 | 
	
		
			
				|  |  | +        /// Sends a message to the server.
 | 
	
		
			
				|  |  | +        /// </summary>
 | 
	
		
			
				|  |  | +        /// <param name="message">The message to send.</param>
 | 
	
		
			
				|  |  | +        /// <returns>
 | 
	
		
			
				|  |  | +        /// <c>true</c> if the message was sent to the server; otherwise, <c>false</c>.
 | 
	
		
			
				|  |  | +        /// </returns>
 | 
	
		
			
				|  |  | +        /// <exception cref="InvalidOperationException">The size of the packet exceeds the maximum size defined by the protocol.</exception>
 | 
	
		
			
				|  |  | +        /// <remarks>
 | 
	
		
			
				|  |  | +        /// This methods returns <c>false</c> when the attempt to send the message results in a
 | 
	
		
			
				|  |  | +        /// <see cref="SocketException"/> or a <see cref="SshException"/>.
 | 
	
		
			
				|  |  | +        /// </remarks>
 | 
	
		
			
				|  |  | +        private bool TrySendMessage(Message message)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            return _session.TrySendMessage(message);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          /// <summary>
 | 
	
		
			
				|  |  |          /// Sends SSH message to the server.
 | 
	
		
			
				|  |  |          /// </summary>
 | 
	
	
		
			
				|  | @@ -424,15 +448,6 @@ namespace Renci.SshNet.Channels
 | 
	
		
			
				|  |  |              _session.SendMessage(message);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        /// <summary>
 | 
	
		
			
				|  |  | -        /// Sends close channel message to the server, and marks the channel closed.
 | 
	
		
			
				|  |  | -        /// </summary>
 | 
	
		
			
				|  |  | -        /// <param name="message">The message to send.</param>
 | 
	
		
			
				|  |  | -        private void SendMessage(ChannelCloseMessage message)
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            _session.SendMessage(message);
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |          /// <summary>
 | 
	
		
			
				|  |  |          /// Sends channel data message to the servers.
 | 
	
		
			
				|  |  |          /// </summary>
 | 
	
	
		
			
				|  | @@ -555,23 +570,23 @@ namespace Renci.SshNet.Channels
 | 
	
		
			
				|  |  |              //
 | 
	
		
			
				|  |  |              // as a solution for this issue we only send a SSH_MSG_CHANNEL_EOF message if we haven't received a
 | 
	
		
			
				|  |  |              // SSH_MSG_CHANNEL_EOF or SSH_MSG_CHANNEL_CLOSE message from the remote party
 | 
	
		
			
				|  |  | -            if (!_closeMessageReceived && !_eofMessageReceived && IsOpen && IsConnected)
 | 
	
		
			
				|  |  | +            if (Interlocked.CompareExchange(ref _eofMessageSent, Considered, Initial) == Initial)
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  | -                if (Interlocked.CompareExchange(ref _eofMessageSent, 1, 0) == 0)
 | 
	
		
			
				|  |  | -                    SendMessage(new ChannelEofMessage(RemoteChannelNumber));
 | 
	
		
			
				|  |  | +                if (!_closeMessageReceived && !_eofMessageReceived && IsOpen && IsConnected)
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    if (TrySendMessage(new ChannelEofMessage(RemoteChannelNumber)))
 | 
	
		
			
				|  |  | +                        _eofMessageSent = Sent;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              // send message to close the channel on the server
 | 
	
		
			
				|  |  | -            // ignore sending close message when client not connected
 | 
	
		
			
				|  |  | -            if (!_closeMessageSent && IsOpen && IsConnected)
 | 
	
		
			
				|  |  | +            if (Interlocked.CompareExchange(ref _closeMessageSent, Considered, Initial) == Initial)
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  | -                lock (this)
 | 
	
		
			
				|  |  | +                // ignore sending close message when client is not connected or the channel is closed
 | 
	
		
			
				|  |  | +                if (IsOpen && IsConnected)
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    if (!_closeMessageSent)
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        SendMessage(new ChannelCloseMessage(RemoteChannelNumber));
 | 
	
		
			
				|  |  | -                        _closeMessageSent = true;
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | +                    if (TrySendMessage(new ChannelCloseMessage(RemoteChannelNumber)))
 | 
	
		
			
				|  |  | +                        _closeMessageSent = Sent;
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -580,17 +595,17 @@ namespace Renci.SshNet.Channels
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              // wait for channel to be closed if we actually sent a close message (either to initiate closing
 | 
	
		
			
				|  |  |              // the channel, or as response to a SSH_MSG_CHANNEL_CLOSE message sent by the server
 | 
	
		
			
				|  |  | -            if (wait && _closeMessageSent)
 | 
	
		
			
				|  |  | +            if (wait && _closeMessageSent == Sent)
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  WaitOnHandle(_channelClosedWaitHandle);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              // reset indicators in case we want to reopen the channel; these are safe to reset
 | 
	
		
			
				|  |  |              // since the channel is marked closed by now
 | 
	
		
			
				|  |  | -            _eofMessageSent = 0;
 | 
	
		
			
				|  |  | +            _eofMessageSent = Initial;
 | 
	
		
			
				|  |  |              _eofMessageReceived = false;
 | 
	
		
			
				|  |  |              _closeMessageReceived = false;
 | 
	
		
			
				|  |  | -            _closeMessageSent = false;
 | 
	
		
			
				|  |  | +            _closeMessageSent = Initial;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          protected virtual void OnDisconnected()
 |