# Serving

> UCall for C

Initialize the server and register routes before polling.
`ucall_server_take_call()` drives one loop with a bounded wait; zero timeout performs one nonblocking progress round.
`ucall_server_take_calls()` drives it continuously until `ucall_server_stop()` or failure.
An interface's `listen_descriptor` accepts on a listening socket the caller opened, such as one systemd passed in, instead of binding `address`; UCall accepts on duplicates and never closes it.
Routing is exact: empty segments are segments and a trailing slash is significant.
A path no route takes answers 404, other verbs' routes answer 405 with `allow`, GET routes serve HEAD, `OPTIONS` answers 204 with `allow`, and `Expect: 100-continue` gets its interim response once the request is next and its body is wanted.
An interface at its connection budget evicts its least recently progressed idle keep-alive connection for a new peer.
A server interface's `max_pipelined_requests` bounds the requests one connection carries at once; zero means one, and replies leave in request order.
Servers support immutable routes, size and latency based application batching, retained request views, and content, error, vectored and streamed replies.
The `metrics_*` configuration reports StatsD counters.
The first `ucall_server_stop()` drains: listeners and idle connections close, and every held request gets its reply before its connection closes; a second stop cuts what is still in flight.
Stop the server, join its polling threads, and finish application use of retained requests before freeing it.
Native I/O retirement during teardown can block.

`#include <ucall/types.h>`

`#include <ucall/server.h>`

## ucall_io_backend_t

A concrete I/O implementation; automatic chooses an available native implementation.

```c
enum ucall_io_backend_t
```

- `ucall_io_backend_automatic_k` = `0`: Initialization picks the fastest backend this machine and its limits allow.
- `ucall_io_backend_posix_k`: Blocking sockets and files, polled with `poll`, on any POSIX system.
- `ucall_io_backend_linux_epollaio_k`: Linux epoll for sockets and Linux AIO for files, the path where io_uring is blocked.
- `ucall_io_backend_linux_uring612_k`: io_uring as Linux 6.12, the older LTS line, provides it.
- `ucall_io_backend_linux_uring618_k`: io_uring as Linux 6.18, the newer LTS line, provides it, with multishot receives.
- `ucall_io_backend_bsd_kqueue_k`: kqueue on FreeBSD, with FreeBSD AIO for files, and on macOS.
- `ucall_io_backend_windows_iocp_k`: I/O completion ports on Windows.

Spellings: ```
char const * ucall_io_backend_name(ucall_io_backend_t backend);
```

```
ucall_io_backend_t ucall_io_backend_from_name(ucall_bytes_view_t name);
```

## ucall_server_t

Opaque server handle.

```c
typedef struct ucall_server_handle_t * ucall_server_t;
```

See also: Deals with `[ucall_received_http_request_t](https://www.unum.cloud/docs/ucall/c/requests.md#ucall_received_http_request_t)`, individually or in counted arrays.

See also: Use with `ucall_server_init()` and `ucall_server_free()` for lifetime.

See also: Use `ucall_server_add_http_endpoint()` and `ucall_server_take_calls()` for logic.

## ucall_http_batch_endpoint_t

One batch endpoint of a server, drained by one application thread; lives until `ucall_server_free()`.

```c
typedef struct ucall_http_batch_endpoint_handle_t * ucall_http_batch_endpoint_t;
```

## ucall_verb_t

HTTP request methods/verbs for endpoint routing.

```c
enum ucall_verb_t
```

- `ucall_verb_unknown_k` = `0`: Unrecognized or not yet parsed.
- `ucall_verb_get_k`: HTTP "GET" method for retrieving resources.
- `ucall_verb_post_k`: HTTP "POST" method for creating resources.
- `ucall_verb_put_k`: HTTP "PUT" method for updating resources.
- `ucall_verb_delete_k`: HTTP "DELETE" method for removing resources.
- `ucall_verb_patch_k`: HTTP "PATCH" method for partial updates.
- `ucall_verb_head_k`: HTTP "HEAD" method for retrieving headers only.
- `ucall_verb_options_k`: HTTP "OPTIONS" method for retrieving supported methods.
- `ucall_verb_any_k`: Matches every method.

