frag_datagram/
lib.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/piot/frag-datagram
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5pub mod client;
6pub mod helpers;
7pub mod prelude;
8pub mod receiver;
9pub mod sender;
10pub mod server;
11
12use bytemuck::{Pod, Zeroable, bytes_of, checked::pod_read_unaligned};
13pub use client::Client;
14pub use helpers::{
15    ConnectRequestHeader, ConnectResponseHeader, FLAG_CONNECT_REQUEST, FLAG_CONNECT_RESPONSE,
16    read_connect_request, read_connect_response, write_connect_request, write_connect_response,
17};
18pub use receiver::Receiver;
19pub use sender::Sender;
20pub use server::{ServerConnection, ServerHub};
21
22use std::mem::size_of;
23
24pub const PAYLOAD_SIZE: usize = 1024;
25pub const HEADER_SIZE: usize = size_of::<HeaderV2>();
26pub const VERSION: u8 = 2;
27pub const MAX_DATAGRAM_SIZE: usize = 1200;
28
29#[repr(C)]
30#[derive(Copy, Clone, Pod, Zeroable)]
31// Do not change or add these fields
32pub struct HeaderV2 {
33    /// Protocol version (currently 2)
34    pub version: u8,
35
36    /// Used for signalling, like acking datagrams and time sync. Not implemented yet.
37    pub flags: u8,
38
39    /// The assigned connection id. Not implemented yet.
40    pub connection_id: u16,
41
42    /// `datagram_counter` is just for drop, reordering and duplicate statistics. Not used by the algorithm for frag-datagrams.
43    /// Increments for every datagram sent, regardless of message.
44    pub datagram_counter: u16,
45
46    /// Increments for each payload that should be sent. Used to identify which complete message fragments belong to.
47    pub msg_id: u16,
48
49    /// The current fragment index (0-based) being sent for this message
50    pub frag_index: u16,
51
52    /// Total number of fragments for this message (1-based count)
53    pub total_frag_count: u16,
54
55    /// The lower 16 bits of monotonic timestamp. Not used yet.
56    pub sender_ts: u16,
57
58    /// The echoback of the 16-bit monotonic timestamp for RTT calculation. Not used yet.
59    pub echo_ts: u16,
60}
61
62/// Write `header` + `payload` into `buf`.
63/// Returns the total number of bytes written on success, or `None` if the buffer is too small.
64#[inline]
65pub fn write_datagram(buf: &mut [u8], header: &HeaderV2, payload: &[u8]) -> Option<usize> {
66    let total = HEADER_SIZE + payload.len();
67    if buf.len() < total {
68        return None;
69    }
70
71    let hdr_bytes = bytes_of(header);
72    buf[..HEADER_SIZE].copy_from_slice(hdr_bytes);
73
74    buf[HEADER_SIZE..total].copy_from_slice(payload);
75
76    Some(total)
77}
78
79/// Read datagram from `buf`.
80/// Returns a tuple of `(header, payload)` on success, or `None` if the buffer is too small.
81#[inline]
82#[must_use]
83pub fn read_datagram(buf: &[u8]) -> Option<(HeaderV2, &[u8])> {
84    if buf.len() < HEADER_SIZE {
85        return None;
86    }
87
88    let header: HeaderV2 = pod_read_unaligned(&buf[..HEADER_SIZE]);
89    let payload = &buf[HEADER_SIZE..];
90
91    Some((header, payload))
92}