ascii-chat 0.6.0
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 "packet.h"
8#include "network.h"
9#include "common.h"
10#include "asciichat_errno.h"
11#include "platform/socket.h"
12#include "buffer_pool.h"
13#include "network/crc32.h"
14#include "crypto/crypto.h"
15#include "network/compression.h"
16#include "util/endian.h"
17#include "util/overflow.h"
18#include "audio/audio.h"
19#include "options/options.h"
20#include "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
43static int calculate_packet_timeout(size_t packet_size) {
44 int base_timeout = network_is_test_environment() ? 1 : SEND_TIMEOUT;
45
46 // For large packets, increase timeout proportionally
47 if (packet_size > LARGE_PACKET_THRESHOLD) {
48 // Add extra timeout per MB above the threshold
49 int extra_timeout =
50 (int)(((double)packet_size - LARGE_PACKET_THRESHOLD) / 1000000.0 * LARGE_PACKET_EXTRA_TIMEOUT_PER_MB) + 1;
51 int total_timeout = base_timeout + extra_timeout;
52
53 // Ensure client timeout is longer than server's RECV_TIMEOUT (30s) to prevent deadlock
54 // Add 10 seconds buffer to account for server processing delays
55 int min_timeout = MIN_CLIENT_TIMEOUT;
56 if (total_timeout < min_timeout) {
57 total_timeout = min_timeout;
58 }
59
60 // Cap at maximum timeout
61 return (total_timeout > MAX_CLIENT_TIMEOUT) ? MAX_CLIENT_TIMEOUT : total_timeout;
62 }
63
64 return base_timeout;
65}
66
76 uint32_t *expected_crc) {
77 if (!header || !pkt_type || !pkt_len || !expected_crc) {
78 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: header=%p, pkt_type=%p, pkt_len=%p, expected_crc=%p",
79 header, pkt_type, pkt_len, expected_crc);
80 }
81
82 // First validate packet length BEFORE converting from network byte order
83 // This prevents potential integer overflow issues
84 uint32_t pkt_len_network = header->length;
85 if (pkt_len_network == 0xFFFFFFFF) {
86 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid packet length in network byte order: 0xFFFFFFFF");
87 }
88
89 // Convert from network byte order using safe helpers
90 uint32_t magic = endian_unpack_u32(header->magic);
91 uint16_t type = endian_unpack_u16(header->type);
92 uint32_t len = endian_unpack_u32(pkt_len_network);
93 uint32_t crc = endian_unpack_u32(header->crc32);
94
95 // Validate magic
96 if (magic != PACKET_MAGIC) {
97 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid packet magic: 0x%x (expected 0x%x)", magic, PACKET_MAGIC);
98 }
99
100 // Validate packet size with bounds checking
101 if (len > MAX_PACKET_SIZE) {
102 return SET_ERRNO(ERROR_NETWORK_SIZE, "Packet too large: %u > %d", len, MAX_PACKET_SIZE);
103 }
104
105 // Validate packet type and size constraints
106 switch (type) {
108 // Protocol version packet has fixed size
109 if (len != sizeof(protocol_version_packet_t)) {
110 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid protocol version packet size: %u, expected %zu", len,
112 }
113 break;
115 // ASCII frame contains header + frame data
116 if (len < sizeof(ascii_frame_packet_t)) {
117 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid ASCII frame packet size: %u, minimum %zu", len,
118 sizeof(ascii_frame_packet_t));
119 }
120 break;
122 // Image frame contains header + pixel data
123 if (len < sizeof(image_frame_packet_t)) {
124 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid image frame packet size: %u, minimum %zu", len,
125 sizeof(image_frame_packet_t));
126 }
127 break;
129 if (len == 0 || len > AUDIO_SAMPLES_PER_PACKET * sizeof(float) * 2) { // Max stereo samples
130 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid audio packet size: %u", len);
131 }
132 break;
134 // Batch must have at least header + some samples
135 if (len < sizeof(audio_batch_packet_t) + sizeof(float)) {
136 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid audio batch packet size: %u", len);
137 }
138 break;
139 case PACKET_TYPE_PING:
140 case PACKET_TYPE_PONG:
141 if (len != 0) { // Ping/pong are just header packets and no payload.
142 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid ping/pong packet size: %u", len);
143 }
144 break;
146 // Client capabilities packet can be empty or contain capability data
147 if (len > 1024) { // Reasonable limit for capability data
148 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid client capabilities packet size: %u", len);
149 }
150 break;
152 if (len != sizeof(client_info_packet_t)) {
153 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid client join packet size: %u, expected %zu", len,
154 sizeof(client_info_packet_t));
155 }
156 break;
158 // Client leave packet can be empty or contain reason
159 if (len > 256) {
160 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid client leave packet size: %u", len);
161 }
162 break;
165 if (len != sizeof(uint32_t)) {
166 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid stream control packet size: %u, expected %zu", len,
167 sizeof(uint32_t));
168 }
169 break;
171 // Size message format: "SIZE:width,height"
172 if (len == 0 || len > 32) { // Reasonable size for "SIZE:1234,5678"
173 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid size message packet size: %u", len);
174 }
175 break;
177 // Audio message format: "AUDIO:num_samples"
178 if (len == 0 || len > 32) { // Reasonable size for "AUDIO:1234"
179 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid audio message packet size: %u", len);
180 }
181 break;
183 // Text message can be empty or contain message
184 if (len > 1024) { // Reasonable limit for text messages
185 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid text message packet size: %u", len);
186 }
187 break;
189 if (len < sizeof(error_packet_t)) {
190 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid error packet size: %u (minimum %zu)", len,
191 sizeof(error_packet_t));
192 }
193 if (len > sizeof(error_packet_t) + MAX_ERROR_MESSAGE_LENGTH) {
194 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Error packet message too large: %u (max %zu)", len,
195 sizeof(error_packet_t) + (size_t)MAX_ERROR_MESSAGE_LENGTH);
196 }
197 break;
198 // All crypto handshake packet types - validate using session parameters
210 // Crypto packets are validated by the crypto handshake context
211 // This is just a basic sanity check for extremely large packets
212 if (len > 65536) { // 64KB should be enough for even large post-quantum crypto packets
213 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Crypto packet too large: %u bytes (max 65536)", len);
214 }
215 // Note: Proper size validation is done in crypto_handshake_validate_packet_size()
216 // which uses the session's crypto parameters for accurate validation
217 break;
218 // ACIP protocol packets (Discovery Service)
236 // ACIP packets - basic size validation
237 // Discovery service packets can vary in size (variable-length strings, etc.)
238 if (len > 65536) { // 64KB max for discovery packets
239 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "ACIP packet too large: %u bytes (max 65536)", len);
240 }
241 break;
242 default:
243 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Unknown packet type: %u", type);
244 }
245
246 // Return parsed values
247 *pkt_type = type;
248 *pkt_len = len;
249 *expected_crc = crc;
250
251 return ASCIICHAT_OK;
252}
253
261asciichat_error_t packet_validate_crc32(const void *data, size_t len, uint32_t expected_crc) {
262 if (!data && len > 0) {
263 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: data=%p but len=%zu", data, len);
264 }
265
266 if (len == 0) {
267 // Empty packets should have CRC32 of 0
268 if (expected_crc != 0) {
269 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid CRC32 for empty packet: 0x%x (expected 0)", expected_crc);
270 }
271 return 0;
272 }
273
274 uint32_t calculated_crc = asciichat_crc32(data, len);
275 if (calculated_crc != expected_crc) {
276 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "CRC32 mismatch: calculated 0x%x, expected 0x%x", calculated_crc,
277 expected_crc);
278 }
279
280 return ASCIICHAT_OK;
281}
282
291asciichat_error_t packet_send(socket_t sockfd, packet_type_t type, const void *data, size_t len) {
292 if (sockfd == INVALID_SOCKET_VALUE) {
293 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid socket descriptor");
294 }
295
296 if (len > MAX_PACKET_SIZE) {
297 return SET_ERRNO(ERROR_NETWORK_SIZE, "Packet too large: %zu > %d", len, MAX_PACKET_SIZE);
298 }
299
301 .type = HOST_TO_NET_U16((uint16_t)type),
302 .length = HOST_TO_NET_U32((uint32_t)len),
303 .crc32 = HOST_TO_NET_U32(len > 0 ? asciichat_crc32(data, len) : 0),
304 .client_id = HOST_TO_NET_U32(0)}; // Always initialize client_id to 0 in network byte order
305
306 // Calculate timeout based on packet size
307 int timeout = calculate_packet_timeout(len);
308
309 // Send header first
310 ssize_t sent = send_with_timeout(sockfd, &header, sizeof(header), timeout);
311 if (sent < 0) {
312 // Error context is already set by send_with_timeout
313 return ERROR_NETWORK;
314 }
315 if ((size_t)sent != sizeof(header)) {
316 return SET_ERRNO(ERROR_NETWORK, "Failed to fully send packet header. Sent %zd/%zu bytes", sent, sizeof(header));
317 }
318
319 // Send payload if present
320 if (len > 0 && data) {
321 // Check socket validity before sending payload to avoid race conditions
322 if (!socket_is_valid(sockfd)) {
323 return SET_ERRNO(ERROR_NETWORK, "Socket became invalid between header and payload send");
324 }
325 sent = send_with_timeout(sockfd, data, len, timeout);
326 // Check for error first to avoid signed/unsigned comparison issues
327 if (sent < 0) {
328 // Error context is already set by send_with_timeout
329 return ERROR_NETWORK;
330 }
331 if ((size_t)sent != len) {
332 return SET_ERRNO(ERROR_NETWORK, "Failed to fully send packet payload. Sent %zd/%zu bytes", sent, len);
333 }
334 }
335
336#ifdef DEBUG_NETWORK
337 log_debug("Sent packet type=%d, len=%zu, errno=%d (%s)", type, len, errno, SAFE_STRERROR(errno));
338#endif
339
340 return 0;
341}
342
351asciichat_error_t packet_receive(socket_t sockfd, packet_type_t *type, void **data, size_t *len) {
352 if (sockfd == INVALID_SOCKET_VALUE) {
353 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid socket descriptor");
354 }
355 if (!type || !data || !len) {
356 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: type=%p, data=%p, len=%p", type, data, len);
357 }
358
359 // Read packet header into memory from network socket
360 packet_header_t header;
361 ssize_t received =
362 recv_with_timeout(sockfd, &header, sizeof(header), network_is_test_environment() ? 1 : RECV_TIMEOUT);
363 if (received < 0) {
364 // Error context is already set by recv_with_timeout
365 return ERROR_NETWORK;
366 }
367 if ((size_t)received != sizeof(header)) {
368 if (received == 0) {
369 log_warn("Connection closed while reading packet header");
370 return SET_ERRNO(ERROR_NETWORK, "Connection closed by peer while reading packet header");
371 }
372
373 return SET_ERRNO(ERROR_NETWORK, "Partial packet header received: %zd/%zu bytes", received, sizeof(header));
374 }
375
376 // Validate packet header
377 uint16_t pkt_type;
378 uint32_t pkt_len;
379 uint32_t expected_crc;
380 if (packet_validate_header(&header, &pkt_type, &pkt_len, &expected_crc) != ASCIICHAT_OK) {
381 // Error context is already set by packet_validate_header
383 }
384
385 // Allocate buffer for payload
386 void *payload = NULL;
387 if (pkt_len > 0) {
388 payload = buffer_pool_alloc(NULL, pkt_len);
389
390 // Use adaptive timeout for large packets
391 int recv_timeout = network_is_test_environment() ? 1 : calculate_packet_timeout(pkt_len);
392 received = recv_with_timeout(sockfd, payload, pkt_len, recv_timeout);
393 if (received < 0) {
394 buffer_pool_free(NULL, payload, pkt_len);
395 return SET_ERRNO_SYS(ERROR_NETWORK, "Failed to receive packet payload");
396 }
397 if (received != (ssize_t)pkt_len) {
398 buffer_pool_free(NULL, payload, pkt_len);
399 return SET_ERRNO(ERROR_NETWORK, "Partial packet payload received: %zd/%u bytes", received, pkt_len);
400 }
401
402 // Validate CRC32
403 if (packet_validate_crc32(payload, pkt_len, expected_crc) != ASCIICHAT_OK) {
404 buffer_pool_free(NULL, payload, pkt_len);
405 // Error context is already set by packet_validate_crc32
407 }
408 }
409
410 // Return results
411 *type = (packet_type_t)pkt_type;
412 *data = payload;
413 *len = pkt_len;
414
415 return ASCIICHAT_OK;
416}
417
418/* ============================================================================
419 * High-Level Secure Packet Functions
420 * ============================================================================
421 * These functions handle encryption and compression for secure communication.
422 */
423
433asciichat_error_t send_packet_secure(socket_t sockfd, packet_type_t type, const void *data, size_t len,
434 crypto_context_t *crypto_ctx) {
435 if (len > MAX_PACKET_SIZE) {
436 return SET_ERRNO(ERROR_NETWORK_SIZE, "Packet too large: %zu > %d", len, MAX_PACKET_SIZE);
437 }
438
439 // Handshake packets are ALWAYS sent unencrypted
440 if (packet_is_handshake_type(type)) {
441 return packet_send(sockfd, type, data, len);
442 }
443
444 // Apply compression if beneficial for large packets
445 const void *final_data = data;
446 size_t final_len = len;
447 void *compressed_data = NULL;
448
449 // Skip compression for pre-compressed data (Opus audio) or if --no-compress flag is set
450 bool should_skip_compression = packet_is_precompressed(type) || GET_OPTION(no_compress);
451 if (!should_skip_compression && len > COMPRESSION_MIN_SIZE && should_compress(len, len)) {
452 void *temp_compressed = NULL;
453 size_t compressed_size = 0;
454
455 // Use configured compression level from options (default: 1 for fastest compression)
456 int compression_level = (GET_OPTION(compression_level) > 0) ? GET_OPTION(compression_level) : 1;
457 asciichat_error_t compress_result = compress_data(data, len, &temp_compressed, &compressed_size, compression_level);
458 if (compress_result == ASCIICHAT_OK) {
459 double ratio = (double)compressed_size / (double)len;
460 if (ratio < COMPRESSION_RATIO_THRESHOLD) {
461 final_data = temp_compressed;
462 final_len = compressed_size;
463 compressed_data = temp_compressed;
464 log_debug("Compressed packet: %zu -> %zu bytes (%.1f%%)", len, compressed_size, ratio * 100.0);
465 } else {
466 SAFE_FREE(temp_compressed);
467 }
468 }
469 }
470
471 // If no crypto context or crypto not ready, send unencrypted
472 bool ready = crypto_ctx ? crypto_is_ready(crypto_ctx) : false;
473 if (!crypto_ctx || !ready) {
474 log_warn_every(LOG_RATE_FAST, "CRYPTO_DEBUG: Sending packet type %d UNENCRYPTED (crypto_ctx=%p, ready=%d)", type,
475 (void *)crypto_ctx, ready);
476 asciichat_error_t result = packet_send(sockfd, type, final_data, final_len);
477 if (compressed_data) {
478 SAFE_FREE(compressed_data);
479 }
480 if (result != ASCIICHAT_OK) {
481 SET_ERRNO(ERROR_NETWORK, "Failed to send packet: %s", asciichat_error_string(result));
482 }
483 return result;
484 }
485
486 // Encrypt the packet: create header + payload, encrypt everything, wrap in PACKET_TYPE_ENCRYPTED
488 .type = HOST_TO_NET_U16((uint16_t)type),
489 .length = HOST_TO_NET_U32((uint32_t)final_len),
490 .crc32 = HOST_TO_NET_U32(final_len > 0 ? asciichat_crc32(final_data, final_len) : 0),
491 .client_id = HOST_TO_NET_U32(0)}; // Always 0 - client_id is not used in practice
492
493 // Combine header + payload for encryption
494 // Check for integer overflow before addition
495 if (final_len > SIZE_MAX - sizeof(header)) {
496 if (compressed_data) {
497 SAFE_FREE(compressed_data);
498 }
499 return SET_ERRNO(ERROR_NETWORK_SIZE, "Packet too large: would overflow plaintext buffer size");
500 }
501 size_t plaintext_len = sizeof(header) + final_len;
502 uint8_t *plaintext = buffer_pool_alloc(NULL, plaintext_len);
503 if (!plaintext) {
504 if (compressed_data) {
505 SAFE_FREE(compressed_data);
506 }
507 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for plaintext packet");
508 }
509
510 memcpy(plaintext, &header, sizeof(header));
511 if (final_len > 0 && final_data) {
512 memcpy(plaintext + sizeof(header), final_data, final_len);
513 }
514
515 // Encrypt
516 // Check for integer overflow before calculating ciphertext size
517 if (plaintext_len > SIZE_MAX - CRYPTO_NONCE_SIZE - CRYPTO_MAC_SIZE) {
518 buffer_pool_free(NULL, plaintext, plaintext_len);
519 if (compressed_data) {
520 SAFE_FREE(compressed_data);
521 }
522 return SET_ERRNO(ERROR_NETWORK_SIZE, "Packet too large: would overflow ciphertext buffer size");
523 }
524 size_t ciphertext_size = plaintext_len + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE;
525 uint8_t *ciphertext = buffer_pool_alloc(NULL, ciphertext_size);
526 if (!ciphertext) {
527 buffer_pool_free(NULL, plaintext, plaintext_len);
528 if (compressed_data) {
529 SAFE_FREE(compressed_data);
530 }
531 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for ciphertext");
532 }
533
534 size_t ciphertext_len;
535 crypto_result_t result =
536 crypto_encrypt(crypto_ctx, plaintext, plaintext_len, ciphertext, ciphertext_size, &ciphertext_len);
537 buffer_pool_free(NULL, plaintext, plaintext_len);
538
539 if (result != CRYPTO_OK) {
540 buffer_pool_free(NULL, ciphertext, ciphertext_size);
541 if (compressed_data) {
542 SAFE_FREE(compressed_data);
543 }
544 return SET_ERRNO(ERROR_CRYPTO, "Failed to encrypt packet: %s", crypto_result_to_string(result));
545 }
546
547 // Send as PACKET_TYPE_ENCRYPTED
548 log_debug_every(LOG_RATE_SLOW, "CRYPTO_DEBUG: Sending encrypted packet (original type %d as PACKET_TYPE_ENCRYPTED)",
549 type);
550 asciichat_error_t send_result = packet_send(sockfd, PACKET_TYPE_ENCRYPTED, ciphertext, ciphertext_len);
551 buffer_pool_free(NULL, ciphertext, ciphertext_size);
552
553 if (compressed_data) {
554 SAFE_FREE(compressed_data);
555 }
556
557 return send_result;
558}
559
568packet_recv_result_t receive_packet_secure(socket_t sockfd, void *crypto_ctx, bool enforce_encryption,
569 packet_envelope_t *envelope) {
570
571 if (!envelope) {
572 SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: envelope=%p", envelope);
573 return PACKET_RECV_ERROR;
574 }
575
576 // Initialize envelope
577 memset(envelope, 0, sizeof(*envelope));
578
579 // Receive packet header
580 packet_header_t header;
581 ssize_t received =
582 recv_with_timeout(sockfd, &header, sizeof(header), network_is_test_environment() ? 1 : RECV_TIMEOUT);
583
584 // Check for errors first (before comparing signed with unsigned)
585 if (received < 0) {
586 SET_ERRNO(ERROR_NETWORK, "Failed to receive packet header: %zd/%zu bytes", received, sizeof(header));
587 return PACKET_RECV_ERROR;
588 }
589
590 if (received == 0) {
591 return PACKET_RECV_EOF;
592 }
593
594 if ((size_t)received != sizeof(header)) {
595 SET_ERRNO(ERROR_NETWORK, "Failed to receive packet header: %zd/%zu bytes", received, sizeof(header));
596 return PACKET_RECV_ERROR;
597 }
598
599 // Convert from network byte order
600 uint32_t magic = NET_TO_HOST_U32(header.magic);
601 uint16_t pkt_type = NET_TO_HOST_U16(header.type);
602 uint32_t pkt_len = NET_TO_HOST_U32(header.length);
603 uint32_t expected_crc = NET_TO_HOST_U32(header.crc32);
604
605 // Validate magic number
606 if (magic != PACKET_MAGIC) {
607 SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid packet magic: 0x%x (expected 0x%x)", magic, PACKET_MAGIC);
608 return PACKET_RECV_ERROR;
609 }
610
611 // Validate packet size
612 if (pkt_len > MAX_PACKET_SIZE) {
613 SET_ERRNO(ERROR_NETWORK_SIZE, "Packet too large: %u > %d", pkt_len, MAX_PACKET_SIZE);
614 return PACKET_RECV_ERROR;
615 }
616
617 // Handle encrypted packets
618 if (pkt_type == PACKET_TYPE_ENCRYPTED) {
619 if (!crypto_ctx) {
620 SET_ERRNO(ERROR_CRYPTO, "Received encrypted packet but no crypto context");
621 return PACKET_RECV_ERROR;
622 }
623
624 // Read encrypted payload
625 uint8_t *ciphertext = buffer_pool_alloc(NULL, pkt_len);
626 if (!ciphertext) {
627 SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for ciphertext");
628 return PACKET_RECV_ERROR;
629 }
630
631 int recv_timeout = network_is_test_environment() ? 1 : calculate_packet_timeout(pkt_len);
632 received = recv_with_timeout(sockfd, ciphertext, pkt_len, recv_timeout);
633 if (received != (ssize_t)pkt_len) {
634 SET_ERRNO(ERROR_NETWORK, "Failed to receive encrypted payload: %zd/%u bytes", received, pkt_len);
635 buffer_pool_free(NULL, ciphertext, pkt_len);
636 return PACKET_RECV_ERROR;
637 }
638
639 // Decrypt - allocate plaintext buffer with extra space
640 // pkt_len is already validated to be <= MAX_PACKET_SIZE, so adding 1024 cannot overflow
641 size_t plaintext_size = (size_t)pkt_len + 1024;
642 uint8_t *plaintext = buffer_pool_alloc(NULL, plaintext_size);
643 if (!plaintext) {
644 SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for plaintext");
645 buffer_pool_free(NULL, ciphertext, pkt_len);
646 return PACKET_RECV_ERROR;
647 }
648
649 size_t plaintext_len;
650 crypto_result_t result = crypto_decrypt(crypto_ctx, ciphertext, pkt_len, plaintext, plaintext_size, &plaintext_len);
651 buffer_pool_free(NULL, ciphertext, pkt_len);
652
653 if (result != CRYPTO_OK) {
654 SET_ERRNO(ERROR_CRYPTO, "Failed to decrypt packet: %s", crypto_result_to_string(result));
655 buffer_pool_free(NULL, plaintext, plaintext_size);
656 return PACKET_RECV_ERROR;
657 }
658
659 if (plaintext_len < sizeof(packet_header_t)) {
660 SET_ERRNO(ERROR_CRYPTO, "Decrypted packet too small: %zu < %zu", plaintext_len, sizeof(packet_header_t));
661 buffer_pool_free(NULL, plaintext, plaintext_size);
662 return PACKET_RECV_ERROR;
663 }
664
665 // Parse decrypted header
666 packet_header_t *decrypted_header = (packet_header_t *)plaintext;
667 pkt_type = NET_TO_HOST_U16(decrypted_header->type);
668 pkt_len = NET_TO_HOST_U32(decrypted_header->length);
669 expected_crc = NET_TO_HOST_U32(decrypted_header->crc32);
670
671 // Extract payload
672 size_t payload_len = plaintext_len - sizeof(packet_header_t);
673 if (payload_len != pkt_len) {
674 SET_ERRNO(ERROR_CRYPTO, "Decrypted payload size mismatch: %zu != %u", payload_len, pkt_len);
675 buffer_pool_free(NULL, plaintext, plaintext_size);
676 return PACKET_RECV_ERROR;
677 }
678
679 // Verify CRC
680 if (pkt_len > 0) {
681 uint32_t actual_crc = asciichat_crc32(plaintext + sizeof(packet_header_t), pkt_len);
682 if (actual_crc != expected_crc) {
683 SET_ERRNO(ERROR_CRYPTO, "Decrypted packet CRC mismatch: 0x%x != 0x%x", actual_crc, expected_crc);
684 buffer_pool_free(NULL, plaintext, plaintext_size);
685 return PACKET_RECV_ERROR;
686 }
687 }
688
689 // Set envelope
690 envelope->type = (packet_type_t)pkt_type;
691 envelope->data = plaintext + sizeof(packet_header_t);
692 envelope->len = pkt_len;
693 envelope->allocated_buffer = plaintext;
694 envelope->allocated_size = plaintext_size;
695
696 return PACKET_RECV_SUCCESS;
697 }
698
699 // Handle unencrypted packets
700 if (enforce_encryption && !packet_is_handshake_type(pkt_type)) {
701 SET_ERRNO(ERROR_CRYPTO, "Received unencrypted packet type %d but encryption is required", pkt_type);
702 return PACKET_RECV_ERROR;
703 }
704
705 // Read payload
706 if (pkt_len > 0) {
707 uint8_t *payload = buffer_pool_alloc(NULL, pkt_len);
708 if (!payload) {
709 SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for payload");
710 return PACKET_RECV_ERROR;
711 }
712
713 int recv_timeout = network_is_test_environment() ? 1 : calculate_packet_timeout(pkt_len);
714 received = recv_with_timeout(sockfd, payload, pkt_len, recv_timeout);
715 if (received != (ssize_t)pkt_len) {
716 SET_ERRNO(ERROR_NETWORK, "Failed to receive payload: %zd/%u bytes", received, pkt_len);
717 buffer_pool_free(NULL, payload, pkt_len);
718 return PACKET_RECV_ERROR;
719 }
720
721 // Verify CRC
722 uint32_t actual_crc = asciichat_crc32(payload, pkt_len);
723 if (actual_crc != expected_crc) {
724 SET_ERRNO(ERROR_NETWORK, "Packet CRC mismatch: 0x%x != 0x%x", actual_crc, expected_crc);
725 buffer_pool_free(NULL, payload, pkt_len);
726 return PACKET_RECV_ERROR;
727 }
728
729 envelope->data = payload;
730 envelope->allocated_buffer = payload;
731 envelope->allocated_size = pkt_len;
732 }
733
734 envelope->type = (packet_type_t)pkt_type;
735 envelope->len = pkt_len;
736
737 return PACKET_RECV_SUCCESS;
738}
739
740/* ============================================================================
741 * Basic Packet Functions (Non-Secure)
742 * ============================================================================
743 * These are the basic packet send/receive functions without encryption.
744 */
745
754int send_packet(socket_t sockfd, packet_type_t type, const void *data, size_t len) {
755 asciichat_error_t result = packet_send(sockfd, type, data, len);
756 return result == ASCIICHAT_OK ? 0 : -1;
757}
758
767int receive_packet(socket_t sockfd, packet_type_t *type, void **data, size_t *len) {
768 asciichat_error_t result = packet_receive(sockfd, type, data, len);
769 return result == ASCIICHAT_OK ? 0 : -1;
770}
771
772/* ============================================================================
773 * Protocol Message Functions
774 * ============================================================================
775 * These functions send specific protocol messages.
776 */
777
784 asciichat_error_t result = send_packet(sockfd, PACKET_TYPE_PING, NULL, 0);
785 return result == ASCIICHAT_OK ? 0 : -1;
786}
787
794 asciichat_error_t result = send_packet(sockfd, PACKET_TYPE_PONG, NULL, 0);
795 return result == ASCIICHAT_OK ? 0 : -1;
796}
797
804 return send_packet(sockfd, PACKET_TYPE_CLEAR_CONSOLE, NULL, 0);
805}
806
808 const char *message) {
809 if (sockfd == INVALID_SOCKET_VALUE) {
810 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid socket descriptor");
811 }
812
813 if (!message) {
814 message = "";
815 }
816
817 size_t message_len = strnlen(message, MAX_ERROR_MESSAGE_LENGTH);
818 if (message_len == MAX_ERROR_MESSAGE_LENGTH) {
819 log_warn("Error message truncated to %zu bytes", (size_t)MAX_ERROR_MESSAGE_LENGTH);
820 }
821
822 size_t payload_len = sizeof(error_packet_t) + message_len;
823 uint8_t *payload = SAFE_MALLOC(payload_len, uint8_t *);
824 if (!payload) {
825 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate %zu bytes for error packet", payload_len);
826 }
827
828 error_packet_t *packet = (error_packet_t *)payload;
830 packet->message_length = HOST_TO_NET_U32((uint32_t)message_len);
831
832 if (message_len > 0) {
833 memcpy(payload + sizeof(error_packet_t), message, message_len);
834 }
835
836 bool encryption_ready = crypto_ctx && crypto_is_ready(crypto_ctx);
837 asciichat_error_t send_result;
838
839 if (encryption_ready) {
840 send_result =
841 send_packet_secure(sockfd, PACKET_TYPE_ERROR_MESSAGE, payload, payload_len, (crypto_context_t *)crypto_ctx);
842 } else {
843 send_result = packet_send(sockfd, PACKET_TYPE_ERROR_MESSAGE, payload, payload_len);
844 }
845 SAFE_FREE(payload);
846
847 if (send_result != ASCIICHAT_OK) {
848 return SET_ERRNO(ERROR_NETWORK, "Failed to send error packet: %s", asciichat_error_string(send_result));
849 }
850
851 return ASCIICHAT_OK;
852}
853
854asciichat_error_t packet_parse_error_message(const void *data, size_t len, asciichat_error_t *out_error_code,
855 char *message_buffer, size_t message_buffer_size,
856 size_t *out_message_length) {
857 if (!data || len < sizeof(error_packet_t) || !out_error_code || !message_buffer || message_buffer_size == 0) {
859 "Invalid parameters: data=%p len=%zu out_error_code=%p message_buffer=%p buffer_size=%zu", data,
860 len, out_error_code, message_buffer, message_buffer_size);
861 }
862
863 const error_packet_t *packet = (const error_packet_t *)data;
864 uint32_t raw_error_code = NET_TO_HOST_U32(packet->error_code);
865 uint32_t raw_message_length = NET_TO_HOST_U32(packet->message_length);
866
867 if (raw_message_length > MAX_ERROR_MESSAGE_LENGTH) {
868 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Error message length too large: %u", raw_message_length);
869 }
870
871 size_t total_required = sizeof(error_packet_t) + (size_t)raw_message_length;
872 if (total_required > len) {
873 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Error packet truncated: expected %zu bytes, have %zu", total_required,
874 len);
875 }
876
877 const uint8_t *message_bytes = (const uint8_t *)data + sizeof(error_packet_t);
878 size_t copy_len = raw_message_length;
879 if (copy_len >= message_buffer_size) {
880 copy_len = message_buffer_size - 1;
881 }
882
883 if (copy_len > 0) {
884 memcpy(message_buffer, message_bytes, copy_len);
885 }
886 message_buffer[copy_len] = '\0';
887
888 if (out_message_length) {
889 *out_message_length = raw_message_length;
890 }
891
892 *out_error_code = (asciichat_error_t)raw_error_code;
893 return ASCIICHAT_OK;
894}
895
897 remote_log_direction_t direction, uint16_t flags, const char *message) {
898 if (sockfd == INVALID_SOCKET_VALUE) {
899 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid socket descriptor");
900 }
901
902 if (level < LOG_DEV || level > LOG_FATAL) {
903 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid log level: %d", level);
904 }
905
906 const char *safe_message = message ? message : "";
907 bool truncated = false;
908 size_t message_len = strnlen(safe_message, MAX_REMOTE_LOG_MESSAGE_LENGTH);
909 if (message_len == MAX_REMOTE_LOG_MESSAGE_LENGTH && safe_message[message_len] != '\0') {
910 truncated = true;
911 }
912
913 size_t payload_len = sizeof(remote_log_packet_t) + message_len;
914 uint8_t *payload = SAFE_MALLOC(payload_len, uint8_t *);
915 if (!payload) {
916 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate %zu bytes for remote log packet", payload_len);
917 }
918
919 remote_log_packet_t *packet = (remote_log_packet_t *)payload;
920 packet->log_level = (uint8_t)level;
921 packet->direction = (uint8_t)direction;
922 uint16_t final_flags = flags;
923 if (truncated) {
924 final_flags |= REMOTE_LOG_FLAG_TRUNCATED;
925 }
926 packet->flags = HOST_TO_NET_U16(final_flags);
927 packet->message_length = HOST_TO_NET_U32((uint32_t)message_len);
928
929 if (message_len > 0) {
930 memcpy(payload + sizeof(remote_log_packet_t), safe_message, message_len);
931 }
932
933 bool encryption_ready = crypto_ctx && crypto_is_ready(crypto_ctx);
934 asciichat_error_t send_result;
935
936 if (encryption_ready) {
937 int secure_result =
938 send_packet_secure(sockfd, PACKET_TYPE_REMOTE_LOG, payload, payload_len, (crypto_context_t *)crypto_ctx);
939 send_result = secure_result == 0 ? ASCIICHAT_OK : ERROR_NETWORK;
940 } else {
941 send_result = packet_send(sockfd, PACKET_TYPE_REMOTE_LOG, payload, payload_len);
942 }
943
944 SAFE_FREE(payload);
945
946 if (send_result != ASCIICHAT_OK) {
947 return SET_ERRNO(ERROR_NETWORK, "Failed to send remote log packet: %d", send_result);
948 }
949
950 return ASCIICHAT_OK;
951}
952
953asciichat_error_t packet_parse_remote_log(const void *data, size_t len, log_level_t *out_level,
954 remote_log_direction_t *out_direction, uint16_t *out_flags,
955 char *message_buffer, size_t message_buffer_size,
956 size_t *out_message_length) {
957 if (!data || len < sizeof(remote_log_packet_t) || !out_level || !out_direction || !out_flags || !message_buffer ||
958 message_buffer_size == 0) {
959 return SET_ERRNO(
961 "Invalid parameters: data=%p len=%zu out_level=%p out_direction=%p out_flags=%p buffer=%p size=%zu", data, len,
962 out_level, out_direction, out_flags, message_buffer, message_buffer_size);
963 }
964
965 const remote_log_packet_t *packet = (const remote_log_packet_t *)data;
966 uint8_t raw_level = packet->log_level;
967 if (raw_level > LOG_FATAL) {
968 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid remote log level: %u", raw_level);
969 }
970 *out_level = (log_level_t)raw_level;
971
972 uint8_t raw_direction = packet->direction;
973 if (raw_direction > REMOTE_LOG_DIRECTION_CLIENT_TO_SERVER) {
974 raw_direction = REMOTE_LOG_DIRECTION_UNKNOWN;
975 }
976 *out_direction = (remote_log_direction_t)raw_direction;
977
978 uint16_t raw_flags = NET_TO_HOST_U16(packet->flags);
979 *out_flags = raw_flags;
980
981 uint32_t raw_message_length = NET_TO_HOST_U32(packet->message_length);
982 if (raw_message_length > MAX_REMOTE_LOG_MESSAGE_LENGTH) {
983 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Remote log message length too large: %u", raw_message_length);
984 }
985
986 size_t total_required = sizeof(remote_log_packet_t) + (size_t)raw_message_length;
987 if (total_required > len) {
988 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Remote log packet truncated: expected %zu bytes, have %zu",
989 total_required, len);
990 }
991
992 const uint8_t *message_bytes = (const uint8_t *)data + sizeof(remote_log_packet_t);
993 size_t copy_len = raw_message_length;
994 if (copy_len >= message_buffer_size) {
995 copy_len = message_buffer_size - 1;
996 }
997
998 if (copy_len > 0) {
999 memcpy(message_buffer, message_bytes, copy_len);
1000 }
1001 message_buffer[copy_len] = '\0';
1002
1003 if (out_message_length) {
1004 *out_message_length = raw_message_length;
1005 }
1006
1007 return ASCIICHAT_OK;
1008}
1009
1017 if (!version) {
1018 SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: version=%p", version);
1019 return -1;
1020 }
1021 return send_packet(sockfd, PACKET_TYPE_PROTOCOL_VERSION, version, sizeof(*version));
1022}
1023
1031 if (!caps) {
1032 SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: caps=%p", caps);
1033 return -1;
1034 }
1035 return send_packet(sockfd, PACKET_TYPE_CRYPTO_CAPABILITIES, caps, sizeof(*caps));
1036}
1037
1045 if (!params) {
1046 SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: params=%p", params);
1047 return -1;
1048 }
1049
1050 // Create a copy and convert uint16_t fields to network byte order
1051 crypto_parameters_packet_t net_params = *params;
1052 log_debug("NETWORK_DEBUG: Before htons: kex=%u, auth=%u, sig=%u, secret=%u", params->kex_public_key_size,
1053 params->auth_public_key_size, params->signature_size, params->shared_secret_size);
1056 net_params.signature_size = HOST_TO_NET_U16(params->signature_size);
1058 log_debug("NETWORK_DEBUG: After htons: kex=%u, auth=%u, sig=%u, secret=%u", net_params.kex_public_key_size,
1059 net_params.auth_public_key_size, net_params.signature_size, net_params.shared_secret_size);
1060
1061 return send_packet(sockfd, PACKET_TYPE_CRYPTO_PARAMETERS, &net_params, sizeof(net_params));
1062}
1063
1064// =============================================================================
1065// Audio Batch Packet Sending
1066// =============================================================================
1067// These functions were moved from lib/network/av.c during refactoring.
1068// They provide socket-level audio packet sending with encryption support.
1069// For transport-agnostic sending, use acip_send_audio_batch() instead.
1070// =============================================================================
1071
1072asciichat_error_t send_audio_batch_packet(socket_t sockfd, const float *samples, int num_samples, int batch_count,
1073 crypto_context_t *crypto_ctx) {
1074 if (!samples || num_samples <= 0 || batch_count <= 0) {
1075 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid audio batch: samples=%p, num_samples=%d, batch_count=%d", samples,
1076 num_samples, batch_count);
1077 }
1078
1079 // Build batch header
1080 audio_batch_packet_t header;
1081 header.batch_count = HOST_TO_NET_U32((u_long)batch_count);
1082 header.total_samples = HOST_TO_NET_U32((u_long)num_samples);
1083 header.sample_rate = HOST_TO_NET_U32(AUDIO_SAMPLE_RATE); // Use system-defined sample rate
1084 header.channels = HOST_TO_NET_U32(1UL); // Mono for now
1085
1086 // Calculate total payload size
1087 size_t data_size = (size_t)num_samples * sizeof(uint32_t); // Send as 32-bit integers for portability
1088 size_t total_size = sizeof(header) + data_size;
1089
1090 // Allocate buffer for header + data
1091 uint8_t *buffer = buffer_pool_alloc(NULL, total_size);
1092 if (!buffer) {
1093 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for audio batch packet");
1094 }
1095
1096 // Copy header
1097 memcpy(buffer, &header, sizeof(header));
1098
1099 // Convert floats to network byte order (as 32-bit integers with scaling)
1100 // Floats in range [-1.0, 1.0] are scaled to INT32 range for transmission
1101 // Use memcpy to avoid alignment issues when casting from uint8_t* to uint32_t*
1102 uint8_t *sample_data_ptr = buffer + sizeof(header);
1103 for (int i = 0; i < num_samples; i++) {
1104 // Clamp samples to [-1.0, 1.0] range before scaling to prevent overflow
1105 float clamped_sample = samples[i];
1106 if (clamped_sample > 1.0f)
1107 clamped_sample = 1.0f;
1108 if (clamped_sample < -1.0f)
1109 clamped_sample = -1.0f;
1110
1111 // Scale float [-1.0, 1.0] to int32 range and convert to network byte order
1112 int32_t scaled = (int32_t)(clamped_sample * 2147483647.0f);
1113 uint32_t network_value = HOST_TO_NET_U32((uint32_t)scaled);
1114 memcpy(sample_data_ptr + (size_t)i * sizeof(uint32_t), &network_value, sizeof(uint32_t));
1115 }
1116
1117#ifndef NDEBUG
1118 // Debug: Log first few samples to verify conversion
1119 static int send_count = 0;
1120 send_count++;
1121 if (send_count % 100 == 0) {
1122 log_info("SEND: samples[0]=%.6f, samples[1]=%.6f, samples[2]=%.6f", (double)samples[0], (double)samples[1],
1123 (double)samples[2]);
1124 log_info("SEND: scaled[0]=%d, scaled[1]=%d, scaled[2]=%d", (int32_t)(samples[0] * 2147483647.0f),
1125 (int32_t)(samples[1] * 2147483647.0f), (int32_t)(samples[2] * 2147483647.0f));
1126 }
1127#endif
1128
1129 // Send packet with encryption support
1130 asciichat_error_t result = send_packet_secure(sockfd, PACKET_TYPE_AUDIO_BATCH, buffer, total_size, crypto_ctx);
1131 buffer_pool_free(NULL, buffer, total_size);
1132
1133 return result;
1134}
1135
1136asciichat_error_t av_send_audio_opus_batch(socket_t sockfd, const uint8_t *opus_data, size_t opus_size,
1137 const uint16_t *frame_sizes, int sample_rate, int frame_duration,
1138 int frame_count, crypto_context_t *crypto_ctx) {
1139 if (!opus_data || opus_size == 0 || !frame_sizes || sample_rate <= 0 || frame_duration <= 0 || frame_count <= 0) {
1141 "Invalid Opus batch parameters: opus_data=%p, opus_size=%zu, frame_sizes=%p, sample_rate=%d, "
1142 "frame_duration=%d, frame_count=%d",
1143 (const void *)opus_data, opus_size, (const void *)frame_sizes, sample_rate, frame_duration,
1144 frame_count);
1145 }
1146
1147 // Validate frame_count to prevent integer overflow in size calculations
1148 // Max reasonable frames per batch: ~1 second of 10ms frames = 100 frames
1149 if (frame_count > 1000) {
1150 return SET_ERRNO(ERROR_INVALID_PARAM, "Too many Opus frames: %d (max 1000)", frame_count);
1151 }
1152
1153 // Allocate buffer for header + frame sizes + encoded data
1154 size_t header_size = 16; // sample_rate (4), frame_duration (4), frame_count (4), reserved (4)
1155 size_t frame_sizes_bytes = (size_t)frame_count * sizeof(uint16_t);
1156 size_t total_size = header_size + frame_sizes_bytes + opus_size;
1157 void *packet_data = buffer_pool_alloc(NULL, total_size);
1158 if (!packet_data) {
1159 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for Opus batch packet: %zu bytes", total_size);
1160 }
1161
1162 // Write header (network byte order for cross-platform compatibility)
1163 uint8_t *buf = (uint8_t *)packet_data;
1164 uint32_t sr = HOST_TO_NET_U32((uint32_t)sample_rate);
1165 uint32_t fd = HOST_TO_NET_U32((uint32_t)frame_duration);
1166 uint32_t fc = HOST_TO_NET_U32((uint32_t)frame_count);
1167 memcpy(buf, &sr, 4);
1168 memcpy(buf + 4, &fd, 4);
1169 memcpy(buf + 8, &fc, 4);
1170 memset(buf + 12, 0, 4); // Reserved
1171
1172 // Write frame sizes array (convert each to network byte order)
1173 uint16_t *frame_sizes_out = (uint16_t *)(buf + header_size);
1174 for (int i = 0; i < frame_count; i++) {
1175 frame_sizes_out[i] = HOST_TO_NET_U16(frame_sizes[i]);
1176 }
1177
1178 // Copy Opus data
1179 memcpy(buf + header_size + frame_sizes_bytes, opus_data, opus_size);
1180
1181 // Send packet (with encryption support)
1182 asciichat_error_t result =
1183 send_packet_secure(sockfd, PACKET_TYPE_AUDIO_OPUS_BATCH, packet_data, total_size, crypto_ctx);
1184
1185 // Clean up
1186 buffer_pool_free(NULL, packet_data, total_size);
1187
1188 return result;
1189}
1190
1191asciichat_error_t send_ascii_frame_packet(socket_t sockfd, const char *frame_data, size_t frame_size) {
1192 if (!frame_data || frame_size == 0) {
1193 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: frame_data=%p, frame_size=%zu", frame_data, frame_size);
1194 }
1195
1196 // Create ASCII frame packet
1197 ascii_frame_packet_t packet;
1198 packet.width = 0; // Will be set by receiver
1199 packet.height = 0; // Will be set by receiver
1200 packet.original_size = (uint32_t)frame_size;
1201 packet.compressed_size = 0;
1202 packet.checksum = 0;
1203 packet.flags = 0;
1204
1205 // Calculate total packet size with overflow checking
1206 size_t total_size;
1207 if (checked_size_add(sizeof(ascii_frame_packet_t), frame_size, &total_size) != ASCIICHAT_OK) {
1208 return SET_ERRNO(ERROR_INVALID_PARAM, "Packet size calculation would overflow");
1209 }
1210
1211 // Allocate buffer for complete packet
1212 void *packet_data = buffer_pool_alloc(NULL, total_size);
1213 if (!packet_data) {
1214 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for ASCII frame packet: %zu bytes", total_size);
1215 }
1216
1217 // Copy packet header and frame data
1218 memcpy(packet_data, &packet, sizeof(ascii_frame_packet_t));
1219 memcpy((char *)packet_data + sizeof(ascii_frame_packet_t), frame_data, frame_size);
1220
1221 // Send packet
1222 asciichat_error_t result = packet_send(sockfd, PACKET_TYPE_ASCII_FRAME, packet_data, total_size);
1223
1224 // Clean up
1225 buffer_pool_free(NULL, packet_data, total_size);
1226
1227 return result;
1228}
1229
1230asciichat_error_t send_image_frame_packet(socket_t sockfd, const void *image_data, uint16_t width, uint16_t height,
1231 uint8_t format) {
1232 if (!image_data || width == 0 || height == 0) {
1233 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: image_data=%p, width=%u, height=%u", image_data, width,
1234 height);
1235 }
1236
1237 // Validate dimensions to prevent integer overflow
1238 // Max reasonable dimensions: 4K (3840x2160) = ~25MB per frame
1239 if (width > 4096 || height > 4096) {
1240 return SET_ERRNO(ERROR_INVALID_PARAM, "Image dimensions too large: %ux%u (max 4096x4096)", width, height);
1241 }
1242
1243 // Create image frame packet
1244 image_frame_packet_t packet;
1245 packet.width = width;
1246 packet.height = height;
1247 packet.pixel_format = format;
1248 packet.compressed_size = 0;
1249 packet.checksum = 0;
1250 packet.timestamp = 0; // Will be set by receiver
1251
1252 // Calculate total packet size
1253 // Cast to size_t before multiplication to prevent integer overflow
1254 // Use overflow-checked multiplication
1255 size_t width_times_height;
1256 if (checked_size_mul((size_t)width, (size_t)height, &width_times_height) != ASCIICHAT_OK) {
1257 return SET_ERRNO(ERROR_BUFFER_OVERFLOW, "Image dimensions too large: %d x %d", width, height);
1258 }
1259
1260 size_t frame_size;
1261 if (checked_size_mul(width_times_height, 3u, &frame_size) != ASCIICHAT_OK) {
1262 return SET_ERRNO(ERROR_BUFFER_OVERFLOW, "Frame size overflow for RGB format");
1263 }
1264
1265 size_t total_size;
1266 if (checked_size_add(sizeof(image_frame_packet_t), frame_size, &total_size) != ASCIICHAT_OK) {
1267 return SET_ERRNO(ERROR_BUFFER_OVERFLOW, "Total packet size overflow");
1268 }
1269
1270 // Allocate buffer for complete packet
1271 void *packet_data = buffer_pool_alloc(NULL, total_size);
1272 if (!packet_data) {
1273 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for image frame packet: %zu bytes", total_size);
1274 }
1275
1276 // Copy packet header and image data
1277 memcpy(packet_data, &packet, sizeof(image_frame_packet_t));
1278 memcpy((char *)packet_data + sizeof(image_frame_packet_t), image_data, frame_size);
1279
1280 // Send packet
1281 asciichat_error_t result = packet_send(sockfd, PACKET_TYPE_IMAGE_FRAME, packet_data, total_size);
1282
1283 // Clean up
1284 buffer_pool_free(NULL, packet_data, total_size);
1285
1286 return result;
1287}
asciichat_error_t error_code
⚠️‼️ Error and/or exit() when things go bad.
🗃️ Lock-Free Unified Memory Buffer Pool with Lazy Allocation
📦 Network Packet Compression Utilities
Hardware-Accelerated CRC32 Checksum Computation.
🔄 Network byte order conversion helpers
#define HOST_TO_NET_U16(val)
Definition endian.h:101
#define HOST_TO_NET_U32(val)
Definition endian.h:71
#define NET_TO_HOST_U16(val)
Definition endian.h:116
#define NET_TO_HOST_U32(val)
Definition endian.h:86
#define AUDIO_SAMPLE_RATE
Audio sample rate (48kHz professional quality, Opus-compatible)
void buffer_pool_free(buffer_pool_t *pool, void *data, size_t size)
Free a buffer back to the pool (lock-free)
void * buffer_pool_alloc(buffer_pool_t *pool, size_t size)
Allocate a buffer from the pool (lock-free fast path)
unsigned short uint16_t
Definition common.h:57
unsigned int uint32_t
Definition common.h:58
#define SAFE_FREE(ptr)
Definition common.h:320
#define SAFE_MALLOC(size, cast)
Definition common.h:208
#define SAFE_STRERROR(errnum)
Definition common.h:385
unsigned char uint8_t
Definition common.h:56
#define COMPRESSION_MIN_SIZE
Minimum packet size to attempt compression (1KB)
Definition compression.h:61
bool should_compress(size_t original_size, size_t compressed_size)
Determine if compression should be used for given data sizes.
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)
Compress data using zstd with configurable compression level.
Definition compression.c:14
#define COMPRESSION_RATIO_THRESHOLD
Compression ratio threshold - only use if <80% original size.
Definition compression.h:58
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)
Encrypt data using XSalsa20-Poly1305.
#define CRYPTO_NONCE_SIZE
Nonce size (XSalsa20)
const char * crypto_result_to_string(crypto_result_t result)
Convert crypto result to human-readable string.
crypto_result_t
Cryptographic operation result codes.
#define CRYPTO_MAC_SIZE
MAC size (Poly1305)
bool crypto_is_ready(const crypto_context_t *ctx)
Check if key exchange is complete and ready for encryption.
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)
Decrypt data using XSalsa20-Poly1305.
@ CRYPTO_OK
#define SET_ERRNO_SYS(code, context_msg,...)
Set error code with custom message and system error context.
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it.
asciichat_error_t
Error and exit codes - unified status values (0-255)
Definition error_codes.h:46
@ ERROR_NETWORK
Definition error_codes.h:69
@ ERROR_NETWORK_PROTOCOL
Definition error_codes.h:73
@ ERROR_MEMORY
Definition error_codes.h:53
@ ASCIICHAT_OK
Definition error_codes.h:48
@ ERROR_NETWORK_SIZE
Definition error_codes.h:74
@ ERROR_CRYPTO
Definition error_codes.h:88
@ ERROR_INVALID_PARAM
@ ERROR_BUFFER_OVERFLOW
Definition error_codes.h:98
#define LOG_RATE_FAST
Log rate limit: 1 second (1,000,000 microseconds)
Definition log_rates.h:26
#define LOG_RATE_SLOW
Log rate limit: 10 seconds (10,000,000 microseconds)
Definition log_rates.h:35
#define log_warn(...)
Log a WARN message.
enum remote_log_direction remote_log_direction_t
Remote log packet direction enumeration.
#define log_debug_every(interval_us, fmt,...)
Rate-limited DEBUG logging.
log_level_t
Logging levels enumeration.
Definition log/logging.h:59
#define log_info(...)
Log an INFO message.
#define log_debug(...)
Log a DEBUG message.
#define log_warn_every(interval_us, fmt,...)
Rate-limited WARN logging.
@ REMOTE_LOG_DIRECTION_UNKNOWN
@ REMOTE_LOG_DIRECTION_CLIENT_TO_SERVER
@ LOG_FATAL
Definition log/logging.h:65
uint32_t pixel_format
Pixel format enum (0=RGB24, 1=RGBA32, 2=BGR24, etc.)
Definition packet.h:774
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:433
uint32_t timestamp
Timestamp when frame was captured (milliseconds since epoch)
Definition packet.h:780
uint32_t magic
Magic number (PACKET_MAGIC) for packet validation.
Definition packet.h:492
uint16_t flags
Additional flags (REMOTE_LOG_FLAG_*)
Definition packet.h:639
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)
Parse a remote log packet payload into components.
Definition packet.c:953
uint32_t message_length
Message payload length in bytes (0-512)
Definition packet.h:641
uint8_t log_level
Log level associated with the message (log_level_t cast to uint8_t)
Definition packet.h:635
uint32_t width
Terminal width in characters.
Definition packet.h:742
asciichat_error_t packet_send_error(socket_t sockfd, const crypto_context_t *crypto_ctx, asciichat_error_t error_code, const char *message)
Send an error packet with optional encryption context.
Definition packet.c:807
asciichat_error_t packet_validate_crc32(const void *data, size_t len, uint32_t expected_crc)
Validate packet CRC32.
Definition packet.c:261
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)
Send a remote log packet with optional encryption context.
Definition packet.c:896
uint32_t message_length
Length of message payload in bytes (0-512)
Definition packet.h:623
asciichat_error_t send_image_frame_packet(socket_t sockfd, const void *image_data, uint16_t width, uint16_t height, uint8_t format)
Send image frame packet.
Definition packet.c:1230
uint16_t auth_public_key_size
Authentication public key size in bytes (e.g., 32 for Ed25519, 1952 for Dilithium3)
Definition packet.h:885
uint32_t length
Payload data length in bytes (0 for header-only packets)
Definition packet.h:496
uint32_t error_code
Error code from asciichat_error_t enumeration.
Definition packet.h:621
void * allocated_buffer
Buffer that needs to be freed by caller (may be NULL if not allocated)
Definition packet.h:990
uint32_t checksum
CRC32 checksum of original ASCII data.
Definition packet.h:750
int send_protocol_version_packet(socket_t sockfd, const protocol_version_packet_t *version)
Send protocol version packet.
Definition packet.c:1016
int send_pong_packet(socket_t sockfd)
Send a pong packet.
Definition packet.c:793
uint32_t original_size
Size of original uncompressed ASCII data in bytes.
Definition packet.h:746
uint32_t height
Terminal height in characters.
Definition packet.h:744
asciichat_error_t send_audio_batch_packet(socket_t sockfd, const float *samples, int num_samples, int batch_count, crypto_context_t *crypto_ctx)
Send a batched audio packet with encryption support.
Definition packet.c:1072
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:351
uint32_t compressed_size
Size of compressed data (0 = not compressed)
Definition packet.h:748
ssize_t send_with_timeout(socket_t sockfd, const void *data, size_t len, int timeout_seconds)
Send data with timeout using chunked transmission.
Definition network.c:200
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)
Parse an error packet payload into components.
Definition packet.c:854
uint16_t signature_size
Signature size in bytes (e.g., 64 for Ed25519, 3309 for Dilithium3)
Definition packet.h:887
int receive_packet(socket_t sockfd, packet_type_t *type, void **data, size_t *len)
Receive a basic packet without encryption.
Definition packet.c:767
asciichat_error_t send_ascii_frame_packet(socket_t sockfd, const char *frame_data, size_t frame_size)
Send ASCII frame packet.
Definition packet.c:1191
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)
Send Opus-encoded audio batch packet with encryption support.
Definition packet.c:1136
#define network_is_test_environment()
Check if we're in a test environment.
Definition network.h:147
size_t allocated_size
Size of allocated buffer in bytes.
Definition packet.h:992
size_t len
Length of payload data in bytes.
Definition packet.h:986
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:754
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:75
void * data
Packet payload data (decrypted and decompressed if applicable)
Definition packet.h:984
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:291
uint32_t compressed_size
Compressed data size (0 = not compressed, >0 = compressed)
Definition packet.h:776
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:568
uint16_t type
Packet type (packet_type_t enumeration)
Definition packet.h:494
#define RECV_TIMEOUT
Receive timeout in seconds (15 seconds)
Definition network.h:118
int send_crypto_capabilities_packet(socket_t sockfd, const crypto_capabilities_packet_t *caps)
Send crypto capabilities packet.
Definition packet.c:1030
uint32_t checksum
CRC32 checksum of pixel data.
Definition packet.h:778
uint32_t channels
Number of audio channels (1=mono, 2=stereo)
Definition packet.h:804
int send_clear_console_packet(socket_t sockfd)
Send a clear console packet.
Definition packet.c:803
uint8_t direction
Direction hint so receivers can annotate origin.
Definition packet.h:637
int send_ping_packet(socket_t sockfd)
Send a ping packet.
Definition packet.c:783
uint32_t height
Image height in pixels.
Definition packet.h:772
packet_type_t type
Packet type (from packet_types.h)
Definition packet.h:982
uint32_t batch_count
Number of audio chunks in this batch (usually AUDIO_BATCH_COUNT = 32)
Definition packet.h:798
uint32_t width
Image width in pixels.
Definition packet.h:770
uint32_t flags
Frame flags bitmask (HAS_COLOR, IS_COMPRESSED, etc.)
Definition packet.h:752
uint32_t sample_rate
Sample rate in Hz (e.g., 44100, 48000)
Definition packet.h:802
uint32_t total_samples
Total audio samples across all chunks (typically 8192)
Definition packet.h:800
ssize_t recv_with_timeout(socket_t sockfd, void *buf, size_t len, int timeout_seconds)
Receive data with timeout.
Definition network.c:272
#define REMOTE_LOG_FLAG_TRUNCATED
Remote log packet flag definitions.
Definition packet.h:628
int send_crypto_parameters_packet(socket_t sockfd, const crypto_parameters_packet_t *params)
Send crypto parameters packet.
Definition packet.c:1044
uint16_t shared_secret_size
Shared secret size in bytes (e.g., 32 for X25519)
Definition packet.h:889
uint16_t kex_public_key_size
Key exchange public key size in bytes (e.g., 32 for X25519, 1568 for Kyber1024)
Definition packet.h:883
uint32_t crc32
CRC32 checksum of payload data (0 if length == 0)
Definition packet.h:498
packet_recv_result_t
Packet reception result codes.
Definition packet.h:1003
#define SEND_TIMEOUT
Send timeout in seconds (5 seconds)
Definition network.h:108
@ PACKET_RECV_ERROR
Network error occurred.
Definition packet.h:1009
@ PACKET_RECV_EOF
Connection closed (EOF)
Definition packet.h:1007
@ PACKET_RECV_SUCCESS
Packet received successfully.
Definition packet.h:1005
#define GET_OPTION(field)
Safely get a specific option field (lock-free read)
Definition options.h:644
#define AUDIO_SAMPLES_PER_PACKET
Samples per audio packet (256 samples)
Definition packet.h:233
#define LARGE_PACKET_THRESHOLD
Large packet size threshold (100KB)
Definition packet.h:103
#define MAX_CLIENT_TIMEOUT
Maximum client timeout in seconds (60 seconds)
Definition packet.h:183
#define LARGE_PACKET_EXTRA_TIMEOUT_PER_MB
Extra timeout per MB for large packets (0.8 seconds per MB)
Definition packet.h:163
packet_type_t
Network protocol packet type enumeration.
Definition packet.h:281
#define MAX_PACKET_SIZE
Maximum packet size (5MB)
Definition packet.h:113
#define MAX_REMOTE_LOG_MESSAGE_LENGTH
Maximum remote log message length (512 bytes)
Definition packet.h:132
#define PACKET_MAGIC
Packet magic number (0xDEADBEEF)
Definition packet.h:251
#define MAX_ERROR_MESSAGE_LENGTH
Maximum error message length (512 bytes)
Definition packet.h:122
#define MIN_CLIENT_TIMEOUT
Minimum client timeout in seconds (10 seconds)
Definition packet.h:173
@ PACKET_TYPE_ACIP_WEBRTC_ICE
WebRTC ICE candidate (bidirectional)
Definition packet.h:390
@ PACKET_TYPE_AUDIO_OPUS_BATCH
Batched Opus-encoded audio frames.
Definition packet.h:359
@ PACKET_TYPE_CLIENT_LEAVE
Clean disconnect notification.
Definition packet.h:302
@ PACKET_TYPE_ACIP_SESSION_INFO
Session info response (Discovery Server -> Client)
Definition packet.h:375
@ PACKET_TYPE_IMAGE_FRAME
Complete RGB image with dimensions.
Definition packet.h:288
@ PACKET_TYPE_CRYPTO_AUTH_RESPONSE
Client -> Server: {HMAC[32]} (UNENCRYPTED)
Definition packet.h:323
@ PACKET_TYPE_TEXT_MESSAGE
Text message.
Definition packet.h:350
@ PACKET_TYPE_AUDIO_MESSAGE
Audio message.
Definition packet.h:348
@ PACKET_TYPE_PONG
Keepalive pong response.
Definition packet.h:297
@ PACKET_TYPE_ACIP_SESSION_RECONNECT
Reconnect to session (Client -> Discovery Server)
Definition packet.h:385
@ PACKET_TYPE_CRYPTO_HANDSHAKE_COMPLETE
Server -> Client: "encryption ready" (UNENCRYPTED)
Definition packet.h:329
@ PACKET_TYPE_STREAM_START
Client requests to start sending video/audio.
Definition packet.h:304
@ PACKET_TYPE_CRYPTO_KEY_EXCHANGE_INIT
Server -> Client: {server_pubkey[32]} (UNENCRYPTED)
Definition packet.h:317
@ PACKET_TYPE_ACIP_ERROR
Generic error response (Discovery Server -> Client)
Definition packet.h:404
@ PACKET_TYPE_AUDIO
Single audio packet (legacy)
Definition packet.h:291
@ PACKET_TYPE_CRYPTO_KEY_EXCHANGE_RESP
Client -> Server: {client_pubkey[32]} (UNENCRYPTED)
Definition packet.h:319
@ PACKET_TYPE_ACIP_STRING_RESERVE
Reserve session string (Client -> Discovery Server)
Definition packet.h:393
@ PACKET_TYPE_CRYPTO_AUTH_FAILED
Server -> Client: "authentication failed" (UNENCRYPTED)
Definition packet.h:325
@ PACKET_TYPE_ENCRYPTED
Encrypted packet (after handshake completion)
Definition packet.h:333
@ PACKET_TYPE_SIZE_MESSAGE
Terminal size message.
Definition packet.h:346
@ PACKET_TYPE_REMOTE_LOG
Bidirectional remote logging packet.
Definition packet.h:354
@ PACKET_TYPE_CRYPTO_SERVER_AUTH_RESP
Server -> Client: {HMAC[32]} server proves knowledge (UNENCRYPTED)
Definition packet.h:327
@ PACKET_TYPE_PROTOCOL_VERSION
Protocol version and capabilities negotiation.
Definition packet.h:283
@ PACKET_TYPE_CLEAR_CONSOLE
Server tells client to clear console.
Definition packet.h:308
@ PACKET_TYPE_CRYPTO_NO_ENCRYPTION
Client -> Server: "I want to proceed without encryption" (UNENCRYPTED)
Definition packet.h:331
@ PACKET_TYPE_ACIP_SESSION_CREATE
Create new session (Client -> Discovery Server)
Definition packet.h:369
@ PACKET_TYPE_ACIP_STRING_RESERVED
String reserved response (Discovery Server -> Client)
Definition packet.h:395
@ PACKET_TYPE_ACIP_DISCOVERY_PING
Discovery server ping (keepalive)
Definition packet.h:402
@ PACKET_TYPE_CRYPTO_AUTH_CHALLENGE
Server -> Client: {nonce[32]} (UNENCRYPTED)
Definition packet.h:321
@ PACKET_TYPE_ASCII_FRAME
Complete ASCII frame with all metadata.
Definition packet.h:286
@ PACKET_TYPE_CRYPTO_PARAMETERS
Server -> Client: Chosen algorithms + data sizes (UNENCRYPTED)
Definition packet.h:315
@ PACKET_TYPE_ACIP_SESSION_LOOKUP
Lookup session by string (Client -> Discovery Server)
Definition packet.h:373
@ PACKET_TYPE_CRYPTO_CAPABILITIES
Client -> Server: Supported crypto algorithms (UNENCRYPTED)
Definition packet.h:313
@ PACKET_TYPE_ACIP_SESSION_LEAVE
Leave session (Client -> Discovery Server)
Definition packet.h:381
@ PACKET_TYPE_ACIP_WEBRTC_SDP
WebRTC SDP offer/answer (bidirectional)
Definition packet.h:388
@ PACKET_TYPE_ACIP_SESSION_JOIN
Join existing session (Client -> Discovery Server)
Definition packet.h:377
@ PACKET_TYPE_ACIP_SESSION_CREATED
Session created response (Discovery Server -> Client)
Definition packet.h:371
@ PACKET_TYPE_ACIP_STRING_RELEASE
Release string reservation (Client -> Discovery Server)
Definition packet.h:399
@ PACKET_TYPE_CLIENT_JOIN
Client announces capability to send media.
Definition packet.h:300
@ PACKET_TYPE_CLIENT_CAPABILITIES
Client reports terminal capabilities.
Definition packet.h:293
@ PACKET_TYPE_ACIP_STRING_RENEW
Renew string reservation (Client -> Discovery Server)
Definition packet.h:397
@ PACKET_TYPE_ERROR_MESSAGE
Error packet with asciichat_error_t code and human-readable message.
Definition packet.h:352
@ PACKET_TYPE_PING
Keepalive ping packet.
Definition packet.h:295
@ PACKET_TYPE_AUDIO_BATCH
Batched audio packets for efficiency.
Definition packet.h:343
@ PACKET_TYPE_ACIP_SESSION_JOINED
Session joined response (Discovery Server -> Client)
Definition packet.h:379
@ PACKET_TYPE_STREAM_STOP
Client stops sending media.
Definition packet.h:306
@ PACKET_TYPE_ACIP_SESSION_END
End session (Host -> Discovery Server)
Definition packet.h:383
int socket_t
Socket handle type (POSIX: int)
Definition socket.h:50
bool socket_is_valid(socket_t sock)
Check if a socket handle is valid.
#define INVALID_SOCKET_VALUE
Invalid socket value (POSIX: -1)
Definition socket.h:52
int errno
#define asciichat_crc32(data, len)
Main CRC32 dispatcher macro - use this in application code.
Definition crc32.h:144
🔊 Audio Capture and Playback Interface for ascii-chat
🌐 Core network I/O operations with timeout support
⚙️ Command-line options parsing and configuration management for ascii-chat
✅ Safe Integer Arithmetic and Overflow Detection
Packet protocol implementation with encryption and compression support.
Cross-platform socket interface for ascii-chat.
ASCII frame packet structure (Packet Type 2)
Definition packet.h:740
Audio batch packet structure (Packet Type 28)
Definition packet.h:796
Client information packet structure.
Definition packet.h:545
Crypto capabilities packet structure (Packet Type 14)
Definition packet.h:844
Cryptographic context structure.
Crypto parameters packet structure (Packet Type 15)
Definition packet.h:873
Error packet structure carrying error code and textual description.
Definition packet.h:619
Image frame packet structure (Packet Type 3)
Definition packet.h:768
Packet envelope containing received packet data.
Definition packet.h:980
Network packet header structure.
Definition packet.h:490
Protocol version negotiation packet structure (Packet Type 1)
Definition packet.h:710
Remote log packet structure carrying log level and message text.
Definition packet.h:633