ascii-chat 0.11.33
Video chat in your terminal
Loading...
Searching...
No Matches
packet.c File Reference

Go to the source code of this file.

Functions

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.
 
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 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.
 
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.
 
packet_recv_result_t receive_packet_secure_with_timeout (socket_t sockfd, void *crypto_ctx, bool enforce_encryption, packet_envelope_t *envelope, uint64_t timeout_ns)
 
int send_packet (socket_t sockfd, packet_type_t type, const void *data, size_t len)
 Send a basic packet without encryption.
 
int receive_packet (socket_t sockfd, packet_type_t *type, void **data, size_t *len)
 Receive a basic packet without encryption.
 
int send_ping_packet (socket_t sockfd)
 Send a ping packet.
 
int send_pong_packet (socket_t sockfd)
 Send a pong packet.
 
asciichat_error_t packet_decrypt_envelope (packet_envelope_t *envelope, void *crypto_ctx)
 Send a clear console packet.
 
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.
 
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.
 
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.
 
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.
 
int send_protocol_version_packet (socket_t sockfd, const protocol_version_packet_t *version)
 Send protocol version packet.
 
int send_crypto_capabilities_packet (socket_t sockfd, const crypto_capabilities_packet_t *caps)
 Send crypto capabilities packet.
 
int send_crypto_parameters_packet (socket_t sockfd, const crypto_parameters_packet_t *params)
 Send crypto parameters packet.
 
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.
 
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.
 

Function Documentation

◆ packet_parse_error_message()

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.

Parameters
dataPacket payload buffer
lenPayload length in bytes
out_error_codeOutput pointer for asciichat_error_t value (must not be NULL)
message_bufferDestination buffer for message string (must not be NULL)
message_buffer_sizeSize of destination buffer in bytes (must be > 0)
out_message_lengthOptional output for message length reported by sender
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 957 of file packet.c.

959 {
960 if (!data || len < sizeof(error_packet_t) || !out_error_code || !message_buffer || message_buffer_size == 0) {
962 "Invalid parameters: data=%p len=%zu out_error_code=%p message_buffer=%p buffer_size=%zu", data,
963 len, out_error_code, message_buffer, message_buffer_size);
964 }
965
966 const error_packet_t *packet = (const error_packet_t *)data;
967 uint32_t raw_error_code = NET_TO_HOST_U32(packet->error_code);
968 uint32_t raw_message_length = NET_TO_HOST_U32(packet->message_length);
969
970 if (raw_message_length > MAX_ERROR_MESSAGE_LENGTH) {
971 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Error message length too large: %u", raw_message_length);
972 }
973
974 size_t total_required = sizeof(error_packet_t) + (size_t)raw_message_length;
975 if (total_required > len) {
976 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Error packet truncated: expected %zu bytes, have %zu", total_required,
977 len);
978 }
979
980 const uint8_t *message_bytes = (const uint8_t *)data + sizeof(error_packet_t);
981 size_t copy_len = raw_message_length;
982 if (copy_len >= message_buffer_size) {
983 copy_len = message_buffer_size - 1;
984 }
985
986 if (copy_len > 0) {
987 memcpy(message_buffer, message_bytes, copy_len);
988 }
989 message_buffer[copy_len] = '\0';
990
991 if (out_message_length) {
992 *out_message_length = raw_message_length;
993 }
994
995 *out_error_code = (asciichat_error_t)raw_error_code;
996 return ASCIICHAT_OK;
997}
#define NET_TO_HOST_U32(val)
Definition endian.h:81
unsigned int uint32_t
Definition common.h:58
unsigned char uint8_t
Definition common.h:56
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it, returning the error code.
asciichat_error_t
Error and exit codes - unified status values (0-255)
Definition error_codes.h:49
@ ERROR_NETWORK_PROTOCOL
Definition error_codes.h:81
@ ASCIICHAT_OK
Definition error_codes.h:51
@ ERROR_INVALID_PARAM
#define MAX_ERROR_MESSAGE_LENGTH
Maximum error message length (512 bytes)
Definition packet.h:124
Error packet structure carrying error code and textual description.
Definition packet.h:727
uint32_t message_length
Length of message payload in bytes (0-512)
Definition packet.h:731
uint32_t error_code
Error code from asciichat_error_t enumeration.
Definition packet.h:729

References ASCIICHAT_OK, error_packet_t::error_code, ERROR_INVALID_PARAM, ERROR_NETWORK_PROTOCOL, MAX_ERROR_MESSAGE_LENGTH, error_packet_t::message_length, NET_TO_HOST_U32, and SET_ERRNO.

◆ packet_parse_remote_log()

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.

Parameters
dataPacket payload buffer
lenPayload length in bytes
out_levelOutput pointer for log level (must not be NULL)
out_directionOutput pointer for direction (must not be NULL)
out_flagsOutput pointer for flags (must not be NULL)
message_bufferDestination buffer for message string (must not be NULL)
message_buffer_sizeSize of destination buffer in bytes (must be > 0)
out_message_lengthOptional output for message length reported by sender
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 1056 of file packet.c.

1059 {
1060 if (!data || len < sizeof(remote_log_packet_t) || !out_level || !out_direction || !out_flags || !message_buffer ||
1061 message_buffer_size == 0) {
1062 return SET_ERRNO(
1064 "Invalid parameters: data=%p len=%zu out_level=%p out_direction=%p out_flags=%p buffer=%p size=%zu", data, len,
1065 out_level, out_direction, out_flags, message_buffer, message_buffer_size);
1066 }
1067
1068 const remote_log_packet_t *packet = (const remote_log_packet_t *)data;
1069 uint8_t raw_level = packet->log_level;
1070 if (raw_level > LOG_FATAL) {
1071 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid remote log level: %u", raw_level);
1072 }
1073 *out_level = (log_level_t)raw_level;
1074
1075 uint8_t raw_direction = packet->direction;
1076 if (raw_direction > REMOTE_LOG_DIRECTION_CLIENT_TO_SERVER) {
1077 raw_direction = REMOTE_LOG_DIRECTION_UNKNOWN;
1078 }
1079 *out_direction = (remote_log_direction_t)raw_direction;
1080
1081 uint16_t raw_flags = NET_TO_HOST_U16(packet->flags);
1082 *out_flags = raw_flags;
1083
1084 uint32_t raw_message_length = NET_TO_HOST_U32(packet->message_length);
1085 if (raw_message_length > MAX_REMOTE_LOG_MESSAGE_LENGTH) {
1086 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Remote log message length too large: %u", raw_message_length);
1087 }
1088
1089 size_t total_required = sizeof(remote_log_packet_t) + (size_t)raw_message_length;
1090 if (total_required > len) {
1091 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Remote log packet truncated: expected %zu bytes, have %zu",
1092 total_required, len);
1093 }
1094
1095 const uint8_t *message_bytes = (const uint8_t *)data + sizeof(remote_log_packet_t);
1096 size_t copy_len = raw_message_length;
1097 if (copy_len >= message_buffer_size) {
1098 copy_len = message_buffer_size - 1;
1099 }
1100
1101 if (copy_len > 0) {
1102 memcpy(message_buffer, message_bytes, copy_len);
1103 }
1104 message_buffer[copy_len] = '\0';
1105
1106 if (out_message_length) {
1107 *out_message_length = raw_message_length;
1108 }
1109
1110 return ASCIICHAT_OK;
1111}
#define NET_TO_HOST_U16(val)
Definition endian.h:111
unsigned short uint16_t
Definition common.h:57
enum remote_log_direction remote_log_direction_t
Remote log packet direction enumeration.
log_level_t
Logging levels enumeration.
Definition types.h:29
@ REMOTE_LOG_DIRECTION_UNKNOWN
Definition network/log.h:21
@ REMOTE_LOG_DIRECTION_CLIENT_TO_SERVER
Definition network/log.h:23
#define MAX_REMOTE_LOG_MESSAGE_LENGTH
Maximum remote log message length (512 bytes)
Definition packet.h:134
Remote log packet structure carrying log level and message text.
Definition packet.h:741
uint16_t flags
Additional flags (REMOTE_LOG_FLAG_*)
Definition packet.h:747
uint32_t message_length
Message payload length in bytes (0-512)
Definition packet.h:749
uint8_t log_level
Log level associated with the message (log_level_t cast to uint8_t)
Definition packet.h:743
uint8_t direction
Direction hint so receivers can annotate origin.
Definition packet.h:745
#define LOG_FATAL
Definition types.h:43

