ascii-chat 0.8.38
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
packet_parsing.c File Reference

📡 Shared packet parsing utilities implementation More...

Go to the source code of this file.

Macros

#define PACKET_MAX_FRAME_SIZE   (256 * 1024 * 1024)
 Maximum frame size (256MB) - prevents memory exhaustion attacks.
 
#define PACKET_MAX_DIMENSION   32768
 Maximum frame dimension (32768x32768) - prevents overflow.
 

Functions

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)
 
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)
 
asciichat_error_t packet_validate_frame_dimensions (uint32_t width, uint32_t height, size_t *out_rgb_size)
 
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)
 

Detailed Description

📡 Shared packet parsing utilities implementation

Provides reusable packet parsing functions used by both server and client protocol handlers to eliminate code duplication and ensure consistency.

Author
Zachary Fogg me@zf.nosp@m.o.gg
Date
December 2025

Definition in file packet_parsing.c.

Macro Definition Documentation

◆ PACKET_MAX_DIMENSION

#define PACKET_MAX_DIMENSION   32768

Maximum frame dimension (32768x32768) - prevents overflow.

Definition at line 31 of file packet_parsing.c.

◆ PACKET_MAX_FRAME_SIZE

#define PACKET_MAX_FRAME_SIZE   (256 * 1024 * 1024)

Maximum frame size (256MB) - prevents memory exhaustion attacks.

Definition at line 25 of file packet_parsing.c.

Function Documentation

◆ packet_decode_frame_data_buffer()

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 
)

Definition at line 89 of file packet_parsing.c.

91 {
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}
asciichat_error_t decompress_data(const void *input, size_t input_size, void *output, size_t output_size)
Definition compression.c:58

References decompress_data().

◆ packet_decode_frame_data_malloc()

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 
)

Definition at line 33 of file packet_parsing.c.

34 {
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}
#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)
Definition util/format.c:10

References decompress_data(), format_bytes_pretty(), and PACKET_MAX_FRAME_SIZE.

◆ packet_parse_opus_batch()

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 
)

Definition at line 173 of file packet_parsing.c.

175 {
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)
182 const size_t header_size = 16;
183 if (packet_len < header_size) {
184 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Opus batch packet too small: %zu < %zu", packet_len, header_size);
185 }
186
187 // Parse header (convert from network byte order)
188 const uint8_t *buf = (const uint8_t *)packet_data;
189 uint32_t sr, fd, fc;
190 memcpy(&sr, buf, 4);
191 memcpy(&fd, buf + 4, 4);
192 memcpy(&fc, buf + 8, 4);
193 *out_sample_rate = (int)NET_TO_HOST_U32(sr);
194 *out_frame_duration = (int)NET_TO_HOST_U32(fd);
195 int frame_count = (int)NET_TO_HOST_U32(fc);
196 *out_frame_count = frame_count;
197
198 // Validate frame count to prevent overflow
199 if (frame_count < 0 || frame_count > 1000) {
200 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid Opus frame count: %d (must be 0-1000)", frame_count);
201 }
202
203 // Extract frame sizes array (after 16-byte header)
204 size_t frame_sizes_bytes = (size_t)frame_count * sizeof(uint16_t);
205 if (packet_len < header_size + frame_sizes_bytes) {
206 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Opus batch packet too small for frame sizes: %zu < %zu", packet_len,
207 header_size + frame_sizes_bytes);
208 }
209 // NOTE: Frame sizes are in network byte order - caller must use NET_TO_HOST_U16() when reading
210 *out_frame_sizes = (const uint16_t *)(buf + header_size);
211
212 // Extract Opus data (after header + frame sizes)
213 *out_opus_data = buf + header_size + frame_sizes_bytes;
214 *out_opus_size = packet_len - header_size - frame_sizes_bytes;
215
216 return ASCIICHAT_OK;
217}

Referenced by handle_audio_opus_batch_packet().

◆ packet_validate_frame_dimensions()

asciichat_error_t packet_validate_frame_dimensions ( uint32_t  width,
uint32_t  height,
size_t *  out_rgb_size 
)

Definition at line 130 of file packet_parsing.c.

130 {
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}
#define PACKET_MAX_DIMENSION
Maximum frame dimension (32768x32768) - prevents overflow.

References format_bytes_pretty(), PACKET_MAX_DIMENSION, and PACKET_MAX_FRAME_SIZE.