Protocols

Technical reference for OctoMY™'s wire protocols, packet formats, and communication layers.

Security Note

All established OctoMY sessions use XChaCha20-Poly1305 AEAD encryption with hybrid asymmetric key exchange (RSA-4096 or Ed25519 via the ISigningKey interface). The multimagic field at the start of every packet enables rapid packet-type dispatch before any crypto operations, providing efficient DoS protection while maintaining full encryption for authenticated traffic.


Protocol stack

Protocol Stack


Default ports

Node Type Port Description
Zoo 8123 NAT traversal and discovery service
Agent 8124 Robot node
Remote 8125 Controller app
Hub 8126 Fleet management

Packet structure

Basic packet format

Packet Format

Every packet begins with a SESSION_ID_TYPE (2-byte quint16) multimagic field. Reserved multimagic values identify protocol control packets; any value at or above MULTIMAGIC_LAST is interpreted as a remote session ID, making the packet courier data.

Protocol magic and version (handshake and data packets)

Handshake and data packets include a 4-byte protocol magic (OCTOMY_PROTOCOL_MAGIC = 0x0C701111) and a 4-byte protocol version (OCTOMY_PROTOCOL_VERSION_CURRENT = 1) immediately after the multimagic. The magic allows early rejection of non-OctoMY traffic; the version selects the QDataStream serialization format.

#define OCTOMY_PROTOCOL_MAGIC          (0x0C701111)
#define OCTOMY_PROTOCOL_VERSION_CURRENT (1)

Session ID

Each side of an established session chooses a local session ID (SESSION_ID_TYPE, 2 bytes). The remote session ID assigned by the peer is used as the multimagic value in courier data packets, so the receiver can look up the correct session in O(1).


Packet types (multimagic values)

OctoMY does not use TCP-style bit-flag headers. Instead, the first 2 bytes of every UDP datagram contain a multimagic value from the Multimagic enum that determines the packet type:

Multimagic Value Integer Description
MULTIMAGIC_IDLE 0 Keepalive / idle packet (no payload beyond multimagic)
MULTIMAGIC_SYN 1 Handshake initiation
MULTIMAGIC_SYNACK 2 Handshake response
MULTIMAGIC_ACK 3 Handshake confirmation
MULTIMAGIC_LAN_ANNOUNCE 4 LAN broadcast: "I exist"
MULTIMAGIC_LAN_ANNOUNCE_ACK 5 LAN unicast: "I see you"
MULTIMAGIC_LAN_IDENTITY_REQ 6 LAN unicast: request identity exchange
MULTIMAGIC_LAN_IDENTITY_RESP 7 LAN unicast: identity exchange response
MULTIMAGIC_NACK 8 Explicit session/trust rejection
>= MULTIMAGIC_LAST >= 9 Courier data (value is the remote session ID)

The receiver dispatches on static_cast<Multimagic>(multimagic) in a switch; values not matching any known control type fall through to the courier-data path.


Handshake protocol

Three-way handshake

Handshake Flow

Handshake packet content

All handshake bodies are hybrid-encrypted with the recipient's public key (see Encryption below). The encrypted payload contains the fields listed; the outer packet is [multimagic:2][encrypted blob].

