Plugin reference

tcp_server

A callback-driven TCP listener with optional TLS.

63 functionsnamespace tcp_serversource plugins/tcp_server/TcpServerPlugin.c

Introduction

The tcp_server plugin is a complete callback-based TCP package: an Open call opens a loopback TCP server (incoming connections are dispatched to a callback), and the SAME plugin can also act as a client — it can send a request to its own (or another) listener via RequestText/RequestBlob (synchronous) or BeginTextRequest/BeginBlobRequest (asynchronous) calls. The plugin supports the full async_meta vocabulary (Capabilities = 4095 = ProfileRouteService), and every job-level query has two names: the native Request* and the async_meta-compatible Job* synonym.

Server + client in one

This plugin is both a TCP server AND a TCP client. Open(callback, timeoutMs) opens a loopback TCP port and dispatches the RAW bytes of every incoming connection to the callback on a background thread. The callback signature is callback i32 NAME(ref blob $Request) (see the extended forms below for the peer's address and certificate); the callback may modify the request blob in place, and the modified bytes become the TCP response. Meanwhile, RequestText(listenerId, text, timeoutMs) synchronously and BeginTextRequest(listenerId, text, timeoutMs) asynchronously open a TCP connection to the listener's port, send the text/blob, and return the response (or an asynchronous requestId).

Peer metadata: the extended callback forms

The handler may declare extra parameters, and the host fills them in with the peer's identity. Three forms are accepted; pick the shortest one that covers what you need:

  • callback i32 NAME(ref blob $Request) — payload only.

  • callback i32 NAME(ref blob $Request, string $PeerHost, i32 $PeerPort) — plus the client's address and port.

  • callback i32 NAME(ref blob $Request, string $PeerHost, i32 $PeerPort, string $PeerCertSubject) — plus the client certificate's subject when the connection is mTLS-verified. It is an empty string when there is no TLS, or when an optional-mode client presented no certificate.

The same forms work on the TCP, HTTP and UDP callback families, so a handler moves between transports unchanged.

What is the client side for?

The RequestText / Begin*Request families exist primarily for TESTING: you call your own server with them to confirm the callback handles requests correctly. The loopback TCP channel has minimal overhead and works like a locally simulated incoming connection. They can also reach other loopback servers (e.g. another tcp_server listener, or another local TCP service).

Relationship to async_meta

The plugin is fully built on the async_meta constants. Capabilities() returns exactly the async_meta.ProfileRouteService() bitmask (=4095) — the entire vocabulary supported. RouteState returns async_meta.RouteStateOpen (=1) / RouteStateClosed (=0); RouteMeta(listenerId, key) knows the async_meta.RouteMeta* keys; JobMeta(requestId, key) knows the async_meta.JobMeta* keys.

Request* / Job* synonym pairs

Job-level (i.e., asynchronous request) query functions all exist under two names. Request* is the native, descriptive name (paints a “request”, HTTP-like image); Job* is the async_meta-vocabulary name. The two names map to the EXACT same handler — pick stylistically. Examples: RequestPhase ↔︎ Phase, RequestStatus ↔︎ Status, RequestError ↔︎ ErrorText, RequestStatusText ↔︎ StatusText, RequestInfo ↔︎ JobInfo, RequestRoute ↔︎ JobRoute, RequestTimeout ↔︎ JobTimeout, RequestKnown ↔︎ JobKnown, RequestMeta ↔︎ JobMeta, RequestHasBlobResult ↔︎ JobHasBlobResult, RequestBlobResultSize ↔︎ JobBlobResultSize.

Optional TLS layer

EnableTls(listenerId, certFile, keyFile) activates TLS on the listener: every subsequent incoming connection is wrapped in TLS by the tls plugin's provider. The listener itself does NOT link OpenSSL — that is resolved at runtime via the tls plugin. On a platform that doesn't support TLS (e.g. Windows pre-bundle), EnableTls returns a clean error and the listener keeps serving plaintext. TLS activation is IDEMPOTENT: calling it again with the same files just returns 0.

Sync vs async request

RequestText(listenerId, text, timeoutMs) and RequestBlob(listenerId, blob, timeoutMs) are SYNCHRONOUS: the call BLOCKS until the TCP connection is established, the request is sent, and the response arrives. BeginTextRequest/BeginBlobRequest are ASYNCHRONOUS: they return immediately with a requestId, and a background thread handles the connect/send/wait. Async jobs are managed with WaitComplete(requestId, timeoutMs), TakeTextResponse(requestId), and TakeBlob(requestId).

Loading the plugin

plugin "builtin:print";
plugin "../plugins/async_meta/AsyncMetaPlugin";
plugin
"../plugins/tcp_server/TcpServerPlugin";

A typical flow — synchronous echo on loopback

callback i32 Echo(ref blob $Request)
{
    // the callback may modify the request bytes in place;
    // these become the TCP response bytes
    return(1);
}
i32 main()
{
    i64 $lid;
    string $resp[64];
    $lid = tcp_server.Open("Echo", 5000);
    $resp = tcp_server.RequestText($lid, "PING", 5000);
    // ... process the response ...
    tcp_server.Close($lid);
    return(0);
}

A typical flow — asynchronous request with WaitComplete + TakeTextResponse

i64 $lid;
i64 $jobId;
string $resp[64];
$lid = tcp_server.Open("Echo", 5000);
$jobId = tcp_server.BeginTextRequest($lid, "HELLO", 5000);
// ... the script does other things ...
tcp_server.WaitComplete($jobId, 5000);
if (tcp_server.Status($jobId) == 0)
{
    $resp = tcp_server.TakeTextResponse($jobId);
    // ... processing ...
}
tcp_server.Close($lid);

What to know about every function (the basics)

  • Capabilities is always ProfileRouteService = 4095 (every async_meta bit).

  • Open binds to loopback (127.0.0.1) on an OS-picked port (query with Port).

  • The Request* and Job* families are SYNONYMS — exactly the same handler. Stylistic choice for code style.

  • RequestText/RequestBlob are synchronous; BeginTextRequest/BeginBlobRequest are asynchronous.

  • WaitComplete takes a requestId (NOT listenerId), and does NOT destroy the request.

  • TakeTextResponse and TakeBlob destroy the request; the requestId is invalid afterward.

  • EnableTls is idempotent — calling it again with the same files just returns 0.

  • RouteClose and Close map to the same handler: close the listener, return the canceled queued requests count.

  • RouteCloseAccepted is a LATCH — once it's 1 it never resets.

  • An error (stopping the script) is caused by a wrong argument count or type, an out-of-range timeoutMs, an invalid listenerId/requestId, a closed plugin, TCP connect failure, and embedded NUL byte in a text response.

How to read the signatures

callbackName is the script-level callback name (callback i32 NAME(ref blob $X)). timeoutMs is the callback run-time (Open) or request I/O (Request*, Begin*) max in ms; -1 = infinite. listenerId is the positive id given by Open. requestId is the positive id given by Begin*. metaKey is one of the async_meta.RouteMeta* or JobMeta* values. The type after the -> arrow is the return type.

Lifecycle and TLS

Opening the listener on a loopback TCP port, optional TLS activation, and plugin shutdown.

tcp_server.Capabilities

tcp_server.Capabilities() -> int

Returns the plugin's capability bitmask matching the async_meta constants.

Parameters

This function takes no arguments.

Return value

async_meta.ProfileRouteService (=4095): every async_meta bit (the entire vocabulary supported).

Example
printf("%d\n", tcp_server.Capabilities());
printf("%d\n", (tcp_server.Capabilities() ==
async_meta.ProfileRouteService()));
Output after running
4095
1
When to use

For backend capability checking with the Supports* helpers. tcp_server supports the FULL vocabulary (like bus) — the Supports* helpers return 1 for everything.

tcp_server.Open

tcp_server.Open(callbackName, timeoutMs) -> int

Opens a TCP listener on loopback IP and dispatches every incoming connection to the callback via a background thread.

Parameters
Parameter Type Description
callbackName string The script-level callback name to call. Signature: callback i32 NAME(ref blob $X).
timeoutMs int The callback run-time limit in ms. -1 = infinite; otherwise 0..2147483647.
Return value

The listenerId (positive i64). A bad argument, bind failure, or thread startup failure raises a runtime error.

Example
callback i32 Echo(ref blob $X) { return(1); }
i64 $lid;
$lid = tcp_server.Open("Echo", 5000);
printf("%d\n", ($lid > 0));
Output after running
1
When to use

For starting a local TCP service (debug server, local RPC, tested protocol). The port is OS-picked; query it with Port($lid). The callback receives RAW TCP bytes — any text or binary protocol is freely implementable.

tcp_server.SetClientCa

tcp_server.SetClientCa(listenerId, caFile, mode) -> 0

Turns on mTLS for this listener: requires (mode 2) or accepts (mode 1) a client certificate that chains to caFile on every TLS connection it accepts. The listener's mTLS shape is therefore Open + SetClientCa + EnableTls. With mTLS on, the 4-parameter callback form receives the verified client certificate's subject.

Parameters
Parameter Type Description
listenerId int The listener id returned by Open.
caFile string Path to the CA bundle (PEM) that client certificates are verified against.
mode int 1 = optional (accept a certificate if offered), 2 = required (the handshake fails without a valid one).
Return value

Returns 0 on success; raises a runtime error on a bad argument, an unknown listener, a missing mTLS-capable TLS provider, or when TLS is already enabled.

Order matters

Call it BEFORE EnableTls / OpenTls. Calling it afterwards is a runtime error by design — otherwise connections accepted in between would run unverified, leaving an unchecked window.

tcp_server.EnableTls

tcp_server.EnableTls(listenerId, certFile, keyFile) -> int

Activates TLS on the listener: every subsequent connection is wrapped in TLS by the tls plugin's provider.

Parameters
Parameter Type Description
listenerId int The listener id.
certFile string The server certificate path (PEM).
keyFile string The private key path (PEM).
Return value

0 (success). Idempotent: calling it again with the same files just returns 0. If TLS is not supported on the platform, a clean runtime error.

Example
i64 $lid;
$lid = tcp_server.Open("Echo", 5000);
// tcp_server.EnableTls($lid, "server.crt", "server.key");
print.Line($"ok");
Output after running
ok
When to use

For a secure local service with a TLS layer. The listener itself does not link OpenSSL — it relies on the tls plugin's provider at runtime. The probe didn't activate TLS (we only document the verb's presence).

tcp_server.OpenCount

tcp_server.OpenCount() -> int

Returns the count of currently open listeners (plugin-wide, global view).

Parameters

This function takes no arguments.

Return value

The number of open listeners (0 if none).

Example
printf("%d\n", tcp_server.OpenCount());
i64 $lid;
$lid = tcp_server.Open("Echo", 5000);
printf("%d\n", tcp_server.OpenCount());
Output after running
0
1
When to use

For resource control and diagnostics. If it does not return to 0 after Close calls, that signals a resource leak.

tcp_server.Close

tcp_server.Close(listenerId) -> int

Closes the given listener: stops the accept thread, shuts down the socket, releases resources.

Parameters
Parameter Type Description
listenerId int The listener id from Open.
Return value

The count of queued requests canceled by the close. Typically 0 (clean close with nothing pending).

Example
i64 $lid;
$lid = tcp_server.Open("Echo", 5000);
printf("%d\n", tcp_server.Close($lid));
Output after running
0
When to use

For clean listener shutdown. Close waits for in-progress callbacks to finish. If you called RouteClose first, Close returns 0 (listener no longer active).

Listener-level state

Current state of the listener: bound port, “open/closed” state, callback name, timeout, full diagnostic text. Route* names are equivalent to the State*/Info names.

tcp_server.Port

tcp_server.Port(listenerId) -> int

Returns the listener's actual, bound TCP port.

Parameters
Parameter Type Description
listenerId int The listener id.
Return value

The port (1..65535).

Example
i64 $lid;
$lid = tcp_server.Open("Echo", 5000);
printf("%d\n", (tcp_server.Port($lid) > 0));
Output after running
1
When to use

For querying the OS-picked port. RequestText/Blob and BeginTextRequest/BeginBlobRequest use this port automatically via the listenerId.

tcp_server.State

tcp_server.State(listenerId) -> int

Returns the listener's state using the async_meta route-state constants.

Parameters
Parameter Type Description
listenerId int The listener id.
Return value

async_meta.RouteStateOpen (=1) or RouteStateClosed (=0).

Example
i64 $lid;
$lid = tcp_server.Open("Echo", 5000);
printf("%d\n", tcp_server.State($lid));
Output after running
1
When to use

For programmatic state checking. Shared vocabulary with the callback_* family.

tcp_server.RouteState

tcp_server.RouteState(listenerId) -> int

Synonym of State — under the async_meta vocabulary.

Parameters
Parameter Type Description
listenerId int The listener id.
Return value

async_meta.RouteStateOpen (=1) or RouteStateClosed (=0).

Example
i64 $lid;
$lid = tcp_server.Open("Echo", 5000);
printf("%d\n", tcp_server.RouteState($lid));
Output after running
1
When to use

For async_meta-compatible code.

tcp_server.StateText

tcp_server.StateText(listenerId) -> string

The state as text.

Parameters
Parameter Type Description
listenerId int The listener id.
Return value

“open” or “closed”.

Example
i64 $lid;
$lid = tcp_server.Open("Echo", 5000);
print.Line(tcp_server.StateText($lid));
Output after running
open
When to use

For logging or UI display.

tcp_server.RouteStateText

tcp_server.RouteStateText(listenerId) -> string

Synonym of StateText.

Parameters
Parameter Type Description
listenerId int The listener id.
Return value

“open” or “closed”.

Example
i64 $lid;
$lid = tcp_server.Open("Echo", 5000);
print.Line(tcp_server.RouteStateText($lid));
Output after running
open
When to use

For logging, under the async_meta vocabulary.

tcp_server.RouteCallback

tcp_server.RouteCallback(listenerId) -> string

Returns the callback name passed at Open.

Parameters
Parameter Type Description
listenerId int The listener id.
Return value

The callback name as text.

Example
i64 $lid;
$lid = tcp_server.Open("Echo", 5000);
print.Line(tcp_server.RouteCallback($lid));
Output after running
Echo
When to use

For reflective queries and diagnostics.

tcp_server.RouteTimeout

tcp_server.RouteTimeout(listenerId) -> int

Returns the timeout value passed at Open, in ms.

Parameters
Parameter Type Description
listenerId int The listener id.
Return value

The timeoutMs value; -1 for infinite.

Example
i64 $lid;
$lid = tcp_server.Open("Echo", 5000);
printf("%d\n", tcp_server.RouteTimeout($lid));
Output after running
5000
When to use

Reflective query of listener configuration.

tcp_server.RouteKnown

tcp_server.RouteKnown(listenerId) -> int

Tells whether the listenerId is known to the plugin.

Parameters
Parameter Type Description
listenerId int The listener id.
Return value

1 if known (open); 0 if not.

Example
i64 $lid;
$lid = tcp_server.Open("Echo", 5000);
printf("%d\n", tcp_server.RouteKnown($lid));
Output after running
1
When to use

Defensive check.

tcp_server.RouteMeta

tcp_server.RouteMeta(listenerId, metaKey) -> int

Returns a specific meta field of the listener by async_meta.RouteMeta* keys.

Parameters
Parameter Type Description
listenerId int The listener id.
metaKey int An async_meta.RouteMeta* value (State, Timeout, Pending, Queued, Running, Drained, Known, CloseAccepted, ClosedQueued).
Return value

The value for the field.

Example
i64 $lid;
$lid = tcp_server.Open("Echo", 5000);
printf("%d\n", tcp_server.RouteMeta($lid,
async_meta.RouteMetaState()));
printf("%d\n", tcp_server.RouteMeta($lid,
async_meta.RouteMetaDrained()));
Output after running
1
1
When to use

Uniform async_meta query — for portable multi-backend code.

tcp_server.Info

tcp_server.Info(listenerId) -> string

Returns the listener's aggregated key=value diagnostic state as a string.

Parameters
Parameter Type Description
listenerId int The listener id.
Return value

A space-separated key=value list.

Example
i64 $lid;
$lid = tcp_server.Open("Echo", 5000);
printf("%d\n", (str.Len(tcp_server.Info($lid)) > 0));
Output after running
1
When to use

Detailed diagnostics in a single call.

tcp_server.RouteInfo

tcp_server.RouteInfo(listenerId) -> string

Synonym of Info — key=value diagnostic state.

Parameters
Parameter Type Description
listenerId int The listener id.
Return value

A space-separated key=value list.

Example
i64 $lid;
$lid = tcp_server.Open("Echo", 5000);
printf("%d\n", (str.Len(tcp_server.RouteInfo($lid)) > 0));
Output after running
1
When to use

For logging, under the async_meta vocabulary.

Listener-level traffic

Listener traffic metrics: active, pending, queued, running connections; drain state and blocking wait. Route* names are synonyms here too.

tcp_server.Pending

tcp_server.Pending(listenerId) -> int

Returns the number of pending (not yet started) requests.

Parameters
Parameter Type Description
listenerId int The listener id.
Return value

The number of pending requests.

Example
i64 $lid;
$lid = tcp_server.Open("Echo", 5000);
printf("%d\n", tcp_server.Pending($lid));
Output after running
0
When to use

Early signal of congestion.

tcp_server.RoutePending

tcp_server.RoutePending(listenerId) -> int

Synonym of Pending.

Parameters
Parameter Type Description
listenerId int The listener id.
Return value

The number of pending requests.

Example
i64 $lid;
$lid = tcp_server.Open("Echo", 5000);
printf("%d\n", tcp_server.RoutePending($lid));
Output after running
0
When to use

Under the async_meta vocabulary.

tcp_server.Queued

tcp_server.Queued(listenerId) -> int

Returns the number of queued requests.

Parameters
Parameter Type Description
listenerId int The listener id.
Return value

The number of queued requests.

Example
i64 $lid;
$lid = tcp_server.Open("Echo", 5000);
printf("%d\n", tcp_server.Queued($lid));
Output after running
0
When to use

For monitoring the internal queue length.

tcp_server.RouteQueued

tcp_server.RouteQueued(listenerId) -> int

Synonym of Queued.

Parameters
Parameter Type Description
listenerId int The listener id.
Return value

The number of queued requests.

Example
i64 $lid;
$lid = tcp_server.Open("Echo", 5000);
printf("%d\n", tcp_server.RouteQueued($lid));
Output after running
0
When to use

Under the async_meta vocabulary.

tcp_server.Running

tcp_server.Running(listenerId) -> int

Returns the number of currently running requests.

Parameters
Parameter Type Description
listenerId int The listener id.
Return value

The number of running requests.

Example
i64 $lid;
$lid = tcp_server.Open("Echo", 5000);
printf("%d\n", tcp_server.Running($lid));
Output after running
0
When to use

For monitoring parallelism.

tcp_server.RouteRunning

tcp_server.RouteRunning(listenerId) -> int

Synonym of Running.

Parameters
Parameter Type Description
listenerId int The listener id.
Return value

The number of running requests.

Example
i64 $lid;
$lid = tcp_server.Open("Echo", 5000);
printf("%d\n", tcp_server.RouteRunning($lid));
Output after running
0
When to use

Under the async_meta vocabulary.

tcp_server.Active

tcp_server.Active(listenerId) -> int

Returns the number of currently active connections.

Parameters
Parameter Type Description
listenerId int The listener id.
Return value

The number of active connections.

Example
i64 $lid;
$lid = tcp_server.Open("Echo", 5000);
printf("%d\n", tcp_server.Active($lid));
Output after running
0
When to use

For monitoring current server load.

tcp_server.Drained

tcp_server.Drained(listenerId) -> int

Tells whether the listener is drained (pending = queued = running = active = 0).

Parameters
Parameter Type Description
listenerId int The listener id.
Return value

1 if drained; 0 if something is in progress.

Example
i64 $lid;
$lid = tcp_server.Open("Echo", 5000);
printf("%d\n", tcp_server.Drained($lid));
Output after running
1
When to use

Before clean shutdown: ensure Drained=1 before calling Close.

tcp_server.RouteDrained

tcp_server.RouteDrained(listenerId) -> int

Synonym of Drained.

Parameters
Parameter Type Description
listenerId int The listener id.
Return value

1 if drained; 0 if not.

Example
i64 $lid;
$lid = tcp_server.Open("Echo", 5000);
printf("%d\n", tcp_server.RouteDrained($lid));
Output after running
1
When to use

Under the async_meta vocabulary.

tcp_server.WaitDrained

tcp_server.WaitDrained(listenerId, timeoutMs) -> int

Blocks until the listener is drained, or timeoutMs expires.

Parameters
Parameter Type Description
listenerId int The listener id.
timeoutMs int Max wait in ms; -1 = infinite.
Return value

1 if drain occurred before timeoutMs expired; 0 if it expired.

Example
i64 $lid;
$lid = tcp_server.Open("Echo", 5000);
printf("%d\n", tcp_server.WaitDrained($lid, 50));
Output after running
1
When to use

In the two-step shutdown pattern: AFTER RouteClose, wait for drain.

tcp_server.WaitRouteDrained

tcp_server.WaitRouteDrained(listenerId, timeoutMs) -> int

Synonym of WaitDrained.

Parameters
Parameter Type Description
listenerId int The listener id.
timeoutMs int Max wait in ms.
Return value

1 if drain occurred; 0 if expired.

Example
i64 $lid;
$lid = tcp_server.Open("Echo", 5000);
printf("%d\n", tcp_server.WaitRouteDrained($lid, 50));
Output after running
1
When to use

Under the async_meta vocabulary.

Request sending (client side)

Sending a TCP request to a listener's port (typically to test your own listener). Request* is synchronous, Begin* is asynchronous.

tcp_server.RequestText

tcp_server.RequestText(listenerId, text, timeoutMs) -> string

Sends a synchronous TCP request to the listener's port and returns the response text.

Parameters
Parameter Type Description
listenerId int The target listener id.
text string The text to send (UTF-8 or ASCII; the response MUST NOT contain NUL bytes).
timeoutMs int Max time for the entire connection (connect + send + receive) in ms.
Return value

The response text. If the response contains a NUL byte, a runtime error.

Example
i64 $lid;
string $resp[64];
$lid = tcp_server.Open("Echo", 5000);
$resp = tcp_server.RequestText($lid, "PING", 5000);
printf("%d\n", str.Len($resp));
Output after running
0
When to use

For testing your own callback: send a specific request and check the response. A simple, synchronous pattern — if you need async, use BeginTextRequest.

tcp_server.RequestBlob

tcp_server.RequestBlob(listenerId, request, timeoutMs) ->
blob

Sends a synchronous TCP request with a blob to the listener's port and returns the response blob.

Parameters
Parameter Type Description
listenerId int The target listener id.
request blob The binary data to send.
timeoutMs int Max time for the entire connection in ms.
Return value

The response blob (the callback-modified bytes). May be empty if the callback didn't write anything.

Example
i64 $lid;
blob $req[3];
blob $resp[16];
$req[0] = 65;
$req[1] = 66;
$req[2] = 67;
$lid = tcp_server.Open("Echo", 5000);
$resp = tcp_server.RequestBlob($lid, $req, 5000);
printf("%d\n", $resp.Length);
Output after running
0
When to use

For binary protocols. NUL bytes are allowed (only RequestText restricts them).

tcp_server.BeginTextRequest

tcp_server.BeginTextRequest(listenerId, text, timeoutMs) ->
int

Starts an asynchronous TCP request: the background thread connects, sends, and waits — the call returns immediately with a requestId.

Parameters
Parameter Type Description
listenerId int The target listener id.
text string The text to send.
timeoutMs int Max I/O time in ms.
Return value

The requestId (positive i64).

Example
i64 $lid;
i64 $jobId;
$lid = tcp_server.Open("Echo", 5000);
$jobId = tcp_server.BeginTextRequest($lid, "HELLO", 5000);
printf("%d\n", ($jobId > 0));
Output after running
1
When to use

For an async testing pattern: start a request, do other things, then WaitComplete + TakeTextResponse.

tcp_server.BeginBlobRequest

tcp_server.BeginBlobRequest(listenerId, request, timeoutMs) ->
int

Starts an asynchronous TCP request with a blob payload.

Parameters
Parameter Type Description
listenerId int The target listener id.
request blob The binary data to send.
timeoutMs int Max I/O time in ms.
Return value

The requestId (positive i64).

Example
i64 $lid;
i64 $jobId;
blob $req[3];
$req[0] = 65;
$req[1] = 66;
$req[2] = 67;
$lid = tcp_server.Open("Echo", 5000);
$jobId = tcp_server.BeginBlobRequest($lid, $req, 5000);
printf("%d\n", ($jobId > 0));
Output after running
1
When to use

For async binary requests. Take the response with TakeBlob after WaitComplete.

Wait and response take

Waiting for an async request to complete and taking the response (text or blob).

tcp_server.WaitComplete

tcp_server.WaitComplete(requestId, timeoutMs) -> int

Blocks until the request completes, but does NOT destroy it — status and result are queryable afterward.

Parameters
Parameter Type Description
requestId int The requestId from Begin*.
timeoutMs int Max wait in ms; -1 = infinite.
Return value

1 if the request completed; 0 if the timeout expired.

Example
i64 $lid;
i64 $jobId;
$lid = tcp_server.Open("Echo", 5000);
$jobId = tcp_server.BeginTextRequest($lid, "HELLO", 5000);
printf("%d\n", tcp_server.WaitComplete($jobId, 5000));
Output after running
1
When to use

First step of the async two-step pattern: wait for completion, verify success via Status / RequestStatus, then TakeTextResponse / TakeBlob the response.

tcp_server.TakeTextResponse

tcp_server.TakeTextResponse(requestId) -> string

Returns the text response of a completed request, and destroys the request.

Parameters
Parameter Type Description
requestId int The requestId.
Return value

The response text. If the request has not completed, a runtime error. If it contains a NUL byte, a runtime error.

Example
i64 $lid;
i64 $jobId;
string $resp[64];
$lid = tcp_server.Open("Echo", 5000);
$jobId = tcp_server.BeginTextRequest($lid, "HELLO", 5000);
tcp_server.WaitComplete($jobId, 5000);
$resp = tcp_server.TakeTextResponse($jobId);
printf("%d\n", str.Len($resp));
Output after running
0
When to use

For a text response. If the callback didn't write anything, the response is an empty string. For binary, use TakeBlob.

tcp_server.TakeBlob

tcp_server.TakeBlob(requestId) -> blob

Returns the blob response of a completed request, and destroys the request.

Parameters
Parameter Type Description
requestId int The requestId.
Return value

The response blob.

Example
i64 $lid;
i64 $jobId;
blob $req[3];
blob $resp[16];
$req[0] = 65;
$req[1] = 66;
$req[2] = 67;
$lid = tcp_server.Open("Echo", 5000);
$jobId = tcp_server.BeginBlobRequest($lid, $req, 5000);
tcp_server.WaitComplete($jobId, 5000);
$resp = tcp_server.TakeBlob($jobId);
printf("%d\n", $resp.Length);
Output after running
0
When to use

For a binary response (may contain NUL bytes). The callback may modify the request bytes in place — these become the response.

Request-level state and metadata

Current state (phase, status, error) and metadata of an async request. Request* and Job* names are SYNONYMS — exactly the same handler, just stylistically interchangeable.

tcp_server.RequestPhase

tcp_server.RequestPhase(requestId) -> int

Returns the request phase from the async_meta.Phase* constants.

Parameters
Parameter Type Description
requestId int The requestId.
Return value

async_meta.PhaseQueued (=0), PhaseRunning (=1), or PhaseCompleted (=2).

Example
i64 $lid;
i64 $jobId;
$lid = tcp_server.Open("Echo", 5000);
$jobId = tcp_server.BeginTextRequest($lid, "HELLO", 5000);
tcp_server.WaitComplete($jobId, 5000);
printf("%d\n", tcp_server.RequestPhase($jobId));
Output after running
2
When to use

For programmatic phase checks. Synonym of Phase.

tcp_server.Phase

tcp_server.Phase(requestId) -> int

Synonym of RequestPhase — under the async_meta vocabulary.

Parameters
Parameter Type Description
requestId int The requestId.
Return value

async_meta.PhaseQueued / PhaseRunning / PhaseCompleted.

Example
i64 $lid;
i64 $jobId;
$lid = tcp_server.Open("Echo", 5000);
$jobId = tcp_server.BeginTextRequest($lid, "HELLO", 5000);
tcp_server.WaitComplete($jobId, 5000);
printf("%d\n", tcp_server.Phase($jobId));
Output after running
2
When to use

For async_meta-compatible code.

tcp_server.RequestPhaseText

tcp_server.RequestPhaseText(requestId) -> string

The phase as text.

Parameters
Parameter Type Description
requestId int The requestId.
Return value

“queued”, “running”, or “completed”.

Example
i64 $lid;
i64 $jobId;
$lid = tcp_server.Open("Echo", 5000);
$jobId = tcp_server.BeginTextRequest($lid, "HELLO", 5000);
tcp_server.WaitComplete($jobId, 5000);
print.Line(tcp_server.RequestPhaseText($jobId));
Output after running
completed
When to use

For logging or UI display.

tcp_server.PhaseText

tcp_server.PhaseText(requestId) -> string

Synonym of RequestPhaseText.

Parameters
Parameter Type Description
requestId int The requestId.
Return value

“queued”, “running”, or “completed”.

Example
i64 $lid;
i64 $jobId;
$lid = tcp_server.Open("Echo", 5000);
$jobId = tcp_server.BeginTextRequest($lid, "HELLO", 5000);
tcp_server.WaitComplete($jobId, 5000);
print.Line(tcp_server.PhaseText($jobId));
Output after running
completed
When to use

Under the async_meta vocabulary.

tcp_server.RequestStatus

tcp_server.RequestStatus(requestId) -> int

Returns the request status: 0 = success, non-zero = error.

Parameters
Parameter Type Description
requestId int The requestId.
Return value

0 if successful; non-zero is the error code.

Example
i64 $lid;
i64 $jobId;
$lid = tcp_server.Open("Echo", 5000);
$jobId = tcp_server.BeginTextRequest($lid, "HELLO", 5000);
tcp_server.WaitComplete($jobId, 5000);
printf("%d\n", tcp_server.RequestStatus($jobId));
Output after running
0
When to use

Worth checking first after WaitComplete.

tcp_server.Status

tcp_server.Status(requestId) -> int

Synonym of RequestStatus.

Parameters
Parameter Type Description
requestId int The requestId.
Return value

0 or error code.

Example
i64 $lid;
i64 $jobId;
$lid = tcp_server.Open("Echo", 5000);
$jobId = tcp_server.BeginTextRequest($lid, "HELLO", 5000);
tcp_server.WaitComplete($jobId, 5000);
printf("%d\n", tcp_server.Status($jobId));
Output after running
0
When to use

Under the async_meta vocabulary.

tcp_server.RequestError

tcp_server.RequestError(requestId) -> string

Returns the request error message (empty on success).

Parameters
Parameter Type Description
requestId int The requestId.
Return value

The error message; empty string on success.

Example
i64 $lid;
i64 $jobId;
$lid = tcp_server.Open("Echo", 5000);
$jobId = tcp_server.BeginTextRequest($lid, "HELLO", 5000);
tcp_server.WaitComplete($jobId, 5000);
printf("%d\n", str.Len(tcp_server.RequestError($jobId)));
Output after running
0
When to use

If Status is non-0, check this for the cause.

tcp_server.ErrorText

tcp_server.ErrorText(requestId) -> string

Synonym of RequestError.

Parameters
Parameter Type Description
requestId int The requestId.
Return value

The error message.

Example
i64 $lid;
i64 $jobId;
$lid = tcp_server.Open("Echo", 5000);
$jobId = tcp_server.BeginTextRequest($lid, "HELLO", 5000);
tcp_server.WaitComplete($jobId, 5000);
printf("%d\n", str.Len(tcp_server.ErrorText($jobId)));
Output after running
0
When to use

Under the async_meta vocabulary.

tcp_server.RequestStatusText

tcp_server.RequestStatusText(requestId) -> string

The textual counterpart of the status.

Parameters
Parameter Type Description
requestId int The requestId.
Return value

“success” on a successful request, other text depending on the error type.

Example
i64 $lid;
i64 $jobId;
$lid = tcp_server.Open("Echo", 5000);
$jobId = tcp_server.BeginTextRequest($lid, "HELLO", 5000);
tcp_server.WaitComplete($jobId, 5000);
print.Line(tcp_server.RequestStatusText($jobId));
Output after running
success
When to use

For logging or user feedback.

tcp_server.StatusText

tcp_server.StatusText(requestId) -> string

Synonym of RequestStatusText.

Parameters
Parameter Type Description
requestId int The requestId.
Return value

“success” or error text.

Example
i64 $lid;
i64 $jobId;
$lid = tcp_server.Open("Echo", 5000);
$jobId = tcp_server.BeginTextRequest($lid, "HELLO", 5000);
tcp_server.WaitComplete($jobId, 5000);
print.Line(tcp_server.StatusText($jobId));
Output after running
success
When to use

Under the async_meta vocabulary.

tcp_server.RequestInfo

tcp_server.RequestInfo(requestId) -> string

Returns the request state as a key=value diagnostic string.

Parameters
Parameter Type Description
requestId int The requestId.
Return value

A space-separated key=value list.

Example
i64 $lid;
i64 $jobId;
$lid = tcp_server.Open("Echo", 5000);
$jobId = tcp_server.BeginTextRequest($lid, "HELLO", 5000);
tcp_server.WaitComplete($jobId, 5000);
printf("%d\n", (str.Len(tcp_server.RequestInfo($jobId)) >
0));
Output after running
1
When to use

Detailed request diagnostics in a single call.

tcp_server.JobInfo

tcp_server.JobInfo(requestId) -> string

Synonym of RequestInfo.

Parameters
Parameter Type Description
requestId int The requestId.
Return value

A key=value diagnostic string.

Example
i64 $lid;
i64 $jobId;
$lid = tcp_server.Open("Echo", 5000);
$jobId = tcp_server.BeginTextRequest($lid, "HELLO", 5000);
tcp_server.WaitComplete($jobId, 5000);
printf("%d\n", (str.Len(tcp_server.JobInfo($jobId)) > 0));
Output after running
1
When to use

Under the async_meta vocabulary.

tcp_server.RequestRoute

tcp_server.RequestRoute(requestId) -> int

Returns the id of the listener the request belongs to.

Parameters
Parameter Type Description
requestId int The requestId.
Return value

The listenerId.

Example
i64 $lid;
i64 $jobId;
$lid = tcp_server.Open("Echo", 5000);
$jobId = tcp_server.BeginTextRequest($lid, "HELLO", 5000);
printf("%d\n", (tcp_server.RequestRoute($jobId) == $lid));
Output after running
1
When to use

Reflective query of the request-owner relation.

tcp_server.JobRoute

tcp_server.JobRoute(requestId) -> int

Synonym of RequestRoute.

Parameters
Parameter Type Description
requestId int The requestId.
Return value

The listenerId.

Example
i64 $lid;
i64 $jobId;
$lid = tcp_server.Open("Echo", 5000);
$jobId = tcp_server.BeginTextRequest($lid, "HELLO", 5000);
printf("%d\n", (tcp_server.JobRoute($jobId) == $lid));
Output after running
1
When to use

Under the async_meta vocabulary.

tcp_server.RequestTimeout

tcp_server.RequestTimeout(requestId) -> int

Returns the request's configured timeout in ms (from Begin*).

Parameters
Parameter Type Description
requestId int The requestId.
Return value

The timeoutMs value.

Example
i64 $lid;
i64 $jobId;
$lid = tcp_server.Open("Echo", 5000);
$jobId = tcp_server.BeginTextRequest($lid, "HELLO", 5000);
printf("%d\n", tcp_server.RequestTimeout($jobId));
Output after running
5000
When to use

For logging or configuration checks.

tcp_server.JobTimeout

tcp_server.JobTimeout(requestId) -> int

Synonym of RequestTimeout.

Parameters
Parameter Type Description
requestId int The requestId.
Return value

The timeoutMs value.

Example
i64 $lid;
i64 $jobId;
$lid = tcp_server.Open("Echo", 5000);
$jobId = tcp_server.BeginTextRequest($lid, "HELLO", 5000);
printf("%d\n", tcp_server.JobTimeout($jobId));
Output after running
5000
When to use

Under the async_meta vocabulary.

tcp_server.RequestKnown

tcp_server.RequestKnown(requestId) -> int

Tells whether the requestId is known to the plugin.

Parameters
Parameter Type Description
requestId int The requestId.
Return value

1 if known; 0 if not (e.g. already destroyed by Take).

Example
i64 $lid;
i64 $jobId;
$lid = tcp_server.Open("Echo", 5000);
$jobId = tcp_server.BeginTextRequest($lid, "HELLO", 5000);
printf("%d\n", tcp_server.RequestKnown($jobId));
Output after running
1
When to use

Defensive check.

tcp_server.JobKnown

tcp_server.JobKnown(requestId) -> int

Synonym of RequestKnown.

Parameters
Parameter Type Description
requestId int The requestId.
Return value

1 if known; 0 if not.

Example
i64 $lid;
i64 $jobId;
$lid = tcp_server.Open("Echo", 5000);
$jobId = tcp_server.BeginTextRequest($lid, "HELLO", 5000);
printf("%d\n", tcp_server.JobKnown($jobId));
Output after running
1
When to use

Under the async_meta vocabulary.

tcp_server.RequestMeta

tcp_server.RequestMeta(requestId, metaKey) -> int

Returns a meta field of the request by async_meta.JobMeta* keys.

Parameters
Parameter Type Description
requestId int The requestId.
metaKey int An async_meta.JobMeta* value (Phase, Status, Route, Timeout, Known, HasBlobResult, BlobResultSize).
Return value

The value for the field.

Example
i64 $lid;
i64 $jobId;
$lid = tcp_server.Open("Echo", 5000);
$jobId = tcp_server.BeginTextRequest($lid, "HELLO", 5000);
tcp_server.WaitComplete($jobId, 5000);
printf("%d\n", tcp_server.RequestMeta($jobId,
async_meta.JobMetaPhase()));
Output after running
2
When to use

Uniform async_meta query on the request state.

tcp_server.JobMeta

tcp_server.JobMeta(requestId, metaKey) -> int

Synonym of RequestMeta.

Parameters
Parameter Type Description
requestId int The requestId.
metaKey int An async_meta.JobMeta* value.
Return value

The value for the field.

Example
i64 $lid;
i64 $jobId;
$lid = tcp_server.Open("Echo", 5000);
$jobId = tcp_server.BeginTextRequest($lid, "HELLO", 5000);
tcp_server.WaitComplete($jobId, 5000);
printf("%d\n", tcp_server.JobMeta($jobId,
async_meta.JobMetaPhase()));
Output after running
2
When to use

Under the async_meta vocabulary — for portable multi-backend code.

tcp_server.RequestHasBlobResult

tcp_server.RequestHasBlobResult(requestId) -> int

Tells whether the request has a blob result.

Parameters
Parameter Type Description
requestId int The requestId.
Return value

1 if yes; 0 if no.

Example
i64 $lid;
i64 $jobId;
$lid = tcp_server.Open("Echo", 5000);
$jobId = tcp_server.BeginTextRequest($lid, "HELLO", 5000);
tcp_server.WaitComplete($jobId, 5000);
printf("%d\n", tcp_server.RequestHasBlobResult($jobId));
Output after running
1
When to use

Take precondition: if 0, TakeBlob raises a runtime error.

tcp_server.JobHasBlobResult

tcp_server.JobHasBlobResult(requestId) -> int

Synonym of RequestHasBlobResult.

Parameters
Parameter Type Description
requestId int The requestId.
Return value

1 if yes; 0 if no.

Example
i64 $lid;
i64 $jobId;
$lid = tcp_server.Open("Echo", 5000);
$jobId = tcp_server.BeginTextRequest($lid, "HELLO", 5000);
tcp_server.WaitComplete($jobId, 5000);
printf("%d\n", tcp_server.JobHasBlobResult($jobId));
Output after running
1
When to use

Under the async_meta vocabulary.

tcp_server.RequestBlobResultSize

tcp_server.RequestBlobResultSize(requestId) -> int

Returns the response blob size in bytes.

Parameters
Parameter Type Description
requestId int The requestId.
Return value

The blob size in bytes.

Example
i64 $lid;
i64 $jobId;
$lid = tcp_server.Open("Echo", 5000);
$jobId = tcp_server.BeginTextRequest($lid, "HELLO", 5000);
tcp_server.WaitComplete($jobId, 5000);
printf("%d\n", tcp_server.RequestBlobResultSize($jobId));
Output after running
0
When to use

For memory pre-allocation: you know how big a blob to allocate for TakeBlob.

tcp_server.JobBlobResultSize

tcp_server.JobBlobResultSize(requestId) -> int

Synonym of RequestBlobResultSize.

Parameters
Parameter Type Description
requestId int The requestId.
Return value

The blob size in bytes.

Example
i64 $lid;
i64 $jobId;
$lid = tcp_server.Open("Echo", 5000);
$jobId = tcp_server.BeginTextRequest($lid, "HELLO", 5000);
tcp_server.WaitComplete($jobId, 5000);
printf("%d\n", tcp_server.JobBlobResultSize($jobId));
Output after running
0
When to use

Under the async_meta vocabulary.

Listener shutdown

Diagnostics of the listener (route) shutdown process and explicit shutdown. RouteClose and Close do the same thing under different names.

tcp_server.RouteCloseAccepted

tcp_server.RouteCloseAccepted(listenerId) -> int

Tells whether a close request has been accepted on the listener.

Parameters
Parameter Type Description
listenerId int The listener id.
Return value

1 if yes; 0 if no RouteClose / Close has happened yet.

Example
i64 $lid;
$lid = tcp_server.Open("Echo", 5000);
tcp_server.RouteClose($lid);
printf("%d\n", tcp_server.RouteCloseAccepted($lid));
Output after running
1
When to use

LATCH: once 1, it never resets. Useful for diagnostics.

tcp_server.RouteClosedQueued

tcp_server.RouteClosedQueued(listenerId) -> int

Returns the count of queued requests canceled by the most recent RouteClose / Close.

Parameters
Parameter Type Description
listenerId int The listener id.
Return value

The count of canceled queued requests.

Example
i64 $lid;
$lid = tcp_server.Open("Echo", 5000);
tcp_server.RouteClose($lid);
printf("%d\n", tcp_server.RouteClosedQueued($lid));
Output after running
0
When to use

For diagnostics: how many requests were lost during shutdown.

tcp_server.RouteClose

tcp_server.RouteClose(listenerId) -> int

Synonym of Close — exact same handler.

Parameters
Parameter Type Description
listenerId int The listener id.
Return value

The count of canceled queued requests (0 = clean close).

Example
i64 $lid;
$lid = tcp_server.Open("Echo", 5000);
printf("%d\n", tcp_server.RouteClose($lid));
Output after running
0
When to use

Under the async_meta vocabulary. Equivalent to Close — stylistic choice.

tcp_server.RouteCloseInfo

tcp_server.RouteCloseInfo(listenerId) -> string

Returns the listener shutdown process as a key=value diagnostic string.

Parameters
Parameter Type Description
listenerId int The listener id.
Return value

A space-separated key=value list.

Example
i64 $lid;
$lid = tcp_server.Open("Echo", 5000);
printf("%d\n", (str.Len(tcp_server.RouteCloseInfo($lid)) >
0));
Output after running
1
When to use

Detailed shutdown diagnostics in a single call.

Practical notes

What the tcp_server plugin is good for

  • Starting a local TCP service on a loopback port (debug server, local RPC, tested protocol).

  • Event-driven processing: every incoming TCP connection is a callback invocation; the callback gets RAW bytes and can implement any protocol.

  • Built-in client side for testing your own server: RequestText/RequestBlob are synchronous, BeginTextRequest/BeginBlobRequest are asynchronous — both open a loopback TCP connection.

  • Optional TLS layer with EnableTls: incoming connections are TLS-wrapped, the callback receives the decoded bytes unchanged.

  • async_meta compatibility with the full vocabulary: Phase, Status, JobMeta, RouteMeta, WaitDrained, RouteClose — every bit supported (Capabilities = 4095).

Server + client in one — the testing pattern

A key feature of the plugin is that a complete TCP exchange is reachable from one script: Open opens a server, and RequestText immediately calls the server itself. This is ideal for testing a callback implementation: you can invoke your own logic through a real TCP channel, ensuring the endpoints communicate properly. A minimal test: open a listener → send RequestText → check the response → close.

Request* vs Job* — synonym pairs

Every job-level (= queryable per async request) function has two names: the native Request* (paints the HTTP/RPC request image) and the async_meta-vocabulary Job*. The two forms are EXACTLY the same handler — pick stylistically. If your code works with other async_meta-compatible backends, Job* is more consistent; if only tcp_server, Request* is more expressive.

Sync vs async request

RequestText/RequestBlob are SYNCHRONOUS: the call blocks until the TCP connection + send + receive finishes. Simple, but the script does nothing else meanwhile. BeginTextRequest/BeginBlobRequest are ASYNCHRONOUS: they return immediately with a requestId, the background thread handles I/O. Then WaitComplete + TakeTextResponse / TakeBlob finish and collect. For high-throughput or parallel testing, the async form is recommended.

TLS activation

EnableTls(listenerId, certFile, keyFile) is IDEMPOTENT: calling it again with the same files just returns 0. The TLS layer runs through the tls plugin's provider — resolved at runtime, so the tcp_server plugin itself does not link OpenSSL. If the platform doesn't support TLS (e.g. a Windows pre-bundle build), EnableTls returns a clean error and the listener keeps serving plaintext.

Callback signature

The callback signature is callback i32 NAME(ref blob $Request). The incoming $Request blob contains the RAW bytes received over the TCP connection — the plugin does not interpret HTTP, does not look for protocol framing. The callback may modify the blob bytes in place, and the modified content becomes the TCP response. If the callback writes nothing, the response is empty (as in the probe — the Echo callback returns 1 without modifying the blob).

Listener shutdown

RouteClose(listenerId) and Close(listenerId) are the SAME handler — two names, identical behavior. The return value is NOT a 1/0 success flag, but the COUNT of queued requests canceled by the close. Typically 0 (clean close with no pending requests). The two-step shutdown pattern: RouteClose → WaitDrained → forced cleanup (if needed). A single Close performs all steps.

Error handling

An invalid listenerId, requestId, wrong argument count or type, out-of-range timeoutMs, touching an already-closed listener or plugin are reported by the runtime as a runtime error, and the script stops. A TCP connect failure (e.g. connecting to a closed listener's port) gives an error code in the Status field; RequestError returns the error text. TakeTextResponse raises a runtime error if the response contains an embedded NUL byte — use TakeBlob instead.