forked from sshnet/SSH.NET
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathForwardedPort.cs
More file actions
171 lines (148 loc) · 5.52 KB
/
ForwardedPort.cs
File metadata and controls
171 lines (148 loc) · 5.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
using System;
using Renci.SshNet.Common;
namespace Renci.SshNet
{
/// <summary>
/// Base class for port forwarding functionality.
/// </summary>
public abstract class ForwardedPort : IForwardedPort
{
/// <summary>
/// Gets or sets the session.
/// </summary>
/// <value>
/// The session.
/// </value>
internal ISession Session { get; set; }
/// <summary>
/// Gets a value indicating whether port forwarding is started.
/// </summary>
/// <value>
/// <see langword="true"/> if port forwarding is started; otherwise, <see langword="false"/>.
/// </value>
public abstract bool IsStarted { get; }
/// <summary>
/// The <see cref="Closing"/> event occurs as the forwarded port is being stopped.
/// </summary>
public event EventHandler Closing;
/// <summary>
/// Occurs when an exception is thrown.
/// </summary>
public event EventHandler<ExceptionEventArgs> Exception;
/// <summary>
/// Occurs when a port forwarding request is received.
/// </summary>
public event EventHandler<PortForwardEventArgs> RequestReceived;
/// <summary>
/// Starts port forwarding.
/// </summary>
/// <exception cref="InvalidOperationException">The current <see cref="ForwardedPort"/> is already started -or- is not linked to a SSH session.</exception>
/// <exception cref="SshConnectionException">The client is not connected.</exception>
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_ErrorOccurred;
StartPort();
}
/// <summary>
/// Stops port forwarding.
/// </summary>
public virtual void Stop()
{
if (IsStarted)
{
StopPort(Session.ConnectionInfo.Timeout);
}
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Starts port forwarding.
/// </summary>
protected abstract void StartPort();
/// <summary>
/// Stops 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 virtual void StopPort(TimeSpan timeout)
{
timeout.EnsureValidTimeout();
RaiseClosing();
var session = Session;
session?.ErrorOccured -= Session_ErrorOccurred;
}
/// <summary>
/// Releases unmanaged and - optionally - managed resources.
/// </summary>
/// <param name="disposing"><see langowrd="true"/> to release both managed and unmanaged resources; <see langowrd="false"/> to release only unmanaged resources.</param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
var session = Session;
if (session is not null)
{
StopPort(session.ConnectionInfo.Timeout);
Session = null;
}
}
}
/// <summary>
/// Ensures the current instance is not disposed.
/// </summary>
/// <exception cref="ObjectDisposedException">The current instance is disposed.</exception>
protected abstract void CheckDisposed();
/// <summary>
/// Raises <see cref="Exception"/> event.
/// </summary>
/// <param name="exception">The exception.</param>
protected void RaiseExceptionEvent(Exception exception)
{
Exception?.Invoke(this, new ExceptionEventArgs(exception));
}
/// <summary>
/// Raises <see cref="RequestReceived"/> event.
/// </summary>
/// <param name="host">Request originator host.</param>
/// <param name="port">Request originator port.</param>
protected void RaiseRequestReceived(string host, uint port)
{
RequestReceived?.Invoke(this, new PortForwardEventArgs(host, port));
}
/// <summary>
/// Raises the <see cref="IForwardedPort.Closing"/> event.
/// </summary>
private void RaiseClosing()
{
Closing?.Invoke(this, EventArgs.Empty);
}
/// <summary>
/// Handles session ErrorOccurred event.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="ExceptionEventArgs"/> instance containing the event data.</param>
private void Session_ErrorOccurred(object sender, ExceptionEventArgs e)
{
RaiseExceptionEvent(e.Exception);
}
}
}