using System; using Renci.SshNet.Common; namespace Renci.SshNet { /// /// Base class for port forwarding functionality. /// public abstract class ForwardedPort : IForwardedPort { /// /// Gets or sets the session. /// /// /// The session. /// internal ISession Session { get; set; } /// /// The event occurs as the forwarded port is being stopped. /// internal event EventHandler Closing; /// /// The event occurs as the forwarded port is being stopped. /// event EventHandler IForwardedPort.Closing { add { Closing += value; } remove { Closing -= value; } } /// /// Gets a value indicating whether port forwarding is started. /// /// /// true if port forwarding is started; otherwise, false. /// public abstract bool IsStarted { get; } /// /// Occurs when an exception is thrown. /// public event EventHandler Exception; /// /// Occurs when a port forwarding request is received. /// public event EventHandler RequestReceived; /// /// Starts port forwarding. /// public virtual void Start() { CheckDisposed(); if (IsStarted) { throw new InvalidOperationException("Forwarded port is already started."); } if (Session is null) { throw new InvalidOperationException("Forwarded port is not added to a client."); } if (!Session.IsConnected) { throw new SshConnectionException("Client not connected."); } Session.ErrorOccured += Session_ErrorOccured; StartPort(); } /// /// Stops port forwarding. /// public virtual void Stop() { if (IsStarted) { StopPort(Session.ConnectionInfo.Timeout); } } /// /// Starts port forwarding. /// protected abstract void StartPort(); /// /// Stops port forwarding, and waits for the specified timeout until all pending /// requests are processed. /// /// The maximum amount of time to wait for pending requests to finish processing. protected virtual void StopPort(TimeSpan timeout) { RaiseClosing(); var session = Session; if (session != null) { session.ErrorOccured -= Session_ErrorOccured; } } /// /// Releases unmanaged and - optionally - managed resources /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected virtual void Dispose(bool disposing) { if (disposing) { var session = Session; if (session != null) { StopPort(session.ConnectionInfo.Timeout); Session = null; } } } /// /// Ensures the current instance is not disposed. /// /// The current instance is disposed. protected abstract void CheckDisposed(); /// /// Raises event. /// /// The exception. protected void RaiseExceptionEvent(Exception exception) { Exception?.Invoke(this, new ExceptionEventArgs(exception)); } /// /// Raises event. /// /// Request originator host. /// Request originator port. protected void RaiseRequestReceived(string host, uint port) { RequestReceived?.Invoke(this, new PortForwardEventArgs(host, port)); } /// /// Raises the event. /// private void RaiseClosing() { Closing?.Invoke(this, EventArgs.Empty); } /// /// Handles session ErrorOccured event. /// /// The source of the event. /// The instance containing the event data. private void Session_ErrorOccured(object sender, ExceptionEventArgs e) { RaiseExceptionEvent(e.Exception); } } }