Skip to content

feat: expose TCP keepalive options through WISP - #1

Closed
syrusakbary wants to merge 2 commits into
multiplexedfrom
codex/tcp-keepalive-options
Closed

syrusakbary wants to merge 2 commits into
multiplexedfrom
codex/tcp-keepalive-options

Conversation

@syrusakbary

@syrusakbary syrusakbary commented Sep 25, 2026 •

Copy link
Copy Markdown

This full TCP keepalive timing work is no longer required for the Pi integration. Edge.js #155 uses the existing basic SO_KEEPALIVE option in its native WASIX binding and skips unsupported timing options. Pi works with the stock libc and original WISP transport. Full configurable probe timing is deferred; Wasmer #7035 and libuv #15 are being kept focused on filesystem timestamps.


Browser WASIX clients currently cannot apply TCP keepalive timing options through WISP: the proxy protocol has no socket-option request or acknowledgement. Add an opt-in, versioned private extension (0xF2, metadata [1]) with SET/GET requests on 0xF2 and replies on 0xF3 for enabled, idle seconds, interval seconds, and probe count. Successful replies read back the actual outbound socket; unsupported options and OS errors remain errors.

The extension waits for a connecting stream, preserves the enabled state when changing timings, and owns a duplicated descriptor until forwarding ends. Stream registrations retain their identity when a closed stream ID is reused. Both peers must negotiate the extension. Existing TWisp/Wispnet IDs remain unchanged, and the Wasmer package enables the extension without loosening its destination policy.

The mux gains backward-compatible stream lifecycle/control hooks and continues reading after an extension packet, fixing the previous early end of its read stream. Control requests wait without holding the transport write lock so failed connections can close and wake the pending request.

The native backend uses POSIX socket options. The WASIX backend imports the new runtime socket option IDs directly, avoiding the old libc mapping, and uses the existing WASIX fd_dup2 operation because Rust's WASI descriptor-cloning implementation returns unsupported. The deployed proxy host must also include the runtime support; this PR does not publish a package or deploy a proxy.

Related runtime work:

Validation:

  • ./wasmer/test-native-keepalive.sh --nocapture: four native tests pass, covering kernel readback, enabled-state preservation, real OS errors, negotiation/version rejection, requests while connecting, failed-connect wakeup, repeated controls, normal DATA after controls, and stream ID reuse.
  • cargo wasix build --release --package epoxy-server --locked: WASIX release build passes.
  • Native build and Clippy complete; Clippy reports existing code warnings and the expanded WISP handler's line-count warning.
  • All six SDK WISP tests pass against both the native proxy and the compiled WASIX proxy running on the updated native Wasmer host. This covers actual timing setters/getters and invalid-value error propagation over RPC, in addition to negotiation, ACK waiting, cancellation, and response routing.
  • SDK browser compatibility tests pass in Chromium and WebKit, and the wasmer.sh production build passes.
  • Full Chromium Pi example passes with rebuilt Edge.js and SDK through both the native proxy and the compiled WASIX proxy on the updated Wasmer host: pnpm install, version, fd/rg, directory-lock heartbeat, a seven-tool streaming loop, persisted sessions, and interactive UI/exit.

Production deployment still requires a host with the companion runtime changes. No package has been published and no proxy deployment has been changed.

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.

2 participants