References ASCIICHAT_OK, remote_log_packet_t::direction, ERROR_INVALID_PARAM, ERROR_NETWORK_PROTOCOL, remote_log_packet_t::flags, LOG_FATAL, remote_log_packet_t::log_level, MAX_REMOTE_LOG_MESSAGE_LENGTH, remote_log_packet_t::message_length, NET_TO_HOST_U16, NET_TO_HOST_U32, REMOTE_LOG_DIRECTION_CLIENT_TO_SERVER, REMOTE_LOG_DIRECTION_UNKNOWN, and SET_ERRNO.

Referenced by handle_remote_log_packet_from_client().

◆ packet_send_error()

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.

Parameters
sockfdSocket file descriptor
crypto_ctxCrypto context for encryption (NULL or not ready sends plaintext)
error_codeError code from asciichat_error_t enumeration
messageHuman-readable message to accompany the error (can be NULL)
Returns
ASCIICHAT_OK on success, error code otherwise

When the crypto context is ready, the packet is encrypted automatically. During the handshake (or when encryption is disabled), the packet is sent in plaintext so protocol errors can be delivered before encryption is active.

Definition at line 910 of file packet.c.

911 {
912 if (sockfd == INVALID_SOCKET_VALUE) {
913 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid socket descriptor");
914 }
915
916 if (!message) {
917 message = "";
918 }
919
920 size_t message_len = strnlen(message, MAX_ERROR_MESSAGE_LENGTH);
921 if (message_len == MAX_ERROR_MESSAGE_LENGTH) {
922 log_warn("Error message truncated to %zu bytes", (size_t)MAX_ERROR_MESSAGE_LENGTH);
923 }
924
925 size_t payload_len = sizeof(error_packet_t) + message_len;
926 uint8_t *payload = SAFE_MALLOC(payload_len, uint8_t *);
927 if (!payload) {
928 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate %zu bytes for error packet", payload_len);
929 }
930
931 error_packet_t *packet = (error_packet_t *)payload;
933 packet->message_length = HOST_TO_NET_U32((uint32_t)message_len);
934
935 if (message_len > 0) {
936 memcpy(payload + sizeof(error_packet_t), message, message_len);
937 }
938
939 bool encryption_ready = crypto_ctx && crypto_is_ready(crypto_ctx);
940 asciichat_error_t send_result;
941
942 if (encryption_ready) {
943 send_result =
944 send_packet_secure(sockfd, PACKET_TYPE_ERROR_MESSAGE, payload, payload_len, (crypto_context_t *)crypto_ctx);
945 } else {
946 send_result = packet_send(sockfd, PACKET_TYPE_ERROR_MESSAGE, payload, payload_len);
947 }
948 SAFE_FREE(payload);
949
950 if (send_result != ASCIICHAT_OK) {
951 return SET_ERRNO(ERROR_NETWORK, "Failed to send error packet: %s", asciichat_error_string(send_result));
952 }
953
954 return ASCIICHAT_OK;
955}
asciichat_error_t error_code
#define HOST_TO_NET_U32(val)
Definition endian.h:66
#define SAFE_FREE(ptr)
Definition common.h:376
#define SAFE_MALLOC(size, cast)
Definition common.h:264
bool crypto_is_ready(const crypto_context_t *ctx)
Check if key exchange is complete and ready for encryption.
@ ERROR_NETWORK
Definition error_codes.h:77
@ ERROR_MEMORY
Definition error_codes.h:56
#define log_warn(...)
Log a WARN message.
Definition log/log.h:574
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:434
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:292
@ PACKET_TYPE_ERROR_MESSAGE
Error packet with asciichat_error_t code and human-readable message.
Definition packet.h:352
#define INVALID_SOCKET_VALUE
Invalid socket value (POSIX: -1)
Definition socket.h:278
Cryptographic context structure.

References ASCIICHAT_OK, crypto_is_ready(), error_packet_t::error_code, error_code, ERROR_INVALID_PARAM, ERROR_MEMORY, ERROR_NETWORK, HOST_TO_NET_U32, INVALID_SOCKET_VALUE, log_warn, MAX_ERROR_MESSAGE_LENGTH, error_packet_t::message_length, packet_send(), PACKET_TYPE_ERROR_MESSAGE, SAFE_FREE, SAFE_MALLOC, send_packet_secure(), and SET_ERRNO.

Referenced by disconnect_client_for_bad_data().

◆ packet_send_remote_log()

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.

