Chapter 25 / 51
Volume 3 · Protocol Development (finale)

Connection takeover: XS_TAKEOVER, the third road

Some business never fits "one question, one answer": SOCKS proxies, upgraded private protocols, long-poll gateways. XS_TAKEOVER lets RequestProc take the whole connection over and run it yourself.

Overview

Positioning: the volume 3 finale. Takeover is the heaviest of the three states — it flips the default division "the driver runs the connection, you produce the content" into "you run the connection". In the right scenario (protocol upgrades/tunnels) it's the only solution; in the wrong one it's needless complexity.

25.1 Intro

The three states were drawn in chapter 4: XS_OK returns the connection to keep-alive, XS_FALLBACK hands it to the static layer. The third state, XS_TAKEOVER, means "this connection is mine from now on" — the driver steps out of event processing, and everything after (I/O, timeouts, closing) is decided by application logic. Typical scenes: HTTP Upgrade to a private protocol, proxy tunnels, push gateways needing cross-request sessions.

25.2 Takeover semantics

RequestProc ──▶ XS_TAKEOVER │ ┌────────────┴────────────┐ │ driver: leaves the keep-alive loop │ /* no more request parsing */ │ app: swaps the event table + does its own I/O │ /* pull / Future / threads */ │ terminal: the app eventually Closes │ └────────────┬────────────┘ ▼ The Close terminal is Destroyed by XServer, releasing the generation lease
  • Takeover point: from the moment RequestProc returns TAKEOVER, the connection is no longer consumed by the HTTP driver
  • Event table: after takeover you swap in your own event handling (never an illegal state)
  • Reclamation contract: the connection object is still Destroyed by XServer in the end — you operate it but don't own its destruction; the Close terminal also releases the generation lease the connection holds
  • Byte synchronization: bytes you consumed/wrote before takeover are still cross-checked by the driver — half an HTTP request + TAKEOVER is rejected as an inconsistency

25.3 Pull mode in practice

func_test carries a real takeover-echo case; the pattern (async pull I/O):

Takeover + async echo (case pattern)pattern mirrors tools/func_test.py's takeover case
typedef struct TakeoverCtx {
    XS_HostInfo*  pHost;      /* across threads, follow the ownership rules */
    xnetstream*   tcp;        /* or tls: the transport after takeover */
} TakeoverCtx;

static XS_RequestResult RequestProc(XS_HttpReq* pReq)
{
    if ( !IsUpgradeTarget(pReq) ) return XS_FALLBACK;

    /* 1. first write the protocol-required reply bytes (e.g. 101 Switching Protocols) */
    /* 2. build the takeover context */
    TakeoverCtx* pCtx = xrtCalloc(1, sizeof(TakeoverCtx));
    pCtx->tcp = pReq->tcp;

    /* 3. hang an async read: data arrives into the callback (the test case uses a thread + RecvAsync) */
    StartTakeoverLoop(pCtx);

    return XS_TAKEOVER;   /* the connection is mine */
}

What just happened: inside the takeover loop you do I/O on pCtx->tcp with the ordinary xrt stream APIs — exactly as in ch. 23. The only difference is this stream's "origin" was an HTTP connection, and you decide what protocol it speaks next.

25.4 Terminal state & reclamation

  • You must eventually Close: takeover is a promise — a forgotten connection sits forever (idle_timeout is a backstop, not the designed path)
  • Close uses the stream API's close semantics; XServer Destroys in the connection's terminal callback and releases the generation lease — so an old generation can wait for all taken-over connections to end before reclaiming (reload_matrix verified this ordering)
  • The takeover context (pCtx) is freed alongside Close — the same registry-style cleanup as WS/TCP
First ask "do I really need takeover?": ordinary business (even SSE/long-poll) works with chunked + regular callbacks (ch. 15's exercise). Takeover is for protocol switching and tunnels — it's an escape hatch, not a daily tool.

25.5 Contract

  • Takeover: finish the protocol reply bytes before returning TAKEOVER; after takeover the driver never consumes the connection again.
  • Terminal: the application performs the final Close; Destroy and lease release are done by XServer at the terminal.
  • Context: the takeover context's lifetime binds to the connection terminal — registry-style cleanup.

Common mistakes

Forgetting to Close after takeover
Symptom
The connection table creeps upward; old generations delay reclamation (leases unreturned).
Cause
The takeover promise unfulfilled — every TAKEOVER needs a Close path (including error branches).
Taking over mid-request
Symptom
The connection is severed immediately.
Cause
The driver cross-checks "bytes the script declared consumed vs the wire" — TAKEOVER with request bytes unconsumed is an inconsistent state. Consume fully, then take over.

Exercises

BasicReproducing takeover echo

Implement /raw per 25.3's pattern: after takeover, switch to line-echo mode (as if the protocol "upgraded" from HTTP).

Acceptance: curl keeps the connection and gets any line echoed; after disconnect, zero leaks (connection table back to empty).
AdvancedA mini SOCKS5 proxy

Implement the CONNECT method: after takeover, open a second stream to the target and pump both ways (xrt dual-stream forwarding).

Acceptance: curl -x through your proxy reaches any HTTP site; either side closing shuts both cleanly.
ChallengeHot reload during takeover

Keep a taken-over connection active, submit a script reload, and verify the old generation waits for the takeover connection to end before reclaiming.

Acceptance: the taken-over connection keeps working; the log shows the old generation's finalize after the connection closed.

Summary

PointConclusion
The third stateXS_TAKEOVER: the driver steps out, the application runs the whole connection
Scenariosprotocol upgrades / tunnels / proxies — not a daily business tool
Takeover disciplinefinish the protocol reply bytes first; consumption checks still apply
Terminal disciplineyou must eventually Close; Destroy and lease release are XServer's
Volume 3 closesfour protocol classes + routing/JSON/templates/vhosts in hand — on to volume 4's hot reload
xrt further reading