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

BaseClient

public abstract class BaseClient : IBaseClient, IDisposable
Serves as base class for client implementations, provides common client functionality.
using Renci.SshNet.Common; using Renci.SshNet.Messages.Transport; using System; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; namespace Renci.SshNet { [System.Runtime.CompilerServices.NullableContext(1)] [System.Runtime.CompilerServices.Nullable(0)] public abstract class BaseClient : IBaseClient, IDisposable { private readonly bool _ownsConnectionInfo; private readonly IServiceFactory _serviceFactory; private readonly object _keepAliveLock = new object(); private TimeSpan _keepAliveInterval; [System.Runtime.CompilerServices.Nullable(2)] private Timer _keepAliveTimer; private ConnectionInfo _connectionInfo; private bool _isDisposed; [System.Runtime.CompilerServices.Nullable(2)] [field: System.Runtime.CompilerServices.Nullable(2)] internal ISession Session { [System.Runtime.CompilerServices.NullableContext(2)] get; [System.Runtime.CompilerServices.NullableContext(2)] private set; } internal IServiceFactory ServiceFactory => _serviceFactory; public ConnectionInfo ConnectionInfo { get { CheckDisposed(); return _connectionInfo; } private set { _connectionInfo = value; } } public virtual bool IsConnected { get { CheckDisposed(); return IsSessionConnected(); } } public TimeSpan KeepAliveInterval { get { CheckDisposed(); return _keepAliveInterval; } set { CheckDisposed(); value.EnsureValidTimeout("KeepAliveInterval"); if (!(value == _keepAliveInterval)) { if (value == Timeout.InfiniteTimeSpan) StopKeepAliveTimer(); else if (_keepAliveTimer != null) { _keepAliveTimer.Change(value, value); } else if (IsSessionConnected()) { _keepAliveTimer = CreateKeepAliveTimer(value, value); } _keepAliveInterval = value; } } } [System.Runtime.CompilerServices.Nullable(new byte[] { 2, 1 })] [method: System.Runtime.CompilerServices.Nullable(new byte[] { 2, 1 })] [field: System.Runtime.CompilerServices.Nullable(new byte[] { 2, 1 })] public event EventHandler<ExceptionEventArgs> ErrorOccurred; [System.Runtime.CompilerServices.Nullable(new byte[] { 2, 1 })] [method: System.Runtime.CompilerServices.Nullable(new byte[] { 2, 1 })] [field: System.Runtime.CompilerServices.Nullable(new byte[] { 2, 1 })] public event EventHandler<HostKeyEventArgs> HostKeyReceived; [System.Runtime.CompilerServices.Nullable(new byte[] { 2, 1 })] [method: System.Runtime.CompilerServices.Nullable(new byte[] { 2, 1 })] [field: System.Runtime.CompilerServices.Nullable(new byte[] { 2, 1 })] public event EventHandler<SshIdentificationEventArgs> ServerIdentificationReceived; protected BaseClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo) : this(connectionInfo, ownsConnectionInfo, new ServiceFactory()) { } private protected BaseClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo, IServiceFactory serviceFactory) { ThrowHelper.ThrowIfNull(connectionInfo, "connectionInfo"); ThrowHelper.ThrowIfNull(serviceFactory, "serviceFactory"); _connectionInfo = connectionInfo; _ownsConnectionInfo = ownsConnectionInfo; _serviceFactory = serviceFactory; _keepAliveInterval = Timeout.InfiniteTimeSpan; } public void Connect() { CheckDisposed(); if (IsConnected) throw new InvalidOperationException("The client is already connected."); OnConnecting(); ISession session = Session; if (session == null || !session.IsConnected) { if (session != null) DisposeSession(session); Session = CreateAndConnectSession(); } try { OnConnected(); } catch { DisposeSession(); throw; } StartKeepAliveTimer(); } [AsyncStateMachine(typeof(<ConnectAsync>d__33))] public Task ConnectAsync(CancellationToken cancellationToken) { <ConnectAsync>d__33 stateMachine = default(<ConnectAsync>d__33); stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create(); stateMachine.<>4__this = this; stateMachine.cancellationToken = cancellationToken; stateMachine.<>1__state = -1; stateMachine.<>t__builder.Start(ref stateMachine); return stateMachine.<>t__builder.Task; } public void Disconnect() { CheckDisposed(); OnDisconnecting(); StopKeepAliveTimer(); DisposeSession(); OnDisconnected(); } [Obsolete("Use KeepAliveInterval to send a keep-alive message at regular intervals.")] public void SendKeepAlive() { CheckDisposed(); SendKeepAliveMessage(); } protected virtual void OnConnecting() { } protected virtual void OnConnected() { } protected virtual void OnDisconnecting() { Session?.OnDisconnecting(); } protected virtual void OnDisconnected() { } private void Session_ErrorOccured([System.Runtime.CompilerServices.Nullable(2)] object sender, ExceptionEventArgs e) { this.ErrorOccurred?.Invoke(this, e); } private void Session_HostKeyReceived([System.Runtime.CompilerServices.Nullable(2)] object sender, HostKeyEventArgs e) { this.HostKeyReceived?.Invoke(this, e); } private void Session_ServerIdentificationReceived([System.Runtime.CompilerServices.Nullable(2)] object sender, SshIdentificationEventArgs e) { this.ServerIdentificationReceived?.Invoke(this, e); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!_isDisposed && disposing) { Disconnect(); if (_ownsConnectionInfo) (_connectionInfo as IDisposable)?.Dispose(); _isDisposed = true; } } protected void CheckDisposed() { ThrowHelper.ThrowObjectDisposedIf(_isDisposed, this); } private void StopKeepAliveTimer() { if (_keepAliveTimer != null) { _keepAliveTimer.Dispose(); _keepAliveTimer = null; } } private void SendKeepAliveMessage() { ISession session = Session; if (session != null && Monitor.TryEnter(_keepAliveLock)) try { session.TrySendMessage(new IgnoreMessage()); } finally { Monitor.Exit(_keepAliveLock); } } private void StartKeepAliveTimer() { if (!(_keepAliveInterval == Timeout.InfiniteTimeSpan) && _keepAliveTimer == null) _keepAliveTimer = CreateKeepAliveTimer(_keepAliveInterval, _keepAliveInterval); } private Timer CreateKeepAliveTimer(TimeSpan dueTime, TimeSpan period) { return new Timer(delegate { SendKeepAliveMessage(); }, Session, dueTime, period); } private ISession CreateAndConnectSession() { ISession session = _serviceFactory.CreateSession(ConnectionInfo, _serviceFactory.CreateSocketFactory()); session.ServerIdentificationReceived += Session_ServerIdentificationReceived; session.HostKeyReceived += Session_HostKeyReceived; session.ErrorOccured += Session_ErrorOccured; try { session.Connect(); return session; } catch { DisposeSession(session); throw; } } [AsyncStateMachine(typeof(<CreateAndConnectSessionAsync>d__51))] private Task<ISession> CreateAndConnectSessionAsync(CancellationToken cancellationToken) { <CreateAndConnectSessionAsync>d__51 stateMachine = default(<CreateAndConnectSessionAsync>d__51); stateMachine.<>t__builder = AsyncTaskMethodBuilder<ISession>.Create(); stateMachine.<>4__this = this; stateMachine.cancellationToken = cancellationToken; stateMachine.<>1__state = -1; stateMachine.<>t__builder.Start(ref stateMachine); return stateMachine.<>t__builder.Task; } private void DisposeSession(ISession session) { session.ErrorOccured -= Session_ErrorOccured; session.HostKeyReceived -= Session_HostKeyReceived; session.ServerIdentificationReceived -= Session_ServerIdentificationReceived; session.Dispose(); } private void DisposeSession() { ISession session = Session; if (session != null) { Session = null; DisposeSession(session); } } private bool IsSessionConnected() { return Session?.IsConnected ?? false; } } }