ChannelDirectTcpip.cs 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. using System;
  2. using System.Linq;
  3. using System.Net;
  4. using System.Net.Sockets;
  5. using System.Threading;
  6. using Renci.SshNet.Common;
  7. using Renci.SshNet.Messages.Connection;
  8. namespace Renci.SshNet.Channels
  9. {
  10. /// <summary>
  11. /// Implements "direct-tcpip" SSH channel.
  12. /// </summary>
  13. internal partial class ChannelDirectTcpip : ClientChannel, IChannelDirectTcpip
  14. {
  15. private EventWaitHandle _channelEof = new AutoResetEvent(false);
  16. private EventWaitHandle _channelOpen = new AutoResetEvent(false);
  17. private EventWaitHandle _channelData = new AutoResetEvent(false);
  18. private EventWaitHandle _channelInterrupted = new ManualResetEvent(false);
  19. private IForwardedPort _forwardedPort;
  20. private Socket _socket;
  21. /// <summary>
  22. /// Gets the type of the channel.
  23. /// </summary>
  24. /// <value>
  25. /// The type of the channel.
  26. /// </value>
  27. public override ChannelTypes ChannelType
  28. {
  29. get { return ChannelTypes.DirectTcpip; }
  30. }
  31. public void Open(string remoteHost, uint port, IForwardedPort forwardedPort, Socket socket)
  32. {
  33. if (IsOpen)
  34. throw new SshException("Channel is already open.");
  35. if (!this.IsConnected)
  36. throw new SshException("Session is not connected.");
  37. _socket = socket;
  38. _forwardedPort = forwardedPort;
  39. _forwardedPort.Closing += ForwardedPort_Closing;
  40. var ep = socket.RemoteEndPoint as IPEndPoint;
  41. // Open channel
  42. this.SendMessage(new ChannelOpenMessage(this.LocalChannelNumber, this.LocalWindowSize, this.LocalPacketSize,
  43. new DirectTcpipChannelInfo(remoteHost, port, ep.Address.ToString(), (uint)ep.Port)));
  44. // Wait for channel to open
  45. this.WaitOnHandle(this._channelOpen);
  46. }
  47. private void ForwardedPort_Closing(object sender, EventArgs eventArgs)
  48. {
  49. // close the socket, hereby interrupting the blocking receive in Bind()
  50. if (_socket != null)
  51. CloseSocket();
  52. }
  53. /// <summary>
  54. /// Binds channel to remote host.
  55. /// </summary>
  56. public void Bind()
  57. {
  58. // Cannot bind if channel is not open
  59. if (!this.IsOpen)
  60. return;
  61. var buffer = new byte[this.RemotePacketSize];
  62. while (this._socket != null && _socket.Connected)
  63. {
  64. try
  65. {
  66. var read = 0;
  67. this.InternalSocketReceive(buffer, ref read);
  68. if (read > 0)
  69. {
  70. this.SendMessage(new ChannelDataMessage(this.RemoteChannelNumber, buffer.Take(read).ToArray()));
  71. }
  72. else
  73. {
  74. // client quit sending
  75. break;
  76. }
  77. }
  78. catch (SocketException exp)
  79. {
  80. switch (exp.SocketErrorCode)
  81. {
  82. case SocketError.WouldBlock:
  83. case SocketError.IOPending:
  84. case SocketError.NoBufferSpaceAvailable:
  85. // socket buffer is probably empty, wait and try again
  86. Thread.Sleep(30);
  87. break;
  88. case SocketError.ConnectionAborted:
  89. case SocketError.ConnectionReset:
  90. // connection was closed after receiving SSH_MSG_CHANNEL_CLOSE message
  91. // in which case the _channelEof waithandle is also set
  92. break;
  93. case SocketError.Interrupted:
  94. // connection was interrupted as part of closing the forwarded port
  95. _channelInterrupted.Set();
  96. break;
  97. default:
  98. throw; // throw any other error
  99. }
  100. }
  101. }
  102. WaitHandle.WaitAny(new WaitHandle[] { _channelEof, _channelInterrupted });
  103. }
  104. /// <summary>
  105. /// Closes the socket, hereby interrupting the blocking receive in <see cref="Bind()"/>.
  106. /// </summary>
  107. private void CloseSocket()
  108. {
  109. if (!_socket.Connected)
  110. return;
  111. _socket.Shutdown(SocketShutdown.Both);
  112. _socket.Close();
  113. }
  114. /// <summary>
  115. /// Closes the channel.
  116. /// </summary>
  117. public override void Close()
  118. {
  119. if (_forwardedPort != null)
  120. {
  121. _forwardedPort.Closing -= ForwardedPort_Closing;
  122. _forwardedPort = null;
  123. }
  124. // close the socket, hereby interrupting the blocking receive in Bind()
  125. if (this._socket != null)
  126. CloseSocket();
  127. // Send EOF message first when channel need to be closed
  128. this.SendMessage(new ChannelEofMessage(this.RemoteChannelNumber));
  129. base.Close();
  130. }
  131. /// <summary>
  132. /// Called when channel data is received.
  133. /// </summary>
  134. /// <param name="data">The data.</param>
  135. protected override void OnData(byte[] data)
  136. {
  137. base.OnData(data);
  138. this.InternalSocketSend(data);
  139. }
  140. /// <summary>
  141. /// Called when channel is opened by the server.
  142. /// </summary>
  143. /// <param name="remoteChannelNumber">The remote channel number.</param>
  144. /// <param name="initialWindowSize">Initial size of the window.</param>
  145. /// <param name="maximumPacketSize">Maximum size of the packet.</param>
  146. protected override void OnOpenConfirmation(uint remoteChannelNumber, uint initialWindowSize, uint maximumPacketSize)
  147. {
  148. base.OnOpenConfirmation(remoteChannelNumber, initialWindowSize, maximumPacketSize);
  149. this._channelOpen.Set();
  150. }
  151. protected override void OnOpenFailure(uint reasonCode, string description, string language)
  152. {
  153. base.OnOpenFailure(reasonCode, description, language);
  154. this._channelOpen.Set();
  155. }
  156. /// <summary>
  157. /// Called when channel has no more data to receive.
  158. /// </summary>
  159. protected override void OnEof()
  160. {
  161. base.OnEof();
  162. // the channel will send no more data, so signal to the client that
  163. // we won't be sending anything anymore
  164. if (_socket != null && _socket.Connected)
  165. _socket.Shutdown(SocketShutdown.Send);
  166. var channelEof = this._channelEof;
  167. if (channelEof != null)
  168. channelEof.Set();
  169. }
  170. protected override void OnClose()
  171. {
  172. base.OnClose();
  173. var channelEof = this._channelEof;
  174. if (channelEof != null)
  175. channelEof.Set();
  176. }
  177. /// <summary>
  178. /// Called whenever an unhandled <see cref="Exception"/> occurs in <see cref="Session"/> causing
  179. /// the message loop to be interrupted.
  180. /// </summary>
  181. protected override void OnErrorOccured(Exception exp)
  182. {
  183. base.OnErrorOccured(exp);
  184. // close the socket, hereby interrupting the blocking receive in Bind()
  185. if (_socket != null)
  186. CloseSocket();
  187. // if error occured, no more data can be received
  188. var channelEof = this._channelEof;
  189. if (channelEof != null)
  190. channelEof.Set();
  191. }
  192. /// <summary>
  193. /// Called when the server wants to terminate the connection immmediately.
  194. /// </summary>
  195. /// <remarks>
  196. /// The sender MUST NOT send or receive any data after this message, and
  197. /// the recipient MUST NOT accept any data after receiving this message.
  198. /// </remarks>
  199. protected override void OnDisconnected()
  200. {
  201. base.OnDisconnected();
  202. // close the socket, hereby interrupting the blocking receive in Bind()
  203. if (_socket != null)
  204. CloseSocket();
  205. // If disconnected, no more data can be received
  206. var channelEof = this._channelEof;
  207. if (channelEof != null)
  208. channelEof.Set();
  209. }
  210. partial void InternalSocketReceive(byte[] buffer, ref int read);
  211. partial void InternalSocketSend(byte[] data);
  212. protected override void Dispose(bool disposing)
  213. {
  214. if (_forwardedPort != null)
  215. {
  216. _forwardedPort.Closing -= ForwardedPort_Closing;
  217. _forwardedPort = null;
  218. }
  219. if (this._socket != null)
  220. {
  221. this._socket.Dispose();
  222. this._socket = null;
  223. }
  224. if (this._channelEof != null)
  225. {
  226. this._channelEof.Dispose();
  227. this._channelEof = null;
  228. }
  229. if (this._channelOpen != null)
  230. {
  231. this._channelOpen.Dispose();
  232. this._channelOpen = null;
  233. }
  234. if (this._channelData != null)
  235. {
  236. this._channelData.Dispose();
  237. this._channelData = null;
  238. }
  239. if (_channelInterrupted != null)
  240. {
  241. _channelInterrupted.Dispose();
  242. _channelInterrupted = null;
  243. }
  244. base.Dispose(disposing);
  245. }
  246. }
  247. }