Parameters
sockfdSocket file descriptor
crypto_ctxCrypto context for encryption (NULL or not ready sends plaintext)
levelLog level to transmit
directionDirection flag (REMOTE_LOG_DIRECTION_*)
flagsAdditional flags (REMOTE_LOG_FLAG_*)
messageLog message text
Returns
ASCIICHAT_OK on success, error code otherwise

Definition at line 999 of file packet.c.

1000 {
1001 if (sockfd == INVALID_SOCKET_VALUE) {
1002 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid socket descriptor");
1003 }
1004
1005 if (level < LOG_DEV || level > LOG_FATAL) {
1006 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid log level: %d", level);
1007 }
1008
1009 const char *safe_message = message ? message : "";
1010 bool truncated = false;
1011 size_t message_len = strnlen(safe_message, MAX_REMOTE_LOG_MESSAGE_LENGTH);
1012 if (message_len == MAX_REMOTE_LOG_MESSAGE_LENGTH && safe_message[message_len] != '\0') {
1013 truncated = true;
1014 }
1015
1016 size_t payload_len = sizeof(remote_log_packet_t) + message_len;
1017 uint8_t *payload = SAFE_MALLOC(payload_len, uint8_t *);
1018 if (!payload) {
1019 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate %zu bytes for remote log packet", payload_len);
1020 }
1021
1022 remote_log_packet_t *packet = (remote_log_packet_t *)payload;
1023 packet->log_level = (uint8_t)level;
1024 packet->direction = (uint8_t)direction;
1025 uint16_t final_flags = flags;
1026 if (truncated) {
1027 final_flags |= REMOTE_LOG_FLAG_TRUNCATED;
1028 }
1029 packet->flags = HOST_TO_NET_U16(final_flags);
1030 packet->message_length = HOST_TO_NET_U32((uint32_t)message_len);
1031
1032 if (message_len > 0) {
1033 memcpy(payload + sizeof(remote_log_packet_t), safe_message, message_len);
1034 }
1035
1036 bool encryption_ready = crypto_ctx && crypto_is_ready(crypto_ctx);
1037 asciichat_error_t send_result;
1038
1039 if (encryption_ready) {
1040 int secure_result =
1041 send_packet_secure(sockfd, PACKET_TYPE_REMOTE_LOG, payload, payload_len, (crypto_context_t *)crypto_ctx);
1042 send_result = secure_result == 0 ? ASCIICHAT_OK : ERROR_NETWORK;
1043 } else {
1044 send_result = packet_send(sockfd, PACKET_TYPE_REMOTE_LOG, payload, payload_len);
1045 }
1046
1047 SAFE_FREE(payload);
1048
1049 if (send_result != ASCIICHAT_OK) {
1050 return SET_ERRNO(ERROR_NETWORK, "Failed to send remote log packet: %d", send_result);
1051 }
1052
1053 return ASCIICHAT_OK;
1054}
#define HOST_TO_NET_U16(val)
Definition endian.h:96
#define REMOTE_LOG_FLAG_TRUNCATED
Remote log packet flag definitions.
Definition packet.h:736
@ PACKET_TYPE_REMOTE_LOG
Bidirectional remote logging packet.
Definition packet.h:354

References ASCIICHAT_OK, crypto_is_ready(), remote_log_packet_t::direction, ERROR_INVALID_PARAM, ERROR_MEMORY, ERROR_NETWORK, remote_log_packet_t::flags, HOST_TO_NET_U16, HOST_TO_NET_U32, INVALID_SOCKET_VALUE, LOG_FATAL, remote_log_packet_t::log_level, MAX_REMOTE_LOG_MESSAGE_LENGTH, remote_log_packet_t::message_length, packet_send(), PACKET_TYPE_REMOTE_LOG, REMOTE_LOG_FLAG_TRUNCATED, SAFE_FREE, SAFE_MALLOC, send_packet_secure(), and SET_ERRNO.

◆ receive_packet_secure_with_timeout()

packet_recv_result_t receive_packet_secure_with_timeout ( socket_t  sockfd,
void *  crypto_ctx,
bool  enforce_encryption,
packet_envelope_t *  envelope,
uint64_t  timeout_ns 
)

Definition at line 575 of file packet.c.

