<PackageReference Include="SSH.NET" Version="2020.0.0" />

ChannelDirectTcpip

Implements "direct-tcpip" SSH channel.
using Renci.SshNet.Abstractions; using Renci.SshNet.Common; using Renci.SshNet.Messages.Connection; using System; using System.Net; using System.Net.Sockets; using System.Threading; namespace Renci.SshNet.Channels { internal class ChannelDirectTcpip : ClientChannel, IChannelDirectTcpip, IDisposable { private readonly object _socketLock = new object(); private EventWaitHandle _channelOpen = new AutoResetEvent(false); private EventWaitHandle _channelData = new AutoResetEvent(false); private IForwardedPort _forwardedPort; private Socket _socket; public override ChannelTypes ChannelType => ChannelTypes.DirectTcpip; public ChannelDirectTcpip(ISession session, uint localChannelNumber, uint localWindowSize, uint localPacketSize) : base(session, localChannelNumber, localWindowSize, localPacketSize) { } public void Open(string remoteHost, uint port, IForwardedPort forwardedPort, Socket socket) { if (base.IsOpen) throw new SshException("Channel is already open."); if (!base.IsConnected) throw new SshException("Session is not connected."); _socket = socket; _forwardedPort = forwardedPort; _forwardedPort.Closing += ForwardedPort_Closing; IPEndPoint iPEndPoint = (IPEndPoint)socket.RemoteEndPoint; SendMessage(new ChannelOpenMessage(base.LocalChannelNumber, base.LocalWindowSize, base.LocalPacketSize, new DirectTcpipChannelInfo(remoteHost, port, iPEndPoint.Address.ToString(), (uint)iPEndPoint.Port))); WaitOnHandle(_channelOpen); } private void ForwardedPort_Closing(object sender, EventArgs eventArgs) { ShutdownSocket(SocketShutdown.Send); CloseSocket(); } public void Bind() { if (base.IsOpen) { byte[] array = new byte[base.RemotePacketSize]; SocketAbstraction.ReadContinuous(_socket, array, 0, array.Length, SendData); } } private void CloseSocket() { if (_socket != null) { lock (_socketLock) { if (_socket != null) { _socket.Dispose(); _socket = null; } } } } private void ShutdownSocket(SocketShutdown how) { if (_socket != null) { lock (_socketLock) { if (_socket.IsConnected()) try { _socket.Shutdown(how); } catch (SocketException) { } } } } protected override void Close() { IForwardedPort forwardedPort = _forwardedPort; if (forwardedPort != null) { forwardedPort.Closing -= ForwardedPort_Closing; _forwardedPort = null; } ShutdownSocket(SocketShutdown.Send); base.Close(); CloseSocket(); } protected override void OnData(byte[] data) { base.OnData(data); if (_socket != null) { lock (_socketLock) { if (_socket.IsConnected()) SocketAbstraction.Send(_socket, data, 0, data.Length); } } } protected override void OnOpenConfirmation(uint remoteChannelNumber, uint initialWindowSize, uint maximumPacketSize) { base.OnOpenConfirmation(remoteChannelNumber, initialWindowSize, maximumPacketSize); _channelOpen.Set(); } protected override void OnOpenFailure(uint reasonCode, string description, string language) { base.OnOpenFailure(reasonCode, description, language); _channelOpen.Set(); } protected override void OnEof() { base.OnEof(); ShutdownSocket(SocketShutdown.Send); } protected override void OnErrorOccured(Exception exp) { base.OnErrorOccured(exp); ShutdownSocket(SocketShutdown.Send); } protected override void OnDisconnected() { base.OnDisconnected(); ShutdownSocket(SocketShutdown.Both); } protected override void Dispose(bool disposing) { base.Dispose(disposing); if (disposing) { if (_socket != null) { lock (_socketLock) { Socket socket = _socket; if (socket != null) { _socket = null; socket.Dispose(); } } } EventWaitHandle channelOpen = _channelOpen; if (channelOpen != null) { _channelOpen = null; channelOpen.Dispose(); } EventWaitHandle channelData = _channelData; if (channelData != null) { _channelData = null; channelData.Dispose(); } } } } }