Skip to main content

Wire Format

This document describes the binary wire format used by RCP (rstmdb Command Protocol).

Frame Structure​

Every message is wrapped in a frame with an 18-byte fixed header:

┌──────────────────────────────────────────────────────────────────────────┐
│ Frame Header (18 bytes) │
├──────────┬──────────┬──────────┬────────────┬─────────────┬─────────────┤
│ Magic │ Version │ Flags │ Header Len │ Payload Len │ CRC32C │
│ 4 bytes │ 2 bytes │ 2 bytes │ 2 bytes │ 4 bytes │ 4 bytes │
├──────────┴──────────┴──────────┴────────────┴─────────────┴─────────────┤
│ [Header Extension] │ Payload (JSON) │
│ header_len bytes │ payload_len bytes │
└─────────────────────┴────────────────────────────────────────────────────┘
0-3 4-5 6-7 8-9 10-13 14-17

Header Fields​

OffsetSizeFieldDescription
04magic"RCPX" (0x52435058)
42versionProtocol version, big-endian (current: 1)
62flagsFrame flags, big-endian (see below)
82header_lenHeader extension length, big-endian
104payload_lenPayload length, big-endian
144crc32cCRC32C of payload, big-endian
18varheader_extReserved for future use (header_len bytes)
18+header_lenvarpayloadUTF-8 JSON message

Magic Bytes​

The magic bytes identify the protocol:

R  C  P  X
52 43 50 58 (ASCII hex)

If a frame doesn't start with RCPX, the connection should be closed.

Version​

Protocol version as a 2-byte big-endian unsigned integer. Current version: 1 (0x0001).

Flags​

2-byte big-endian bitfield:

Bit   Mask     Name           Description
──────────────────────────────────────────────
0 0x0001 CRC_PRESENT CRC32C checksum is present and must be validated
1 0x0002 COMPRESSED Payload is compressed (reserved, not yet used)
2 0x0004 STREAM Frame is part of a stream
3 0x0008 END_STREAM Final frame of a stream
4-15 — Reserved Must be zero for protocol v1

Valid flag mask for v1: 0x000F. Frames with bits outside this mask set must be rejected.

Header Extension​

The header_len field specifies the length of an optional header extension area between the fixed header and the payload. Currently unused (should be 0 in v1). Clients must skip header_len bytes before reading the payload.

Payload Length​

The payload length is encoded as a 4-byte big-endian unsigned integer.

Maximum payload size: 16 MiB (16,777,216 bytes)

CRC32C Checksum​

The CRC32C (Castagnoli) checksum is computed over the payload bytes only.

let checksum = crc32c::crc32c(&payload);

The checksum is only validated when the CRC_PRESENT flag (bit 0) is set.

On receive:

  1. Read the fixed header (18 bytes)
  2. Skip header_len bytes (header extension)
  3. Read payload_len bytes of payload
  4. If CRC_PRESENT flag is set, compute CRC32C of payload and compare with header checksum
  5. Reject frame if mismatch

Byte Order​

All multi-byte integers are big-endian (network byte order).

Example Frame​

Request to ping the server:

{"type":"request","id":"1","op":"PING"}

Wire format (hex):

52 43 50 58     # Magic: "RCPX"
00 01 # Version: 1
00 01 # Flags: CRC_PRESENT
00 00 # Header extension length: 0
00 00 00 26 # Payload length: 38 bytes
A1 B2 C3 D4 # CRC32C (example)
7B 22 74 79... # Payload: JSON bytes

JSONL Mode​

For debugging, JSONL (JSON Lines) mode uses newline-delimited JSON:

{"type":"request","id":"1","op":"PING"}\n
{"type":"response","id":"1","status":"ok"}\n

JSONL Rules​

  • Each message is a single line of JSON
  • Lines are terminated with \n (0x0A)
  • No framing header or CRC
  • Max line length: 16 MiB

Switching to JSONL​

JSONL mode is negotiated during the HELLO handshake. The client sends preferred wire_modes and the server picks the first supported mode:

{
"op": "HELLO",
"params": {
"protocol_version": 1,
"wire_modes": ["binary_json", "jsonl"]
}
}

Server config:

network:
wire_mode: jsonl

CLI flag:

rstmdb-cli --wire-mode jsonl ping

Parsing Algorithm​

Binary Mode​

1. Read 4 bytes (magic)
2. If magic != "RCPX", close connection
3. Read 14 bytes (rest of fixed header)
4. Extract version from bytes 4-5
5. If version != 1, close connection (UNSUPPORTED_PROTOCOL)
6. Extract flags from bytes 6-7
7. If flags & ~0x000F != 0, close connection (invalid flags)
8. Extract header_len from bytes 8-9
9. Extract payload_len from bytes 10-13
10. If payload_len > 16 MiB, close connection
11. Skip header_len bytes (header extension)
12. Read payload_len bytes (payload)
13. If flags & CRC_PRESENT:
a. Compute CRC32C of payload
b. If CRC != header CRC, close connection
14. Parse payload as UTF-8 JSON
15. Process message

JSONL Mode​

1. Read until newline
2. If line length > 16 MiB, close connection
3. Parse line as JSON
4. Process message

Error Handling​

Invalid Magic​

Close the connection immediately. This indicates either:

  • Wrong protocol
  • Connection to wrong port
  • Data corruption

Unsupported Version​

Close the connection with UNSUPPORTED_PROTOCOL error.

Invalid Flags​

Close the connection. Unknown flag bits may indicate a newer protocol version.

CRC Mismatch​

Close the connection. The data is corrupted and cannot be trusted.

Oversized Frame​

Close the connection. This protects against memory exhaustion attacks.

Invalid JSON​

Send an error response if possible, then close:

{
"type": "response",
"id": null,
"status": "error",
"error": {
"code": "BAD_REQUEST",
"message": "Invalid JSON in request"
}
}

Performance Considerations​

CRC32C Hardware Acceleration​

CRC32C (Castagnoli polynomial) is hardware-accelerated on:

  • x86_64 with SSE4.2
  • ARM with CRC instructions

The crc32c crate automatically uses hardware acceleration when available.

Buffer Sizes​

Recommended buffer sizes:

  • Read buffer: 8 KiB (default)
  • Write buffer: 64 KiB
  • Max in-flight requests: 1000

TCP Settings​

Recommended TCP socket options:

  • TCP_NODELAY: enabled (reduce latency)
  • SO_KEEPALIVE: enabled (detect dead connections)