ascii-chat 0.8.38
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
packet.c
Go to the documentation of this file.
1
7#include <ascii-chat/network/packet.h>
8#include <ascii-chat/network/network.h>
9#include <ascii-chat/common.h>
10#include <ascii-chat/asciichat_errno.h>
11#include <ascii-chat/platform/socket.h>
12#include <ascii-chat/buffer_pool.h>
13#include <ascii-chat/network/crc32.h>
14#include <ascii-chat/crypto/crypto.h>
15#include <ascii-chat/network/compression.h>
16#include <ascii-chat/util/endian.h>
17#include <ascii-chat/util/overflow.h>
18#include <ascii-chat/audio/audio.h>
19#include <ascii-chat/options/options.h>
20#include <ascii-chat/options/rcu.h> // For RCU-based options access
21#include <stdint.h>
22#include <errno.h>
23#include <stdbool.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27
28// Network timeout constants are defined in packet_types.h
29
30/* ============================================================================
31 * Packet Protocol Implementation
32 * ============================================================================
33 * This module handles packet verification, CRC validation, and protocol
34 * compliance checking for all network packets.
35 */
36
37// Use network_network_is_test_environment() from network.h
38
45static uint64_t calculate_packet_timeout(size_t packet_size) {
46 uint64_t base_timeout = network_is_test_environment() ? (1ULL * NS_PER_SEC_INT) : (SEND_TIMEOUT * NS_PER_SEC_INT);
47
48 // For large packets, increase timeout proportionally
49 if (packet_size > LARGE_PACKET_THRESHOLD) {
50 // Add extra timeout per MB above the threshold
51 uint64_t extra_timeout =
52 (uint64_t)(((double)packet_size - LARGE_PACKET_THRESHOLD) / 1000000.0 * LARGE_PACKET_EXTRA_TIMEOUT_PER_MB) +
53 NS_PER_MS_INT;
54 uint64_t total_timeout = base_timeout + extra_timeout;
55
56 // Ensure client timeout is longer than server's RECV_TIMEOUT (30s) to prevent deadlock
57 // Add 10 seconds buffer to account for server processing delays
58 if (total_timeout < MIN_CLIENT_TIMEOUT) {
59 total_timeout = MIN_CLIENT_TIMEOUT;
60 }
61
62 // Cap at maximum timeout
63 return (total_timeout > MAX_CLIENT_TIMEOUT) ? MAX_CLIENT_TIMEOUT : total_timeout;
64 }
65
66 return base_timeout;
67}
68
77asciichat_error_t packet_validate_header(const packet_header_t *header, uint16_t *pkt_type, uint32_t *pkt_len,
78 uint32_t *expected_crc) {
79 if (!header || !pkt_type || !pkt_len || !expected_crc) {
80 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: header=%p, pkt_type=%p, pkt_len=%p, expected_crc=%p",
81 header, pkt_type, pkt_len, expected_crc);
82 }
83
84 // First validate packet length BEFORE converting from network byte order
85 // This prevents potential integer overflow issues
86 uint32_t pkt_len_network = header->length;
87 if (pkt_len_network == 0xFFFFFFFF) {
88 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid packet length in network byte order: 0xFFFFFFFF");
89 }
90
91 // Convert from network byte order using safe helpers
92 uint64_t magic = endian_unpack_u64(header->magic);
93 uint16_t type = endian_unpack_u16(header->type);
94 uint32_t len = endian_unpack_u32(pkt_len_network);
95 uint32_t crc = endian_unpack_u32(header->crc32);
96
97 // Validate magic
98 if (magic != PACKET_MAGIC) {
99 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid packet magic: 0x%x (expected 0x%x)", magic, PACKET_MAGIC);
100 }
101
102 // Validate packet size with bounds checking
103 if (len > MAX_PACKET_SIZE) {
104 return SET_ERRNO(ERROR_NETWORK_SIZE, "Packet too large: %u > %d", len, MAX_PACKET_SIZE);
105 }
106
107 // Validate packet type and size constraints
108 switch (type) {
109 case PACKET_TYPE_PROTOCOL_VERSION:
110 // Protocol version packet has fixed size
111 if (len != sizeof(protocol_version_packet_t)) {
112 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid protocol version packet size: %u, expected %zu", len,
113 sizeof(protocol_version_packet_t));
114 }
115 break;
116 case PACKET_TYPE_ASCII_FRAME:
117 // ASCII frame contains header + frame data
118 if (len < sizeof(ascii_frame_packet_t)) {
119 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid ASCII frame packet size: %u, minimum %zu", len,
120 sizeof(ascii_frame_packet_t));
121 }
122 break;
123 case PACKET_TYPE_IMAGE_FRAME:
124 // Image frame contains header + pixel data
125 if (len < sizeof(image_frame_packet_t)) {
126 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid image frame packet size: %u, minimum %zu", len,
127 sizeof(image_frame_packet_t));
128 }
129 break;
130 case PACKET_TYPE_AUDIO_BATCH:
131 // Batch must have at least header + some samples
132 if (len < sizeof(audio_batch_packet_t) + sizeof(float)) {
133 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid audio batch packet size: %u", len);
134 }
135 break;
136 case PACKET_TYPE_PING:
137 case PACKET_TYPE_PONG:
138 if (len != 0) { // Ping/pong are just header packets and no payload.
139 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid ping/pong packet size: %u", len);
140 }
141 break;
142 case PACKET_TYPE_CLIENT_CAPABILITIES:
143 // Client capabilities packet can be empty or contain capability data
144 if (len > 1024) { // Reasonable limit for capability data
145 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid client capabilities packet size: %u", len);
146 }
147 break;
148 case PACKET_TYPE_CLIENT_JOIN:
149 if (len != sizeof(client_info_packet_t)) {
150 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid client join packet size: %u, expected %zu", len,
151 sizeof(client_info_packet_t));
152 }
153 break;
154 case PACKET_TYPE_CLIENT_LEAVE:
155 // Client leave packet can be empty or contain reason
156 if (len > 256) {
157 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid client leave packet size: %u", len);
158 }
159 break;
160 case PACKET_TYPE_STREAM_START:
161 case PACKET_TYPE_STREAM_STOP:
162 if (len != sizeof(uint32_t)) {
163 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid stream control packet size: %u, expected %zu", len,
164 sizeof(uint32_t));
165 }
166 break;
167 case PACKET_TYPE_SIZE_MESSAGE:
168 // Size message format: "SIZE:width,height"
169 if (len == 0 || len > 32) { // Reasonable size for "SIZE:1234,5678"
170 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid size message packet size: %u", len);
171 }
172 break;
173 case PACKET_TYPE_AUDIO_MESSAGE:
174 // Audio message format: "AUDIO:num_samples"
175 if (len == 0 || len > 32) { // Reasonable size for "AUDIO:1234"
176 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid audio message packet size: %u", len);
177 }
178 break;
179 case PACKET_TYPE_TEXT_MESSAGE:
180 // Text message can be empty or contain message
181 if (len > 1024) { // Reasonable limit for text messages
182 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid text message packet size: %u", len);
183 }
184 break;
185 case PACKET_TYPE_ERROR_MESSAGE:
186 if (len < sizeof(error_packet_t)) {
187 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid error packet size: %u (minimum %zu)", len,
188 sizeof(error_packet_t));
189 }
190 if (len > sizeof(error_packet_t) + MAX_ERROR_MESSAGE_LENGTH) {
191 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Error packet message too large: %u (max %zu)", len,
192 sizeof(error_packet_t) + (size_t)MAX_ERROR_MESSAGE_LENGTH);
193 }
194 break;
195 // All crypto handshake packet types - validate using session parameters
196 case PACKET_TYPE_CRYPTO_CAPABILITIES:
197 case PACKET_TYPE_CRYPTO_PARAMETERS:
198 case PACKET_TYPE_CRYPTO_KEY_EXCHANGE_INIT:
199 case PACKET_TYPE_CRYPTO_KEY_EXCHANGE_RESP:
200 case PACKET_TYPE_CRYPTO_AUTH_CHALLENGE:
201 case PACKET_TYPE_CRYPTO_AUTH_RESPONSE:
202 case PACKET_TYPE_CRYPTO_AUTH_FAILED:
203 case PACKET_TYPE_CRYPTO_SERVER_AUTH_RESP:
204 case PACKET_TYPE_CRYPTO_HANDSHAKE_COMPLETE:
205 case PACKET_TYPE_CRYPTO_NO_ENCRYPTION:
206 case PACKET_TYPE_ENCRYPTED:
207 // Crypto packets are validated by the crypto handshake context
208 // This is just a basic sanity check for extremely large packets
209 if (len > 65536) { // 64KB should be enough for even large post-quantum crypto packets
210 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Crypto packet too large: %u bytes (max 65536)", len);
211 }
212 // Note: Proper size validation is done in crypto_handshake_validate_packet_size()
213 // which uses the session's crypto parameters for accurate validation
214 break;
215 // ACIP protocol packets (Discovery Service)
216 case PACKET_TYPE_ACIP_SESSION_CREATE:
217 case PACKET_TYPE_ACIP_SESSION_CREATED:
218 case PACKET_TYPE_ACIP_SESSION_LOOKUP:
219 case PACKET_TYPE_ACIP_SESSION_INFO:
220 case PACKET_TYPE_ACIP_SESSION_JOIN:
221 case PACKET_TYPE_ACIP_SESSION_JOINED:
222 case PACKET_TYPE_ACIP_SESSION_LEAVE:
223 case PACKET_TYPE_ACIP_SESSION_END:
224 case PACKET_TYPE_ACIP_SESSION_RECONNECT:
225 case PACKET_TYPE_ACIP_WEBRTC_SDP:
226 case PACKET_TYPE_ACIP_WEBRTC_ICE:
227 case PACKET_TYPE_ACIP_STRING_RESERVE:
228 case PACKET_TYPE_ACIP_STRING_RESERVED:
229 case PACKET_TYPE_ACIP_STRING_RENEW:
230 case PACKET_TYPE_ACIP_STRING_RELEASE:
231 case PACKET_TYPE_ACIP_DISCOVERY_PING:
232 case PACKET_TYPE_ACIP_ERROR:
233 // ACIP packets - basic size validation
234 // Discovery service packets can vary in size (variable-length strings, etc.)
235 if (len > 65536) { // 64KB max for discovery packets
236 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "ACIP packet too large: %u bytes (max 65536)", len);
237 }
238 break;
239 default:
240 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Unknown packet type: %u", type);
241 }
242
243 // Return parsed values
244 *pkt_type = type;
245 *pkt_len = len;
246 *expected_crc = crc;
247
248 return ASCIICHAT_OK;
249}
250
258asciichat_error_t packet_validate_crc32(const void *data, size_t len, uint32_t expected_crc) {
259 if (!data && len > 0) {
260 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: data=%p but len=%zu", data, len);
261 }
262
263 if (len == 0) {
264 // Empty packets should have CRC32 of 0
265 if (expected_crc != 0) {
266 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid CRC32 for empty packet: 0x%x (expected 0)", expected_crc);
267 }
268 return 0;
269 }
270
271 uint32_t calculated_crc = asciichat_crc32(data, len);
272 if (calculated_crc != expected_crc) {
273 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "CRC32 mismatch: calculated 0x%x, expected 0x%x", calculated_crc,
274 expected_crc);
275 }
276
277 return ASCIICHAT_OK;
278}
279
288asciichat_error_t packet_send(socket_t sockfd, packet_type_t type, const void *data, size_t len) {
289 if (sockfd == INVALID_SOCKET_VALUE) {
290 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid socket descriptor");
291 }
292
293 if (len > MAX_PACKET_SIZE) {
294 return SET_ERRNO(ERROR_NETWORK_SIZE, "Packet too large: %zu > %d", len, MAX_PACKET_SIZE);
295 }
296
297 packet_header_t header = {.magic = HOST_TO_NET_U64(PACKET_MAGIC),
298 .type = HOST_TO_NET_U16((uint16_t)type),
299 .length = HOST_TO_NET_U32((uint32_t)len),
300 .crc32 = HOST_TO_NET_U32(len > 0 ? asciichat_crc32(data, len) : 0),
301 .client_id = HOST_TO_NET_U32(0)}; // Always initialize client_id to 0 in network byte order
302
303 // Calculate timeout based on packet size (in nanoseconds)
304 uint64_t timeout = calculate_packet_timeout(len);
305
306 // Send header first
307 ssize_t sent = send_with_timeout(sockfd, &header, sizeof(header), timeout);
308 if (sent < 0) {
309 // Error context is already set by send_with_timeout
310 return ERROR_NETWORK;
311 }
312 if ((size_t)sent != sizeof(header)) {
313 return SET_ERRNO(ERROR_NETWORK, "Failed to fully send packet header. Sent %zd/%zu bytes", sent, sizeof(header));
314 }
315
316 // Send payload if present
317 if (len > 0 && data) {
318 // Check socket validity before sending payload to avoid race conditions
319 if (!socket_is_valid(sockfd)) {
320 return SET_ERRNO(ERROR_NETWORK, "Socket became invalid between header and payload send");
321 }
322 sent = send_with_timeout(sockfd, data, len, timeout);
323 // Check for error first to avoid signed/unsigned comparison issues
324 if (sent < 0) {
325 // Error context is already set by send_with_timeout
326 return ERROR_NETWORK;
327 }
328 if ((size_t)sent != len) {
329 return SET_ERRNO(ERROR_NETWORK, "Failed to fully send packet payload. Sent %zd/%zu bytes", sent, len);
330 }
331 }
332
333#ifdef DEBUG_NETWORK
334 log_debug("Sent packet type=%d, len=%zu, errno=%d (%s)", type, len, errno, SAFE_STRERROR(errno));
335#endif
336
337 return 0;
338}
339
348asciichat_error_t packet_receive(socket_t sockfd, packet_type_t *type, void **data, size_t *len) {
349 if (sockfd == INVALID_SOCKET_VALUE) {
350 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid socket descriptor");
351 }
352 if (!type || !data || !len) {
353 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: type=%p, data=%p, len=%p", type, data, len);
354 }
355
356 // Read packet header into memory from network socket
357 packet_header_t header;
358 uint64_t header_timeout_ns =
359 network_is_test_environment() ? (1ULL * NS_PER_SEC_INT) : (RECV_TIMEOUT * NS_PER_SEC_INT);
360 ssize_t received = recv_with_timeout(sockfd, &header, sizeof(header), header_timeout_ns);
361 if (received < 0) {
362 // Error context is already set by recv_with_timeout
363 return ERROR_NETWORK;
364 }
365 if ((size_t)received != sizeof(header)) {
366 if (received == 0) {
367 log_warn("Connection closed while reading packet header");
368 return SET_ERRNO(ERROR_NETWORK, "Connection closed by peer while reading packet header");
369 }
370
371 return SET_ERRNO(ERROR_NETWORK, "Partial packet header received: %zd/%zu bytes", received, sizeof(header));
372 }
373
374 // Validate packet header
375 uint16_t pkt_type;
376 uint32_t pkt_len;
377 uint32_t expected_crc;
378 if (packet_validate_header(&header, &pkt_type, &pkt_len, &expected_crc) != ASCIICHAT_OK) {
379 // Error context is already set by packet_validate_header
380 return ERROR_NETWORK_PROTOCOL;
381 }
382
383 // Allocate buffer for payload
384 void *payload = NULL;
385 if (pkt_len > 0) {
386 payload = buffer_pool_alloc(NULL, pkt_len);
387
388 // Use adaptive timeout for large packets
389 uint64_t recv_timeout = network_is_test_environment() ? (1ULL * NS_PER_SEC_INT) : calculate_packet_timeout(pkt_len);
390 received = recv_with_timeout(sockfd, payload, pkt_len, recv_timeout);
391 if (received < 0) {
392 buffer_pool_free(NULL, payload, pkt_len);
393 return SET_ERRNO_SYS(ERROR_NETWORK, "Failed to receive packet payload");
394 }
395 if (received != (ssize_t)pkt_len) {
396 buffer_pool_free(NULL, payload, pkt_len);
397 return SET_ERRNO(ERROR_NETWORK, "Partial packet payload received: %zd/%u bytes", received, pkt_len);
398 }
399
400 // Validate CRC32
401 if (packet_validate_crc32(payload, pkt_len, expected_crc) != ASCIICHAT_OK) {
402 buffer_pool_free(NULL, payload, pkt_len);
403 // Error context is already set by packet_validate_crc32
404 return ERROR_NETWORK_PROTOCOL;
405 }
406 }
407
408 // Return results
409 *type = (packet_type_t)pkt_type;
410 *data = payload;
411 *len = pkt_len;
412
413 return ASCIICHAT_OK;
414}
415
416/* ============================================================================
417 * High-Level Secure Packet Functions
418 * ============================================================================
419 * These functions handle encryption and compression for secure communication.
420 */
421
431asciichat_error_t send_packet_secure(socket_t sockfd, packet_type_t type, const void *data, size_t len,
432 crypto_context_t *crypto_ctx) {
433 if (len > MAX_PACKET_SIZE) {
434 return SET_ERRNO(ERROR_NETWORK_SIZE, "Packet too large: %zu > %d", len, MAX_PACKET_SIZE);
435 }
436
437 // Handshake packets are ALWAYS sent unencrypted
438 if (packet_is_handshake_type(type)) {
439 return packet_send(sockfd, type, data, len);
440 }
441
442 // Apply compression if beneficial for large packets
443 const void *final_data = data;
444 size_t final_len = len;
445 void *compressed_data = NULL;
446
447 // Skip compression for pre-compressed data (Opus audio) or if --no-compress flag is set
448 bool should_skip_compression = packet_is_precompressed(type) || GET_OPTION(no_compress);
449 if (!should_skip_compression && len > COMPRESSION_MIN_SIZE && should_compress(len, len)) {
450 void *temp_compressed = NULL;
451 size_t compressed_size = 0;
452
453 // Use configured compression level from options (default: 1 for fastest compression)
454 int compression_level = (GET_OPTION(compression_level) > 0) ? GET_OPTION(compression_level) : 1;
455 asciichat_error_t compress_result = compress_data(data, len, &temp_compressed, &compressed_size, compression_level);
456 if (compress_result == ASCIICHAT_OK) {
457 double ratio = (double)compressed_size / (double)len;
458 if (ratio < COMPRESSION_RATIO_THRESHOLD) {
459 final_data = temp_compressed;
460 final_len = compressed_size;
461 compressed_data = temp_compressed;
462 log_debug("Compressed packet: %zu -> %zu bytes (%.1f%%)", len, compressed_size, ratio * 100.0);
463 } else {
464 SAFE_FREE(temp_compressed);
465 }
466 }
467 }
468
469 // If no crypto context or crypto not ready, send unencrypted
470 bool ready = crypto_ctx ? crypto_is_ready(crypto_ctx) : false;
471 if (!crypto_ctx || !ready) {
472 log_warn_every(LOG_RATE_FAST, "CRYPTO_DEBUG: Sending packet type %d UNENCRYPTED (crypto_ctx=%p, ready=%d)", type,
473 (void *)crypto_ctx, ready);
474 asciichat_error_t result = packet_send(sockfd, type, final_data, final_len);
475 if (compressed_data) {
476 SAFE_FREE(compressed_data);
477 }
478 if (result != ASCIICHAT_OK) {
479 SET_ERRNO(ERROR_NETWORK, "Failed to send packet: %s", asciichat_error_string(result));
480 }
481 return result;
482 }
483
484 // Encrypt the packet: create header + payload, encrypt everything, wrap in PACKET_TYPE_ENCRYPTED
485 packet_header_t header = {.magic = HOST_TO_NET_U64(PACKET_MAGIC),
486 .type = HOST_TO_NET_U16((uint16_t)type),
487 .length = HOST_TO_NET_U32((uint32_t)final_len),
488 .crc32 = HOST_TO_NET_U32(final_len > 0 ? asciichat_crc32(final_data, final_len) : 0),
489 .client_id = HOST_TO_NET_U32(0)}; // Always 0 - client_id is not used in practice
490
491 // Combine header + payload for encryption
492 // Check for integer overflow before addition
493 if (final_len > SIZE_MAX - sizeof(header)) {
494 if (compressed_data) {
495 SAFE_FREE(compressed_data);
496 }
497 return SET_ERRNO(ERROR_NETWORK_SIZE, "Packet too large: would overflow plaintext buffer size");
498 }
499 size_t plaintext_len = sizeof(header) + final_len;
500 uint8_t *plaintext = buffer_pool_alloc(NULL, plaintext_len);
501 if (!plaintext) {
502 if (compressed_data) {
503 SAFE_FREE(compressed_data);
504 }
505 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for plaintext packet");
506 }
507
508 memcpy(plaintext, &header, sizeof(header));
509 if (final_len > 0 && final_data) {
510 memcpy(plaintext + sizeof(header), final_data, final_len);
511 }
512
513 // Encrypt
514 // Check for integer overflow before calculating ciphertext size
515 if (plaintext_len > SIZE_MAX - CRYPTO_NONCE_SIZE - CRYPTO_MAC_SIZE) {
516 buffer_pool_free(NULL, plaintext, plaintext_len);
517 if (compressed_data) {
518 SAFE_FREE(compressed_data);
519 }
520 return SET_ERRNO(ERROR_NETWORK_SIZE, "Packet too large: would overflow ciphertext buffer size");
521 }
522 size_t ciphertext_size = plaintext_len + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE;
523 uint8_t *ciphertext = buffer_pool_alloc(NULL, ciphertext_size);
524 if (!ciphertext) {
525 buffer_pool_free(NULL, plaintext, plaintext_len);
526 if (compressed_data) {
527 SAFE_FREE(compressed_data);
528 }
529 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for ciphertext");
530 }
531
532 size_t ciphertext_len;
533 crypto_result_t result =
534 crypto_encrypt(crypto_ctx, plaintext, plaintext_len, ciphertext, ciphertext_size, &ciphertext_len);
535 buffer_pool_free(NULL, plaintext, plaintext_len);
536
537 if (result != CRYPTO_OK) {
538 buffer_pool_free(NULL, ciphertext, ciphertext_size);
539 if (compressed_data) {
540 SAFE_FREE(compressed_data);
541 }
542 return SET_ERRNO(ERROR_CRYPTO, "Failed to encrypt packet: %s", crypto_result_to_string(result));
543 }
544
545 // Send as PACKET_TYPE_ENCRYPTED
546 log_debug_every(LOG_RATE_SLOW, "CRYPTO_DEBUG: Sending encrypted packet (original type %d as PACKET_TYPE_ENCRYPTED)",
547 type);
548 asciichat_error_t send_result = packet_send(sockfd, PACKET_TYPE_ENCRYPTED, ciphertext, ciphertext_len);
549 buffer_pool_free(NULL, ciphertext, ciphertext_size);
550
551 if (compressed_data) {
552 SAFE_FREE(compressed_data);
553 }
554
555 return send_result;
556}
557
566packet_recv_result_t receive_packet_secure(socket_t sockfd, void *crypto_ctx, bool enforce_encryption,
567 packet_envelope_t *envelope) {
568
569 if (!envelope) {
570 SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: envelope=%p", envelope);
571 return PACKET_RECV_ERROR;
572 }
573
574 // Initialize envelope
575 memset(envelope, 0, sizeof(*envelope));
576
577 // Receive packet header
578 packet_header_t header;
579 uint64_t header_timeout_ns =
580 network_is_test_environment() ? (1ULL * NS_PER_SEC_INT) : (RECV_TIMEOUT * NS_PER_SEC_INT);
581 ssize_t received = recv_with_timeout(sockfd, &header, sizeof(header), header_timeout_ns);
582
583 // Check for errors first (before comparing signed with unsigned)
584 if (received < 0) {
585 SET_ERRNO(ERROR_NETWORK, "Failed to receive packet header: %zd/%zu bytes", received, sizeof(header));
586 return PACKET_RECV_ERROR;
587 }
588
589 if (received == 0) {
590 return PACKET_RECV_EOF;
591 }
592
593 if ((size_t)received != sizeof(header)) {
594 SET_ERRNO(ERROR_NETWORK, "Failed to receive packet header: %zd/%zu bytes", received, sizeof(header));
595 return PACKET_RECV_ERROR;
596 }
597
598 // Convert from network byte order
599 uint64_t magic = NET_TO_HOST_U64(header.magic);
600 uint16_t pkt_type = NET_TO_HOST_U16(header.type);
601 uint32_t pkt_len = NET_TO_HOST_U32(header.length);
602 uint32_t expected_crc = NET_TO_HOST_U32(header.crc32);
603
604 // Validate magic number
605 if (magic != PACKET_MAGIC) {
606 SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid packet magic: 0x%llx (expected 0x%llx)", magic, PACKET_MAGIC);
607 return PACKET_RECV_ERROR;
608 }
609
610 // Validate packet size
611 if (pkt_len > MAX_PACKET_SIZE) {
612 SET_ERRNO(ERROR_NETWORK_SIZE, "Packet too large: %u > %d", pkt_len, MAX_PACKET_SIZE);
613 return PACKET_RECV_ERROR;
614 }
615
616 // Handle encrypted packets
617 if (pkt_type == PACKET_TYPE_ENCRYPTED) {
618 if (!crypto_ctx) {
619 SET_ERRNO(ERROR_CRYPTO, "Received encrypted packet but no crypto context");
620 return PACKET_RECV_ERROR;
621 }
622
623 // Read encrypted payload
624 uint8_t *ciphertext = buffer_pool_alloc(NULL, pkt_len);
625 if (!ciphertext) {
626 SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for ciphertext");
627 return PACKET_RECV_ERROR;
628 }
629
630 uint64_t recv_timeout = network_is_test_environment() ? (1ULL * NS_PER_SEC_INT) : calculate_packet_timeout(pkt_len);
631 received = recv_with_timeout(sockfd, ciphertext, pkt_len, recv_timeout);
632 if (received != (ssize_t)pkt_len) {
633 SET_ERRNO(ERROR_NETWORK, "Failed to receive encrypted payload: %zd/%u bytes", received, pkt_len);
634 buffer_pool_free(NULL, ciphertext, pkt_len);
635 return PACKET_RECV_ERROR;
636 }
637
638 // Decrypt - allocate plaintext buffer with extra space
639 // pkt_len is already validated to be <= MAX_PACKET_SIZE, so adding 1024 cannot overflow
640 size_t plaintext_size = (size_t)pkt_len + 1024;
641 uint8_t *plaintext = buffer_pool_alloc(NULL, plaintext_size);
642 if (!plaintext) {
643 SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for plaintext");
644 buffer_pool_free(NULL, ciphertext, pkt_len);
645 return PACKET_RECV_ERROR;
646 }
647
648 size_t plaintext_len;
649 crypto_result_t result = crypto_decrypt(crypto_ctx, ciphertext, pkt_len, plaintext, plaintext_size, &plaintext_len);
650 buffer_pool_free(NULL, ciphertext, pkt_len);
651
652 if (result != CRYPTO_OK) {
653 SET_ERRNO(ERROR_CRYPTO, "Failed to decrypt packet: %s", crypto_result_to_string(result));
654 buffer_pool_free(NULL, plaintext, plaintext_size);
655 return PACKET_RECV_ERROR;
656 }
657
658 if (plaintext_len < sizeof(packet_header_t)) {
659 SET_ERRNO(ERROR_CRYPTO, "Decrypted packet too small: %zu < %zu", plaintext_len, sizeof(packet_header_t));
660 buffer_pool_free(NULL, plaintext, plaintext_size);
661 return PACKET_RECV_ERROR;
662 }
663
664 // Parse decrypted header
665 packet_header_t *decrypted_header = (packet_header_t *)plaintext;
666 pkt_type = NET_TO_HOST_U16(decrypted_header->type);
667 pkt_len = NET_TO_HOST_U32(decrypted_header->length);
668 expected_crc = NET_TO_HOST_U32(decrypted_header->crc32);
669
670 // Extract payload
671 size_t payload_len = plaintext_len - sizeof(packet_header_t);
672 if (payload_len != pkt_len) {
673 SET_ERRNO(ERROR_CRYPTO, "Decrypted payload size mismatch: %zu != %u", payload_len, pkt_len);
674 buffer_pool_free(NULL, plaintext, plaintext_size);
675 return PACKET_RECV_ERROR;
676 }
677
678 // Verify CRC
679 if (pkt_len > 0) {
680 uint32_t actual_crc = asciichat_crc32(plaintext + sizeof(packet_header_t), pkt_len);
681 if (actual_crc != expected_crc) {
682 SET_ERRNO(ERROR_CRYPTO, "Decrypted packet CRC mismatch: 0x%x != 0x%x", actual_crc, expected_crc);
683 buffer_pool_free(NULL, plaintext, plaintext_size);
684 return PACKET_RECV_ERROR;
685 }
686 }
687
688 // Set envelope
689 envelope->type = (packet_type_t)pkt_type;
690 envelope->data = plaintext + sizeof(packet_header_t);
691 envelope->len = pkt_len;
692 envelope->allocated_buffer = plaintext;
693 envelope->allocated_size = plaintext_size;
694
695 return PACKET_RECV_SUCCESS;
696 }
697
698 // Handle unencrypted packets
699 if (enforce_encryption && !packet_is_handshake_type(pkt_type)) {
700 SET_ERRNO(ERROR_CRYPTO, "Received unencrypted packet type %d but encryption is required", pkt_type);
701 return PACKET_RECV_ERROR;
702 }
703
704 // Read payload
705 if (pkt_len > 0) {
706 uint8_t *payload = buffer_pool_alloc(NULL, pkt_len);
707 if (!payload) {
708 SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for payload");
709 return PACKET_RECV_ERROR;
710 }
711
712 uint64_t recv_timeout = network_is_test_environment() ? (1ULL * NS_PER_SEC_INT) : calculate_packet_timeout(pkt_len);
713 received = recv_with_timeout(sockfd, payload, pkt_len, recv_timeout);
714 if (received != (ssize_t)pkt_len) {
715 SET_ERRNO(ERROR_NETWORK, "Failed to receive payload: %zd/%u bytes", received, pkt_len);
716 buffer_pool_free(NULL, payload, pkt_len);
717 return PACKET_RECV_ERROR;
718 }
719
720 // Verify CRC
721 uint32_t actual_crc = asciichat_crc32(payload, pkt_len);
722 if (actual_crc != expected_crc) {
723 SET_ERRNO(ERROR_NETWORK, "Packet CRC mismatch: 0x%x != 0x%x", actual_crc, expected_crc);
724 buffer_pool_free(NULL, payload, pkt_len);
725 return PACKET_RECV_ERROR;
726 }
727
728 envelope->data = payload;
729 envelope->allocated_buffer = payload;
730 envelope->allocated_size = pkt_len;
731 }
732
733 envelope->type = (packet_type_t)pkt_type;
734 envelope->len = pkt_len;
735
736 return PACKET_RECV_SUCCESS;
737}
738
739/* ============================================================================
740 * Basic Packet Functions (Non-Secure)
741 * ============================================================================
742 * These are the basic packet send/receive functions without encryption.
743 */
744
753int send_packet(socket_t sockfd, packet_type_t type, const void *data, size_t len) {
754 asciichat_error_t result = packet_send(sockfd, type, data, len);
755 return result == ASCIICHAT_OK ? 0 : -1;
756}
757
766int receive_packet(socket_t sockfd, packet_type_t *type, void **data, size_t *len) {
767 asciichat_error_t result = packet_receive(sockfd, type, data, len);
768 return result == ASCIICHAT_OK ? 0 : -1;
769}
770
771/* ============================================================================
772 * Protocol Message Functions
773 * ============================================================================
774 * These functions send specific protocol messages.
775 */
776
783 return send_packet(sockfd, PACKET_TYPE_PING, NULL, 0);
784}
785
792 return send_packet(sockfd, PACKET_TYPE_PONG, NULL, 0);
793}
794
801 return send_packet(sockfd, PACKET_TYPE_CLEAR_CONSOLE, NULL, 0);
802}
803
804asciichat_error_t packet_send_error(socket_t sockfd, const crypto_context_t *crypto_ctx, asciichat_error_t error_code,
805 const char *message) {
806 if (sockfd == INVALID_SOCKET_VALUE) {
807 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid socket descriptor");
808 }
809
810 if (!message) {
811 message = "";
812 }
813
814 size_t message_len = strnlen(message, MAX_ERROR_MESSAGE_LENGTH);
815 if (message_len == MAX_ERROR_MESSAGE_LENGTH) {
816 log_warn("Error message truncated to %zu bytes", (size_t)MAX_ERROR_MESSAGE_LENGTH);
817 }
818
819 size_t payload_len = sizeof(error_packet_t) + message_len;
820 uint8_t *payload = SAFE_MALLOC(payload_len, uint8_t *);
821 if (!payload) {
822 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate %zu bytes for error packet", payload_len);
823 }
824
825 error_packet_t *packet = (error_packet_t *)payload;
826 packet->error_code = HOST_TO_NET_U32((uint32_t)error_code);
827 packet->message_length = HOST_TO_NET_U32((uint32_t)message_len);
828
829 if (message_len > 0) {
830 memcpy(payload + sizeof(error_packet_t), message, message_len);
831 }
832
833 bool encryption_ready = crypto_ctx && crypto_is_ready(crypto_ctx);
834 asciichat_error_t send_result;
835
836 if (encryption_ready) {
837 send_result =
838 send_packet_secure(sockfd, PACKET_TYPE_ERROR_MESSAGE, payload, payload_len, (crypto_context_t *)crypto_ctx);
839 } else {
840 send_result = packet_send(sockfd, PACKET_TYPE_ERROR_MESSAGE, payload, payload_len);
841 }
842 SAFE_FREE(payload);
843
844 if (send_result != ASCIICHAT_OK) {
845 return SET_ERRNO(ERROR_NETWORK, "Failed to send error packet: %s", asciichat_error_string(send_result));
846 }
847
848 return ASCIICHAT_OK;
849}
850
851asciichat_error_t packet_parse_error_message(const void *data, size_t len, asciichat_error_t *out_error_code,
852 char *message_buffer, size_t message_buffer_size,
853 size_t *out_message_length) {
854 if (!data || len < sizeof(error_packet_t) || !out_error_code || !message_buffer || message_buffer_size == 0) {
855 return SET_ERRNO(ERROR_INVALID_PARAM,
856 "Invalid parameters: data=%p len=%zu out_error_code=%p message_buffer=%p buffer_size=%zu", data,
857 len, out_error_code, message_buffer, message_buffer_size);
858 }
859
860 const error_packet_t *packet = (const error_packet_t *)data;
861 uint32_t raw_error_code = NET_TO_HOST_U32(packet->error_code);
862 uint32_t raw_message_length = NET_TO_HOST_U32(packet->message_length);
863
864 if (raw_message_length > MAX_ERROR_MESSAGE_LENGTH) {
865 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Error message length too large: %u", raw_message_length);
866 }
867
868 size_t total_required = sizeof(error_packet_t) + (size_t)raw_message_length;
869 if (total_required > len) {
870 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Error packet truncated: expected %zu bytes, have %zu", total_required,
871 len);
872 }
873
874 const uint8_t *message_bytes = (const uint8_t *)data + sizeof(error_packet_t);
875 size_t copy_len = raw_message_length;
876 if (copy_len >= message_buffer_size) {
877 copy_len = message_buffer_size - 1;
878 }
879
880 if (copy_len > 0) {
881 memcpy(message_buffer, message_bytes, copy_len);
882 }
883 message_buffer[copy_len] = '\0';
884
885 if (out_message_length) {
886 *out_message_length = raw_message_length;
887 }
888
889 *out_error_code = (asciichat_error_t)raw_error_code;
890 return ASCIICHAT_OK;
891}
892
893asciichat_error_t packet_send_remote_log(socket_t sockfd, const crypto_context_t *crypto_ctx, log_level_t level,
894 remote_log_direction_t direction, uint16_t flags, const char *message) {
895 if (sockfd == INVALID_SOCKET_VALUE) {
896 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid socket descriptor");
897 }
898
899 if (level < LOG_DEV || level > LOG_FATAL) {
900 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid log level: %d", level);
901 }
902
903 const char *safe_message = message ? message : "";
904 bool truncated = false;
905 size_t message_len = strnlen(safe_message, MAX_REMOTE_LOG_MESSAGE_LENGTH);
906 if (message_len == MAX_REMOTE_LOG_MESSAGE_LENGTH && safe_message[message_len] != '\0') {
907 truncated = true;
908 }
909
910 size_t payload_len = sizeof(remote_log_packet_t) + message_len;
911 uint8_t *payload = SAFE_MALLOC(payload_len, uint8_t *);
912 if (!payload) {
913 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate %zu bytes for remote log packet", payload_len);
914 }
915
916 remote_log_packet_t *packet = (remote_log_packet_t *)payload;
917 packet->log_level = (uint8_t)level;
918 packet->direction = (uint8_t)direction;
919 uint16_t final_flags = flags;
920 if (truncated) {
921 final_flags |= REMOTE_LOG_FLAG_TRUNCATED;
922 }
923 packet->flags = HOST_TO_NET_U16(final_flags);
924 packet->message_length = HOST_TO_NET_U32((uint32_t)message_len);
925
926 if (message_len > 0) {
927 memcpy(payload + sizeof(remote_log_packet_t), safe_message, message_len);
928 }
929
930 bool encryption_ready = crypto_ctx && crypto_is_ready(crypto_ctx);
931 asciichat_error_t send_result;
932
933 if (encryption_ready) {
934 int secure_result =
935 send_packet_secure(sockfd, PACKET_TYPE_REMOTE_LOG, payload, payload_len, (crypto_context_t *)crypto_ctx);
936 send_result = secure_result == 0 ? ASCIICHAT_OK : ERROR_NETWORK;
937 } else {
938 send_result = packet_send(sockfd, PACKET_TYPE_REMOTE_LOG, payload, payload_len);
939 }
940
941 SAFE_FREE(payload);
942
943 if (send_result != ASCIICHAT_OK) {
944 return SET_ERRNO(ERROR_NETWORK, "Failed to send remote log packet: %d", send_result);
945 }
946
947 return ASCIICHAT_OK;
948}
949
950asciichat_error_t packet_parse_remote_log(const void *data, size_t len, log_level_t *out_level,
951 remote_log_direction_t *out_direction, uint16_t *out_flags,
952 char *message_buffer, size_t message_buffer_size,
953 size_t *out_message_length) {
954 if (!data || len < sizeof(remote_log_packet_t) || !out_level || !out_direction || !out_flags || !message_buffer ||
955 message_buffer_size == 0) {
956 return SET_ERRNO(
957 ERROR_INVALID_PARAM,
958 "Invalid parameters: data=%p len=%zu out_level=%p out_direction=%p out_flags=%p buffer=%p size=%zu", data, len,
959 out_level, out_direction, out_flags, message_buffer, message_buffer_size);
960 }
961
962 const remote_log_packet_t *packet = (const remote_log_packet_t *)data;
963 uint8_t raw_level = packet->log_level;
964 if (raw_level > LOG_FATAL) {
965 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid remote log level: %u", raw_level);
966 }
967 *out_level = (log_level_t)raw_level;
968
969 uint8_t raw_direction = packet->direction;
970 if (raw_direction > REMOTE_LOG_DIRECTION_CLIENT_TO_SERVER) {
971 raw_direction = REMOTE_LOG_DIRECTION_UNKNOWN;
972 }
973 *out_direction = (remote_log_direction_t)raw_direction;
974
975 uint16_t raw_flags = NET_TO_HOST_U16(packet->flags);
976 *out_flags = raw_flags;
977
978 uint32_t raw_message_length = NET_TO_HOST_U32(packet->message_length);
979 if (raw_message_length > MAX_REMOTE_LOG_MESSAGE_LENGTH) {
980 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Remote log message length too large: %u", raw_message_length);
981 }
982
983 size_t total_required = sizeof(remote_log_packet_t) + (size_t)raw_message_length;
984 if (total_required > len) {
985 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Remote log packet truncated: expected %zu bytes, have %zu",
986 total_required, len);
987 }
988
989 const uint8_t *message_bytes = (const uint8_t *)data + sizeof(remote_log_packet_t);
990 size_t copy_len = raw_message_length;
991 if (copy_len >= message_buffer_size) {
992 copy_len = message_buffer_size - 1;
993 }
994
995 if (copy_len > 0) {
996 memcpy(message_buffer, message_bytes, copy_len);
997 }
998 message_buffer[copy_len] = '\0';
999
1000 if (out_message_length) {
1001 *out_message_length = raw_message_length;
1002 }
1003
1004 return ASCIICHAT_OK;
1005}
1006
1013int send_protocol_version_packet(socket_t sockfd, const protocol_version_packet_t *version) {
1014 if (!version) {
1015 SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: version=%p", version);
1016 return -1;
1017 }
1018 return send_packet(sockfd, PACKET_TYPE_PROTOCOL_VERSION, version, sizeof(*version));
1019}
1020
1027int send_crypto_capabilities_packet(socket_t sockfd, const crypto_capabilities_packet_t *caps) {
1028 if (!caps) {
1029 SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: caps=%p", caps);
1030 return -1;
1031 }
1032 return send_packet(sockfd, PACKET_TYPE_CRYPTO_CAPABILITIES, caps, sizeof(*caps));
1033}
1034
1041int send_crypto_parameters_packet(socket_t sockfd, const crypto_parameters_packet_t *params) {
1042 if (!params) {
1043 SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: params=%p", params);
1044 return -1;
1045 }
1046
1047 // Create a copy and convert uint16_t fields to network byte order
1048 crypto_parameters_packet_t net_params = *params;
1049 log_debug("NETWORK_DEBUG: Before htons: kex=%u, auth=%u, sig=%u, secret=%u", params->kex_public_key_size,
1050 params->auth_public_key_size, params->signature_size, params->shared_secret_size);
1051 net_params.kex_public_key_size = HOST_TO_NET_U16(params->kex_public_key_size);
1052 net_params.auth_public_key_size = HOST_TO_NET_U16(params->auth_public_key_size);
1053 net_params.signature_size = HOST_TO_NET_U16(params->signature_size);
1054 net_params.shared_secret_size = HOST_TO_NET_U16(params->shared_secret_size);
1055 log_debug("NETWORK_DEBUG: After htons: kex=%u, auth=%u, sig=%u, secret=%u", net_params.kex_public_key_size,
1056 net_params.auth_public_key_size, net_params.signature_size, net_params.shared_secret_size);
1057
1058 return send_packet(sockfd, PACKET_TYPE_CRYPTO_PARAMETERS, &net_params, sizeof(net_params));
1059}
1060
1061// =============================================================================
1062// Audio Batch Packet Sending
1063// =============================================================================
1064// These functions were moved from lib/network/av.c during refactoring.
1065// They provide socket-level audio packet sending with encryption support.
1066// For transport-agnostic sending, use acip_send_audio_batch() instead.
1067// =============================================================================
1068
1069asciichat_error_t send_audio_batch_packet(socket_t sockfd, const float *samples, int num_samples, int batch_count,
1070 crypto_context_t *crypto_ctx) {
1071 if (!samples || num_samples <= 0 || batch_count <= 0) {
1072 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid audio batch: samples=%p, num_samples=%d, batch_count=%d", samples,
1073 num_samples, batch_count);
1074 }
1075
1076 // Build batch header
1077 audio_batch_packet_t header;
1078 header.batch_count = HOST_TO_NET_U32((u_long)batch_count);
1079 header.total_samples = HOST_TO_NET_U32((u_long)num_samples);
1080 header.sample_rate = HOST_TO_NET_U32(AUDIO_SAMPLE_RATE); // Use system-defined sample rate
1081 header.channels = HOST_TO_NET_U32(1UL); // Mono for now
1082
1083 // Calculate total payload size
1084 size_t data_size = (size_t)num_samples * sizeof(uint32_t); // Send as 32-bit integers for portability
1085 size_t total_size = sizeof(header) + data_size;
1086
1087 // Allocate buffer for header + data
1088 uint8_t *buffer = buffer_pool_alloc(NULL, total_size);
1089 if (!buffer) {
1090 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for audio batch packet");
1091 }
1092
1093 // Copy header
1094 memcpy(buffer, &header, sizeof(header));
1095
1096 // Convert floats to network byte order (as 32-bit integers with scaling)
1097 // Floats in range [-1.0, 1.0] are scaled to INT32 range for transmission
1098 // Use memcpy to avoid alignment issues when casting from uint8_t* to uint32_t*
1099 uint8_t *sample_data_ptr = buffer + sizeof(header);
1100 for (int i = 0; i < num_samples; i++) {
1101 // Clamp samples to [-1.0, 1.0] range before scaling to prevent overflow
1102 float clamped_sample = samples[i];
1103 if (clamped_sample > 1.0f)
1104 clamped_sample = 1.0f;
1105 if (clamped_sample < -1.0f)
1106 clamped_sample = -1.0f;
1107
1108 // Scale float [-1.0, 1.0] to int32 range and convert to network byte order
1109 int32_t scaled = (int32_t)(clamped_sample * 2147483647.0f);
1110 uint32_t network_value = HOST_TO_NET_U32((uint32_t)scaled);
1111 memcpy(sample_data_ptr + (size_t)i * sizeof(uint32_t), &network_value, sizeof(uint32_t));
1112 }
1113
1114#ifndef NDEBUG
1115 // Debug: Log first few samples to verify conversion
1116 static int send_count = 0;
1117 send_count++;
1118 if (send_count % 100 == 0) {
1119 log_info("SEND: samples[0]=%.6f, samples[1]=%.6f, samples[2]=%.6f", (double)samples[0], (double)samples[1],
1120 (double)samples[2]);
1121 log_info("SEND: scaled[0]=%d, scaled[1]=%d, scaled[2]=%d", (int32_t)(samples[0] * 2147483647.0f),
1122 (int32_t)(samples[1] * 2147483647.0f), (int32_t)(samples[2] * 2147483647.0f));
1123 }
1124#endif
1125
1126 // Send packet with encryption support
1127 asciichat_error_t result = send_packet_secure(sockfd, PACKET_TYPE_AUDIO_BATCH, buffer, total_size, crypto_ctx);
1128 buffer_pool_free(NULL, buffer, total_size);
1129
1130 return result;
1131}
1132
1133asciichat_error_t av_send_audio_opus_batch(socket_t sockfd, const uint8_t *opus_data, size_t opus_size,
1134 const uint16_t *frame_sizes, int sample_rate, int frame_duration,
1135 int frame_count, crypto_context_t *crypto_ctx) {
1136 if (!opus_data || opus_size == 0 || !frame_sizes || sample_rate <= 0 || frame_duration <= 0 || frame_count <= 0) {
1137 return SET_ERRNO(ERROR_INVALID_PARAM,
1138 "Invalid Opus batch parameters: opus_data=%p, opus_size=%zu, frame_sizes=%p, sample_rate=%d, "
1139 "frame_duration=%d, frame_count=%d",
1140 (const void *)opus_data, opus_size, (const void *)frame_sizes, sample_rate, frame_duration,
1141 frame_count);
1142 }
1143
1144 // Validate frame_count to prevent integer overflow in size calculations
1145 // Max reasonable frames per batch: ~1 second of 10ms frames = 100 frames
1146 if (frame_count > 1000) {
1147 return SET_ERRNO(ERROR_INVALID_PARAM, "Too many Opus frames: %d (max 1000)", frame_count);
1148 }
1149
1150 // Allocate buffer for header + frame sizes + encoded data
1151 size_t header_size = 16; // sample_rate (4), frame_duration (4), frame_count (4), reserved (4)
1152 size_t frame_sizes_bytes = (size_t)frame_count * sizeof(uint16_t);
1153 size_t total_size = header_size + frame_sizes_bytes + opus_size;
1154 void *packet_data = buffer_pool_alloc(NULL, total_size);
1155 if (!packet_data) {
1156 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for Opus batch packet: %zu bytes", total_size);
1157 }
1158
1159 // Write header (network byte order for cross-platform compatibility)
1160 uint8_t *buf = (uint8_t *)packet_data;
1161 uint32_t sr = HOST_TO_NET_U32((uint32_t)sample_rate);
1162 uint32_t fd = HOST_TO_NET_U32((uint32_t)frame_duration);
1163 uint32_t fc = HOST_TO_NET_U32((uint32_t)frame_count);
1164 memcpy(buf, &sr, 4);
1165 memcpy(buf + 4, &fd, 4);
1166 memcpy(buf + 8, &fc, 4);
1167 memset(buf + 12, 0, 4); // Reserved
1168
1169 // Write frame sizes array (convert each to network byte order)
1170 uint16_t *frame_sizes_out = (uint16_t *)(buf + header_size);
1171 for (int i = 0; i < frame_count; i++) {
1172 frame_sizes_out[i] = HOST_TO_NET_U16(frame_sizes[i]);
1173 }
1174
1175 // Copy Opus data
1176 memcpy(buf + header_size + frame_sizes_bytes, opus_data, opus_size);
1177
1178 // Send packet (with encryption support)
1179 asciichat_error_t result =
1180 send_packet_secure(sockfd, PACKET_TYPE_AUDIO_OPUS_BATCH, packet_data, total_size, crypto_ctx);
1181
1182 // Clean up
1183 buffer_pool_free(NULL, packet_data, total_size);
1184
1185 return result;
1186}
1187
1188asciichat_error_t send_ascii_frame_packet(socket_t sockfd, const char *frame_data, size_t frame_size) {
1189 if (!frame_data || frame_size == 0) {
1190 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: frame_data=%p, frame_size=%zu", frame_data, frame_size);
1191 }
1192
1193 // Create ASCII frame packet
1194 ascii_frame_packet_t packet;
1195 packet.width = 0; // Will be set by receiver
1196 packet.height = 0; // Will be set by receiver
1197 packet.original_size = (uint32_t)frame_size;
1198 packet.compressed_size = 0;
1199 packet.checksum = 0;
1200 packet.flags = 0;
1201
1202 // Calculate total packet size with overflow checking
1203 size_t total_size;
1204 if (checked_size_add(sizeof(ascii_frame_packet_t), frame_size, &total_size) != ASCIICHAT_OK) {
1205 return SET_ERRNO(ERROR_INVALID_PARAM, "Packet size calculation would overflow");
1206 }
1207
1208 // Allocate buffer for complete packet
1209 void *packet_data = buffer_pool_alloc(NULL, total_size);
1210 if (!packet_data) {
1211 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for ASCII frame packet: %zu bytes", total_size);
1212 }
1213
1214 // Copy packet header and frame data
1215 memcpy(packet_data, &packet, sizeof(ascii_frame_packet_t));
1216 memcpy((char *)packet_data + sizeof(ascii_frame_packet_t), frame_data, frame_size);
1217
1218 // Send packet
1219 asciichat_error_t result = packet_send(sockfd, PACKET_TYPE_ASCII_FRAME, packet_data, total_size);
1220
1221 // Clean up
1222 buffer_pool_free(NULL, packet_data, total_size);
1223
1224 return result;
1225}
1226
1227asciichat_error_t send_image_frame_packet(socket_t sockfd, const void *image_data, uint16_t width, uint16_t height,
1228 uint8_t format) {
1229 if (!image_data || width == 0 || height == 0) {
1230 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: image_data=%p, width=%u, height=%u", image_data, width,
1231 height);
1232 }
1233
1234 // Validate dimensions to prevent integer overflow
1235 // Max reasonable dimensions: 4K (3840x2160) = ~25MB per frame
1236 if (width > 4096 || height > 4096) {
1237 return SET_ERRNO(ERROR_INVALID_PARAM, "Image dimensions too large: %ux%u (max 4096x4096)", width, height);
1238 }
1239
1240 // Create image frame packet
1241 image_frame_packet_t packet;
1242 packet.width = width;
1243 packet.height = height;
1244 packet.pixel_format = format;
1245 packet.compressed_size = 0;
1246 packet.checksum = 0;
1247 packet.timestamp = 0; // Will be set by receiver
1248
1249 // Calculate total packet size
1250 // Cast to size_t before multiplication to prevent integer overflow
1251 // Use overflow-checked multiplication
1252 size_t width_times_height;
1253 if (checked_size_mul((size_t)width, (size_t)height, &width_times_height) != ASCIICHAT_OK) {
1254 return SET_ERRNO(ERROR_BUFFER_OVERFLOW, "Image dimensions too large: %d x %d", width, height);
1255 }
1256
1257 size_t frame_size;
1258 if (checked_size_mul(width_times_height, 3u, &frame_size) != ASCIICHAT_OK) {
1259 return SET_ERRNO(ERROR_BUFFER_OVERFLOW, "Frame size overflow for RGB format");
1260 }
1261
1262 size_t total_size;
1263 if (checked_size_add(sizeof(image_frame_packet_t), frame_size, &total_size) != ASCIICHAT_OK) {
1264 return SET_ERRNO(ERROR_BUFFER_OVERFLOW, "Total packet size overflow");
1265 }
1266
1267 // Allocate buffer for complete packet
1268 void *packet_data = buffer_pool_alloc(NULL, total_size);
1269 if (!packet_data) {
1270 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for image frame packet: %zu bytes", total_size);
1271 }
1272
1273 // Copy packet header and image data
1274 memcpy(packet_data, &packet, sizeof(image_frame_packet_t));
1275 memcpy((char *)packet_data + sizeof(image_frame_packet_t), image_data, frame_size);
1276
1277 // Send packet
1278 asciichat_error_t result = packet_send(sockfd, PACKET_TYPE_IMAGE_FRAME, packet_data, total_size);
1279
1280 // Clean up
1281 buffer_pool_free(NULL, packet_data, total_size);
1282
1283 return result;
1284}
asciichat_error_t error_code
void buffer_pool_free(buffer_pool_t *pool, void *data, size_t size)
void * buffer_pool_alloc(buffer_pool_t *pool, size_t size)
Definition buffer_pool.c:99
bool should_compress(size_t original_size, size_t compressed_size)
Definition compression.c:74
asciichat_error_t compress_data(const void *input, size_t input_size, void **output, size_t *output_size, int compression_level)
Definition compression.c:14
int socket_t
crypto_result_t crypto_encrypt(crypto_context_t *ctx, const uint8_t *plaintext, size_t plaintext_len, uint8_t *ciphertext_out, size_t ciphertext_out_size, size_t *ciphertext_len_out)
const char * crypto_result_to_string(crypto_result_t result)
bool crypto_is_ready(const crypto_context_t *ctx)
crypto_result_t crypto_decrypt(crypto_context_t *ctx, const uint8_t *ciphertext, size_t ciphertext_len, uint8_t *plaintext_out, size_t plaintext_out_size, size_t *plaintext_len_out)
ssize_t recv_with_timeout(socket_t sockfd, void *buf, size_t len, uint64_t timeout_ns)
Receive data with timeout.
ssize_t send_with_timeout(socket_t sockfd, const void *data, size_t len, uint64_t timeout_ns)
Send data with timeout using chunked transmission.
asciichat_error_t send_packet_secure(socket_t sockfd, packet_type_t type, const void *data, size_t len, crypto_context_t *crypto_ctx)
Send a packet with encryption and compression support.
Definition packet.c:431
asciichat_error_t packet_parse_remote_log(const void *data, size_t len, log_level_t *out_level, remote_log_direction_t *out_direction, uint16_t *out_flags, char *message_buffer, size_t message_buffer_size, size_t *out_message_length)
Definition packet.c:950
asciichat_error_t packet_send_error(socket_t sockfd, const crypto_context_t *crypto_ctx, asciichat_error_t error_code, const char *message)
Definition packet.c:804
asciichat_error_t packet_validate_crc32(const void *data, size_t len, uint32_t expected_crc)
Validate packet CRC32.
Definition packet.c:258
asciichat_error_t packet_send_remote_log(socket_t sockfd, const crypto_context_t *crypto_ctx, log_level_t level, remote_log_direction_t direction, uint16_t flags, const char *message)
Definition packet.c:893
asciichat_error_t send_image_frame_packet(socket_t sockfd, const void *image_data, uint16_t width, uint16_t height, uint8_t format)
Definition packet.c:1227
int send_protocol_version_packet(socket_t sockfd, const protocol_version_packet_t *version)
Send protocol version packet.
Definition packet.c:1013
int send_pong_packet(socket_t sockfd)
Send a pong packet.
Definition packet.c:791
asciichat_error_t send_audio_batch_packet(socket_t sockfd, const float *samples, int num_samples, int batch_count, crypto_context_t *crypto_ctx)
Definition packet.c:1069
asciichat_error_t packet_receive(socket_t sockfd, packet_type_t *type, void **data, size_t *len)
Receive a packet with proper header validation and CRC32 checking.
Definition packet.c:348
asciichat_error_t packet_parse_error_message(const void *data, size_t len, asciichat_error_t *out_error_code, char *message_buffer, size_t message_buffer_size, size_t *out_message_length)
Definition packet.c:851
int receive_packet(socket_t sockfd, packet_type_t *type, void **data, size_t *len)
Receive a basic packet without encryption.
Definition packet.c:766
asciichat_error_t send_ascii_frame_packet(socket_t sockfd, const char *frame_data, size_t frame_size)
Definition packet.c:1188
asciichat_error_t av_send_audio_opus_batch(socket_t sockfd, const uint8_t *opus_data, size_t opus_size, const uint16_t *frame_sizes, int sample_rate, int frame_duration, int frame_count, crypto_context_t *crypto_ctx)
Definition packet.c:1133
int send_packet(socket_t sockfd, packet_type_t type, const void *data, size_t len)
Send a basic packet without encryption.
Definition packet.c:753
asciichat_error_t packet_validate_header(const packet_header_t *header, uint16_t *pkt_type, uint32_t *pkt_len, uint32_t *expected_crc)
Validate packet header and return parsed information.
Definition packet.c:77
asciichat_error_t packet_send(socket_t sockfd, packet_type_t type, const void *data, size_t len)
Send a packet with proper header and CRC32.
Definition packet.c:288
packet_recv_result_t receive_packet_secure(socket_t sockfd, void *crypto_ctx, bool enforce_encryption, packet_envelope_t *envelope)
Receive a packet with decryption and decompression support.
Definition packet.c:566
int send_crypto_capabilities_packet(socket_t sockfd, const crypto_capabilities_packet_t *caps)
Send crypto capabilities packet.
Definition packet.c:1027
int send_clear_console_packet(socket_t sockfd)
Send a clear console packet.
Definition packet.c:800
int send_ping_packet(socket_t sockfd)
Send a ping packet.
Definition packet.c:782
int send_crypto_parameters_packet(socket_t sockfd, const crypto_parameters_packet_t *params)
Send crypto parameters packet.
Definition packet.c:1041