SYN Packet (initiator -> responder, encrypted with responder's public key):

Field Size Description
Sender ID 64 bytes Full node identity hash (hex-decoded to 32 raw bytes + QDataStream framing)
Destination ID 64 bytes Intended recipient identity (prevents cross-nonce pollution on shared ports)
Desired Session ID 2 bytes Local session ID the initiator wants the responder to use
SYN Nonce 4 bytes Random SESSION_NONCE_TYPE challenge
Key Material 32 bytes Random AEAD key bytes for RSA/cross-algorithm key-transport path (only when encryption is enabled)

SYN-ACK Packet (responder -> initiator, encrypted with initiator's public key):

Field Size Description
Sender ID 64 bytes Responder's full node identity hash
Desired Session ID 2 bytes Local session ID the responder wants the initiator to use
Return Nonce 4 bytes Echo of the initiator's SYN nonce (proves receipt)
SYN-ACK Nonce 4 bytes Responder's own random challenge
Key Material Hash 32 bytes SHA256(keyMaterial) as confirmation of receipt (only when encryption is enabled)

ACK Packet (initiator -> responder, encrypted with responder's public key):

Field Size Description
Sender ID 64 bytes Initiator's full node identity hash
Return Nonce 4 bytes Echo of the responder's SYN-ACK nonce (proves receipt)

Encryption

Hybrid asymmetric encryption (handshake)

Handshake packets use hybrid encryption: an asymmetric key exchange produces a one-time symmetric key, which is used for XChaCha20-Poly1305 AEAD encryption of the actual payload. The wire format depends on the recipient's key algorithm:

RSA hybrid (version byte 0x01):

[0x01][RSA-encrypted symKey : rsaKeyBytes][nonce : 24][AEAD ciphertext + tag : N + 16]

A random 32-byte symmetric key is generated, RSA-encrypted with the recipient's public key, and prepended. The payload is then AEAD-encrypted with that symmetric key.

Ed25519 hybrid (version byte 0x02):

[0x02][ephemeral Ed25519 pubkey : 32][nonce : 24][AEAD ciphertext + tag : N + 16]

An ephemeral Ed25519 keypair is generated. Both keys are converted to X25519. An ECDH key exchange with the recipient's X25519 public key produces the shared secret. The payload is AEAD-encrypted with that shared secret.

The version byte allows decrypt() to auto-detect the format and use the correct unwrapping path.

Session key derivation

After the three-way handshake completes, both sides derive a shared session key for AEAD encryption of all subsequent courier data:

sessionKey = SHA256(sharedSecret_or_keyMaterial || synNonce_BE || synAckNonce_BE)

The derivation path depends on the key algorithms in use:

Scenario Path Shared Secret Source
Both Ed25519 ECDH x25519KeyExchange(mySecret, theirPublic)
RSA or cross-algorithm Key-transport 32-byte keyMaterial sent in SYN

Nonces are serialized big-endian before hashing.

Courier data encryption (AEAD)

Established sessions encrypt courier data using XChaCha20-Poly1305 with the derived session key:

[sessionID : 2][nonceCounter : 8][AEAD ciphertext + tag]

Reliability system

OctoMY does not have per-packet sequence numbers, ack bitmasks, or a transport-level retransmission layer. Reliability is handled per-courier at the application level:

Aspect Mechanism
Unreliable couriers Fire-and-forget (sensors, joystick input)
Reliable couriers Courier-specific ack/retransmit (e.g., BlobCourier uses chunk-level acknowledgments)
RTT measurement SessionCourier heartbeat echo timestamps (16-byte payload: [myTimestamp:8][echoOfRemoteTimestamp:8])
Connection detection Heartbeat-based; session expires after configurable inactivity timeout (default 5 minutes)

Flow control

FlowControl uses RTT-based send-rate adjustment rather than a sliding window or congestion-avoidance algorithm:

Mode Condition Send Rate
Good RTT <= 250 ms 30 Hz
Bad RTT > 250 ms 10 Hz

Transitions:


Discovery protocol

LAN multicast discovery

Multicast Discovery

Discovery packet format

LAN discovery uses its own simple binary format (not QDataStream). The magic is "OCTOMY" (6 ASCII bytes):

Field Offset Size Description
Magic 0 6 bytes "OCTOMY"
Version 6 1 byte Protocol version (0x01)
Packet Type 7 2 bytes Multimagic value (big-endian)
Node ID 9 64 bytes ASCII node identity hash (left-padded to 64 chars)
Node Type 73 1 byte Agent / Remote / Hub
Comms Port 74 2 bytes Comms channel port (big-endian)
Reply Port 76 2 bytes Ephemeral unicast reply port (big-endian)

Total: 78 bytes.

Discovery packet types: MULTIMAGIC_LAN_ANNOUNCE (broadcast), MULTIMAGIC_LAN_ANNOUNCE_ACK (unicast response).

Identity exchange packets (MULTIMAGIC_LAN_IDENTITY_REQ, MULTIMAGIC_LAN_IDENTITY_RESP) use a larger variable-length format that includes the node's display name and public key in DER encoding.


NAT traversal

Hole punching

NAT Hole Punching

Punch protocol

  1. Both nodes register with Zoo server
  2. Zoo provides peer's external address
  3. Both send simultaneous UDP packets
  4. NAT creates mapping, allowing responses
  5. Direct communication established

Blob transfer protocol

Large data transfer

For data larger than MTU (~1400 bytes):

Blob Header:

Field Size Description
Blob ID 4 bytes Unique identifier
Total Size 4 bytes Total blob size
Chunk Count 2 bytes Number of chunks
Chunk Size 2 bytes Size per chunk

Chunk Packet:

Field Size Description
Blob ID 4 bytes Unique identifier
Chunk Index 2 bytes Chunk sequence number
Flags 1 byte FIRST, LAST, etc.
Data Variable Up to chunk size

Blob reassembly

Blob Reassembly


Courier protocol

Courier ID allocation

ID Range Purpose
0-15 System couriers
16-127 Built-in couriers
128-255 Custom couriers

Standard courier IDs

ID Courier Description
0 System Handshake, keepalive
1 Discovery Peer discovery
2 AgentState State synchronization
3 Sensors Sensor data stream
4 Blob Large data transfer
5-15 Reserved Future system use

Heartbeat and keepalive

Keepalive mechanism

Keepalive

SessionCourier heartbeat

The SessionCourier sends a 16-byte heartbeat payload at ~1 Hz:

Field Size Description
My Timestamp 8 bytes Sender's current time (ms since epoch)
Echo Timestamp 8 bytes Last timestamp received from remote

When the remote echoes back our timestamp, RTT is computed as now - echoedTimestamp. This drives FlowControl and connection-alive detection.

MULTIMAGIC_IDLE packets (multimagic only, no payload) serve as a lightweight keepalive for sessions that have no active couriers.


Error handling

Protocol errors

Error Response
Invalid protocol magic Drop packet
Version mismatch Drop packet, emit error
Decryption failed (0-byte plaintext) Drop packet (logged at debug level for shared-port scenarios)
Unknown multimagic in control range Drop packet
Session not established for courier data Drop packet, emit error

Connection errors

Error Detection Recovery
Packet loss Courier-specific (e.g., missing chunk acks) Courier-specific retransmit
Connection lost Heartbeat timeout Re-handshake
NAT timeout Hole closed Re-punch
Session expired 5-minute inactivity default Session pruned; new handshake required

Security considerations

Protections

Threat Protection
Eavesdropping XChaCha20-Poly1305 AEAD encryption (handshake and courier data)
Replay attacks 64-bit sliding window on nonce counter (checkAndUpdateRxNonce)
Impersonation RSA or Ed25519 key verification via ISigningKey interface
DoS Rate limiting; multimagic dispatch allows early rejection before crypto
Man-in-the-middle Identicon verification during pairing (visual confirmation of key fingerprints)

Best practices