#pragma once /* SPDX-License-Identifier: Unlicense */ #include #include #include /* FRAME FORMAT ============ Every frame contents: 0 1 2 3 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Protocol version (0) | Frame type | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Connection ID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | : : Data : : | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Connection ID is zero for FT_HANDSHAKE, otherwise it must always be set to the one received with FT_HANDSHAKE_RESP frame. Data for FT_HANDSHAKE: 0 1 2 3 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Requested tick period | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Data for FT_HANDSHAKE_RESP: 0 1 2 3 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Actual tick period | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ If FT_HANDSHAKE_RESP is received by the client then connection is considered to be established. Data for FT_SYN and FT_SYNACK: 0 1 2 3 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Current tick counter value | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | RESERVED |L| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Previous ping roundtrip time | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Resend counter | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Where: `Resend counter` - Number of times this frame has been sent without getting a response. `L` - bit indicating that previous ping response is not yet received, which means that it is essentially lost. `D` - bit indicating that connection should be terminated by either client or server initiative. Data for FT_ACK: 0 1 2 3 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Current tick counter value | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ EXCHANGE SEQUENCE ================= Legend: ">" - client > server "<" - client < server > FT_HANDSHAKE(requested_parameters) < FT_HANDSHAKE_RESP(actually_applied parameters) (connection established) < FT_SYN(tick=0) > FT_SYNACK(tick=0) < FT_ACK(tick=0) (1 tick goes by) < FT_SYN(tick=1) > FT_SYNACK(tick=1) < FT_ACK(tick=1) (1 tick goes by) ... */ enum frame_type { FT_NONE = 0, ///< Not an actual type FT_HANDSHAKE, ///< From client FT_HANDSHAKE_RESP, ///< From server FT_SYN, ///< From server FT_SYNACK, ///< From client FT_ACK, ///< From server /// From server, in response to invalid connection_id or invalid tick period /// requested. Or from client as an immediate disconnect request without /// awaiting any response. FT_RST, FT_MAX, ///< Not an actual type }; struct frame { uint32_t addr; uint32_t connection_id; uint16_t port; enum frame_type type; union { struct frame_data_handshake { uint32_t tick_period; } handshake; // FT_HANDSHAKE, FT_HANDSHAKE_RESP struct frame_data_syn { uint32_t tick; uint32_t roundtrip_prev; uint32_t repeat; bool prev_is_lost; } syn; // FT_SYN, FT_SYNACK struct frame_data_ack { uint32_t tick; } ack; // FT_ACK }; }; struct frame ParseFrame(void const *buffer, size_t buffer_size); size_t SerializeFrame(void *buffer, size_t buffer_size, struct frame const *);