Files
alknet/tasks/server/serve-loop.md
glm-5.1 596c89ce24 refactor!: rebrand wraith to alknet
Rename all crates, CLI commands, constants, type names, doc comments,
and documentation from wraith to alknet. Includes wire-protocol changes:
ALPN wraith-ssh -> alknet-ssh, reserved destination prefix wraith- ->
alknet-, SSH auth username wraith -> alknet.
2026-06-05 10:04:32 +00:00

3.4 KiB

id, name, status, depends_on, scope, risk, impact, level
id name status depends_on scope risk impact level
server/serve-loop Implement server accept loop, graceful shutdown, and ServeOptions config completed
server/handler
server/channel-proxy
server/rate-limiting-and-logging
transport/trait-and-types
moderate medium component implementation

Description

Implement the server's main accept loop and configuration. This ties together the transport acceptor, server handler, rate limiting, and logging into a coherent server process.

ServeOptions is the programmatic configuration struct (ADR-011) for the server. The accept loop:

  1. Binds a TransportAcceptor based on transport mode
  2. Accepts incoming connections (respecting rate limits)
  3. Creates a ServerHandler per connection
  4. Passes the stream to russh::server::run_stream()
  5. Handles graceful shutdown on SIGTERM/SIGINT

Acceptance Criteria

  • crates/alknet-core/src/server/mod.rs re-exports all server components
  • ServeOptions struct with fields matching server.md CLI interface: key, authorized_keys, cert_authority, transport_mode, listen_addr, tls_cert, tls_key, acme_domain, stealth, proxy, iroh_relay, max_connections_per_ip, max_auth_attempts
  • Server::new(opts: ServeOptions) -> Result<Server> — creates server with bound acceptor, auth config, rate limiter
  • Server::run() — enters accept loop, for each connection: check rate limit → create handler → run_stream()
  • Stealth mode integration: if enabled, protocol detection before run_stream()
  • Graceful shutdown: Server::shutdown() method and signal handler (SIGTERM/SIGINT)
    • Stop accepting new connections
    • Send SSH disconnect to active sessions
    • Wait for drain timeout (~2 seconds per session)
    • Forcibly terminate remaining connections
  • iroh mode: prints endpoint ID on startup
  • ServeOptions::key and ServeOptions::authorized_keys accept KeySource (file or in-memory)
  • Integration test: start server, client connects via mock transport, session works, shutdown completes

References

  • docs/architecture/server.md — full server spec including graceful shutdown
  • docs/architecture/decisions/011-no-ssh-config-programmatic-api.md — ServeOptions programmatic struct

Notes

Key design decisions:

  • Server::run(acceptor, endpoint_info) takes a generic TransportAcceptor and optional endpoint info string, keeping transport binding separate from the accept loop
  • handle_disconnect returns a future (Handle::disconnect is async in russh 0.49), takes String args
  • shutdown_rx is cloned to avoid needing &mut self on Arc<Server> in the select loop
  • ServeTransportMode is a separate enum from TransportKind to keep serve options independent of transport types
  • Stealth mode only applies when both stealth=true AND transport_mode=Tls

Summary

Implemented server accept loop and configuration in crates/alknet-core/src/server/serve.rs:

  • ServeOptions struct with all CLI interface fields, builder pattern, KeySource support
  • Server::new() creates server with russh config, auth config, rate limiter
  • Server::run(acceptor, endpoint_info) enters accept loop with rate limiting, stealth detection, russh::server::run_stream()
  • Server::shutdown() sends SSH disconnect to active sessions, waits drain timeout, aborts remaining
  • SIGTERM/SIGINT handler on unix platforms
  • iroh endpoint ID logged on startup
  • All 216 tests pass, clippy clean