Skip to content

Send a stable host id to the relay on host connections - #679

Open
Juan Pablo Acosta (jpablo2002) wants to merge 3 commits into
mainfrom
dev/acostajuan/send-host-process-id
Open

Send a stable host id to the relay on host connections#679
Juan Pablo Acosta (jpablo2002) wants to merge 3 commits into
mainfrom
dev/acostajuan/send-host-process-id

Conversation

@jpablo2002

Copy link
Copy Markdown
Contributor

Host connections now send an X-Tunnels-Host-Process-Id request header identifying the host process. The relay uses it to tell a host reconnecting to a tunnel it already holds from a genuinely different host taking that tunnel over.

Why

When two hosts race for the same tunnel, each connect evicts the incumbent with TooManyConnections; the evicted host reconnects, evicts the challenger, and the loop sustains itself, tearing down every live client bridge each time.

We need an identity that is stable across a host's own reconnects. Host connections authenticate as ClientNone, so there is no SSH key on the wire, and the request correlation id is per-connection — a host redialling after sleep/wake or a dropped network would fail to recognize itself. The SDK is the only place that knows the answer, so it sends it explicitly.

MultiModeTunnelHost.HostId is minted once per process and already reported on TunnelEndpoint.HostId, so it's a proven-stable identity.

What changed

  • C# (TunnelRelayStreamFactory.cs) — sets the header from MultiModeTunnelHost.HostId when the sub-protocol list contains a host sub-protocol. The header name is a new public const, TunnelRelayConnection.HostIdHeaderName.
  • TypeScript (defaultTunnelRelayStreamFactory.ts) — same, from MultiModeTunnelHost.hostId, on the Node path.
  • Rust (relay_tunnel_host.rs) — adds the header to the relay host's WebSocket request, from the host_id the host already generates and reports on its endpoint.

Only host connections send it; clients are untouched.

Notes

  • Browser hosts are excluded by construction. The browser branch of the TS factory can't set request headers at all — that's why it already smuggles the access token in as a sub-protocol. Documented inline.
  • Go and Java are unaffected. Both ship a client and a management client but no host implementation, so there is no connection for the header to ride on.
  • Not added to TunnelHeaderNames. That file is the generated contract surface, and generating this into Go/Java would produce a constant nothing can use. It lives next to the three host implementations that actually send it.
  • Rust's id is per-RelayTunnelHost, not per-process. It's stable across the reconnects the host performs internally, which is the case that matters. A caller that constructs a fresh RelayTunnelHost on reconnect gets a new id and is arbitrated as a new host — the same as today's behavior, never worse.

Compatibility

Fully backward compatible in both directions. The relay ignores the header when it's absent and treats an unidentified host exactly as it does today, so old SDKs against a new service are unchanged and a new SDK against an older service is a no-op — the header is simply dropped. It's also stripped at web forwarding, so it never reaches a customer's app.

Testing

C# builds clean and the existing suite passes; TypeScript compiles and lints clean. No new unit tests — both suites substitute a mock stream factory, so the default factory this change touches isn't reachable from them.

… tell a host reconnecting to its own tunnel from a different host taking it over.
Matches the C# and TypeScript SDKs so the relay can identify a reconnecting host process.
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

@jpablo2002

Copy link
Copy Markdown
Contributor Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines will not run the associated pipelines, because the pull request was updated after the run command was issued. Review the pull request again and issue a new run command.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant