PSSP protocol reference
Technical reference

PSSP v1 protocol

PSSP transports opaque byte payloads over topic-based publish/subscribe connections. Application clients decide payload meaning and persistence; the broker only authenticates, authorizes, buffers, and distributes data.

Endpoints and QoS

TrafficPortTransportPurpose
QoS 16688TCP; TLS 1.3 in productionControl records and data requiring broker acceptance, acknowledgements, fan-out, and replay.
QoS 06688UDPBest-effort heartbeat or loss-tolerant data after associating the UDP endpoint with a live TCP session.

TCP and UDP use the same numeric port but independent sockets. In production both flow through an authenticated session; UDP is associated using the temporary token supplied by the broker.

Record framing

Every PSSP record has a fixed header followed by a UTF-8 JSON control header and an opaque byte payload. Numeric lengths use big-endian ordering. TCP receivers must buffer fragments until a whole record is available.

0..1     magic: "PS" for TCP, "PU" for UDP
2        protocol version: 1
3        record type
4        flags: bit 0 = AES-256-GCM encrypted
5..6     JSON header length, unsigned 16-bit (default maximum: 1,024)
7..10    opaque payload length, unsigned 32-bit (default maximum: 65,536)
11..     UTF-8 JSON header
          opaque payload bytes
          GCM tag: 16 bytes, only when encrypted
Authenticated metadata

For encrypted records, the fixed header and JSON header are AES-GCM additional authenticated data. The JSON header therefore cannot be modified without detection.

Encrypted fieldRule
seqRequired positive integer in every encrypted header. TCP accepts strictly increasing values. UDP keeps a 64-sequence replay window to allow ordinary datagram reordering while rejecting duplicates and old packets.
Session keyFresh 32-byte AES key for each authenticated production connection. It exists in RAM only and is removed when the connection ends.

Session lifecycle

  1. Connect. Open TCP on port 6688. Negotiate TLS 1.3 first only when TLS is configured.
  2. Negotiate. Send HELLO; receive HELLO_ACK containing protocol limits, a connection ID, and TLS/encryption policy.
  3. Set up protection. With TLS off and PSSP AES on, verify the pinned Broker X25519 key from HELLO_ACK, then send KEY_REQUEST. Both peers derive a fresh AES key through X25519 + HKDF before authentication; no symmetric key is sent. With TLS + AES, authenticate first and KEY delivers the fresh AES key inside TLS.
  4. Authenticate. Send AUTH with clientId, username, and password. AES-only mode encrypts this record. The same valid client ID may maintain multiple concurrent sessions.
  5. Use PSSP. Subscribe, publish QoS 1 TCP data, and optionally bind UDP for QoS 0. Production records after key setup use AES-GCM.
  6. Close or reconnect. The broker removes the connection's key and UDP association. A subscriber can reconnect with the same workerID and request resume while retained data remains available.

Record types

RecordDirectionPurpose
HELLO / HELLO_ACKClient ↔ brokerVersion and policy negotiation.
AUTH / AUTH_OK / AUTH_ERRORClient ↔ brokerCredential login and per-connection identity.
KEY_REQUEST / KEYClient ↔ brokerTLS mode establishes AES inside TLS. AES-only mode uses a pinned X25519 Broker key plus HKDF; KEY carries no symmetric key.
PING / PONGBothTCP or UDP liveness test.
SUBSCRIBE / SUBACKClient ↔ brokerCreate a topic-filter subscription with latest, earliest, or resume starting position.
UNSUBSCRIBE / UNSUBACKClient ↔ brokerEnd one subscription.
PUBLISH / PUBACKClient ↔ brokerQoS 1 broker acceptance and duplicate-retry detection.
MESSAGE / MSGACKBroker ↔ clientSubscriber delivery and acknowledgement after application handoff.
GAPBroker → clientIndicates requested data was evicted from finite topic memory.
UDP_BIND / UDP_BIND_ACKClient ↔ brokerAssociate a UDP source endpoint with the current TCP session.
CLOSEClient → brokerNormal session close request.

Topics, filters, and authorization

Concrete publish topics

Slash-delimited paths, maximum 256 bytes. They cannot contain + or #, empty path elements, dot segments, or control characters.

devices/a1/audio/chunks
control/room-7/start

Subscription filters

+ matches one segment. A final # matches all remaining segments.

devices/+/audio/#
control/#

The broker evaluates the authenticated credential's publish and subscribe ACL filters for every request. Access is denied unless explicitly permitted.

QoS, buffering, and recovery

QoS 1 — TCP

  1. The publisher gives every retryable message a publisherSessionId and monotonically increasing publisherSequence.
  2. The broker checks identity, ACL, and limits; duplicate publisher identifiers do not create a second buffer entry.
  3. The broker appends the opaque data to the bounded ring for the topic, returns PUBACK, and fans out MESSAGE records to matching subscriptions.
  4. A subscriber sends MSGACK only after its own durable application handoff. It can later reconnect using the same workerID and request resume.

QoS 0 — UDP

UDP is best effort. It has no PUBACK, subscriber acknowledgement, retry, buffering, or replay. Use it for heartbeats and data that the application can safely lose. Production UDP uses AES-GCM anti-replay protection.

Finite retention

Each topic ring has limits for bytes, message count, and age. If the broker cannot replay a requested sequence because it was evicted, it sends GAP { earliestSequence, latestSequence }. The receiving application must recover from its own archive if it needs that data.

Security modes

ModeRequired flagsRecord protectionAppropriate location
TLS + AEStls.enabled = true
encryption.enabled = true
TLS 1.3, then per-session AES-256-GCM PSSP records.Production networks.
AES onlytls.enabled = false
encryption.enabled = true
pinned X25519 Broker public key
Ephemeral X25519 + HKDF derives a new AES key before encrypted authentication. No symmetric key crosses TCP.Certificate-free protected deployments with securely provisioned client pins.
Plaintls.enabled = false
encryption.enabled = false
allow_insecure_tcp_udp = true
No TLS or AES. A short-lived RAM-only UDP token still binds UDP to the authenticated TCP session.Only a trusted/private network.