using System;
using System.Threading;
namespace Renci.SshNet
{
///
/// Provides functionality for forwarding connections from the client to destination servers via the SSH server,
/// also known as dynamic port forwarding.
///
public partial class ForwardedPortDynamic : ForwardedPort
{
private EventWaitHandle _listenerCompleted;
///
/// Gets the bound host.
///
public string BoundHost { get; private set; }
///
/// Gets the bound port.
///
public uint BoundPort { get; private set; }
///
/// Gets or sets a value indicating whether port forwarding is started.
///
///
/// true if port forwarding is started; otherwise, false.
///
public override bool IsStarted
{
get { return _listenerCompleted != null && !_listenerCompleted.WaitOne(0); }
}
///
/// Initializes a new instance of the class.
///
/// The port.
public ForwardedPortDynamic(uint port)
: this(string.Empty, port)
{
}
///
/// Initializes a new instance of the class.
///
/// The host.
/// The port.
public ForwardedPortDynamic(string host, uint port)
{
BoundHost = host;
BoundPort = port;
}
///
/// Starts local port forwarding.
///
protected override void StartPort()
{
InternalStart();
}
///
/// Stops local 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 override void StopPort(TimeSpan timeout)
{
if (IsStarted)
{
// prevent new requests from getting processed before we signal existing
// channels that the port is closing
StopListener();
// signal existing channels that the port is closing
base.StopPort(timeout);
}
// wait for open channels to close
InternalStop(timeout);
}
///
/// Ensures the current instance is not disposed.
///
/// The current instance is disposed.
protected override void CheckDisposed()
{
if (_isDisposed)
throw new ObjectDisposedException(GetType().FullName);
}
partial void InternalStart();
///
/// Stops the listener.
///
partial void StopListener();
///
/// Waits for pending requests to finish, and channels to close.
///
/// The maximum time to wait for the forwarded port to stop.
partial void InternalStop(TimeSpan timeout);
#region IDisposable Members
///
/// Holds a value indicating whether the current instance is disposed.
///
///
/// true if the current instance is disposed; otherwise, false.
///
private bool _isDisposed;
///
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged ResourceMessages.
///
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
partial void InternalDispose(bool disposing);
///
/// Releases unmanaged and - optionally - managed resources
///
/// true to release both managed and unmanaged resources; false to release only unmanaged ResourceMessages.
protected override void Dispose(bool disposing)
{
if (!_isDisposed)
{
base.Dispose(disposing);
if (disposing)
{
if (_listenerCompleted != null)
{
_listenerCompleted.Dispose();
_listenerCompleted = null;
}
}
InternalDispose(disposing);
_isDisposed = true;
}
}
///
/// Releases unmanaged resources and performs other cleanup operations before the
/// is reclaimed by garbage collection.
///
~ForwardedPortDynamic()
{
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false);
}
#endregion
}
}