ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
datagram.c
Go to the documentation of this file.
1#include "datagram.h"
2
3#include <ascii-chat/buffer.h>
7#include <string.h>
8
9#define MAX_WIRE_PACKET (sizeof(packet_header_t) + CRYPTO_MAX_PLAINTEXT_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE)
10#define FLOW_BUDGET (QUIC_DATAGRAM_BUDGET / 2)
11#define FLOW_SLOTS (QUIC_DATAGRAM_SLOTS / 2)
12
13static bool media_flow(acip_traffic_class_t flow) {
14 return flow == ACIP_TRAFFIC_AUDIO || flow == ACIP_TRAFFIC_VISUAL;
15}
16
17static void put16(uint8_t *p, uint16_t value) {
18 value = HOST_TO_NET_U16(value);
19 memcpy(p, &value, sizeof(value));
20}
21static void put32(uint8_t *p, uint32_t value) {
22 value = HOST_TO_NET_U32(value);
23 memcpy(p, &value, sizeof(value));
24}
25static void put64(uint8_t *p, uint64_t value) {
26 value = HOST_TO_NET_U64(value);
27 memcpy(p, &value, sizeof(value));
28}
29static uint16_t get16(const uint8_t *p) {
30 uint16_t value;
31 memcpy(&value, p, sizeof(value));
32 return NET_TO_HOST_U16(value);
33}
34static uint32_t get32(const uint8_t *p) {
35 uint32_t value;
36 memcpy(&value, p, sizeof(value));
37 return NET_TO_HOST_U32(value);
38}
39static uint64_t get64(const uint8_t *p) {
40 uint64_t value;
41 memcpy(&value, p, sizeof(value));
42 return NET_TO_HOST_U64(value);
43}
44
45asciichat_error_t quic_datagram_fragment(acip_traffic_class_t flow, uint64_t id, const void *packet, size_t length,
46 uint16_t unit, uint16_t index, void *out, size_t capacity,
47 size_t *out_length) {
48 if (!out_length)
49 return SET_ERRNO(ERROR_INVALID_PARAM, "Missing QUIC datagram output length");
50 *out_length = 0;
51 if (!media_flow(flow) || !id || !packet || !length || length > MAX_WIRE_PACKET || !unit || !out)
52 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid QUIC datagram fragment parameters");
53 size_t count = (length + unit - 1) / unit;
54 if (count > QUIC_DATAGRAM_MAX_FRAGMENTS || index >= count)
55 return SET_ERRNO(ERROR_NETWORK_SIZE, "Invalid QUIC datagram fragment count or index");
56 size_t offset = (size_t)index * unit;
57 size_t part = length - offset < unit ? length - offset : unit;
58 if (capacity < QUIC_DATAGRAM_HEADER_SIZE + part)
59 return SET_ERRNO(ERROR_BUFFER_FULL, "QUIC datagram output buffer is too small");
60 uint8_t *wire = out;
61 memcpy(wire, "ACQD", sizeof("ACQD") - 1);
62 wire[4] = 1;
63 wire[5] = (uint8_t)flow;
64 wire[6] = wire[7] = 0;
65 put64(wire + 8, id);
66 put32(wire + 16, (uint32_t)length);
67 put16(wire + 20, unit);
68 put16(wire + 22, index);
69 put16(wire + 24, (uint16_t)count);
70 wire[26] = wire[27] = 0;
71 memcpy(wire + QUIC_DATAGRAM_HEADER_SIZE, (const uint8_t *)packet + offset, part);
72 *out_length = QUIC_DATAGRAM_HEADER_SIZE + part;
73 return ASCIICHAT_OK;
74}
75
76static void clear_slot(quic_datagram_reader_t *reader, quic_datagram_slot_t *slot) {
77 if (!slot->data)
78 return;
79 reader->bytes -= slot->cost;
80 buffer_release(slot->data);
82 memset(slot, 0, sizeof(*slot));
83}
84
86 if (!reader || now_ns < reader->last_time_ns)
87 return;
88 reader->last_time_ns = now_ns;
89 for (size_t i = 0; i < QUIC_DATAGRAM_SLOTS; ++i) {
90 quic_datagram_slot_t *slot = &reader->slots[i];
91 if (slot->data && now_ns - slot->started_ns >= QUIC_DATAGRAM_EXPIRY_NS)
92 clear_slot(reader, slot);
93 }
94}
95
97 if (!reader)
98 return;
99 for (size_t i = 0; i < QUIC_DATAGRAM_SLOTS; ++i)
100 clear_slot(reader, &reader->slots[i]);
101 memset(reader, 0, sizeof(*reader));
102}
103
104asciichat_error_t quic_datagram_read(quic_datagram_reader_t *reader, const void *data, size_t length, uint64_t now_ns,
105 acip_traffic_class_t *flow_out, uint8_t **out, size_t *out_length) {
106 if (!out || !out_length || !flow_out)
107 return SET_ERRNO(ERROR_INVALID_PARAM, "Missing QUIC datagram output");
108 *out = NULL;
109 *out_length = 0;
110 if (!reader || !data || length < QUIC_DATAGRAM_HEADER_SIZE || now_ns < reader->last_time_ns)
111 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid QUIC datagram input");
112 const uint8_t *wire = data;
114 uint64_t id = get64(wire + 8);
115 uint32_t total = get32(wire + 16);
116 uint16_t unit = get16(wire + 20), index = get16(wire + 22), count = get16(wire + 24);
117 if (memcmp(wire, "ACQD", sizeof("ACQD") - 1) || wire[4] != 1 || !media_flow(flow) || wire[6] || wire[7] || wire[26] ||
118 wire[27] || !id || !total || total > MAX_WIRE_PACKET || !unit || !count || count > QUIC_DATAGRAM_MAX_FRAGMENTS ||
119 count != ((size_t)total + unit - 1) / unit || index >= count)
120 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid QUIC datagram envelope");
121 size_t offset = (size_t)index * unit;
122 size_t part = total - offset < unit ? total - offset : unit;
123 if (length != QUIC_DATAGRAM_HEADER_SIZE + part)
124 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid QUIC datagram fragment size");
125 quic_datagram_expire(reader, now_ns);
126 size_t first = flow == ACIP_TRAFFIC_AUDIO ? 0 : FLOW_SLOTS;
127 quic_datagram_slot_t *slot = NULL, *empty = NULL;
128 size_t flow_bytes = 0;
129 for (size_t i = first; i < first + FLOW_SLOTS; ++i) {
130 quic_datagram_slot_t *candidate = &reader->slots[i];
131 flow_bytes += candidate->cost;
132 if (candidate->data && candidate->id == id)
133 slot = candidate;
134 else if (!candidate->data && !empty)
135 empty = candidate;
136 }
137 if (slot && (slot->total != total || slot->unit != unit || slot->count != count))
138 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Conflicting QUIC datagram fragments");
139 if (!slot) {
140 if (!empty || total > FLOW_BUDGET - flow_bytes)
141 return SET_ERRNO(ERROR_BUFFER_FULL, "QUIC datagram reassembly budget exhausted");
142 size_t bitmap_size = (count + 7U) / 8U;
143 uint8_t *packet = buffer_alloc(NULL, total);
144 uint8_t *bitmap = buffer_alloc(NULL, bitmap_size);
145 if (!packet || !bitmap) {
146 buffer_release(packet);
147 buffer_release(bitmap);
148 return SET_ERRNO(ERROR_MEMORY, "Cannot allocate QUIC datagram reassembly");
149 }
150 size_t cost = buffer_capacity(packet) + buffer_capacity(bitmap);
151 if (cost > FLOW_BUDGET - flow_bytes) {
152 buffer_release(packet);
153 buffer_release(bitmap);
154 return SET_ERRNO(ERROR_BUFFER_FULL, "QUIC datagram reassembly budget exhausted");
155 }
156 memset(bitmap, 0, bitmap_size);
157 *empty = (quic_datagram_slot_t){.data = packet,
158 .received = bitmap,
159 .cost = cost,
160 .id = id,
161 .started_ns = now_ns,
162 .total = total,
163 .unit = unit,
164 .count = count,
165 .traffic_class = flow};
166 reader->bytes += cost;
167 slot = empty;
168 }
169 uint8_t mask = (uint8_t)(1U << (index % 8));
170 if (slot->received[index / 8] & mask) {
171 if (memcmp(slot->data + offset, wire + QUIC_DATAGRAM_HEADER_SIZE, part))
172 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Conflicting duplicate QUIC datagram fragment");
173 return ASCIICHAT_OK;
174 }
175 memcpy(slot->data + offset, wire + QUIC_DATAGRAM_HEADER_SIZE, part);
176 slot->received[index / 8] |= mask;
177 if (++slot->received_count == slot->count) {
178 *out = slot->data;
179 *out_length = slot->total;
180 *flow_out = flow;
181 slot->data = NULL;
182 reader->bytes -= slot->cost;
184 memset(slot, 0, sizeof(*slot));
185 }
186 return ASCIICHAT_OK;
187}
#define SET_ERRNO(code,...)
size_t buffer_capacity(const void *data)
Definition buffer.c:280
void * buffer_alloc(buffer_domain_t *domain, size_t size)
Definition buffer.c:274
#define buffer_release(data)
Definition buffer.h:91
void quic_datagram_reset(quic_datagram_reader_t *reader)
Definition datagram.c:96
#define FLOW_BUDGET
Definition datagram.c:10
void quic_datagram_expire(quic_datagram_reader_t *reader, uint64_t now_ns)
Definition datagram.c:85
#define MAX_WIRE_PACKET
Definition datagram.c:9
#define FLOW_SLOTS
Definition datagram.c:11
asciichat_error_t quic_datagram_fragment(acip_traffic_class_t flow, uint64_t id, const void *packet, size_t length, uint16_t unit, uint16_t index, void *out, size_t capacity, size_t *out_length)
Definition datagram.c:45
asciichat_error_t quic_datagram_read(quic_datagram_reader_t *reader, const void *data, size_t length, uint64_t now_ns, acip_traffic_class_t *flow_out, uint8_t **out, size_t *out_length)
Definition datagram.c:104
#define QUIC_DATAGRAM_EXPIRY_NS
Definition datagram.h:15
#define QUIC_DATAGRAM_HEADER_SIZE
Definition datagram.h:11
#define QUIC_DATAGRAM_MAX_FRAGMENTS
Definition datagram.h:12
#define QUIC_DATAGRAM_SLOTS
Definition datagram.h:13
🔄 Network byte order conversion helpers
#define HOST_TO_NET_U16(val)
Definition endian.h:96
#define NET_TO_HOST_U64(val)
Definition endian.h:228
#define HOST_TO_NET_U32(val)
Definition endian.h:66
#define HOST_TO_NET_U64(val)
Definition endian.h:213
#define NET_TO_HOST_U16(val)
Definition endian.h:111
#define NET_TO_HOST_U32(val)
Definition endian.h:81
unsigned short uint16_t
Definition common.h:61
unsigned int uint32_t
Definition common.h:62
unsigned long long uint64_t
Definition common.h:63
unsigned char uint8_t
Definition common.h:60
asciichat_error_t
Error and exit codes - unified status values (0-255).
Definition error_codes.h:44
@ ERROR_BUFFER_FULL
@ ERROR_NETWORK_PROTOCOL
Definition error_codes.h:76
@ ERROR_MEMORY
Definition error_codes.h:51
@ ASCIICHAT_OK
Definition error_codes.h:46
@ ERROR_NETWORK_SIZE
Definition error_codes.h:77
@ ERROR_INVALID_PARAM
static bool size_t index
Definition queries.h:8
static bool size_t gotel_query_t * out
Definition queries.h:8
🔤 String Manipulation and Shell Escaping Utilities
acip quic datagram slot keeps the values that move through the subsystem: data, received,...
Definition datagram.h:34
quic_datagram_slot_t slots[8U]
Definition datagram.h:35
uint16_t received_count
Definition datagram.h:23
uint64_t started_ns
Definition datagram.h:21
uint8_t * received
Definition datagram.h:19
acip_traffic_class_t
Definition traffic.h:5
@ ACIP_TRAFFIC_VISUAL
Definition traffic.h:8
@ ACIP_TRAFFIC_AUDIO
Definition traffic.h:7