The two services the mod talks to outside a session: the master (the lobby list, the join, the
TURN credential) and the signaling relay (the rendezvous a joiner and a host use to reach each
other). Both are VPS infrastructure and never ship in the mod. What they are for, who owns what
and what they refuse is on docs/master-server.md; this file is how to build, run and change
them.
| bin | default port | env |
|---|---|---|
coop-master |
COOP_MASTER_PORT (10001) |
COOP_TURN_SECRET, COOP_SIGNALING_TOKEN, COOP_SIGNALING_URL, COOP_STUN_URI, COOP_TURN_URI |
coop-signaling |
COOP_SIGNALING_PORT (10000) |
COOP_SIGNALING_TOKEN* |
* required: the process refuses to start (exit 1) without it. All secrets are env-only;
nothing is hardcoded, and it stays that way.
cargo build --release # -> target/release/coop-master(.exe), coop-signaling(.exe)
cargo test # unit tests incl. the byte-exact TURN-credential vector
Cross-compile for the Linux box from Windows with cargo build --release --target x86_64-unknown-linux-gnu (needs the target and a linker), or build on the box. One static
binary per service; no interpreter on the box to rot.
The rig builds and launches the signaling binary for its own scenarios, so a line-protocol change is proven against the copy that ships. The browser rig uses a synthetic lobby list as its source instead of a master, because a real master's rate limits and per-IP caps are the wrong fixture for many synthetic rows from one address.
- Endpoints:
/v1/host,/v1/heartbeat,/v1/leave,/v1/visibility,/v1/join,/v1/lobbies,/v1/latest,/healthz. The mod's side iscoop/net/lobby_clientandcoop/net/lobby_announcer. - The TURN credential, the byte-exact spot:
username = "<unixExp>:<label>",password = base64(HMAC-SHA1(TURN_SECRET, username)),ttl = 120, two?transportURIs. Unit-tested against a fixed reference vector; a mismatch breaks coturn auth silently. - Signaling: a
<token> <identity>greeting, then<dest> <hex>relay lines; pre-auth and authed pools; per-IP caps; a duplicate identity evicts the older connection. The registration challenge (a peer proves its key before it may be addressed) is drilled against a live relay, locally against a built relay, or with--remoteagainst the live one.
Rightmost X-Forwarded-For from a loopback proxy only, so the rate-limit and target address
cannot be spoofed; constant-time token compare; an opaque lobbyId against a secret sessionId;
control-character strip and codepoint clamp on every string; per-(address, class) sliding-window
rate limits; a global LRU and per-address lobby caps; a LOBBY_TTL sweep; bounded header, body
and connection caps with read timeouts.
- Multi-thread tokio with a single
Mutex<MasterState>on the master; one task owns the socket in the relay. No lock is ever held across an await. - Evicting a duplicate identity drops the peer's relay
Sender, which closes the channel and shuts the old socket down at once; nothing waits on the OS to unwedge a stale reader. - A bounded per-destination channel with drop-on-full: a slow destination can never head-of-line-block a sender, and memory per destination is hard-bounded.
- Typed JSON through serde replaces hand-rolled key validation.
LATEST_PROTO,LATEST_MODandLATEST_URLin the master binary's source are the operator constants that name the newest build for the update check, which is informational and never a gate;LOBBY_TTLsits beside them.