Skip to content

Protocol primer

This page is a working summary of the RHPv2 wire protocol so you can use the library effectively without bouncing between specs. The authoritative documents are PWP-0222 and PWP-0245.

Transport

  • TCP, default port 9000, persistent connection.
  • Optionally WebSocket at ws://{host}:{port}/rhp (not yet wired up in this library).
  • Localhost / RFC1918 clients are admitted without authentication.
  • Public clients must send AUTH with credentials from XRouter's USERPASS.SYS.

Framing

┌──────┬──────┬─────────────────────────┐
│ lenH │ lenL │  RHP Message (JSON)     │
└──────┴──────┴─────────────────────────┘
   1B     1B          ≤ 65535B
  • Two-byte big-endian length prefix.
  • Total message size ≤ 65 535 bytes.
  • Payload is a single JSON object with a string type discriminator.

The library implements this in RhpFraming.

Anatomy of a message

Every message is a JSON object. The required field is type; the optional id correlates a request with its reply. Server-pushed notifications carry a seqno instead.

{
  "type": "open",
  "id": 7,
  "pfam": "ax25",
  "mode": "stream",
  "port": "1",
  "local": "G8PZT",
  "remote": "GB7PZT",
  "flags": 128
}

If id is omitted

The spec says the server only replies on error. The library auto-assigns ids on every request method, so successful replies always come back to your await.

Message catalogue

Connection management

Type Direction Purpose
auth C → S Credentials for non-LAN clients.
authReply S → C errCode 0 (Ok) or 14 (Unauthorised).
open C → S Combined create + connect/listen.
openReply S → C Allocates a socket handle.
accept S → C Inbound connection on a listener.
close C ↔ S Tear down a socket.
closeReply S → C Acknowledge close.

BSD-style lifecycle

socketbindlisten / connect → … → close, each with its own reply. Useful when you need finer control than open provides.

Data transfer

Type Direction Purpose
send C → S Outbound stream / dgram payload.
sendReply S → C Acknowledgement (carries STREAM status flags).
sendto C → S Outbound datagram with explicit dest.
sendtoReply S → C Acknowledgement.
recv S → C Inbound payload (or trace frame).

Status

Type Direction Purpose
status both C→S query; S→C async link state.
statusReply S → C Returned only on query failure.

Protocol families & socket modes

Family Layer Use cases
unix 7 XRouter CLI / app sockets.
inet 3-4 TCP / UDP / ICMP / IP / DNS.
ax25 2 AX.25, APRS, digipeating.
netrom 3-4 NetRom datagrams & streams.
Mode Notes
stream Ordered, reliable octet stream.
dgram Unreliable datagram.
seqpkt Sequenced reliable packets (AX.25).
custom User-specified protocol.
semiraw Addresses + raw payload.
trace Decoded headers + payload (monitoring).
raw Complete raw packet.

Flag bitfields

OpenFlags (in open / listen)

Bit Name Meaning
0x00 Passive Listener (default).
0x01 TraceIncoming Trace incoming frames (RAW/TRACE).
0x02 TraceOutgoing Trace outgoing frames (RAW/TRACE).
0x04 TraceSupervisory Include AX.25 S-frames (TRACE only).
0x80 Active Perform a connect.

StatusFlags

Bit Name Meaning
1 ConOk OK to accept (listeners).
2 Connected Downlink up.
4 Busy Not clear to send (flow control).

Address formats

Family Format Example
ax25 callsign with optional SSID G8PZT-1, GB7GLO
netrom <usercall>[@nodecall][:svcnum] G8PZT-1@G8PZT
inet <ip>[:port] 192.168.3.22:25

Error codes

The library exposes these as RhpV2.Client.Protocol.RhpErrorCode.* and surfaces non-zero replies via RhpServerException.

Code Text
0 Ok
1 Unspecified
2 Bad or missing type
3 Invalid handle
4 No memory
5 Bad or missing mode
6 Invalid local address
7 Invalid remote address
8 Bad or missing family
9 Duplicate socket
10 No such port
11 Invalid protocol
12 Bad parameter
13 No buffers
14 Unauthorised
15 No Route
16 Operation not supported

Spec quirks the library tolerates

  • AUTHREPLY uses errCode/errText (capital C). Most other replies use errcode/errtext. The library uses PropertyNameCaseInsensitive on read and matches the spec literally on write.
  • PWP-0222 spells the connect reply type as ConnectReply (PascalCase). The library writes connectReply (camelCase) — and reads either.
  • Unknown type values surface as UnknownMessage, preserving the raw JSON for forward compatibility.

Lifecycle examples

Outgoing AX.25 keyboard session

sequenceDiagram
    participant C as Client
    participant X as XRouter
    C->>X: open {pfam:ax25, mode:stream, local:G8PZT, remote:GB7PZT, flags:0x80}
    X-->>C: openReply {handle:42}
    X-->>C: status   {handle:42, flags:CONNECTED}
    C->>X: send {handle:42, data:"hello\r"}
    X-->>C: sendReply {handle:42, status:CONNECTED}
    X-->>C: recv {handle:42, data:"hi there\r"}
    C->>X: close {handle:42}
    X-->>C: closeReply {handle:42}

Incoming listener

sequenceDiagram
    participant C as Client
    participant X as XRouter
    C->>X: open {pfam:ax25, mode:stream, local:G8PZT, flags:0x00}
    X-->>C: openReply {handle:1}
    Note right of X: ...later, an AX.25 SABM arrives...
    X-->>C: accept {handle:1, child:2, remote:M0XYZ}
    X-->>C: status {handle:2, flags:CONNECTED}