ascii-chat 0.11.33
Video chat in your terminal
Loading...
Searching...
No Matches
network/packet/parsing.c
Go to the documentation of this file.
1
19#include <string.h>
20
25#define PACKET_MAX_FRAME_SIZE (256 * 1024 * 1024)
26
31#define PACKET_MAX_DIMENSION 32768
32
33char *packet_decode_frame_data_malloc(const char *frame_data_ptr, size_t frame_data_len, bool is_compressed,
34 uint32_t original_size, uint32_t compressed_size) {
35 // Validate size before allocation to prevent excessive memory usage
36 if (original_size > PACKET_MAX_FRAME_SIZE) {
37 char size_str[32];
38 format_bytes_pretty(original_size, size_str, sizeof(size_str));
39 SET_ERRNO(ERROR_NETWORK_SIZE, "Frame size exceeds maximum: %s (max %d MB)", size_str,
40 PACKET_MAX_FRAME_SIZE / (1024 * 1024));
41 return NULL;
42 }
43
44 // Allocate buffer with extra byte for null terminator
45 char *frame_data = SAFE_MALLOC(original_size + 1, char *);
46 if (!frame_data) {
47 SET_ERRNO(ERROR_MEMORY, "Failed to allocate %u bytes for frame decode", original_size);
48 return NULL;
49 }
50
51 if (is_compressed) {
52 // Validate compressed frame size
53 if (frame_data_len != compressed_size) {
54 SET_ERRNO(ERROR_NETWORK_SIZE, "Compressed frame size mismatch: expected %u, got %zu", compressed_size,
55 frame_data_len);
56 SAFE_FREE(frame_data);
57 return NULL;
58 }
59
60 // Decompress using compression API
61 asciichat_error_t decompress_result = decompress_data(frame_data_ptr, frame_data_len, frame_data, original_size);
62
63 if (decompress_result != ASCIICHAT_OK) {
64 SET_ERRNO(ERROR_COMPRESSION, "Decompression failed for expected size %u: %s", original_size,
65 asciichat_error_string(decompress_result));
66 SAFE_FREE(frame_data);
67 return NULL;
68 }
69
70 log_debug("Decompressed frame: %zu -> %u bytes", frame_data_len, original_size);
71 } else {
72 // Uncompressed frame - validate size
73 if (frame_data_len != original_size) {
74 log_error("Uncompressed frame size mismatch: expected %u, got %zu", original_size, frame_data_len);
75 SAFE_FREE(frame_data);
76 return NULL;
77 }
78
79 // Only copy the actual amount of data we received
80 size_t copy_size = (frame_data_len > original_size) ? original_size : frame_data_len;
81 memcpy(frame_data, frame_data_ptr, copy_size);
82 }
83
84 // Null-terminate the frame data
85 frame_data[original_size] = '\0';
86 return frame_data;
87}
88
89asciichat_error_t packet_decode_frame_data_buffer(const char *frame_data_ptr, size_t frame_data_len, bool is_compressed,
90 void *output_buffer, size_t output_size, uint32_t original_size,
91 uint32_t compressed_size) {
92 if (!frame_data_ptr || !output_buffer) {
93 return SET_ERRNO(ERROR_INVALID_PARAM, "NULL pointer in frame decode");
94 }
95
96 if (output_size < original_size) {
97 return SET_ERRNO(ERROR_BUFFER_FULL, "Output buffer too small: %zu < %u", output_size, original_size);
98 }
99
100 if (is_compressed) {
101 // Validate compressed frame size
102 if (frame_data_len != compressed_size) {
103 return SET_ERRNO(ERROR_NETWORK_SIZE, "Compressed frame size mismatch: expected %u, got %zu", compressed_size,
104 frame_data_len);
105 }
106
107 // Decompress using compression API
108 asciichat_error_t decompress_result = decompress_data(frame_data_ptr, frame_data_len, output_buffer, original_size);
109
110 if (decompress_result != ASCIICHAT_OK) {
111 return SET_ERRNO(ERROR_COMPRESSION, "Decompression failed for expected size %u: %s", original_size,
112 asciichat_error_string(decompress_result));
113 }
114
115 log_debug("Decompressed frame to buffer: %zu -> %u bytes", frame_data_len, original_size);
116 } else {
117 // Uncompressed frame - validate size
118 if (frame_data_len != original_size) {
119 return SET_ERRNO(ERROR_NETWORK_SIZE, "Uncompressed frame size mismatch: expected %u, got %zu", original_size,
120 frame_data_len);
121 }
122
123 // Copy data to output buffer
124 memcpy(output_buffer, frame_data_ptr, original_size);
125 }
126
127 return ASCIICHAT_OK;
128}
129
131 if (!out_rgb_size) {
132 return SET_ERRNO(ERROR_INVALID_PARAM, "out_rgb_size pointer is NULL");
133 }
134
135 // Check dimensions are non-zero
136 if (width == 0 || height == 0) {
137 return SET_ERRNO(ERROR_INVALID_STATE, "Frame dimensions cannot be zero: %ux%u", width, height);
138 }
139
140 // Check dimensions are within reasonable bounds
141 if (width > PACKET_MAX_DIMENSION || height > PACKET_MAX_DIMENSION) {
142 return SET_ERRNO(ERROR_INVALID_STATE, "Frame dimensions exceed maximum: %ux%u (max %u)", width, height,
144 }
145
146 // Calculate RGB buffer size with overflow checking (width * height * 3 bytes per pixel)
147 size_t pixel_count = 0;
148 if (safe_size_mul(width, height, &pixel_count) != 0) {
149 return SET_ERRNO(ERROR_MEMORY, "Frame dimension multiplication overflow: %u * %u", width, height);
150 }
151
152 size_t rgb_size = 0;
153 if (safe_size_mul(pixel_count, 3, &rgb_size) != 0) {
154 return SET_ERRNO(ERROR_MEMORY, "RGB buffer size overflow: %zu * 3", pixel_count);
155 }
156
157 // Validate final buffer size against maximum
158 if (rgb_size > PACKET_MAX_FRAME_SIZE) {
159 char size_str[32];
160 format_bytes_pretty(rgb_size, size_str, sizeof(size_str));
161 return SET_ERRNO(ERROR_MEMORY, "Frame buffer size exceeds maximum: %s (max %d MB)", size_str,
162 PACKET_MAX_FRAME_SIZE / (1024 * 1024));
163 }
164
165 *out_rgb_size = rgb_size;
166 return ASCIICHAT_OK;
167}
168
169// NOTE: packet_parse_audio_batch_header has been moved to lib/audio/audio.c as audio_parse_batch_header
170// This module now provides a wrapper inline function in packet_parsing.h for backwards compatibility
171// See lib/audio/audio.h for the canonical implementation
172
173asciichat_error_t packet_parse_opus_batch(const void *packet_data, size_t packet_len, const uint8_t **out_opus_data,
174 size_t *out_opus_size, const uint16_t **out_frame_sizes, int *out_sample_rate,
175 int *out_frame_duration, int *out_frame_count) {
176 if (!packet_data || !out_opus_data || !out_opus_size || !out_frame_sizes || !out_sample_rate || !out_frame_duration ||
177 !out_frame_count) {
178 return SET_ERRNO(ERROR_INVALID_PARAM, "NULL parameter in Opus batch parsing");
179 }
180
181 // Verify minimum packet size (16-byte header: sample_rate + frame_duration + frame_count + reserved)
182 const size_t header_size = 16;
183 if (packet_len < header_size) {
184 // DEBUG: Log first few bytes of corrupted packet to understand what's happening
185 char hex_buf[256];
186 size_t bytes_to_show = (packet_len < 32) ? packet_len : 32;
187 for (size_t i = 0; i < bytes_to_show; i++) {
188 snprintf(hex_buf + i * 2, 3, "%02x", ((uint8_t *)packet_data)[i]);
189 }
190 hex_buf[bytes_to_show * 2] = '\0';
191 log_error("★ OPUS_BATCH_RCV_DEBUG: packet_len=%zu, expected_min=%zu, first_bytes=%s", packet_len, header_size,
192 hex_buf);
193 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Opus batch packet too small: %zu < %zu", packet_len, header_size);
194 }
195
196 // Parse header (convert from network byte order)
197 const uint8_t *buf = (const uint8_t *)packet_data;
198 uint32_t sr, fd, fc;
199 memcpy(&sr, buf, 4);
200 memcpy(&fd, buf + 4, 4);
201 memcpy(&fc, buf + 8, 4);
202 *out_sample_rate = (int)NET_TO_HOST_U32(sr);
203 *out_frame_duration = (int)NET_TO_HOST_U32(fd);
204 int frame_count = (int)NET_TO_HOST_U32(fc);
205 *out_frame_count = frame_count;
206
207 // Validate frame count to prevent overflow
208 if (frame_count < 0 || frame_count > 1000) {
209 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid Opus frame count: %d (must be 0-1000)", frame_count);
210 }
211
212 // Extract frame sizes array (after 16-byte header)
213 size_t frame_sizes_bytes = (size_t)frame_count * sizeof(uint16_t);
214 if (packet_len < header_size + frame_sizes_bytes) {
215 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Opus batch packet too small for frame sizes: %zu < %zu", packet_len,
216 header_size + frame_sizes_bytes);
217 }
218 // NOTE: Frame sizes are in network byte order - caller must use NET_TO_HOST_U16() when reading
219 *out_frame_sizes = (const uint16_t *)(buf + header_size);
220
221 // Extract Opus data (after header + frame sizes)
222 *out_opus_data = buf + header_size + frame_sizes_bytes;
223 *out_opus_size = packet_len - header_size - frame_sizes_bytes;
224
225 return ASCIICHAT_OK;
226}
🔢 Byte-Level Access and Arithmetic Utilities
📦 Network Packet Compression Utilities
🔄 Network byte order conversion helpers
#define NET_TO_HOST_U32(val)
Definition endian.h:81
unsigned short uint16_t
Definition common.h:57
unsigned int uint32_t
Definition common.h:58
#define SAFE_FREE(ptr)
Definition common.h:376
#define SAFE_MALLOC(size, cast)
Definition common.h:264
#define safe_size_mul
Definition common.h:488
unsigned char uint8_t
Definition common.h:56
asciichat_error_t decompress_data(const void *input, size_t input_size, void *output, size_t output_size)
Decompress data using zstd.
Definition compression.c:58
#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_INVALID_STATE
@ ERROR_COMPRESSION
@ ERROR_BUFFER_FULL
@ ERROR_NETWORK_PROTOCOL
Definition error_codes.h:81
@ ERROR_MEMORY
Definition error_codes.h:56
@ ASCIICHAT_OK
Definition error_codes.h:51
@ ERROR_NETWORK_SIZE
Definition error_codes.h:82
@ ERROR_INVALID_PARAM
#define log_error(...)
Log an ERROR message.
Definition log/log.h:587
#define log_debug(...)
Log a DEBUG message.
Definition log/log.h:548
asciichat_error_t packet_parse_opus_batch(const void *packet_data, size_t packet_len, const uint8_t **out_opus_data, size_t *out_opus_size, const uint16_t **out_frame_sizes, int *out_sample_rate, int *out_frame_duration, int *out_frame_count)
Parse Opus audio batch packet header and extract frame data.
#define PACKET_MAX_DIMENSION
Maximum frame dimension (32768x32768) - prevents overflow.
asciichat_error_t packet_decode_frame_data_buffer(const char *frame_data_ptr, size_t frame_data_len, bool is_compressed, void *output_buffer, size_t output_size, uint32_t original_size, uint32_t compressed_size)
Decode frame data (fixed buffer version for server handlers)
asciichat_error_t packet_validate_frame_dimensions(uint32_t width, uint32_t height, size_t *out_rgb_size)
Validate frame dimensions and calculate RGB buffer size.
char * packet_decode_frame_data_malloc(const char *frame_data_ptr, size_t frame_data_len, bool is_compressed, uint32_t original_size, uint32_t compressed_size)
Decode frame data (malloc version for client handlers)
#define PACKET_MAX_FRAME_SIZE
Maximum frame size (256MB) - prevents memory exhaustion attacks.
void format_bytes_pretty(size_t bytes, char *out, size_t out_capacity)
Format byte count into human-readable string.
Definition util/format.c:10
📊 String Formatting Utilities