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>
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);
49 if (packet_size > LARGE_PACKET_THRESHOLD) {
51 uint64_t extra_timeout =
52 (uint64_t)(((
double)packet_size - LARGE_PACKET_THRESHOLD) / 1000000.0 * LARGE_PACKET_EXTRA_TIMEOUT_PER_MB) +
54 uint64_t total_timeout = base_timeout + extra_timeout;
58 if (total_timeout < MIN_CLIENT_TIMEOUT) {
59 total_timeout = MIN_CLIENT_TIMEOUT;
63 return (total_timeout > MAX_CLIENT_TIMEOUT) ? MAX_CLIENT_TIMEOUT : total_timeout;
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);
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");
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);
98 if (magic != PACKET_MAGIC) {
99 return SET_ERRNO(ERROR_NETWORK_PROTOCOL,
"Invalid packet magic: 0x%x (expected 0x%x)", magic, PACKET_MAGIC);
103 if (len > MAX_PACKET_SIZE) {
104 return SET_ERRNO(ERROR_NETWORK_SIZE,
"Packet too large: %u > %d", len, MAX_PACKET_SIZE);
109 case PACKET_TYPE_PROTOCOL_VERSION:
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));
116 case PACKET_TYPE_ASCII_FRAME:
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));
123 case PACKET_TYPE_IMAGE_FRAME:
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));
130 case PACKET_TYPE_AUDIO_BATCH:
132 if (len <
sizeof(audio_batch_packet_t) +
sizeof(
float)) {
133 return SET_ERRNO(ERROR_NETWORK_PROTOCOL,
"Invalid audio batch packet size: %u", len);
136 case PACKET_TYPE_PING:
137 case PACKET_TYPE_PONG:
139 return SET_ERRNO(ERROR_NETWORK_PROTOCOL,
"Invalid ping/pong packet size: %u", len);
142 case PACKET_TYPE_CLIENT_CAPABILITIES:
145 return SET_ERRNO(ERROR_NETWORK_PROTOCOL,
"Invalid client capabilities packet size: %u", len);
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));
154 case PACKET_TYPE_CLIENT_LEAVE:
157 return SET_ERRNO(ERROR_NETWORK_PROTOCOL,
"Invalid client leave packet size: %u", len);
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,
167 case PACKET_TYPE_SIZE_MESSAGE:
169 if (len == 0 || len > 32) {
170 return SET_ERRNO(ERROR_NETWORK_PROTOCOL,
"Invalid size message packet size: %u", len);
173 case PACKET_TYPE_AUDIO_MESSAGE:
175 if (len == 0 || len > 32) {
176 return SET_ERRNO(ERROR_NETWORK_PROTOCOL,
"Invalid audio message packet size: %u", len);
179 case PACKET_TYPE_TEXT_MESSAGE:
182 return SET_ERRNO(ERROR_NETWORK_PROTOCOL,
"Invalid text message packet size: %u", len);
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));
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);
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:
210 return SET_ERRNO(ERROR_NETWORK_PROTOCOL,
"Crypto packet too large: %u bytes (max 65536)", len);
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:
236 return SET_ERRNO(ERROR_NETWORK_PROTOCOL,
"ACIP packet too large: %u bytes (max 65536)", len);
240 return SET_ERRNO(ERROR_NETWORK_PROTOCOL,
"Unknown packet type: %u", type);
259 if (!data && len > 0) {
260 return SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid parameters: data=%p but len=%zu", data, len);
265 if (expected_crc != 0) {
266 return SET_ERRNO(ERROR_NETWORK_PROTOCOL,
"Invalid CRC32 for empty packet: 0x%x (expected 0)", expected_crc);
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,
289 if (sockfd == INVALID_SOCKET_VALUE) {
290 return SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid socket descriptor");
293 if (len > MAX_PACKET_SIZE) {
294 return SET_ERRNO(ERROR_NETWORK_SIZE,
"Packet too large: %zu > %d", len, MAX_PACKET_SIZE);
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)};
304 uint64_t timeout = calculate_packet_timeout(len);
310 return ERROR_NETWORK;
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));
317 if (len > 0 && data) {
319 if (!socket_is_valid(sockfd)) {
320 return SET_ERRNO(ERROR_NETWORK,
"Socket became invalid between header and payload send");
326 return ERROR_NETWORK;
328 if ((
size_t)sent != len) {
329 return SET_ERRNO(ERROR_NETWORK,
"Failed to fully send packet payload. Sent %zd/%zu bytes", sent, len);
334 log_debug(
"Sent packet type=%d, len=%zu, errno=%d (%s)", type, len, errno, SAFE_STRERROR(errno));
349 if (sockfd == INVALID_SOCKET_VALUE) {
350 return SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid socket descriptor");
352 if (!type || !data || !len) {
353 return SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid parameters: type=%p, data=%p, len=%p", type, data, len);
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);
363 return ERROR_NETWORK;
365 if ((
size_t)received !=
sizeof(header)) {
367 log_warn(
"Connection closed while reading packet header");
368 return SET_ERRNO(ERROR_NETWORK,
"Connection closed by peer while reading packet header");
371 return SET_ERRNO(ERROR_NETWORK,
"Partial packet header received: %zd/%zu bytes", received,
sizeof(header));
377 uint32_t expected_crc;
380 return ERROR_NETWORK_PROTOCOL;
384 void *payload = NULL;
389 uint64_t recv_timeout = network_is_test_environment() ? (1ULL * NS_PER_SEC_INT) : calculate_packet_timeout(pkt_len);
393 return SET_ERRNO_SYS(ERROR_NETWORK,
"Failed to receive packet payload");
395 if (received != (ssize_t)pkt_len) {
397 return SET_ERRNO(ERROR_NETWORK,
"Partial packet payload received: %zd/%u bytes", received, pkt_len);
404 return ERROR_NETWORK_PROTOCOL;
409 *type = (packet_type_t)pkt_type;
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);
438 if (packet_is_handshake_type(type)) {
443 const void *final_data = data;
444 size_t final_len = len;
445 void *compressed_data = NULL;
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;
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);
464 SAFE_FREE(temp_compressed);
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);
478 if (result != ASCIICHAT_OK) {
479 SET_ERRNO(ERROR_NETWORK,
"Failed to send packet: %s", asciichat_error_string(result));
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)};
493 if (final_len > SIZE_MAX -
sizeof(header)) {
494 if (compressed_data) {
495 SAFE_FREE(compressed_data);
497 return SET_ERRNO(ERROR_NETWORK_SIZE,
"Packet too large: would overflow plaintext buffer size");
499 size_t plaintext_len =
sizeof(header) + final_len;
502 if (compressed_data) {
503 SAFE_FREE(compressed_data);
505 return SET_ERRNO(ERROR_MEMORY,
"Failed to allocate buffer for plaintext packet");
508 memcpy(plaintext, &header,
sizeof(header));
509 if (final_len > 0 && final_data) {
510 memcpy(plaintext +
sizeof(header), final_data, final_len);
515 if (plaintext_len > SIZE_MAX - CRYPTO_NONCE_SIZE - CRYPTO_MAC_SIZE) {
517 if (compressed_data) {
518 SAFE_FREE(compressed_data);
520 return SET_ERRNO(ERROR_NETWORK_SIZE,
"Packet too large: would overflow ciphertext buffer size");
522 size_t ciphertext_size = plaintext_len + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE;
526 if (compressed_data) {
527 SAFE_FREE(compressed_data);
529 return SET_ERRNO(ERROR_MEMORY,
"Failed to allocate buffer for ciphertext");
532 size_t ciphertext_len;
533 crypto_result_t result =
534 crypto_encrypt(crypto_ctx, plaintext, plaintext_len, ciphertext, ciphertext_size, &ciphertext_len);
537 if (result != CRYPTO_OK) {
539 if (compressed_data) {
540 SAFE_FREE(compressed_data);
546 log_debug_every(LOG_RATE_SLOW,
"CRYPTO_DEBUG: Sending encrypted packet (original type %d as PACKET_TYPE_ENCRYPTED)",
548 asciichat_error_t send_result =
packet_send(sockfd, PACKET_TYPE_ENCRYPTED, ciphertext, ciphertext_len);
551 if (compressed_data) {
552 SAFE_FREE(compressed_data);
567 packet_envelope_t *envelope) {
570 SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid parameters: envelope=%p", envelope);
571 return PACKET_RECV_ERROR;
575 memset(envelope, 0,
sizeof(*envelope));
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);
585 SET_ERRNO(ERROR_NETWORK,
"Failed to receive packet header: %zd/%zu bytes", received,
sizeof(header));
586 return PACKET_RECV_ERROR;
590 return PACKET_RECV_EOF;
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;
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);
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;
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;
617 if (pkt_type == PACKET_TYPE_ENCRYPTED) {
619 SET_ERRNO(ERROR_CRYPTO,
"Received encrypted packet but no crypto context");
620 return PACKET_RECV_ERROR;
626 SET_ERRNO(ERROR_MEMORY,
"Failed to allocate buffer for ciphertext");
627 return PACKET_RECV_ERROR;
630 uint64_t recv_timeout = network_is_test_environment() ? (1ULL * NS_PER_SEC_INT) : calculate_packet_timeout(pkt_len);
632 if (received != (ssize_t)pkt_len) {
633 SET_ERRNO(ERROR_NETWORK,
"Failed to receive encrypted payload: %zd/%u bytes", received, pkt_len);
635 return PACKET_RECV_ERROR;
640 size_t plaintext_size = (size_t)pkt_len + 1024;
643 SET_ERRNO(ERROR_MEMORY,
"Failed to allocate buffer for plaintext");
645 return PACKET_RECV_ERROR;
648 size_t plaintext_len;
649 crypto_result_t result =
crypto_decrypt(crypto_ctx, ciphertext, pkt_len, plaintext, plaintext_size, &plaintext_len);
652 if (result != CRYPTO_OK) {
655 return PACKET_RECV_ERROR;
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));
661 return PACKET_RECV_ERROR;
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);
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);
675 return PACKET_RECV_ERROR;
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);
684 return PACKET_RECV_ERROR;
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;
695 return PACKET_RECV_SUCCESS;
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;
708 SET_ERRNO(ERROR_MEMORY,
"Failed to allocate buffer for payload");
709 return PACKET_RECV_ERROR;
712 uint64_t recv_timeout = network_is_test_environment() ? (1ULL * NS_PER_SEC_INT) : calculate_packet_timeout(pkt_len);
714 if (received != (ssize_t)pkt_len) {
715 SET_ERRNO(ERROR_NETWORK,
"Failed to receive payload: %zd/%u bytes", received, pkt_len);
717 return PACKET_RECV_ERROR;
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);
725 return PACKET_RECV_ERROR;
728 envelope->data = payload;
729 envelope->allocated_buffer = payload;
730 envelope->allocated_size = pkt_len;
733 envelope->type = (packet_type_t)pkt_type;
734 envelope->len = pkt_len;
736 return PACKET_RECV_SUCCESS;
754 asciichat_error_t result =
packet_send(sockfd, type, data, len);
755 return result == ASCIICHAT_OK ? 0 : -1;
767 asciichat_error_t result =
packet_receive(sockfd, type, data, len);
768 return result == ASCIICHAT_OK ? 0 : -1;
783 return send_packet(sockfd, PACKET_TYPE_PING, NULL, 0);
792 return send_packet(sockfd, PACKET_TYPE_PONG, NULL, 0);
801 return send_packet(sockfd, PACKET_TYPE_CLEAR_CONSOLE, NULL, 0);
805 const char *message) {
806 if (sockfd == INVALID_SOCKET_VALUE) {
807 return SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid socket descriptor");
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);
819 size_t payload_len =
sizeof(error_packet_t) + message_len;
820 uint8_t *payload = SAFE_MALLOC(payload_len, uint8_t *);
822 return SET_ERRNO(ERROR_MEMORY,
"Failed to allocate %zu bytes for error packet", payload_len);
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);
829 if (message_len > 0) {
830 memcpy(payload +
sizeof(error_packet_t), message, message_len);
834 asciichat_error_t send_result;
836 if (encryption_ready) {
838 send_packet_secure(sockfd, PACKET_TYPE_ERROR_MESSAGE, payload, payload_len, (crypto_context_t *)crypto_ctx);
840 send_result =
packet_send(sockfd, PACKET_TYPE_ERROR_MESSAGE, payload, payload_len);
844 if (send_result != ASCIICHAT_OK) {
845 return SET_ERRNO(ERROR_NETWORK,
"Failed to send error packet: %s", asciichat_error_string(send_result));
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);
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);
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);
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,
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;
881 memcpy(message_buffer, message_bytes, copy_len);
883 message_buffer[copy_len] =
'\0';
885 if (out_message_length) {
886 *out_message_length = raw_message_length;
889 *out_error_code = (asciichat_error_t)raw_error_code;
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");
899 if (level < LOG_DEV || level > LOG_FATAL) {
900 return SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid log level: %d", level);
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') {
910 size_t payload_len =
sizeof(remote_log_packet_t) + message_len;
911 uint8_t *payload = SAFE_MALLOC(payload_len, uint8_t *);
913 return SET_ERRNO(ERROR_MEMORY,
"Failed to allocate %zu bytes for remote log packet", payload_len);
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;
921 final_flags |= REMOTE_LOG_FLAG_TRUNCATED;
923 packet->flags = HOST_TO_NET_U16(final_flags);
924 packet->message_length = HOST_TO_NET_U32((uint32_t)message_len);
926 if (message_len > 0) {
927 memcpy(payload +
sizeof(remote_log_packet_t), safe_message, message_len);
931 asciichat_error_t send_result;
933 if (encryption_ready) {
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;
938 send_result =
packet_send(sockfd, PACKET_TYPE_REMOTE_LOG, payload, payload_len);
943 if (send_result != ASCIICHAT_OK) {
944 return SET_ERRNO(ERROR_NETWORK,
"Failed to send remote log packet: %d", send_result);
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) {
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);
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);
967 *out_level = (log_level_t)raw_level;
969 uint8_t raw_direction = packet->direction;
970 if (raw_direction > REMOTE_LOG_DIRECTION_CLIENT_TO_SERVER) {
971 raw_direction = REMOTE_LOG_DIRECTION_UNKNOWN;
973 *out_direction = (remote_log_direction_t)raw_direction;
975 uint16_t raw_flags = NET_TO_HOST_U16(packet->flags);
976 *out_flags = raw_flags;
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);
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);
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;
996 memcpy(message_buffer, message_bytes, copy_len);
998 message_buffer[copy_len] =
'\0';
1000 if (out_message_length) {
1001 *out_message_length = raw_message_length;
1004 return ASCIICHAT_OK;
1015 SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid parameters: version=%p", version);
1018 return send_packet(sockfd, PACKET_TYPE_PROTOCOL_VERSION, version,
sizeof(*version));
1029 SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid parameters: caps=%p", caps);
1032 return send_packet(sockfd, PACKET_TYPE_CRYPTO_CAPABILITIES, caps,
sizeof(*caps));
1043 SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid parameters: params=%p", params);
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);
1058 return send_packet(sockfd, PACKET_TYPE_CRYPTO_PARAMETERS, &net_params,
sizeof(net_params));
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);
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);
1081 header.channels = HOST_TO_NET_U32(1UL);
1084 size_t data_size = (size_t)num_samples *
sizeof(uint32_t);
1085 size_t total_size =
sizeof(header) + data_size;
1090 return SET_ERRNO(ERROR_MEMORY,
"Failed to allocate buffer for audio batch packet");
1094 memcpy(buffer, &header,
sizeof(header));
1099 uint8_t *sample_data_ptr = buffer +
sizeof(header);
1100 for (
int i = 0; i < num_samples; i++) {
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;
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));
1116 static int send_count = 0;
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));
1127 asciichat_error_t result =
send_packet_secure(sockfd, PACKET_TYPE_AUDIO_BATCH, buffer, total_size, crypto_ctx);
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,
1146 if (frame_count > 1000) {
1147 return SET_ERRNO(ERROR_INVALID_PARAM,
"Too many Opus frames: %d (max 1000)", frame_count);
1151 size_t header_size = 16;
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;
1156 return SET_ERRNO(ERROR_MEMORY,
"Failed to allocate buffer for Opus batch packet: %zu bytes", total_size);
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);
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]);
1176 memcpy(buf + header_size + frame_sizes_bytes, opus_data, opus_size);
1179 asciichat_error_t result =
1180 send_packet_secure(sockfd, PACKET_TYPE_AUDIO_OPUS_BATCH, packet_data, total_size, crypto_ctx);
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);
1194 ascii_frame_packet_t packet;
1197 packet.original_size = (uint32_t)frame_size;
1198 packet.compressed_size = 0;
1199 packet.checksum = 0;
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");
1211 return SET_ERRNO(ERROR_MEMORY,
"Failed to allocate buffer for ASCII frame packet: %zu bytes", total_size);
1215 memcpy(packet_data, &packet,
sizeof(ascii_frame_packet_t));
1216 memcpy((
char *)packet_data +
sizeof(ascii_frame_packet_t), frame_data, frame_size);
1219 asciichat_error_t result =
packet_send(sockfd, PACKET_TYPE_ASCII_FRAME, packet_data, total_size);
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,
1236 if (width > 4096 || height > 4096) {
1237 return SET_ERRNO(ERROR_INVALID_PARAM,
"Image dimensions too large: %ux%u (max 4096x4096)", width, height);
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;
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);
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");
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");
1270 return SET_ERRNO(ERROR_MEMORY,
"Failed to allocate buffer for image frame packet: %zu bytes", total_size);
1274 memcpy(packet_data, &packet,
sizeof(image_frame_packet_t));
1275 memcpy((
char *)packet_data +
sizeof(image_frame_packet_t), image_data, frame_size);
1278 asciichat_error_t result =
packet_send(sockfd, PACKET_TYPE_IMAGE_FRAME, packet_data, total_size);
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)
bool should_compress(size_t original_size, size_t compressed_size)
asciichat_error_t compress_data(const void *input, size_t input_size, void **output, size_t *output_size, int compression_level)
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.
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)
asciichat_error_t packet_send_error(socket_t sockfd, const crypto_context_t *crypto_ctx, asciichat_error_t error_code, const char *message)
asciichat_error_t packet_validate_crc32(const void *data, size_t len, uint32_t expected_crc)
Validate packet CRC32.
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)
asciichat_error_t send_image_frame_packet(socket_t sockfd, const void *image_data, uint16_t width, uint16_t height, uint8_t format)
int send_protocol_version_packet(socket_t sockfd, const protocol_version_packet_t *version)
Send protocol version packet.
int send_pong_packet(socket_t sockfd)
Send a pong packet.
asciichat_error_t send_audio_batch_packet(socket_t sockfd, const float *samples, int num_samples, int batch_count, crypto_context_t *crypto_ctx)
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.
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)
int receive_packet(socket_t sockfd, packet_type_t *type, void **data, size_t *len)
Receive a basic packet without encryption.
asciichat_error_t send_ascii_frame_packet(socket_t sockfd, const char *frame_data, size_t frame_size)
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)
int send_packet(socket_t sockfd, packet_type_t type, const void *data, size_t len)
Send a basic packet without encryption.
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.
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.
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.
int send_crypto_capabilities_packet(socket_t sockfd, const crypto_capabilities_packet_t *caps)
Send crypto capabilities packet.
int send_clear_console_packet(socket_t sockfd)
Send a clear console packet.
int send_ping_packet(socket_t sockfd)
Send a ping packet.
int send_crypto_parameters_packet(socket_t sockfd, const crypto_parameters_packet_t *params)
Send crypto parameters packet.