## ucall_log_level_t

Severity of a log line, from the most verbose up.

```c
enum ucall_log_level_t
```

- `ucall_log_level_debug_k`: Detail for debugging.
- `ucall_log_level_info_k`: Normal lifecycle events.
- `ucall_log_level_warning_k`: Something unexpected that the library recovered from.
- `ucall_log_level_error_k`: An operation failed.
- `ucall_log_level_fatal_k`: The server or client cannot continue.

## ucall_log_format_t

Shape of each log line.

```c
enum ucall_log_format_t
```

- `ucall_log_format_human_k`: Human-readable unit-normalized lines.
- `ucall_log_format_json_k`: Newline-delimited JSONs documents.

## ucall_log_callback_t

Receives one formatted log line, without a trailing newline.

```c
typedef void(*) ucall_log_callback_t(ucall_log_level_t level, ucall_bytes_view_t line, void *context);
```

Called on whichever thread produced the line, including application polling threads. The callback must be thread-safe and return quickly.

## ucall_log_t

The single log sink of a client or a server.

```c
struct ucall_log_t
```

UCall writes nothing anywhere on its own: every line goes to `callback`, and without one the library stays silent.

- `callback` `ucall_log_callback_t`: Receives every line at or above `level`.
- `context` `void *`: Passed verbatim to `callback`.
- `format` `ucall_log_format_t`: Line format.
- `level` `ucall_log_level_t`: Lines below this severity are never formatted.

## ucall_network_interface_t

One virtualized network interface, and every policy applying to what arrives on it.

```c
struct ucall_network_interface_t
```

An interface is an address the server answers on, together with the security posture and admission limits for the connections it accepts. Several of them live under one server, which is what lets a single server answer VPN-internal Noise traffic and public plaintext at once, across as many physical devices as the machine has.

Encryption and admission live on the interface rather than on the server, so one server serves plaintext on loopback for health checks while requiring Noise on the wire - without standing up a second server to do it.

- `address` `ucall_bytes_view_t`: Listening address in "host:port" form, required unless `listen_descriptor` is set; the resolved options report the bound address, or an AF_UNIX socket's path.
- `listen_descriptor` `intptr_t const *`: A listening stream socket to accept on instead of binding `address`, such as one systemd or a supervisor passed in, or NULL to bind.
- `device_name` `ucall_bytes_view_t`: Physical device to pin this interface to with `SO_BINDTODEVICE`, such as "eth0", or empty to bind by address alone.
- `security` `ucall_security_t`: Encryption for connections accepted here.
- `noise_private_key` `ucall_noise_key_t const *`: Server identity for handshakes.
- `noise_peer_key` `ucall_noise_key_t const *`: The initiator's static public key, which KK hashes before the first message.
- `peer_authorizer` `ucall_peer_authorizer_t`: Vets client static keys.
- `peer_authorizer_context` `void *`: Passed verbatim to `peer_authorizer`.
- `event_loops` `size_t`: Event loops accepting on this interface.
- `max_concurrent_connections` `size_t`: Required open-connection budget across this interface's loops.
- `max_pipelined_requests` `size_t`: Requests one connection may have in flight before UCall stops reading from it; zero means one.
- `max_request_bytes` `size_t`: Largest request head and buffered body; past it the reply is 413 and the connection lingers closed.
- `reply_directories` `ucall_bytes_view_t const *`: Directories that path parts of replies to this interface's requests resolve beneath, by position, each copied during `ucall_server_init()`.
- `reply_directories_count` `size_t`: Entries in `reply_directories`.

## ucall_server_options_t

Configuration parameters for the UCall server.

```c
struct ucall_server_options_t
```

