Public Access
Add port forwarding: local, remote and dynamic, per terminal session
A host can now carry port forwards (-L, -R, -D), saved inside its encrypted payload as RelayTicketRequest.PortForwardId already assumed, so they sync and merge per forward like tags and pinned paths. The host schema moves to version 8 only for hosts that carry forwards. ISshConnection gains StartForwardAsync over SSH.NET's forwarded ports. Every listener binds loopback and there is no bind-address field: a forward is something any member of a shared keychain can edit. A remote forward's target is resolved here, IPv4 first, rather than by SSH.NET's constructor, which takes the first DNS answer and can send ::1. Forwards start with every terminal opened to the host and stop with its connection; a reconnect starts them again. The session sidebar lists them with state, failure reason and an on/off switch, the status bar counts the listening ones, and the host editor and detail pane gain a PORT FORWARDS section. A forward that cannot start fails alone. The phone does not start forwards yet: it has no surface showing what is listening, and its More screen now says so. No byte counts, since SSH.NET keeps none.
This commit is contained in:
1 parent
c8848ec1e3
commit
f05deb4fbc
36 files changed
+2776
-42
No files matched your search
@@ -550,6 +550,51 @@ public sealed class TerminalWorkspace : IAsyncDisposable
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts a port forward over one terminal's connection.
|
||||
/// </summary>
|
||||
/// <param name="sessionId">The terminal whose connection the forward runs over.</param>
|
||||
/// <param name="spec">What to forward.</param>
|
||||
/// <param name="cancellationToken">Abandons the start.</param>
|
||||
/// <returns>The forward, which the caller may dispose to stop it sooner.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// <b>The forward lives as long as the session, and this object does not keep a list of them.</b> SSH.NET
|
||||
/// stops every forward on a connection when the connection is disposed, which is what both
|
||||
/// <see cref="CloseSessionAsync"/> and the release of a session that ended on its own already do — so a
|
||||
/// second record here would be a copy of a fact the library already enforces, and the one that could
|
||||
/// disagree with it. Disposing a handle after its session has gone is safe.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Refused for a session that is not running, for the reason <see cref="PasteAsync"/> refuses one: a tab
|
||||
/// whose shell ended is still on screen, and a forward started on its connection would be a listener
|
||||
/// over a transport that is already being torn down.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <exception cref="InvalidOperationException">The session is not running.</exception>
|
||||
/// <exception cref="SshPortForwardException">The forward could not be started.</exception>
|
||||
public Task<ISshPortForward> StartForwardAsync(
|
||||
uint sessionId,
|
||||
SshPortForwardSpec spec,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(spec);
|
||||
|
||||
ISshConnection connection;
|
||||
|
||||
lock (sessionGate)
|
||||
{
|
||||
if (!sessions.TryGetValue(sessionId, out var session) || session.Run.IsCompleted)
|
||||
{
|
||||
throw new InvalidOperationException("That terminal is no longer connected.");
|
||||
}
|
||||
|
||||
connection = session.Connection;
|
||||
}
|
||||
|
||||
return connection.StartForwardAsync(spec, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows one terminal's pane and hides the others.
|
||||
/// </summary>
|
||||
|
||||
Reference in new issue
Block a user