576 {
577
578 if (!envelope) {
579 SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: envelope=%p", envelope);
580 return PACKET_RECV_ERROR;
581 }
582
583 // Initialize envelope
584 memset(envelope, 0, sizeof(*envelope));
585
586 // Receive packet header
587 packet_header_t header;
588 ssize_t received = recv_with_timeout(sockfd, &header, sizeof(header), timeout_ns);
589
590 // Check for errors first (before comparing signed with unsigned)
591 if (received < 0) {
592 /* Preserve a poll timeout so callers can wait for the next signaling packet
593 * without treating an idle connection as a receive failure. */
594 asciichat_error_context_t error_context;
595 if (HAS_ERRNO(&error_context) && error_context.code == ERROR_NETWORK_TIMEOUT) {
596 return PACKET_RECV_ERROR;
597 }
598 SET_ERRNO(ERROR_NETWORK, "Failed to receive packet header: %zd/%zu bytes", received, sizeof(header));
599 return PACKET_RECV_ERROR;
600 }
601
602 if (received == 0) {
603 return PACKET_RECV_EOF;
604 }
605
606 if ((size_t)received != sizeof(header)) {
607 SET_ERRNO(ERROR_NETWORK, "Failed to receive packet header: %zd/%zu bytes", received, sizeof(header));
608 return PACKET_RECV_ERROR;
609 }
610
611 // Convert from network byte order
612 uint64_t magic = NET_TO_HOST_U64(header.magic);
613 uint16_t pkt_type = NET_TO_HOST_U16(header.type);
614 uint32_t pkt_len = NET_TO_HOST_U32(header.length);
615 uint32_t expected_crc = NET_TO_HOST_U32(header.crc32);
616
617 // DEBUG: Log raw header bytes for debugging packet misalignment
618 char header_hex[95];
619 for (size_t i = 0; i < sizeof(header); i++) {
620 snprintf(&header_hex[i * 2], 3, "%02x", ((uint8_t *)&header)[i]);
621 }
622 header_hex[94] = '\0';
623
624 // DEBUG: Log all received packet types in detail
625 log_info("[RECV_PKT_HEADER] 🔍 Received packet: type=%u (0x%04x), len=%u, client_id=%u, raw=%s", pkt_type, pkt_type,
626 pkt_len, header.client_id, header_hex);
627
628 // Validate magic number
629 if (magic != PACKET_MAGIC) {
630 SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid packet magic: 0x%llx (expected 0x%llx)", magic, PACKET_MAGIC);
631 return PACKET_RECV_ERROR;
632 }
633
634 // Validate packet size
635 if (pkt_len > MAX_PACKET_SIZE) {
636 SET_ERRNO(ERROR_NETWORK_SIZE, "Packet too large: %u > %d", pkt_len, MAX_PACKET_SIZE);
637 return PACKET_RECV_ERROR;
638 }
639
640 // Handle encrypted packets
641 if (pkt_type == PACKET_TYPE_ENCRYPTED) {
642 if (!crypto_ctx) {
643 SET_ERRNO(ERROR_CRYPTO, "Received encrypted packet but no crypto context");
644 return PACKET_RECV_ERROR;
645 }
646
647 // Read encrypted payload
648 uint8_t *ciphertext = buffer_pool_alloc(NULL, pkt_len);
649 if (!ciphertext) {
650 SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for ciphertext");
651 return PACKET_RECV_ERROR;
652 }
653
654 uint64_t recv_timeout = MAX(timeout_ns, calculate_packet_timeout(pkt_len));
655 received = recv_with_timeout(sockfd, ciphertext, pkt_len, recv_timeout);
656 if (received != (ssize_t)pkt_len) {
657 SET_ERRNO(ERROR_NETWORK, "Failed to receive encrypted payload: %zd/%u bytes", received, pkt_len);
658 buffer_pool_free(NULL, ciphertext, pkt_len);
659 return PACKET_RECV_ERROR;
660 }
661
662 // Decrypt - allocate plaintext buffer with extra space
663 // pkt_len is already validated to be <= MAX_PACKET_SIZE, so adding 1024 cannot overflow
664 size_t plaintext_size = (size_t)pkt_len + 1024;
665 uint8_t *plaintext = buffer_pool_alloc(NULL, plaintext_size);
666 if (!plaintext) {
667 SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for plaintext");
668 buffer_pool_free(NULL, ciphertext, pkt_len);
669 return PACKET_RECV_ERROR;
670 }
671
672 size_t plaintext_len;
673 crypto_result_t result = crypto_decrypt(crypto_ctx, ciphertext, pkt_len, plaintext, plaintext_size, &plaintext_len);
674 buffer_pool_free(NULL, ciphertext, pkt_len);
675
676 if (result != CRYPTO_OK) {
677 SET_ERRNO(ERROR_CRYPTO, "Failed to decrypt packet: %s", crypto_result_to_string(result));
678 buffer_pool_free(NULL, plaintext, plaintext_size);
679 return PACKET_RECV_ERROR;
680 }
681
682 if (plaintext_len < sizeof(packet_header_t)) {
683 SET_ERRNO(ERROR_CRYPTO, "Decrypted packet too small: %zu < %zu", plaintext_len, sizeof(packet_header_t));
684 buffer_pool_free(NULL, plaintext, plaintext_size);
685 return PACKET_RECV_ERROR;
686 }
687
688 // Parse decrypted header
689 packet_header_t *decrypted_header = (packet_header_t *)plaintext;
690 pkt_type = NET_TO_HOST_U16(decrypted_header->type);
691
692 // DEBUG: Log decrypted packet type
693 log_info("[RECV_PKT_DECRYPTED] 🔐 After decryption: actual_type=%u (0x%04x), len=%u", pkt_type, pkt_type,
694 NET_TO_HOST_U32(decrypted_header->length));
695 pkt_len = NET_TO_HOST_U32(decrypted_header->length);
696 expected_crc = NET_TO_HOST_U32(decrypted_header->crc32);
697
698 // Extract payload
699 size_t payload_len = plaintext_len - sizeof(packet_header_t);
700 if (payload_len != pkt_len) {
701 SET_ERRNO(ERROR_CRYPTO, "Decrypted payload size mismatch: %zu != %u", payload_len, pkt_len);
702 buffer_pool_free(NULL, plaintext, plaintext_size);
703 return PACKET_RECV_ERROR;
704 }
705
706 // Verify CRC
707 if (pkt_len > 0) {
708 uint32_t actual_crc = asciichat_crc32(plaintext + sizeof(packet_header_t), pkt_len);
709 if (actual_crc != expected_crc) {
710 SET_ERRNO(ERROR_CRYPTO, "Decrypted packet CRC mismatch: 0x%x != 0x%x", actual_crc, expected_crc);
711 buffer_pool_free(NULL, plaintext, plaintext_size);
712 return PACKET_RECV_ERROR;
713 }
714 }
715
716 // Set envelope
717 envelope->type = (packet_type_t)pkt_type;
718 envelope->data = plaintext + sizeof(packet_header_t);
719 envelope->len = pkt_len;
720 envelope->allocated_buffer = plaintext;
721 envelope->allocated_size = plaintext_size;
722
723 return PACKET_RECV_SUCCESS;
724 }
725
726 // Handle unencrypted packets
727 if (enforce_encryption && !packet_is_handshake_type(pkt_type)) {
728 SET_ERRNO(ERROR_CRYPTO, "Received unencrypted packet type %d but encryption is required", pkt_type);
729 return PACKET_RECV_ERROR;
730 }
731
732 // Read payload and return header+payload in envelope (matching encrypted path format)
733 size_t total_size = sizeof(packet_header_t) + pkt_len;
734 uint8_t *packet_buf = buffer_pool_alloc(NULL, total_size);
735 if (!packet_buf) {
736 SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for packet");
737 return PACKET_RECV_ERROR;
738 }
739
740 // Copy header into buffer
741 memcpy(packet_buf, &header, sizeof(packet_header_t));
742
743 if (pkt_len > 0) {
744 uint64_t recv_timeout = calculate_packet_timeout(pkt_len);
745 received = recv_with_timeout(sockfd, packet_buf + sizeof(packet_header_t), pkt_len, recv_timeout);
746 if (received != (ssize_t)pkt_len) {
747 SET_ERRNO(ERROR_NETWORK, "Failed to receive payload: %zd/%u bytes", received, pkt_len);
748 buffer_pool_free(NULL, packet_buf, total_size);
749 return PACKET_RECV_ERROR;
750 }
751
752 // Verify CRC
753 uint32_t actual_crc = asciichat_crc32(packet_buf + sizeof(packet_header_t), pkt_len);
754 if (actual_crc != expected_crc) {
755 SET_ERRNO(ERROR_NETWORK, "Packet CRC mismatch: 0x%x != 0x%x", actual_crc, expected_crc);
756 buffer_pool_free(NULL, packet_buf, total_size);
757 return PACKET_RECV_ERROR;
758 }
759 }
760
761 envelope->data = packet_buf;
762 envelope->allocated_buffer = packet_buf;
763 envelope->allocated_size = total_size;
764 envelope->type = (packet_type_t)pkt_type;
765 envelope->len = total_size;
766
767 return PACKET_RECV_SUCCESS;
768}
#define NET_TO_HOST_U64(val)
Definition endian.h:228
void buffer_pool_free(buffer_pool_t *pool, const 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 long long uint64_t
Definition common.h:59
const char * crypto_result_to_string(crypto_result_t result)
Convert crypto result to human-readable string.
crypto_result_t
Cryptographic operation result codes.
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.
#define HAS_ERRNO(var)
Check if an error occurred and get full context.
@ ERROR_NETWORK_SIZE
Definition error_codes.h:82
@ ERROR_CRYPTO
Definition error_codes.h:96
@ ERROR_NETWORK_TIMEOUT
Definition error_codes.h:80
#define log_info(...)
Log an INFO message.
Definition log/log.h:561
ssize_t recv_with_timeout(socket_t sockfd, void *buf, size_t len, uint64_t timeout_ns)
Receive data with timeout.
@ PACKET_RECV_ERROR
Network error occurred.
Definition packet.h:1158
@ PACKET_RECV_EOF
Connection closed (EOF)
Definition packet.h:1156
@ PACKET_RECV_SUCCESS
Packet received successfully.
Definition packet.h:1154
packet_type_t
Network protocol packet type enumeration.
Definition packet.h:286
#define MAX_PACKET_SIZE
Maximum packet size (5MB)
Definition packet.h:115
#define PACKET_MAGIC
Packet magic number (alias for MAGIC_PACKET_VALID)
Definition packet.h:255
@ PACKET_TYPE_ENCRYPTED
Encrypted packet (after handshake completion)
Definition packet.h:333
#define asciichat_crc32(data, len)
Main CRC32 dispatcher macro - use this in application code.
Definition crc32.h:144
#define MAX(a, b)
Definition param.h:10
Error context structure.
asciichat_error_t code
Error code (asciichat_error_t enum value)
void * allocated_buffer
Buffer that needs to be freed by caller (may be NULL if not allocated)
Definition packet.h:1139
size_t allocated_size
Size of allocated buffer in bytes.
Definition packet.h:1141
size_t len
Length of payload data in bytes.
Definition packet.h:1135
void * data
Packet payload data (decrypted and decompressed if applicable)
Definition packet.h:1133
packet_type_t type
Packet type (from packet_types.h)
Definition packet.h:1131
Network packet header structure.
Definition packet.h:598
uint32_t client_id
Client ID (0 = server, >0 = client identifier)
Definition packet.h:608
uint32_t length
Payload data length in bytes (0 for header-only packets)
Definition packet.h:604
uint64_t magic
Magic number (PACKET_MAGIC = 0xA5C11C4A1 "ASCIICHAT" in hex) for packet validation.
Definition packet.h:600
uint16_t type
Packet type (packet_type_t enumeration)
Definition packet.h:602
uint32_t crc32
CRC32 checksum of payload data (0 if length == 0)
Definition packet.h:606

References packet_envelope_t::allocated_buffer, packet_envelope_t::allocated_size, asciichat_crc32, buffer_pool_alloc(), buffer_pool_free(), packet_header_t::client_id, asciichat_error_context_t::code, packet_header_t::crc32, crypto_decrypt(), CRYPTO_OK, crypto_result_to_string(), packet_envelope_t::data, ERROR_CRYPTO, ERROR_INVALID_PARAM, ERROR_MEMORY, ERROR_NETWORK, ERROR_NETWORK_PROTOCOL, ERROR_NETWORK_SIZE, ERROR_NETWORK_TIMEOUT, HAS_ERRNO, packet_envelope_t::len, packet_header_t::length, log_info, packet_header_t::magic, MAX, MAX_PACKET_SIZE, NET_TO_HOST_U16, NET_TO_HOST_U32, NET_TO_HOST_U64, PACKET_MAGIC, PACKET_RECV_EOF, PACKET_RECV_ERROR, PACKET_RECV_SUCCESS, PACKET_TYPE_ENCRYPTED, recv_with_timeout(), SET_ERRNO, packet_header_t::type, and packet_envelope_t::type.

Referenced by receive_packet_secure().