- `interfaces` `ucall_network_interface_t const *`: Interfaces to answer on.
- `interfaces_count` `size_t`: Entries in `interfaces`.
- `log` `ucall_log_t`: Where log lines go.
- `metrics_address` `ucall_bytes_view_t`: StatsD UDP endpoint "host:port"; empty disables emission.
- `metrics_sample_rate` `float`: Fraction of finished requests whose latency is reported, in (0.0, 1.0].
- `metrics_prefix` `ucall_bytes_view_t`: Metric name prefix; empty takes "ucall".
- `metrics_tags` `ucall_bytes_view_t const *`: Global tags, each "key:value".
- `metrics_tags_count` `size_t`: Entries in `metrics_tags`.
- `metrics_interval_microseconds` `size_t`: Microseconds between one event loop's datagrams.
- `backend` `ucall_io_backend_t`: Requested I/O backend; automatic chooses an available native backend.
- `cpu_class` `ucall_cpu_class_t`: Ceiling on the CPU class: the newest compiled class under it runs, and unknown takes the initialization thread's capabilities.

See also: Initialize with `ucall_server_init()`.

## ucall_event_loop_statistics_t

Counters of one event loop since initialization; divided by `requests`, they price one call.

```c
struct ucall_event_loop_statistics_t
```

Only the loop's polling owner advances them. Byte counters cover the bytes UCall itself moves, never the copies the kernel makes between socket buffers and user memory.

- `polls` `uint64_t`: Engine polls the loop issued, each taking zero or more completions.
- `empty_polls` `uint64_t`: Engine polls that took no completion.
- `kernel_enters` `uint64_t`: System calls: io_uring enters, or other backends' waits, registrations and socket calls.
- `submissions` `uint64_t`: Operations queued: io_uring submission entries, or requests another backend accepted.
- `completions` `uint64_t`: Results taken: io_uring completion entries, or operations another backend finished.
- `cancellations` `uint64_t`: Pending operations, or io_uring multishot receives, the engine asked to cancel.
- `accepts` `uint64_t`: Connections accepted and handed to this loop.
- `requests` `uint64_t`: HTTP requests parsed and dispatched to an endpoint or an error reply.
- `receive_rearms` `uint64_t`: Multishot receives armed again on a socket that already streamed, only on io_uring 6.18.
- `bytes_received` `uint64_t`: Bytes the kernel reported received on this loop's connections, ciphertext under Noise.
- `bytes_sent` `uint64_t`: Bytes the kernel reported sent from this loop's connections, ciphertext under Noise.
- `bytes_copied` `uint64_t`: Bytes UCall copied: receive appends, reply bodies, Noise records and parked receives.
- `zero_copy_sends` `uint64_t`: Sends that left without copying: reply segments and file windows.
- `zero_copy_fallbacks` `uint64_t`: Zero-copy sends the kernel copied anyway or refused to pin, as loopback always does.
- `copying_sends` `uint64_t`: Sends that copied instead of pinning: the socket was demoted or refused zero-copy.
- `file_reads_asynchronous` `uint64_t`: File reads the kernel finishes later: io_uring, Linux or FreeBSD AIO, or overlapped I/O.
- `file_reads_blocking` `uint64_t`: File reads the loop issued itself and blocked on, as the posix backend and macOS do.
- `bytes_read` `uint64_t`: Bytes the kernel reported read from files into the loop's file windows.
- `file_window_overlaps` `uint64_t`: File reads submitted while an earlier window of the same stream waited to send or sent.
- `linger_resets` `uint64_t`: Lingering closes reset at their deadline because the kernel still held what they sent.
- `ready_passes` `uint64_t`: Passes the loop made over a ready connection, each advancing it as far as it goes.
- `replied_dequeues` `uint64_t`: Replied exchanges the loop took from its queue to adopt their reply segments.
- `refused_requests` `uint64_t`: Requests the loop answered itself with 400, 404, 405, 413, 501, 503 or 505.
- `handshake_failures` `uint64_t`: Connections whose Noise handshake failed.
- `authorizer_refusals` `uint64_t`: Connections whose authenticated peer key the interface's authorizer refused.

## ucall_batch_endpoint_statistics_t

Counters of one batch endpoint since registration; they say how large its batches were and why each fired.

```c
struct ucall_batch_endpoint_statistics_t
```

Only the endpoint's polling owner advances them. Batches released by a stop fire no callback and count nowhere.

