/// <summary> /// Stops remote port forwarding. /// </summary> /// <param name="timeout">The maximum amount of time to wait for the port to stop.</param> protected override void StopPort(TimeSpan timeout) { if (!ForwardedPortStatus.ToStopping(ref _status)) { return; } base.StopPort(timeout); // send global request to cancel direct tcpip Session.SendMessage(new CancelTcpIpForwardGlobalRequestMessage(BoundHost, BoundPort)); // wait for response on global request to cancel direct tcpip or completion of message // listener loop (in which case response on global request can never be received) WaitHandle.WaitAny(new[] { _globalRequestResponse, Session.MessageListenerCompleted }, timeout); // unsubscribe from session events as either the tcpip forward is cancelled at the // server, or our session message loop has completed Session.RequestSuccessReceived -= Session_RequestSuccess; Session.RequestFailureReceived -= Session_RequestFailure; Session.ChannelOpenReceived -= Session_ChannelOpening; // wait for pending channels to close _pendingChannelCountdown.Signal(); _pendingChannelCountdown.Wait(timeout); _status = ForwardedPortStatus.Stopped; }
/// <summary> /// Stops local port forwarding, and waits for the specified timeout until all pending /// requests are processed. /// </summary> /// <param name="timeout">The maximum amount of time to wait for pending requests to finish processing.</param> protected override void StopPort(TimeSpan timeout) { if (!ForwardedPortStatus.ToStopping(ref _status)) { return; } // signal existing channels that the port is closing base.StopPort(timeout); // prevent new requests from getting processed StopListener(); // wait for open channels to close InternalStop(timeout); // mark port stopped _status = ForwardedPortStatus.Stopped; }
/// <summary> /// Starts local port forwarding. /// </summary> protected override void StartPort() { if (!ForwardedPortStatus.ToStarting(ref _status)) { return; } try { InternalStart(); } catch (Exception) { _status = ForwardedPortStatus.Stopped; throw; } }
/// <summary> /// Starts remote port forwarding. /// </summary> protected override void StartPort() { if (!ForwardedPortStatus.ToStarting(ref _status)) { return; } InitializePendingChannelCountdown(); try { Session.RegisterMessage("SSH_MSG_REQUEST_FAILURE"); Session.RegisterMessage("SSH_MSG_REQUEST_SUCCESS"); Session.RegisterMessage("SSH_MSG_CHANNEL_OPEN"); Session.RequestSuccessReceived += Session_RequestSuccess; Session.RequestFailureReceived += Session_RequestFailure; Session.ChannelOpenReceived += Session_ChannelOpening; // send global request to start forwarding Session.SendMessage(new TcpIpForwardGlobalRequestMessage(BoundHost, BoundPort)); // wat for response on global request to start direct tcpip Session.WaitOnHandle(_globalRequestResponse); if (!_requestStatus) { throw new SshException(string.Format(CultureInfo.CurrentCulture, "Port forwarding for '{0}' port '{1}' failed to start.", Host, Port)); } } catch (Exception) { // mark port stopped _status = ForwardedPortStatus.Stopped; // when the request to start port forward was rejected or failed, then we're no longer // interested in these events Session.RequestSuccessReceived -= Session_RequestSuccess; Session.RequestFailureReceived -= Session_RequestFailure; Session.ChannelOpenReceived -= Session_ChannelOpening; throw; } _status = ForwardedPortStatus.Started; }
/// <summary> /// Initializes a new instance of the <see cref="ForwardedPortRemote" /> class. /// </summary> /// <param name="boundHostAddress">The bound host address.</param> /// <param name="boundPort">The bound port.</param> /// <param name="hostAddress">The host address.</param> /// <param name="port">The port.</param> /// <exception cref="ArgumentNullException"><paramref name="boundHostAddress"/> is <c>null</c>.</exception> /// <exception cref="ArgumentNullException"><paramref name="hostAddress"/> is <c>null</c>.</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="boundPort" /> is greater than <see cref="F:System.Net.IPEndPoint.MaxPort" />.</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="port" /> is greater than <see cref="F:System.Net.IPEndPoint.MaxPort" />.</exception> public ForwardedPortRemote(IPAddress boundHostAddress, uint boundPort, IPAddress hostAddress, uint port) { if (boundHostAddress == null) { throw new ArgumentNullException("boundHostAddress"); } if (hostAddress == null) { throw new ArgumentNullException("hostAddress"); } boundPort.ValidatePort("boundPort"); port.ValidatePort("port"); BoundHostAddress = boundHostAddress; BoundPort = boundPort; HostAddress = hostAddress; Port = port; _status = ForwardedPortStatus.Stopped; }
/// <summary> /// Initializes a new instance of the <see cref="ForwardedPortLocal"/> class. /// </summary> /// <param name="boundHost">The bound host.</param> /// <param name="boundPort">The bound port.</param> /// <param name="host">The host.</param> /// <param name="port">The port.</param> /// <exception cref="ArgumentNullException"><paramref name="boundHost"/> is <c>null</c>.</exception> /// <exception cref="ArgumentNullException"><paramref name="host"/> is <c>null</c>.</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="boundPort" /> is greater than <see cref="F:System.Net.IPEndPoint.MaxPort" />.</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="port" /> is greater than <see cref="F:System.Net.IPEndPoint.MaxPort" />.</exception> public ForwardedPortLocal(string boundHost, uint boundPort, string host, uint port) { if (boundHost == null) { throw new ArgumentNullException("boundHost"); } if (host == null) { throw new ArgumentNullException("host"); } boundPort.ValidatePort("boundPort"); port.ValidatePort("port"); BoundHost = boundHost; BoundPort = boundPort; Host = host; Port = port; _status = ForwardedPortStatus.Stopped; }
/// <summary> /// Returns a value indicating whether <paramref name="status"/> has been changed to <see cref="Starting"/>. /// </summary> /// <param name="status">The status to transition from.</param> /// <returns> /// <c>true</c> if <paramref name="status"/> has been changed to <see cref="Starting"/>; otherwise, <c>false</c>. /// </returns> /// <exception cref="InvalidOperationException">Cannot transition <paramref name="status"/> to <see cref="Starting"/>.</exception> /// <remarks> /// While a transition from <see cref="Started"/> to <see cref="Starting"/> is not possible, this method will /// return <c>false</c> for any such attempts. This is related to concurrency. /// </remarks> public static bool ToStarting(ref ForwardedPortStatus status) { // attemp to transition from Stopped to Starting var previousStatus = Interlocked.CompareExchange(ref status, Starting, Stopped); if (previousStatus == Starting || previousStatus == Started) { // port is already Starting or Started, so no transition to Starting is necessary return(false); } // we've successfully transitioned from Stopped to Starting if (status == Starting) { return(true); } // there's no valid transition from status to Starting throw new InvalidOperationException(string.Format("Forwarded port cannot transition from '{0}' to '{1}'.", previousStatus, Starting)); }
/// <summary> /// Initializes a new instance of the <see cref="ForwardedPortDynamic"/> class. /// </summary> /// <param name="host">The host.</param> /// <param name="port">The port.</param> public ForwardedPortDynamic(string host, uint port) { BoundHost = host; BoundPort = port; _status = ForwardedPortStatus.Stopped; }