UDP#

Overview#

The UDP protocol is optional and useful when it is important to quickly transmit updates between different geographical locations.

There are third-party vendors allowing you to use their network, e.g. microwave, to transmit UDP packets.

This implementation is such that a gateway may encode messages such that a listener can rebuild the state of the gateway and itself act like a read-only gateway.

The roq-udp-subscriber is the read-only gateway.

Payload#

Offset

Width

Type

Description

0

1

uint8_t

Encoding (1 native, 2 flatbuffers, …)

1

1

uint8_t

Current fragment number (0-based)

2

1

uint8_t

Max fragment number (0-based)

3

1

uint8_t

Object type

4

2

uint16_t

Object ID

6

2

uint16_t

Session ID (UTC, seconds since epoch % 65536)

8

4

uint32_t

Sequence number (wraps around)

12

4

uint32_t

Last published sequence number of encoded object (object type + object id)

16

[0;512]

Encoded payload (may be empty, e.g. heartbeat)

Note

The maximum length of the encoded payload is 512 bytes. An encoded payload larger than 512 bytes will be split into a number of fragements such that each fragment has the length 512 except the last which will have a length less than or equal to 512. The maximum number of fragments is 256.

The choice of 512 bytes is losely based on a discussion found on Stack Overflow.

Description#

The producer will fetch current time when it starts and use this to identify the session. Consumers must support sequence number wrap-around as well as sequence reset when the session id changes.

A message will be split into fragments when the total payload length exceeds 512 bytes. The buffer offset of the current fragment should be computed as field #2 (current fragment number) times 512. The total length of the message is known when the last fragment has been received, i.e. field #2 (current fragment number) equals field #3 (max fragment number). Total message length can not exceed 128 KiB (256 * 512 = 131072 bytes);

The object type and id are opaque values. You can depend on the pair (of type and id) to correlate current and last sequence number for a given session id. However, you must reset any cached values upon observing a new session id.

You should not cache sequence numbers for any updates having the object type equal to zero.

Note

The actual object type should be discovered by decoding the payload.

The last sequence number is per-object and based off the sequence number from the incremental channel.

This makes it possible to * correlate snapshot with incremental channels * correlate within the incremental channel

Usually we want to initialize by caching updates from the incremental channel, wait for a snapshot, then apply the cached updates followed by updates from the incremental channel.

Sometimes we may see drops within the incremental channel. It is possible to mark all objects in an unknown state when a drop is detected. The last sequence number for a following update can be used to detect if a particular object was affected by the drop (in which case it should re-initialize using the snapshot channel).

If the subscriber has seen all published sequence numbers, i.e. the publisher started after the subscriber, then the subscriber may accept an incremental update when it has the zero value for the last sequence number instead of waiting for the object to become available on the snapshot channel.

Channels#

The publisher allows you to configure the two channels (snapshot and increment) using each their own pair of network interface and port. This makes it possible to e.g. use (slow) internet for snapshots and (fast) microwave for increments.