Protocol
UnixProto
UnixProto is the transport Unixgram runs on. It solves one problem: get a message there and back over a bad connection without advertising what is being sent. Here is how.
The path of a message
The transport stack
Handshake and session
Two independent layers
The transport decides how a payload is delimited on the TCP stream. The packet decides what is inside one payload. Neither knows about the other: a client may pick any transport and the packet format does not change.
Five transports
The transport is chosen once, from the first bytes of the connection. Each option trades overhead against how closely the stream resembles random noise.
Obfuscation
The entire stream, transport tag included, is wrapped in AES-256-CTR. This is not encryption — the key is derived from the handshake itself. Its job is different: to remove the recognisable headers that let traffic be classified as "a messenger".
The encrypted channel
Key agreement is X25519; HKDF-SHA256 then produces a 256-bit auth key. Inside the packet sit a salt, a message id, a method and its parameters. The salt is compared in constant time and the message id must strictly increase — that is the replay guard. Plaintext calls are refused.
Realtime over WebSocket
The second path is MessagePack frames on a separate port. The protocol version is negotiated as a single integer during the handshake and can only be lowered. A client asking for too old a version is refused terminally and falls back to the secondary channel.
Delivery across replicas
The connection registry lives in-process, so a push that lands on one replica is invisible to clients of the others. Every push is therefore published to a shared Redis channel and each replica delivers to its own clients. The sender waits for its own copy to come back — otherwise locally connected clients would receive the event twice.
Transports and their per-packet overhead
| Transport | Tag | Framing | Overhead |
|---|---|---|---|
| legacy | — | uint32 BE length + body | 4 B |
| abridged | 0xef | length/4 in one byte; 0x7f + 3 B LE when longer | 1–4 B |
| intermediate | 0xeeeeeeee | uint32 LE length + body | 4 B |
| padded intermediate | 0xdddddddd | uint32 LE length + body + 0–15 random bytes | 4–19 B |
| full | — | length + seqno + body + CRC32 | 12 B |