Skip to content

Add outbound websocket client mode (--connect)#1523

Open
semistrict wants to merge 5 commits intotsl0922:mainfrom
semistrict:outbound-websocket
Open

Add outbound websocket client mode (--connect)#1523
semistrict wants to merge 5 commits intotsl0922:mainfrom
semistrict:outbound-websocket

Conversation

@semistrict
Copy link
Copy Markdown

Summary

  • Adds --connect <ws://url> option that puts ttyd in client mode: instead of listening for incoming browser connections, ttyd connects outbound to a remote WebSocket server and bridges the local PTY to it
  • The remote endpoint receives terminal output (OUTPUT) and can send input (INPUT, RESIZE_TERMINAL, PAUSE, RESUME) using the same binary protocol
  • Supports both ws:// and wss:// (TLS) URLs

Usage

# Connect to a remote WebSocket server, sharing a bash session
ttyd --connect ws://relay.example.com:8080/ws -W bash

# With TLS
ttyd --connect wss://relay.example.com/ws -W bash

Use cases

  • NAT traversal: ttyd connects outbound to a relay server when it can't listen on a public port
  • Service integration: bridge a local terminal to a remote service that accepts WebSocket connections

Changes

  • src/server.h: Added connect_url field to server struct
  • src/server.c: Added --connect CLI option, client protocol array, and client-mode branching in main() (skips vhost creation, uses lws_client_connect_via_info() instead)
  • src/protocol.c: Extracted shared helpers (handle_writeable, receive_append, handle_command, handle_close) used by both server and client callbacks. Added callback_tty_client() for client-mode connections
  • test/test-outbound.js: End-to-end test — starts a WS server, connects ttyd in client mode, verifies bidirectional OUTPUT/INPUT and clean disconnect

Test plan

  • ttyd --help shows the new --connect option
  • Server mode (no --connect) is unchanged
  • Client mode against a compatible WebSocket server (OUTPUT, SET_WINDOW_TITLE, SET_PREFERENCES sent)
  • Remote input received and executed by local PTY
  • Connection error handling (unreachable host, refused connection)
  • Clean disconnect (code 1000) on process exit
  • wss:// with TLS-enabled endpoint

Add --connect option that puts ttyd in client mode: instead of listening
for incoming browser connections, ttyd connects outbound to a remote
WebSocket server and bridges the local PTY to it. The remote endpoint
receives terminal output and can send input using the same binary protocol.

Usage: ttyd --connect ws://host:port/path -W <command>
Extract handle_writeable(), receive_append(), handle_command(),
receive_cleanup(), and handle_close() as shared static helpers.
Both callback_tty (server) and callback_tty_client use them,
eliminating ~90 lines of duplication.
Node.js test that starts a WS server, connects ttyd in client mode,
verifies bidirectional communication (OUTPUT sent, INPUT echoed back),
and checks for clean disconnect.

Run: cd test && npm install && node test-outbound.js [path-to-ttyd]
Enables `make test` / `ctest` which runs the Node.js e2e test
against the built ttyd binary.
Adds a ttyd-sanitized build target (excluded from default build) and
a test-sanitized custom target that builds it and runs the e2e tests
under AddressSanitizer + UndefinedBehaviorSanitizer.

Usage: cd build && cmake .. && make test-sanitized
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