PSSP working flow
Architecture and sequences

How PSSP data moves

This page traces an application client—from a future device or server-side integration—to the PSSP broker and then to one or more subscribers. The opaque payload does not change form inside the broker.

System view

Publisher clientFuture device / serviceopaque bytes + topic QoS 0 UDPheartbeat / loss-tolerant PSSP Brokerauthenticate + ACLTopic ring bufferbounded memoryfan-out to filtersdoes not parse payload Subscriber Amessage → durable handoffMSGACK Subscriber Bsame or different filterindependent delivery TCP QoS 1 PUBLISH UDP QoS 0 PING/PUBLISH

Any future OX Device or WebService becomes a normal PSSP publisher, subscriber, or both. Neither needs to be embedded inside the broker or desktop-client project.

1. Secure connection and session-key flow

PSSP clientPSSP broker 1. TCP connect + optional TLS 1.3 handshake 2. HELLO { supportedVersion } 3. HELLO_ACK { connectionId, limits, encryptionRequired } 4. AUTH, or TLS-off AES: KEY_REQUEST { client X25519 key + salt } 5. AUTH_OK, or KEY { public metadata; no AES key } 6. TLS-off AES: encrypted AUTH; TLS + AES: KEY_REQUEST 7. TLS + AES: KEY { AES key inside TLS } 8. Subsequent PSSP records use AES-GCM
  1. The broker creates the AES key only after successful authentication.
  2. The key and nonce prefixes are unique to this TCP session and exist only in RAM.
  3. On TCP close/drop, the broker removes the session key, sequence state, UDP association, and connection state.
Independent modes

With TLS off and AES on, the client verifies the Broker X25519 public-key pin, derives AES locally through X25519 + HKDF, and encrypts AUTH and later records; the symmetric key is never sent. With TLS/AES both deliberately disabled and allow_insecure_tcp_udp = true, key steps are omitted and all credentials/records are plain network traffic.

2. QoS 1 publish, buffering, and delivery

PublisherBrokerSubscriber SUBSCRIBE { filter, workerID, from } SUBACK PUBLISH { topic, publisherSessionId, publisherSequence } + bytes Check ACL + limitsdeduplicate, append topic ring PUBACK { topicSequence, duplicate } MESSAGE { topic, topicSequence, metadata } + same bytes Application durable handoffqueue / persist before ACK MSGACK { subscriptionId, topic, topicSequence }
  1. Subscriber establishes a filter before the publisher writes new data.
  2. Publisher sends the opaque payload over TCP QoS 1. The publisher retry identity prevents a retry from creating a duplicate topic entry.
  3. Broker adds data to the topic’s finite ring, then acknowledges acceptance with PUBACK. A slow subscriber cannot delay that acknowledgement.
  4. Broker sends matching subscribers a MESSAGE containing the untouched payload.
  5. Subscriber application completes its own handoff and sends MSGACK. That cursor enables later resume while data remains retained.

3. Reconnect and bounded recovery

Reconnected subscribersame client/user +same workerID Broker topic ringresume cursor retainedfor configured TTLfinite bytes / count / age Replay MESSAGEsequences after MSGACK GAPrecover from app archive SUBSCRIBE from: "resume" history available requested range evicted

Subscriber resume state is held in broker memory for subscriber_resume_ttl_seconds. It cannot survive a broker restart. A GAP is an explicit signal that PSSP alone cannot recreate removed data.

4. QoS 0 UDP bind and heartbeat

Authenticated clientBroker UDP socket UDP_BIND { udpAssociationToken } (AES-GCM in production) UDP_BIND_ACK — broker records source endpoint PING or QoS 0 PUBLISH PONG (for heartbeat)

QoS 0 does not return PUBACK, does not buffer data, and does not replay it. If the TCP session closes, the association token is removed and the UDP source stops being valid.