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.h File Reference

Go to the source code of this file.

Data Structures

struct  quic_datagram_slot_t
struct  quic_datagram_reader_t
 acip quic datagram slot keeps the values that move through the subsystem: data, received, cost, id. Some members are pointers into caller- or subsystem-owned memory, so lifetime follows the API that populated them rather than the struct copy itself. More...

Macros

#define QUIC_DATAGRAM_HEADER_SIZE   28U
#define QUIC_DATAGRAM_MAX_FRAGMENTS   4096U
#define QUIC_DATAGRAM_SLOTS   8U
#define QUIC_DATAGRAM_BUDGET   (4U * 1024U * 1024U)
#define QUIC_DATAGRAM_EXPIRY_NS   UINT64_C(1000000000)

Functions

asciichat_error_t quic_datagram_fragment (acip_traffic_class_t traffic_class, uint64_t id, const void *packet, size_t length, uint16_t unit, uint16_t index, void *out, size_t capacity, size_t *out_length)
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 *traffic_class, uint8_t **out, size_t *out_length)
void quic_datagram_expire (quic_datagram_reader_t *reader, uint64_t now_ns)
void quic_datagram_reset (quic_datagram_reader_t *reader)

Macro Definition Documentation

◆ QUIC_DATAGRAM_BUDGET

#define QUIC_DATAGRAM_BUDGET   (4U * 1024U * 1024U)

Definition at line 14 of file datagram.h.

◆ QUIC_DATAGRAM_EXPIRY_NS

#define QUIC_DATAGRAM_EXPIRY_NS   UINT64_C(1000000000)

Definition at line 15 of file datagram.h.

Referenced by quic_connection_expiry(), and quic_datagram_expire().

◆ QUIC_DATAGRAM_HEADER_SIZE

#define QUIC_DATAGRAM_HEADER_SIZE   28U

◆ QUIC_DATAGRAM_MAX_FRAGMENTS

#define QUIC_DATAGRAM_MAX_FRAGMENTS   4096U

◆ QUIC_DATAGRAM_SLOTS

#define QUIC_DATAGRAM_SLOTS   8U

Definition at line 13 of file datagram.h.

Referenced by quic_connection_expiry(), quic_datagram_expire(), and quic_datagram_reset().

Function Documentation

◆ quic_datagram_expire()

void quic_datagram_expire ( quic_datagram_reader_t * reader,
uint64_t now_ns )

Definition at line 85 of file datagram.c.

85 {
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}
#define QUIC_DATAGRAM_EXPIRY_NS
Definition datagram.h:15
#define QUIC_DATAGRAM_SLOTS
Definition datagram.h:13
quic_datagram_slot_t slots[8U]
Definition datagram.h:35
uint64_t started_ns
Definition datagram.h:21

References quic_datagram_slot_t::data, quic_datagram_reader_t::last_time_ns, QUIC_DATAGRAM_EXPIRY_NS, QUIC_DATAGRAM_SLOTS, quic_datagram_reader_t::slots, and quic_datagram_slot_t::started_ns.

Referenced by quic_datagram_read().

◆ quic_datagram_fragment()

asciichat_error_t quic_datagram_fragment ( acip_traffic_class_t traffic_class,
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 at line 45 of file datagram.c.

47 {
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}
#define SET_ERRNO(code,...)
#define MAX_WIRE_PACKET
Definition datagram.c:9
#define QUIC_DATAGRAM_HEADER_SIZE
Definition datagram.h:11
#define QUIC_DATAGRAM_MAX_FRAGMENTS
Definition datagram.h:12
unsigned short uint16_t
Definition common.h:61
unsigned int uint32_t
Definition common.h:62
unsigned char uint8_t
Definition common.h:60
@ ERROR_BUFFER_FULL
@ 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

References ASCIICHAT_OK, ERROR_BUFFER_FULL, ERROR_INVALID_PARAM, ERROR_NETWORK_SIZE, index, MAX_WIRE_PACKET, out, QUIC_DATAGRAM_HEADER_SIZE, QUIC_DATAGRAM_MAX_FRAGMENTS, and SET_ERRNO.

◆ quic_datagram_read()

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 * traffic_class,
uint8_t ** out,
size_t * out_length )

Definition at line 104 of file datagram.c.

105 {
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}
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
#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 FLOW_SLOTS
Definition datagram.c:11
unsigned long long uint64_t
Definition common.h:63
@ ERROR_NETWORK_PROTOCOL
Definition error_codes.h:76
@ ERROR_MEMORY
Definition error_codes.h:51
uint16_t received_count
Definition datagram.h:23
uint8_t * received
Definition datagram.h:19
acip_traffic_class_t
Definition traffic.h:5
@ ACIP_TRAFFIC_AUDIO
Definition traffic.h:7

References ACIP_TRAFFIC_AUDIO, ASCIICHAT_OK, buffer_alloc(), buffer_capacity(), buffer_release, quic_datagram_reader_t::bytes, quic_datagram_slot_t::cost, quic_datagram_slot_t::count, quic_datagram_slot_t::data, ERROR_BUFFER_FULL, ERROR_INVALID_PARAM, ERROR_MEMORY, ERROR_NETWORK_PROTOCOL, FLOW_BUDGET, FLOW_SLOTS, quic_datagram_slot_t::id, index, MAX_WIRE_PACKET, out, quic_datagram_expire(), QUIC_DATAGRAM_HEADER_SIZE, QUIC_DATAGRAM_MAX_FRAGMENTS, quic_datagram_slot_t::received, quic_datagram_slot_t::received_count, SET_ERRNO, quic_datagram_reader_t::slots, quic_datagram_slot_t::total, and quic_datagram_slot_t::unit.

◆ quic_datagram_reset()

void quic_datagram_reset ( quic_datagram_reader_t * reader)

Definition at line 96 of file datagram.c.

96 {
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}

References QUIC_DATAGRAM_SLOTS, and quic_datagram_reader_t::slots.

Referenced by quic_connection_destroy().