ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
queue.c
Go to the documentation of this file.
1#include <defer.h>
3#include <ascii-chat/common.h>
4#include <libplatform/mutex.h>
7#include <string.h>
8
15
36
38 if (!config || !config->max_bytes ||
40 SET_ERRNO(ERROR_INVALID_PARAM, "Queue needs a byte limit and a valid overflow policy");
41 return NULL;
42 }
44 queue->config = *config;
45 if (mutex_init(&queue->mutex, "packet_queue") != 0) {
46 return NULL;
47 }
48 defer_named(queue_mutex, mutex_destroy(&queue->mutex));
49 buffer_domain_config_t memory = {64 * 1024 * 1024, 8 * 1024 * 1024, 5000000000ULL, false};
50 if (buffer_domain_create(&memory, &queue->domain) != ASCIICHAT_OK) {
51 return NULL;
52 }
53 defer_cancel(queue_mutex);
54 packet_queue_t *result = queue;
55 queue = NULL;
56 return result;
57}
58
59packet_queue_t *packet_queue_create(size_t max_packets) {
60 packet_queue_config_t config = {max_packets, 16 * 1024 * 1024, PACKET_QUEUE_REJECT};
61 return packet_queue_create_config(&config);
62}
63
64/* All list access, including reclamation, is serialized by the queue mutex. */
65static packet_node_t *pop_locked(packet_queue_t *queue) {
66 packet_node_t *node = queue->head;
67 if (node) {
68 queue->head = node->next;
69 if (!queue->head)
70 queue->tail = NULL;
71 queue->count--;
72 queue->bytes -= node->packet.data_len;
73 node->next = NULL;
74 }
75 return node;
76}
77
79 if (!packet)
80 return;
81 buffer_release(packet->data);
82 /* packet is the first member of the owning node allocation. */
83 buffer_release(packet);
84}
85
86static asciichat_error_t push(packet_queue_t *queue, packet_type_t type, const void *data, size_t length,
87 uint32_t client_id) {
88 if (!queue || length > UINT32_MAX || (length && !data) || type == 0 || type > 10000)
89 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid queued packet");
90 mutex_lock(&queue->mutex);
91 if (queue->stopped) {
92 mutex_unlock(&queue->mutex);
93 return SET_ERRNO(ERROR_INVALID_STATE, "Packet queue stopped");
94 }
95 if (length > queue->config.max_bytes) {
96 mutex_unlock(&queue->mutex);
97 return SET_ERRNO(ERROR_BUFFER, "Packet exceeds queue byte limit");
98 }
99 bool full = (queue->config.max_packets && queue->count >= queue->config.max_packets) ||
100 length > queue->config.max_bytes - queue->bytes;
101 if (full && queue->config.overflow == PACKET_QUEUE_REJECT) {
102 mutex_unlock(&queue->mutex);
103 return SET_ERRNO(ERROR_BUFFER, "Packet queue is full");
104 }
105 packet_node_t *node = buffer_alloc(queue->domain, sizeof(*node));
106 if (!node) {
107 mutex_unlock(&queue->mutex);
108 return SET_ERRNO(ERROR_MEMORY, "Queue memory budget exhausted");
109 }
110 /* Do not drop existing packets unless the new packet can be admitted. */
111 while (queue->head && ((queue->config.max_packets && queue->count >= queue->config.max_packets) ||
112 length > queue->config.max_bytes - queue->bytes)) {
113 packet_node_t *old = pop_locked(queue);
114 queue->dropped++;
116 }
117 memset(node, 0, sizeof(*node));
121 node->packet.header.client_id = HOST_TO_NET_U32(client_id);
122 node->packet.header.crc32 = HOST_TO_NET_U32(length ? asciichat_crc32(data, length) : 0);
123 node->packet.data = data;
124 node->packet.data_len = length;
125 if (queue->tail)
126 queue->tail->next = node;
127 else
128 queue->head = node;
129 queue->tail = node;
130 queue->count++;
131 queue->bytes += length;
132 queue->enqueued++;
133 mutex_unlock(&queue->mutex);
134 return ASCIICHAT_OK;
135}
136
138 uint32_t client_id) {
139 if (!data || (length && !*data) || length > buffer_capacity(*data))
140 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid owned packet buffer");
141 asciichat_error_t result = push(queue, type, *data, length, client_id);
142 if (result == ASCIICHAT_OK)
143 *data = NULL;
144 return result;
145}
146
147asciichat_error_t packet_queue_push_shared(packet_queue_t *queue, packet_type_t type, const void *data, size_t length,
148 uint32_t client_id) {
149 if (length > buffer_capacity(data))
150 return SET_ERRNO(ERROR_INVALID_PARAM, "Shared packet exceeds buffer capacity");
151 const void *shared = buffer_share(data);
152 if (data && !shared)
153 return SET_ERRNO(ERROR_INVALID_STATE, "Cannot share packet buffer");
154 asciichat_error_t result = push(queue, type, shared, length, client_id);
155 if (result != ASCIICHAT_OK)
156 buffer_release(shared);
157 return result;
158}
159
160asciichat_error_t packet_queue_push_copy(packet_queue_t *queue, packet_type_t type, const void *data, size_t length,
161 uint32_t client_id) {
162 if (!queue || (length && !data) || length > queue->config.max_bytes)
163 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid packet copy");
164 void *copy = NULL;
165 if (length) {
166 copy = buffer_alloc(queue->domain, length);
167 if (!copy)
168 return SET_ERRNO(ERROR_MEMORY, "Cannot copy packet within memory budget");
169 memcpy(copy, data, length);
170 }
171 asciichat_error_t result = packet_queue_push_take(queue, type, &copy, length, client_id);
172 buffer_release(copy);
173 return result;
174}
175
177 if (!queue)
178 return NULL;
179 mutex_lock(&queue->mutex);
180 packet_node_t *node = queue->stopped ? NULL : pop_locked(queue);
181 if (node)
182 queue->dequeued++;
183 mutex_unlock(&queue->mutex);
184 if (node && !packet_queue_validate_packet(&node->packet)) {
186 return NULL;
187 }
188 return node ? &node->packet : NULL;
189}
190
194
196 if (!queue)
197 return;
198 mutex_lock(&queue->mutex);
199 packet_node_t *node;
200 while ((node = pop_locked(queue)))
202 mutex_unlock(&queue->mutex);
203}
204
206 if (!queue)
207 return;
208 mutex_lock(&queue->mutex);
209 queue->stopped = true;
210 mutex_unlock(&queue->mutex);
211}
212
214 if (!queue)
215 return;
216 packet_queue_stop(queue);
217 packet_queue_clear(queue);
219 mutex_destroy(&queue->mutex);
220 SAFE_FREE(queue);
221}
222
224 if (!queue)
225 return 0;
226 mutex_lock(&queue->mutex);
227 size_t count = queue->count;
228 mutex_unlock(&queue->mutex);
229 return count;
230}
231
233 return packet_queue_size(queue) == 0;
234}
235
237 if (!queue)
238 return false;
239 mutex_lock(&queue->mutex);
240 bool full = (queue->config.max_packets && queue->count >= queue->config.max_packets) ||
241 queue->bytes >= queue->config.max_bytes;
242 mutex_unlock(&queue->mutex);
243 return full;
244}
245
246void packet_queue_get_stats(packet_queue_t *queue, uint64_t *enqueued, uint64_t *dequeued, uint64_t *dropped) {
247 if (!queue)
248 return;
249 mutex_lock(&queue->mutex);
250 if (enqueued)
251 *enqueued = queue->enqueued;
252 if (dequeued)
253 *dequeued = queue->dequeued;
254 if (dropped)
255 *dropped = queue->dropped;
256 mutex_unlock(&queue->mutex);
257}
258
260 return packet && NET_TO_HOST_U64(packet->header.magic) == PACKET_MAGIC && NET_TO_HOST_U16(packet->header.type) > 0 &&
261 NET_TO_HOST_U16(packet->header.type) <= 10000 && NET_TO_HOST_U32(packet->header.length) == packet->data_len &&
262 (!packet->data_len ||
263 (packet->data && NET_TO_HOST_U32(packet->header.crc32) == asciichat_crc32(packet->data, packet->data_len)));
264}
#define SET_ERRNO(code,...)
size_t buffer_capacity(const void *data)
Definition buffer.c:280
void buffer_domain_close(buffer_domain_t **slot)
Definition buffer.c:156
void * buffer_alloc(buffer_domain_t *domain, size_t size)
Definition buffer.c:274
asciichat_error_t buffer_domain_create(const buffer_domain_config_t *config, buffer_domain_t **out)
Definition buffer.c:125
const void * buffer_share(const void *data)
Definition buffer.c:304
struct buffer_domain buffer_domain_t
Definition buffer.h:24
#define buffer_release(data)
Definition buffer.h:91
⚙️ Common definitions, error codes, macros, and types shared throughout the application
Hardware-Accelerated CRC32 Checksum Computation.
🔄 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
#define SAFE_FREE(ptr)
Definition common.h:377
#define SAFE_CALLOC_DEFER_FREE(name, count, size, cast)
Definition common.h:389
unsigned long long uint64_t
Definition common.h:63
asciichat_error_t
Error and exit codes - unified status values (0-255).
Definition error_codes.h:44
@ ERROR_INVALID_STATE
@ ERROR_MEMORY
Definition error_codes.h:51
@ ASCIICHAT_OK
Definition error_codes.h:46
@ ERROR_INVALID_PARAM
@ ERROR_BUFFER
packet_type_t
Network protocol packet type enumeration.
Definition packet.h:301
#define PACKET_MAGIC
Packet magic number (alias for MAGIC_PACKET_VALID).
Definition packet.h:270
#define asciichat_crc32(data, len)
Main CRC32 dispatcher macro - use this in application code.
Definition crc32.h:147
void packet_queue_clear(packet_queue_t *queue)
Definition queue.c:195
packet_queue_t * packet_queue_create_config(const packet_queue_config_t *config)
Definition queue.c:37
void packet_queue_stop(packet_queue_t *queue)
Definition queue.c:205
packet_queue_t * packet_queue_create(size_t max_packets)
Definition queue.c:59
asciichat_error_t packet_queue_push_shared(packet_queue_t *queue, packet_type_t type, const void *data, size_t length, uint32_t client_id)
Definition queue.c:147
void packet_queue_get_stats(packet_queue_t *queue, uint64_t *enqueued, uint64_t *dequeued, uint64_t *dropped)
Definition queue.c:246
bool packet_queue_is_empty(packet_queue_t *queue)
Definition queue.c:232
void packet_queue_free_packet(queued_packet_t *packet)
Definition queue.c:78
bool packet_queue_is_full(packet_queue_t *queue)
Definition queue.c:236
queued_packet_t * packet_queue_try_dequeue(packet_queue_t *queue)
Definition queue.c:176
asciichat_error_t packet_queue_push_copy(packet_queue_t *queue, packet_type_t type, const void *data, size_t length, uint32_t client_id)
Definition queue.c:160
void packet_queue_destroy(packet_queue_t *queue)
Definition queue.c:213
struct packet_node packet_node_t
bool packet_queue_validate_packet(const queued_packet_t *packet)
Definition queue.c:259
asciichat_error_t packet_queue_push_take(packet_queue_t *queue, packet_type_t type, void **data, size_t length, uint32_t client_id)
Definition queue.c:137
queued_packet_t * packet_queue_dequeue(packet_queue_t *queue)
Definition queue.c:191
size_t packet_queue_size(packet_queue_t *queue)
Definition queue.c:223
@ PACKET_QUEUE_REJECT
Definition queue.h:13
@ PACKET_QUEUE_DROP_OLDEST
Definition queue.h:13
struct packet_queue packet_queue_t
Definition queue.h:12
🔤 String Manipulation and Shell Escaping Utilities
uint32_t client_id
Client ID (0 = server, >0 = client identifier).
Definition packet.h:638
uint32_t length
Payload data length in bytes (0 for header-only packets).
Definition packet.h:634
uint64_t magic
Magic number (PACKET_MAGIC = 0xA5C11C4A1 "ASCIICHAT" in hex) for packet validation.
Definition packet.h:630
uint16_t type
Packet type (packet_type_t enumeration).
Definition packet.h:632
uint32_t crc32
CRC32 checksum of payload data (0 if length == 0).
Definition packet.h:636
struct packet_node * next
Definition queue.c:13
queued_packet_t packet
Definition queue.c:12
packet_queue_overflow_t overflow
Definition queue.h:18
For packet node, this is the live record that ties packet, next together. The owning code creates it,...
Definition queue.c:23
size_t bytes
Definition queue.c:30
buffer_domain_t * domain
Definition queue.c:27
uint64_t enqueued
Definition queue.c:31
mutex_t mutex
Definition queue.c:24
bool stopped
Definition queue.c:34
uint64_t dequeued
Definition queue.c:32
size_t count
Definition queue.c:29
uint64_t dropped
Definition queue.c:33
packet_node_t * head
Definition queue.c:25
packet_queue_config_t config
Definition queue.c:28
packet_node_t * tail
Definition queue.c:26
const void * data
Definition queue.h:8
size_t data_len
Definition queue.h:9
packet_header_t header
Definition queue.h:7