using System; using System.Linq; using System.Net; using System.Net.Sockets; using System.Threading; using Renci.SshNet.Common; using Renci.SshNet.Messages.Connection; namespace Renci.SshNet.Channels { /// /// Implements "forwarded-tcpip" SSH channel. /// internal partial class ChannelForwardedTcpip : Channel { private Socket _socket; /// /// Gets the type of the channel. /// /// /// The type of the channel. /// public override ChannelTypes ChannelType { get { return ChannelTypes.ForwardedTcpip; } } /// /// Initializes a new instance of the class. /// public ChannelForwardedTcpip() : base() { } /// /// Binds channel to specified connected host. /// /// The connected host. /// The connected port. public void Bind(string connectedHost, uint connectedPort) { byte[] buffer = null; this.ServerWindowSize = this.LocalWindowSize; if (!this.IsConnected) { throw new SshException("Session is not connected."); } // Try to connect to the socket try { // Get buffer in memory for data exchange buffer = new byte[this.PacketSize - 9]; this.OpenSocket(connectedHost, connectedPort); // Send channel open confirmation message this.SendMessage(new ChannelOpenConfirmationMessage(this.RemoteChannelNumber, this.LocalWindowSize, this.PacketSize, this.LocalChannelNumber)); } catch (Exception exp) { // Send channel open failure message this.SendMessage(new ChannelOpenFailureMessage(this.RemoteChannelNumber, exp.ToString(), 2)); throw; } // Start reading data from the port and send to channel while (this._socket.Connected || this.IsConnected) { try { int read = 0; this.InternalSocketReceive(buffer, ref read); if (read > 0) { this.SendMessage(new ChannelDataMessage(this.RemoteChannelNumber, buffer.Take(read).ToArray())); } else { // Zero bytes received when remote host shuts down the connection break; } } catch (SocketException exp) { if (exp.SocketErrorCode == SocketError.WouldBlock || exp.SocketErrorCode == SocketError.IOPending || exp.SocketErrorCode == SocketError.NoBufferSpaceAvailable) { // socket buffer is probably empty, wait and try again Thread.Sleep(30); } else if (exp.SocketErrorCode == SocketError.ConnectionAborted) { break; } else throw; // throw any other error } } this.Close(); } partial void OpenSocket(string connectedHost, uint connectedPort); public override void Close() { // Send EOF message first when channel need to be closed this.SendMessage(new ChannelEofMessage(this.RemoteChannelNumber)); base.Close(); } /// /// Called when channel data is received. /// /// The data. protected override void OnData(byte[] data) { base.OnData(data); // Read data from the channel and send it to the port this.InternalSocketSend(data); } partial void InternalSocketSend(byte[] data); partial void InternalSocketReceive(byte[] buffer, ref int read); /// /// Releases unmanaged and - optionally - managed resources /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected override void Dispose(bool disposing) { if (this._socket != null) { this._socket.Dispose(); this._socket = null; } base.Dispose(disposing); } } }