- `batches` `uint64_t`: Callbacks invoked.
- `requests` `uint64_t`: Requests delivered across those callbacks.
- `filled_batches` `uint64_t`: Batches that fired on reaching `max_batch_size`.
- `ready_batches` `uint64_t`: Batches that fired on reaching `min_batch_size` below the maximum.
- `expired_batches` `uint64_t`: Batches that fired below `min_batch_size` once `max_latency_microseconds` passed.

## ucall_server_init

Initializes the server state.

```c
void ucall_server_init(ucall_server_init_t *arguments);
```

- `server`: Output for the new server.
- `outcome`: Synchronous initialization result.
- `options`: Requested configuration.
- `resolved`: Optional output for `options` with every default filled in, including each interface's `event_loops`.

Notes: Call during setup only, before any loop is polled.

Statuses: - [`ucall_status_invalid_argument_k`](https://www.unum.cloud/docs/ucall/c/errors.md#ucall_status_invalid_argument_k) An output, the configuration or its interfaces are missing, or a metrics setting, an address, a device name, a security mode with the key or authorizer it needs, a connection budget or the reply directories are unusable.
- [`ucall_status_unsupported_k`](https://www.unum.cloud/docs/ucall/c/errors.md#ucall_status_unsupported_k) This machine does not run the requested CPU class, no I/O backend serves the configuration on it, a device is named outside Linux, or an interface asks Windows for several loops.
- [`ucall_status_connection_failed_k`](https://www.unum.cloud/docs/ucall/c/errors.md#ucall_status_connection_failed_k) The metrics address or a listening address does not resolve, or no socket binds to it.
- [`ucall_status_not_found_k`](https://www.unum.cloud/docs/ucall/c/errors.md#ucall_status_not_found_k) A reply directory does not exist.
- [`ucall_status_overflow_k`](https://www.unum.cloud/docs/ucall/c/errors.md#ucall_status_overflow_k) The connection and pipelining budgets overflow their counters.

## ucall_server_free

Frees the server state after its polling callers have returned.

```c
void ucall_server_free(ucall_server_t server);
```

Does nothing for `NULL`.

- `server` (in): Server from `ucall_server_init()`, or `NULL`.

Notes: Stop and join polling threads, and finish application use of retained requests before teardown. Remaining request handles become invalid. Native I/O retirement can block, and on a thread other than a polling owner it waits for the kernel to end that owner's ring, which a forked child that never called `exec` prolongs until it exits. Returns without freeing while a client bound to it lives; free those first.

## ucall_server_stop

Requests shutdown and wakes blocked polling callers and batch polling owners.

```c
void ucall_server_stop(ucall_server_t server);
```

The first call drains: the server stops accepting, closes idle connections, and answers the requests it already holds with `connection:` close, closing each connection after its last reply. Polling callers return once their loop has no connection left, and batch polling owners once every loop has returned. Any later call, or `ucall_server_free()`, cuts instead: replies still in flight are abandoned and their peers reset.

Safe from an endpoint callback or a separate thread.

- `server` (in): Server from `ucall_server_init()`, or `NULL`.

## ucall_server_take_call

Advances one server loop and invokes ready callbacks on the calling thread.

```c
void ucall_server_take_call(ucall_server_take_call_t *arguments);
```

Callbacks run synchronously; the timeout cannot preempt them.

- `server`: Initialized server whose routes are ready.
- `outcome`: Outcome of this polling round.
- `event_loop_index`: Zero-based loop index; each loop has one polling owner.
- `timeout_microseconds`: Maximum wait; zero performs one bounded nonblocking progress round.

Statuses: - [`ucall_status_connection_closed_k`](https://www.unum.cloud/docs/ucall/c/errors.md#ucall_status_connection_closed_k) The loop retired after a stop: its drain or cut ended, so a caller polling in slices stops here.
- [`ucall_status_uninitialized_k`](https://www.unum.cloud/docs/ucall/c/errors.md#ucall_status_uninitialized_k) The `server` is `NULL`.
- [`ucall_status_invalid_argument_k`](https://www.unum.cloud/docs/ucall/c/errors.md#ucall_status_invalid_argument_k) The `event_loop_index` is past the last loop.
- [`ucall_status_overflow_k`](https://www.unum.cloud/docs/ucall/c/errors.md#ucall_status_overflow_k) The loop's connections, acceptors or pipelined requests overflow the counters its first poll sizes.

## ucall_server_take_calls

Drives one server loop until `ucall_server_stop()` or an I/O failure.

```c
void ucall_server_take_calls(ucall_server_take_calls_t *arguments);
```

- `server`: Initialized server whose routes are ready.
- `outcome`: Final outcome after polling stops or fails.
- `event_loop_index`: Zero-based loop index; each loop has one polling owner.

Statuses: - [`ucall_status_uninitialized_k`](https://www.unum.cloud/docs/ucall/c/errors.md#ucall_status_uninitialized_k) The `server` is `NULL`.
- [`ucall_status_invalid_argument_k`](https://www.unum.cloud/docs/ucall/c/errors.md#ucall_status_invalid_argument_k) The `event_loop_index` is past the last loop.
- [`ucall_status_overflow_k`](https://www.unum.cloud/docs/ucall/c/errors.md#ucall_status_overflow_k) The loop's connections, acceptors or pipelined requests overflow the counters its first poll sizes.

## ucall_server_event_loop_statistics

Copies one loop's counters, from any thread whose CPU runs the server's CPU class.

```c
void ucall_server_event_loop_statistics(
    ucall_server_event_loop_statistics_t *arguments);
```

Each counter is read on its own, so a snapshot of a running loop is not one instant.

- `server`: Initialized server.
- `outcome`: The verb's status, listed on the verb.
- `event_loop_index`: Zero-based loop index.
- `statistics`: Output for a snapshot of the loop's counters, zeroed on failure.

Statuses: - [`ucall_status_uninitialized_k`](https://www.unum.cloud/docs/ucall/c/errors.md#ucall_status_uninitialized_k) The `server` is `NULL`.
- [`ucall_status_invalid_argument_k`](https://www.unum.cloud/docs/ucall/c/errors.md#ucall_status_invalid_argument_k) The `statistics` output is `NULL`, or the loop index is past the last loop.

## ucall_server_batch_endpoint_statistics

Copies one batch endpoint's counters from any thread on a CPU of the server's class.

```c
void ucall_server_batch_endpoint_statistics(
    ucall_server_batch_endpoint_statistics_t *arguments);
```

Each counter is read on its own, so a snapshot of a polled endpoint is not one instant.

- `server`: Initialized server that registered `endpoint`.
- `outcome`: The verb's status, listed on the verb.
- `endpoint`: Endpoint from `ucall_server_add_http_batch_endpoint()`.
- `statistics`: Output for a snapshot of the endpoint's counters, zeroed on failure.

Statuses: - [`ucall_status_uninitialized_k`](https://www.unum.cloud/docs/ucall/c/errors.md#ucall_status_uninitialized_k) The `server` is `NULL`.
- [`ucall_status_invalid_argument_k`](https://www.unum.cloud/docs/ucall/c/errors.md#ucall_status_invalid_argument_k) The `endpoint` or the `statistics` output is `NULL`.

## ucall_server_add_http_endpoint

Registers a function callback to be triggered when a matching request arrives.

```c
void ucall_server_add_http_endpoint(
    ucall_server_add_http_endpoint_t *arguments);
```

The `uri_template` field supports URI template syntax (RFC 6570 subset):

- `"/users/{id}"` matches `"/users/123"` or `"/users/abc"`
- `"/posts/{year}/{month}"` matches `"/posts/2024/03"`
- `"/files/{*path}"` matches `"/files/a/b/c.txt"` (greedy, captures `"a/b/c.txt"`)Routing precedence: Literals match before template variables, before greedy wildcards.

- `server`: The server this call operates on.
- `outcome`: The verb's status, listed on the verb.
- `uri_template`: URI template, with an explicit byte length.
- `verb`: HTTP method for this endpoint.
- `callback`: Function pointer to the callback.
- `context`: Optional payload/tag for metadata (e.g., for CPython runtime).
- `body_delivery`: Whether the callback runs once the body is buffered, or at headers time with the body pulled through ucall_server_request_body_chunk().

See also: RFC 6570 Section 3.2.2, simple string expansion: [https://www.rfc-editor.org/rfc/rfc6570#section-3.2.2](https://www.rfc-editor.org/rfc/rfc6570#section-3.2.2)

Notes: Call during setup only, before any loop is polled.

Statuses: - [`ucall_status_uninitialized_k`](https://www.unum.cloud/docs/ucall/c/errors.md#ucall_status_uninitialized_k) The `server` is `NULL`.
- [`ucall_status_invalid_argument_k`](https://www.unum.cloud/docs/ucall/c/errors.md#ucall_status_invalid_argument_k) The `callback` is `NULL`, the `verb` is unknown, or the template is empty, lacks its leading slash, carries a query, a fragment or a malformed segment, or names a placeholder another template names differently at the same position.
- [`ucall_status_contended_k`](https://www.unum.cloud/docs/ucall/c/errors.md#ucall_status_contended_k) A loop of the server was already polled.
- [`ucall_status_already_exists_k`](https://www.unum.cloud/docs/ucall/c/errors.md#ucall_status_already_exists_k) An endpoint of the same `verb` has the same or an equivalent template.

## ucall_server_add_http_batch_endpoint

Registers a batching callback to collect multiple requests and process them together.

```c
void ucall_server_add_http_batch_endpoint(
    ucall_server_add_http_batch_endpoint_t *arguments);
```

Very handy for batch-processing and high-latency operations (e.g., GPU inference).

Unlike client-side batching, which packs several calls into one request, the server aggregates independent requests from different sources and dispatches them together.

Batching behavior:

- Batch size < `min_batch_size:` Wait for more requests (up to `max_latency_microseconds`).
- Batch size >= `min_batch_size:` Dispatch immediately (optimal utilization).
- Batch size >= `max_batch_size:` Force dispatch (prevent unbounded growth).Requests from every event loop share one queue per batch endpoint. The callback receives a counted array of request handles on the thread polling that endpoint through `ucall_server_take_batch()` or `ucall_server_take_batches()`, never on an event loop. Registration returns the endpoint's handle, so each endpoint can have its own polling thread. Copy the request handles into application-owned storage to process them later; received bytes need no copy.

- `server`: The server this call operates on.
- `outcome`: The verb's status, listed on the verb.
- `uri_template`: URI template, with an explicit byte length.
- `verb`: HTTP method for this endpoint.
- `callback`: Function pointer to the batch callback.
- `context`: Optional payload/tag for metadata (e.g., for CPython runtime).
- `min_batch_size`: Optimal batch size.
- `max_batch_size`: Maximum requests per batch.
- `max_latency_microseconds`: Maximum wait time for partial batches.
- `endpoint`: Receives the endpoint that `ucall_server_take_batch()` and `ucall_server_take_batches()` poll; required.

Notes: Call during setup only, before any loop is polled.

Statuses: - [`ucall_status_uninitialized_k`](https://www.unum.cloud/docs/ucall/c/errors.md#ucall_status_uninitialized_k) The `server` is `NULL`.
- [`ucall_status_invalid_argument_k`](https://www.unum.cloud/docs/ucall/c/errors.md#ucall_status_invalid_argument_k) The `endpoint` output or the `callback` is `NULL`, the minimum batch size exceeds the maximum, the `verb` is unknown, or the template is empty, lacks its leading slash, carries a query, a fragment or a malformed segment, or names a placeholder another template names differently at the same position.
- [`ucall_status_contended_k`](https://www.unum.cloud/docs/ucall/c/errors.md#ucall_status_contended_k) A loop of the server was already polled.
- [`ucall_status_already_exists_k`](https://www.unum.cloud/docs/ucall/c/errors.md#ucall_status_already_exists_k) An endpoint of the same `verb` has the same or an equivalent template.

