xs.json in depth · service-level fields
xs.json is XServer's single assembly surface. This chapter covers every preset field of services[i] — not just "how to write it" but "what happens when you write it wrong".
Overview
7.1 Intro
Config systems suffer two common diseases. One is looseness — a misspelled field is silently ignored until production bites. The other is scatter — behavior spread across config files, environment variables and command lines. xs.json's answer is fail-fast plus a single source: every preset field that is invalid is named and rejected at startup, and every non-preset field flows untouched into Custom for the application — a field the host doesn't know is never swallowed and never guessed at.
7.2 The five protocol classes (class)
| class | Semantics | Script callbacks |
|---|---|---|
http | HTTP/1.1 + HTTPS (TLS switch) | RequestProc |
ws | WebSocket + WSS | WsOpen/Text/Binary/Ping/Pong/Close |
tcp | Raw stream / TLS stream | EventOpen/Data/Close |
udp | Datagrams (no TLS) | EventDgram |
custom | Event-driven custom service | Application-defined (via the Engine entry point) |
Values outside the whitelist fail fast. Picking is simple: what a browser speaks → http/ws; byte streams → tcp; connectionless → udp; everything else, roll your own.
7.3 Endpoint fields
{
"ip": "0.0.0.0", /* listen address, default all interfaces */
"port": 80, /* plaintext port, required unless custom */
"tls": true, /* enable the TLS port; forbidden on udp */
"port_tls": 443, /* default 443; colliding with the plaintext port on the same IP is rejected */
"ip_tls": "0.0.0.0" /* defaults to ip */
}
What just happened: a service has at most two endpoints (plaintext + TLS). The collision rule is a startup check — the plaintext and TLS ports clashing on the same IP is rejected outright; there is no silent "the later one wins". Certificate paths are not service-level: they live at the host level (chapter 8); the service level only decides "whether a TLS port exists".
7.4 Limit fields
| Field | Purpose | Constraint |
|---|---|---|
backlog | Listen backlog (passed through to xrt) | uint32 range validation |
recv_limit | Per-read stream cap | ≤SIZE_MAX; on udp ≤65535 |
recv_limit is a memory defense line: the cap on data pulled in per read. On tcp it shapes the per-connection buffer peak; on udp datagrams are naturally ≤64KB, so the cap tightens to 65535. Request-level header/body limits are not preset service fields — they are Custom knobs (chapter 9) read by the http driver.
7.5 Service-level script defaults
Five script-related fields may be written at the service level as defaults for all hosts:
{
"class": "http",
"name": "my-site",
"port": 8080,
"path": "wwwroot", /* static root */
"devlang": "c", /* script language */
"devfile": "main.c", /* script entry */
"dev_inc": "includes", /* extra header dirs (semicolon-separated) */
"dev_lib": "librarys" /* extra library dirs */
}
When host_default is absent, these five fields synthesize the DefaultHost — that is why chapter 4's minimal app needed no host_default. Host-level fields with the same names override item by item.
7.6 Contract
- Validation: the class whitelist, port 1–65535, tls×udp mutual exclusion, port collisions — all named and fail-fast at startup.
- Defaults: service-level script fields are only a default source for the host level, not a second config system.
- Uniqueness: name is globally unique — it is the runtime key for xsServerFind and the target descriptor of reloads.
Common mistakes
- Symptom
- Startup fails; the error names a plaintext/TLS port collision.
- Cause
- port and port_tls are equal on the same IP (or each collides with other services).
{ "ip": "0.0.0.0", "port": 8080,
"tls": true, "port_tls": 8080 }{ "ip": "0.0.0.0", "port": 8080,
"tls": true, "port_tls": 8443 }- Symptom
- Startup fails: tls on udp.
- Cause
- UDP is a datagram protocol; XServer does not wrap TLS over UDP — secure UDP transport is the application's business (e.g. build a DTLS-style scheme yourself).
{ "class": "udp", "port": 9000,
"tls": true }{ "class": "udp", "port": 9000 }Exercises
Write an xs.json containing four services — http (8080), ws (8081), tcp (8082), udp (8083) — all runnable on the default variant (scripts may export nothing).
bound lines in the boot log; Ctrl+C exits gracefully.Create in turn: port out of range, missing port, plaintext/TLS collision, tls on udp — record each error message.
Enable the TLS port on an http service with a certificate (the home repository's test certs work), hit both endpoints with curl and observe the handshake differences.
Summary
| Point | Conclusion |
|---|---|
| Five classes | http / ws / tcp / udp / custom; whitelist fail-fast |
| Endpoints | Plaintext + TLS dual endpoints; same-IP collision rejected |
| Limits | backlog passes through to xrt; recv_limit on udp ≤65535 |
| Script defaults | Five service-level fields synthesize the DefaultHost; host level overrides item by item |
| Quick lookup | the ref-config field reference |
- xrt reference · net — the underlying semantics of backlog / REUSE_PORT listener options
- xrt reference · udp — datagram size and its relation to recv_limit