1 |
|
|
#include <time.h> |
2 |
|
|
#include <stdio.h> |
3 |
|
|
#include <stdlib.h> |
4 |
|
|
#include <stdint.h> |
5 |
|
|
#include <string.h> |
6 |
|
|
#include <sys/types.h> |
7 |
|
|
#include <unistd.h> |
8 |
|
|
#include <arpa/inet.h> |
9 |
|
|
#include <math.h> |
10 |
|
|
|
11 |
|
|
#include "frame.h" |
12 |
|
|
#include "str.h" |
13 |
|
|
#include "alloc.h" |
14 |
|
|
#include "log.h" |
15 |
|
|
#include "predict.h" |
16 |
|
|
|
17 |
|
|
#if defined(_MSC_VER) |
18 |
|
|
/* Microsoft C/C++-compatible compiler */ |
19 |
|
|
#include <intrin.h> |
20 |
|
|
#elif defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__)) |
21 |
|
|
/* GCC-compatible compiler, targeting x86/x86-64 */ |
22 |
|
|
#include <x86intrin.h> |
23 |
|
|
#elif defined(__GNUC__) && defined(__ARM_NEON__) |
24 |
|
|
/* GCC-compatible compiler, targeting ARM with NEON */ |
25 |
|
|
#include <arm_neon.h> |
26 |
|
|
#elif defined(__GNUC__) && defined(__IWMMXT__) |
27 |
|
|
/* GCC-compatible compiler, targeting ARM with WMMX */ |
28 |
|
|
#include <mmintrin.h> |
29 |
|
|
#elif (defined(__GNUC__) || defined(__xlC__)) && \ |
30 |
|
|
(defined(__VEC__) || defined(__ALTIVEC__)) |
31 |
|
|
/* XLC or GCC-compatible compiler, targeting PowerPC with VMX/VSX */ |
32 |
|
|
#include <altivec.h> |
33 |
|
|
#elif defined(__GNUC__) && defined(__SPE__) |
34 |
|
|
/* GCC-compatible compiler, targeting PowerPC with SPE */ |
35 |
|
|
#include <spe.h> |
36 |
|
|
#endif |
37 |
|
|
|
38 |
|
|
/** |
39 |
|
|
* Converts the unsigned 64 bit integer from host byte order to network byte |
40 |
|
|
* order. |
41 |
|
|
* |
42 |
|
|
* @param length [size_t] "The length of the random byte string" |
43 |
|
|
* @return [char *] "Random byte string of the given length" |
44 |
|
|
*/ |
45 |
|
1 |
static char *random_bytes(int length) { |
46 |
|
1 |
char *res = WSS_malloc(length); |
47 |
|
|
/* Seed number for rand() */ |
48 |
|
1 |
srand((unsigned int) time(0) + getpid()); |
49 |
|
|
|
50 |
✓✓ |
121 |
while (likely(length--)) { |
51 |
|
120 |
res[length] = rand(); |
52 |
|
120 |
srand(rand()); |
53 |
|
|
} |
54 |
|
|
|
55 |
|
1 |
return res; |
56 |
|
|
} |
57 |
|
|
|
58 |
|
|
/** |
59 |
|
|
* Converts the unsigned 64 bit integer from host byte order to network byte |
60 |
|
|
* order. |
61 |
|
|
* |
62 |
|
|
* @param value [uint64_t] "A 64 bit unsigned integer" |
63 |
|
|
* @return [uint64_t] "The 64 bit unsigned integer in network byte order" |
64 |
|
|
*/ |
65 |
|
3 |
static inline uint64_t htonl64(uint64_t value) { |
66 |
|
3 |
static const int num = 42; |
67 |
|
|
|
68 |
|
|
/** |
69 |
|
|
* If this check is true, the system is using the little endian |
70 |
|
|
* convention. Else the system is using the big endian convention, which |
71 |
|
|
* means that we do not have to represent our integers in another way. |
72 |
|
|
*/ |
73 |
|
3 |
if (*(char *)&num == 42) { |
74 |
|
3 |
const uint32_t high = (uint32_t)(value >> 32); |
75 |
|
3 |
const uint32_t low = (uint32_t)(value & 0xFFFFFFFF); |
76 |
|
|
|
77 |
|
3 |
return (((uint64_t)(htonl(low))) << 32) | htonl(high); |
78 |
|
|
} else { |
79 |
|
|
return value; |
80 |
|
|
} |
81 |
|
|
} |
82 |
|
|
|
83 |
|
|
/** |
84 |
|
|
* Converts the unsigned 16 bit integer from host byte order to network byte |
85 |
|
|
* order. |
86 |
|
|
* |
87 |
|
|
* @param value [uint16_t] "A 16 bit unsigned integer" |
88 |
|
|
* @return [uint16_t] "The 16 bit unsigned integer in network byte order" |
89 |
|
|
*/ |
90 |
|
22 |
static inline uint16_t htons16(uint16_t value) { |
91 |
|
22 |
static const int num = 42; |
92 |
|
|
|
93 |
|
|
/** |
94 |
|
|
* If this check is true, the system is using the little endian |
95 |
|
|
* convention. Else the system is using the big endian convention, which |
96 |
|
|
* means that we do not have to represent our integers in another way. |
97 |
|
|
*/ |
98 |
|
22 |
if (*(char *)&num == 42) { |
99 |
|
22 |
return ntohs(value); |
100 |
|
|
} else { |
101 |
|
|
return value; |
102 |
|
|
} |
103 |
|
|
} |
104 |
|
|
|
105 |
|
9 |
static void unmask(wss_frame_t *frame) { |
106 |
|
9 |
char *applicationData = frame->payload+frame->extensionDataLength; |
107 |
|
9 |
uint64_t i = 0; |
108 |
|
|
#if defined(__AVX512F__) |
109 |
|
9 |
__m512i masked_data; |
110 |
|
9 |
uint32_t mask; |
111 |
✓✓ |
9 |
memcpy(&mask, frame->maskingKey, sizeof(uint32_t)); |
112 |
✓✓ |
9 |
__m512i maskingKey = _mm512_setr_epi32( |
113 |
|
|
(int)mask, |
114 |
|
|
(int)mask, |
115 |
|
|
(int)mask, |
116 |
|
|
(int)mask, |
117 |
|
|
(int)mask, |
118 |
|
|
(int)mask, |
119 |
|
|
(int)mask, |
120 |
|
|
(int)mask, |
121 |
|
|
(int)mask, |
122 |
|
|
(int)mask, |
123 |
|
|
(int)mask, |
124 |
|
|
(int)mask, |
125 |
|
|
(int)mask, |
126 |
|
|
(int)mask, |
127 |
|
|
(int)mask, |
128 |
|
|
(int)mask |
129 |
|
|
); |
130 |
|
|
|
131 |
|
9 |
uint64_t size = sizeof(__m512i); |
132 |
|
|
|
133 |
✓✓ |
9 |
if ( likely(frame->applicationDataLength > size) ) { |
134 |
✓✓ |
2072 |
for (; likely(i <= frame->applicationDataLength - size); i += size) { |
135 |
|
2068 |
masked_data = _mm512_loadu_si512((const void *)(applicationData+i)); |
136 |
|
2068 |
_mm512_storeu_si512((void *)(applicationData+i), _mm512_xor_si512 (masked_data, maskingKey)); |
137 |
|
|
} |
138 |
|
|
} |
139 |
|
|
|
140 |
|
|
// last part |
141 |
✓✗ |
9 |
if ( likely(i < frame->applicationDataLength) ) { |
142 |
|
9 |
char buffer[size]; |
143 |
|
9 |
memset(buffer, '\0', size); |
144 |
|
9 |
memcpy(buffer, applicationData + i, frame->applicationDataLength - i); |
145 |
|
9 |
masked_data = _mm512_loadu_si512((const void *)buffer); |
146 |
|
9 |
_mm512_storeu_si512((void *)buffer, _mm512_xor_si512 (masked_data, maskingKey)); |
147 |
|
9 |
memcpy(applicationData + i, buffer, (frame->applicationDataLength - i)); |
148 |
|
|
} |
149 |
|
|
#elif defined(__AVX2__) && defined(__AVX__) |
150 |
|
|
__m256i masked_data; |
151 |
|
|
__m256i maskingKey = _mm256_setr_epi8( |
152 |
|
|
frame->maskingKey[0], |
153 |
|
|
frame->maskingKey[1], |
154 |
|
|
frame->maskingKey[2], |
155 |
|
|
frame->maskingKey[3], |
156 |
|
|
frame->maskingKey[0], |
157 |
|
|
frame->maskingKey[1], |
158 |
|
|
frame->maskingKey[2], |
159 |
|
|
frame->maskingKey[3], |
160 |
|
|
frame->maskingKey[0], |
161 |
|
|
frame->maskingKey[1], |
162 |
|
|
frame->maskingKey[2], |
163 |
|
|
frame->maskingKey[3], |
164 |
|
|
frame->maskingKey[0], |
165 |
|
|
frame->maskingKey[1], |
166 |
|
|
frame->maskingKey[2], |
167 |
|
|
frame->maskingKey[3], |
168 |
|
|
frame->maskingKey[0], |
169 |
|
|
frame->maskingKey[1], |
170 |
|
|
frame->maskingKey[2], |
171 |
|
|
frame->maskingKey[3], |
172 |
|
|
frame->maskingKey[0], |
173 |
|
|
frame->maskingKey[1], |
174 |
|
|
frame->maskingKey[2], |
175 |
|
|
frame->maskingKey[3], |
176 |
|
|
frame->maskingKey[0], |
177 |
|
|
frame->maskingKey[1], |
178 |
|
|
frame->maskingKey[2], |
179 |
|
|
frame->maskingKey[3], |
180 |
|
|
frame->maskingKey[0], |
181 |
|
|
frame->maskingKey[1], |
182 |
|
|
frame->maskingKey[2], |
183 |
|
|
frame->maskingKey[3] |
184 |
|
|
); |
185 |
|
|
|
186 |
|
|
uint64_t size = sizeof(__m256i); |
187 |
|
|
|
188 |
|
|
if ( likely(frame->applicationDataLength > size) ) { |
189 |
|
|
for (; likely(i <= frame->applicationDataLength - size); i += size) { |
190 |
|
|
masked_data = _mm256_loadu_si256((const __m256i *)(applicationData+i)); |
191 |
|
|
_mm256_storeu_si256((__m256i *)(applicationData+i), _mm256_xor_si256 (masked_data, maskingKey)); |
192 |
|
|
} |
193 |
|
|
} |
194 |
|
|
|
195 |
|
|
// last part |
196 |
|
|
if ( likely(i < frame->applicationDataLength) ) { |
197 |
|
|
char buffer[size]; |
198 |
|
|
memset(buffer, '\0', size); |
199 |
|
|
memcpy(buffer, applicationData + i, frame->applicationDataLength - i); |
200 |
|
|
masked_data = _mm256_loadu_si256((const __m256i *)buffer); |
201 |
|
|
_mm256_storeu_si256((__m256i *)buffer, _mm256_xor_si256 (masked_data, maskingKey)); |
202 |
|
|
memcpy(applicationData + i, buffer, (frame->applicationDataLength - i)); |
203 |
|
|
} |
204 |
|
|
#elif defined(__SSE2__) |
205 |
|
|
__m128i masked_data; |
206 |
|
|
__m128i maskingKey = _mm_setr_epi8( |
207 |
|
|
frame->maskingKey[0], |
208 |
|
|
frame->maskingKey[1], |
209 |
|
|
frame->maskingKey[2], |
210 |
|
|
frame->maskingKey[3], |
211 |
|
|
frame->maskingKey[0], |
212 |
|
|
frame->maskingKey[1], |
213 |
|
|
frame->maskingKey[2], |
214 |
|
|
frame->maskingKey[3], |
215 |
|
|
frame->maskingKey[0], |
216 |
|
|
frame->maskingKey[1], |
217 |
|
|
frame->maskingKey[2], |
218 |
|
|
frame->maskingKey[3], |
219 |
|
|
frame->maskingKey[0], |
220 |
|
|
frame->maskingKey[1], |
221 |
|
|
frame->maskingKey[2], |
222 |
|
|
frame->maskingKey[3] |
223 |
|
|
); |
224 |
|
|
|
225 |
|
|
uint64_t size = sizeof(__m128i); |
226 |
|
|
|
227 |
|
|
if ( likely(frame->applicationDataLength > size) ) { |
228 |
|
|
for (; likely(i <= frame->applicationDataLength - size); i += size) { |
229 |
|
|
masked_data = _mm_loadu_si128((const __m128i *)(applicationData+i)); |
230 |
|
|
_mm_storeu_si128((__m128i *)(applicationData+i), _mm_xor_si128 (masked_data, maskingKey)); |
231 |
|
|
} |
232 |
|
|
} |
233 |
|
|
|
234 |
|
|
if ( likely(i < frame->applicationDataLength) ) { |
235 |
|
|
char buffer[size]; |
236 |
|
|
memset(buffer, '\0', size); |
237 |
|
|
memcpy(buffer, applicationData + i, frame->applicationDataLength - i); |
238 |
|
|
masked_data = _mm_loadu_si128((const __m128i *)buffer); |
239 |
|
|
_mm_storeu_si128((__m128i *)buffer, _mm_xor_si128 (masked_data, maskingKey)); |
240 |
|
|
memcpy(applicationData + i, buffer, (frame->applicationDataLength - i)); |
241 |
|
|
} |
242 |
|
|
#else |
243 |
|
|
uint64_t j; |
244 |
|
|
for (j = 0; likely(i < frame->applicationDataLength); i++, j++){ |
245 |
|
|
applicationData[j] = applicationData[i] ^ frame->maskingKey[j % 4]; |
246 |
|
|
} |
247 |
|
|
#endif |
248 |
|
9 |
} |
249 |
|
|
|
250 |
|
|
/** |
251 |
|
|
* Parses a payload of data into a websocket frame. Returns the frame and |
252 |
|
|
* corrects the offset pointer in order for multiple frames to be processed |
253 |
|
|
* from the same payload. |
254 |
|
|
* |
255 |
|
|
* @param payload [char *] "The payload to be processed" |
256 |
|
|
* @param length [size_t] "The length of the payload" |
257 |
|
|
* @param offset [size_t *] "A pointer to an offset" |
258 |
|
|
* @return [wss_frame_t *] "A websocket frame" |
259 |
|
|
*/ |
260 |
|
11 |
wss_frame_t *WSS_parse_frame(char *payload, size_t length, size_t *offset) { |
261 |
|
11 |
wss_frame_t *frame; |
262 |
|
|
|
263 |
✓✓ |
11 |
if ( unlikely(NULL == payload) ) { |
264 |
|
1 |
WSS_log_error("Payload cannot be NULL"); |
265 |
|
1 |
return NULL; |
266 |
|
|
} |
267 |
|
|
|
268 |
✗✓ |
10 |
if ( unlikely(NULL == (frame = WSS_malloc(sizeof(wss_frame_t)))) ) { |
269 |
|
|
WSS_log_error("Unable to allocate frame"); |
270 |
|
|
return NULL; |
271 |
|
|
} |
272 |
|
|
|
273 |
|
10 |
WSS_log_trace("Parsing frame starting from offset %lu", *offset); |
274 |
|
|
|
275 |
|
10 |
frame->mask = false; |
276 |
|
10 |
frame->payloadLength = 0; |
277 |
|
10 |
frame->applicationDataLength = 0; |
278 |
|
10 |
frame->extensionDataLength = 0; |
279 |
|
|
|
280 |
|
10 |
frame->fin = 0x80 & payload[*offset]; |
281 |
|
10 |
frame->rsv1 = 0x40 & payload[*offset]; |
282 |
|
10 |
frame->rsv2 = 0x20 & payload[*offset]; |
283 |
|
10 |
frame->rsv3 = 0x10 & payload[*offset]; |
284 |
|
10 |
frame->opcode = 0x0F & payload[*offset]; |
285 |
|
|
|
286 |
|
10 |
*offset += 1; |
287 |
|
|
|
288 |
✓✓ |
10 |
if ( likely(*offset < length) ) { |
289 |
|
9 |
frame->mask = 0x80 & payload[*offset]; |
290 |
|
9 |
frame->payloadLength = 0x7F & payload[*offset]; |
291 |
|
|
} |
292 |
|
10 |
*offset += 1; |
293 |
|
|
|
294 |
✓✓✓ |
10 |
switch (frame->payloadLength) { |
295 |
|
2 |
case 126: |
296 |
✓✗ |
2 |
if ( likely(*offset+sizeof(uint16_t) <= length) ) { |
297 |
|
2 |
memcpy(&frame->payloadLength, payload+*offset, sizeof(uint16_t)); |
298 |
|
2 |
frame->payloadLength = htons16(frame->payloadLength); |
299 |
|
|
} |
300 |
|
2 |
*offset += sizeof(uint16_t); |
301 |
|
2 |
break; |
302 |
|
2 |
case 127: |
303 |
✓✗ |
2 |
if ( likely(*offset+sizeof(uint64_t) <= length) ) { |
304 |
|
2 |
memcpy(&frame->payloadLength, payload+*offset, sizeof(uint64_t)); |
305 |
|
2 |
frame->payloadLength = htonl64(frame->payloadLength); |
306 |
|
|
} |
307 |
|
2 |
*offset += sizeof(uint64_t); |
308 |
|
2 |
break; |
309 |
|
|
} |
310 |
|
|
|
311 |
✓✓ |
10 |
if ( likely(frame->mask) ) { |
312 |
✓✗ |
9 |
if ( likely(*offset+sizeof(uint32_t) <= length) ) { |
313 |
|
9 |
memcpy(frame->maskingKey, payload+*offset, sizeof(uint32_t)); |
314 |
|
|
} |
315 |
|
9 |
*offset += sizeof(uint32_t); |
316 |
|
|
} |
317 |
|
|
|
318 |
|
10 |
frame->applicationDataLength = frame->payloadLength-frame->extensionDataLength; |
319 |
✓✓ |
10 |
if ( likely(frame->applicationDataLength > 0) ) { |
320 |
✓✗ |
9 |
if ( likely(*offset+frame->applicationDataLength <= length) ) { |
321 |
✗✓ |
9 |
if ( unlikely(NULL == (frame->payload = WSS_malloc(frame->applicationDataLength))) ) { |
322 |
|
|
WSS_log_error("Unable to allocate frame application data"); |
323 |
|
|
return NULL; |
324 |
|
|
} |
325 |
|
|
|
326 |
|
9 |
memcpy(frame->payload, payload+*offset, frame->applicationDataLength); |
327 |
|
|
} |
328 |
|
9 |
*offset += frame->applicationDataLength; |
329 |
|
|
} |
330 |
|
|
|
331 |
✓✓✓✗
|
10 |
if ( likely(frame->mask && *offset <= length) ) { |
332 |
|
9 |
unmask(frame); |
333 |
|
|
} |
334 |
|
|
|
335 |
|
|
return frame; |
336 |
|
|
} |
337 |
|
|
|
338 |
|
|
/** |
339 |
|
|
* Converts a single frame into a char array. |
340 |
|
|
* |
341 |
|
|
* @param frame [wss_frame_t *] "The frame" |
342 |
|
|
* @param message [char **] "A pointer to a char array which should be filled with the frame data" |
343 |
|
|
* @return [size_t] "The size of the frame data" |
344 |
|
|
*/ |
345 |
|
8 |
size_t WSS_stringify_frame(wss_frame_t *frame, char **message) { |
346 |
|
8 |
size_t offset = 0; |
347 |
|
8 |
size_t len = 2; |
348 |
|
8 |
char *mes; |
349 |
|
|
|
350 |
✓✓ |
8 |
if ( unlikely(NULL == frame) ) { |
351 |
|
2 |
*message = NULL; |
352 |
|
2 |
return 0; |
353 |
|
|
} |
354 |
|
|
|
355 |
|
6 |
WSS_log_trace("Creating byte message from frame"); |
356 |
|
|
|
357 |
✓✓ |
6 |
if ( likely(frame->payloadLength > 125) ) { |
358 |
✓✓ |
2 |
if ( likely(frame->payloadLength <= 65535) ) { |
359 |
|
|
len += sizeof(uint16_t); |
360 |
|
|
} else { |
361 |
|
1 |
len += sizeof(uint64_t); |
362 |
|
|
} |
363 |
|
|
} |
364 |
|
|
|
365 |
|
6 |
len += frame->payloadLength; |
366 |
|
|
|
367 |
✗✓ |
6 |
if ( unlikely(NULL == (mes = WSS_malloc(len*sizeof(char)))) ) { |
368 |
|
|
WSS_log_error("Unable to allocate return message"); |
369 |
|
|
*message = NULL; |
370 |
|
|
return 0; |
371 |
|
|
} |
372 |
|
|
|
373 |
✓✗ |
6 |
if (frame->fin) { |
374 |
|
6 |
mes[offset] |= 0x80; |
375 |
|
|
} |
376 |
|
|
|
377 |
✓✓ |
6 |
if (frame->rsv1) { |
378 |
|
1 |
mes[offset] |= 0x40; |
379 |
|
|
} |
380 |
|
|
|
381 |
✓✓ |
6 |
if ( unlikely(frame->rsv2) ) { |
382 |
|
1 |
mes[offset] |= 0x20; |
383 |
|
|
} |
384 |
|
|
|
385 |
✓✓ |
6 |
if ( unlikely(frame->rsv3) ) { |
386 |
|
1 |
mes[offset] |= 0x10; |
387 |
|
|
} |
388 |
|
|
|
389 |
|
6 |
mes[offset++] |= 0xF & frame->opcode; |
390 |
|
|
|
391 |
✓✓ |
6 |
if ( unlikely(frame->payloadLength <= 125) ) { |
392 |
|
4 |
mes[offset++] = frame->payloadLength; |
393 |
✓✓ |
2 |
} else if ( likely(frame->payloadLength <= 65535) ) { |
394 |
|
1 |
uint16_t plen; |
395 |
|
1 |
mes[offset++] = 126; |
396 |
|
1 |
plen = htons16(frame->payloadLength); |
397 |
|
1 |
memcpy(mes+offset, &plen, sizeof(plen)); |
398 |
|
1 |
offset += sizeof(plen); |
399 |
|
|
} else { |
400 |
|
1 |
uint64_t plen; |
401 |
|
1 |
mes[offset++] = 127; |
402 |
|
1 |
plen = htonl64(frame->payloadLength); |
403 |
|
1 |
memcpy(mes+offset, &plen, sizeof(plen)); |
404 |
|
1 |
offset += sizeof(plen); |
405 |
|
|
} |
406 |
|
|
|
407 |
✗✓ |
6 |
if ( unlikely(frame->extensionDataLength > 0) ) { |
408 |
|
|
memcpy(mes+offset, frame->payload, frame->extensionDataLength); |
409 |
|
|
offset += frame->extensionDataLength; |
410 |
|
|
} |
411 |
|
|
|
412 |
✓✗ |
6 |
if ( likely(frame->applicationDataLength > 0) ) { |
413 |
|
6 |
memcpy(mes+offset, frame->payload+frame->extensionDataLength, frame->applicationDataLength); |
414 |
|
6 |
offset += frame->applicationDataLength; |
415 |
|
|
} |
416 |
|
|
|
417 |
|
6 |
*message = mes; |
418 |
|
|
|
419 |
|
6 |
return offset; |
420 |
|
|
} |
421 |
|
|
|
422 |
|
|
/** |
423 |
|
|
* Converts an array of frames into a char array that can be written to others. |
424 |
|
|
* |
425 |
|
|
* @param frames [wss_frame_t **] "The frames to be converted" |
426 |
|
|
* @param size [size_t] "The amount of frames" |
427 |
|
|
* @param message [char **] "A pointer to a char array which should be filled with the frame data" |
428 |
|
|
* @return [size_t] "The size of the frame data" |
429 |
|
|
*/ |
430 |
|
3 |
size_t WSS_stringify_frames(wss_frame_t **frames, size_t size, char **message) { |
431 |
|
3 |
size_t i, n; |
432 |
|
3 |
char *f; |
433 |
|
3 |
char *msg = NULL; |
434 |
|
3 |
size_t message_length = 0; |
435 |
|
|
|
436 |
|
3 |
WSS_log_trace("Creating byte message from frames"); |
437 |
|
|
|
438 |
✓✓ |
8 |
for (i = 0; likely(i < size); i++) { |
439 |
|
3 |
n = WSS_stringify_frame(frames[i], &f); |
440 |
|
|
|
441 |
|
|
// If we receive less than two bytes, we did not receive a valid frame |
442 |
✓✓ |
3 |
if ( unlikely(n < 2) ) { |
443 |
|
1 |
WSS_log_error("Received invalid frame"); |
444 |
|
1 |
*message = NULL; |
445 |
|
1 |
WSS_free((void **)&f); |
446 |
|
1 |
WSS_free((void **)&msg); |
447 |
|
1 |
return 0; |
448 |
|
|
} |
449 |
|
|
|
450 |
✗✓ |
2 |
if ( unlikely(NULL == (msg = WSS_realloc((void **) &msg, |
451 |
|
|
message_length*sizeof(char), (message_length+n+1)*sizeof(char)))) ) { |
452 |
|
|
WSS_log_error("Unable to allocate message string"); |
453 |
|
|
*message = NULL; |
454 |
|
|
WSS_free((void **)&f); |
455 |
|
|
return 0; |
456 |
|
|
} |
457 |
|
|
|
458 |
|
2 |
memcpy(msg+message_length, f, n); |
459 |
|
2 |
message_length += n; |
460 |
|
|
|
461 |
|
2 |
WSS_free((void **) &f); |
462 |
|
|
} |
463 |
|
|
|
464 |
|
2 |
*message = msg; |
465 |
|
|
|
466 |
|
2 |
return message_length; |
467 |
|
|
} |
468 |
|
|
|
469 |
|
|
/** |
470 |
|
|
* Creates a series of frames from a message. |
471 |
|
|
* |
472 |
|
|
* @param config [wss_config_t *] "The server configuration" |
473 |
|
|
* @param opcode [wss_opcode_t] "The opcode that the frames should be" |
474 |
|
|
* @param message [char *] "The message to be converted into frames" |
475 |
|
|
* @param message_length [size_t] "The length of the message" |
476 |
|
|
* @param fs [wss_frame_t ***] "The frames created from the message" |
477 |
|
|
* @return [size_t] "The amount of frames created" |
478 |
|
|
*/ |
479 |
|
8 |
size_t WSS_create_frames(wss_config_t *config, wss_opcode_t opcode, char *message, size_t message_length, wss_frame_t ***fs) { |
480 |
|
8 |
size_t i, j, offset = 0; |
481 |
|
8 |
wss_frame_t *frame; |
482 |
|
8 |
size_t frames_count; |
483 |
|
8 |
wss_frame_t **frames; |
484 |
|
8 |
wss_close_t code; |
485 |
|
8 |
char *msg = message; |
486 |
|
|
|
487 |
✓✓ |
8 |
if ( unlikely(NULL == config) ) { |
488 |
|
1 |
*fs = NULL; |
489 |
|
1 |
return 0; |
490 |
|
|
} |
491 |
|
|
|
492 |
✓✓ |
7 |
if ( unlikely(NULL == message && message_length != 0) ) { |
493 |
|
1 |
*fs = NULL; |
494 |
|
1 |
return 0; |
495 |
|
|
} |
496 |
|
|
|
497 |
✓✓ |
6 |
frames_count = MAX(1, (size_t)ceil((double)message_length/(double)config->size_frame)); |
498 |
|
|
|
499 |
✗✓ |
6 |
if ( unlikely(NULL == (*fs = WSS_malloc(frames_count*sizeof(wss_frame_t *)))) ) { |
500 |
|
|
WSS_log_error("Unable to allocate closing frame"); |
501 |
|
|
*fs = NULL; |
502 |
|
|
return 0; |
503 |
|
|
} |
504 |
|
|
|
505 |
|
6 |
frames = *fs; |
506 |
|
|
|
507 |
✓✓ |
6 |
if (opcode == CLOSE_FRAME) { |
508 |
✓✓ |
4 |
if ( likely(message_length >= sizeof(uint16_t)) ) { |
509 |
|
2 |
memcpy(&code, msg, sizeof(uint16_t)); |
510 |
|
2 |
code = ntohs(code); |
511 |
|
2 |
msg = msg + sizeof(uint16_t); |
512 |
✓✓ |
2 |
} else if ( unlikely(message_length == 1) ) { |
513 |
|
1 |
code = CLOSE_PROTOCOL; |
514 |
|
1 |
msg = msg + 1; |
515 |
|
|
} else { |
516 |
|
1 |
code = CLOSE_NORMAL; |
517 |
|
|
} |
518 |
|
|
|
519 |
|
4 |
frame = WSS_closing_frame(code, msg); |
520 |
|
4 |
frames[0] = frame; |
521 |
|
4 |
return 1; |
522 |
|
|
} |
523 |
|
|
|
524 |
✓✓ |
5 |
for (i = 0; i < frames_count; i++) { |
525 |
|
|
// Always allocate one frame |
526 |
✗✓ |
3 |
if ( unlikely(NULL == (frame = WSS_malloc(sizeof(wss_frame_t)))) ) { |
527 |
|
|
WSS_log_error("Unable to allocate frame"); |
528 |
|
|
for (j = 0; j < i; j++) { |
529 |
|
|
WSS_free_frame(frames[j]); |
530 |
|
|
} |
531 |
|
|
WSS_free((void **)&frames); |
532 |
|
|
*fs = NULL; |
533 |
|
|
return 0; |
534 |
|
|
} |
535 |
|
|
|
536 |
|
3 |
frame->fin = 0; |
537 |
|
3 |
frame->opcode = opcode; |
538 |
|
3 |
frame->mask = 0; |
539 |
|
|
|
540 |
|
3 |
frame->applicationDataLength = MIN(message_length-(config->size_frame*i), config->size_frame); |
541 |
✗✓ |
3 |
if ( unlikely(NULL == (frame->payload = WSS_malloc(frame->applicationDataLength+1))) ) { |
542 |
|
|
WSS_log_error("Unable to allocate frame application data"); |
543 |
|
|
for (j = 0; j < i; j++) { |
544 |
|
|
WSS_free_frame(frames[j]); |
545 |
|
|
} |
546 |
|
|
WSS_free((void **)&frame); |
547 |
|
|
WSS_free((void **)&frames); |
548 |
|
|
*fs = NULL; |
549 |
|
|
return 0; |
550 |
|
|
} |
551 |
|
3 |
memcpy(frame->payload, msg+offset, frame->applicationDataLength); |
552 |
|
3 |
frame->payloadLength += frame->extensionDataLength; |
553 |
|
3 |
frame->payloadLength += frame->applicationDataLength; |
554 |
|
3 |
offset += frame->payloadLength; |
555 |
|
|
|
556 |
|
3 |
frames[i] = frame; |
557 |
|
|
} |
558 |
|
|
|
559 |
|
2 |
frames[frames_count-1]->fin = 1; |
560 |
|
|
|
561 |
|
2 |
return frames_count; |
562 |
|
|
} |
563 |
|
|
|
564 |
|
|
/** |
565 |
|
|
* Creates a closing frame given a reason for the closure. |
566 |
|
|
* |
567 |
|
|
* @param reason [wss_close_t] "The reason for the closure" |
568 |
|
|
* @return [wss_frame_t *] "A websocket frame" |
569 |
|
|
*/ |
570 |
|
20 |
wss_frame_t *WSS_closing_frame(wss_close_t reason, char *message) { |
571 |
|
20 |
wss_frame_t *frame; |
572 |
|
20 |
uint16_t nbo_reason; |
573 |
|
20 |
char *reason_str = message; |
574 |
|
|
|
575 |
|
20 |
WSS_log_trace("Creating closing frame"); |
576 |
|
|
|
577 |
✗✓ |
20 |
if ( unlikely(NULL == (frame = WSS_malloc(sizeof(wss_frame_t)))) ) { |
578 |
|
|
WSS_log_error("Unable to allocate closing frame"); |
579 |
|
|
return NULL; |
580 |
|
|
} |
581 |
|
|
|
582 |
|
20 |
frame->fin = 1; |
583 |
|
20 |
frame->opcode = CLOSE_FRAME; |
584 |
|
20 |
frame->mask = 0; |
585 |
|
|
|
586 |
✓✓ |
20 |
if (NULL == reason_str) { |
587 |
✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓
|
16 |
switch (reason) { |
588 |
|
|
case CLOSE_NORMAL: |
589 |
|
|
reason_str = "Normal close"; |
590 |
|
|
break; |
591 |
|
1 |
case CLOSE_SHUTDOWN: |
592 |
|
1 |
reason_str = "Server is shutting down"; |
593 |
|
1 |
break; |
594 |
|
1 |
case CLOSE_PROTOCOL: |
595 |
|
1 |
reason_str = "Experienced a protocol error"; |
596 |
|
1 |
break; |
597 |
|
1 |
case CLOSE_TYPE: |
598 |
|
1 |
reason_str = "Unsupported data type"; |
599 |
|
1 |
break; |
600 |
|
1 |
case CLOSE_NO_STATUS_CODE: |
601 |
|
1 |
reason_str = "No status received"; |
602 |
|
1 |
break; |
603 |
|
1 |
case CLOSE_ABNORMAL: |
604 |
|
1 |
reason_str = "Abnormal closure"; |
605 |
|
1 |
break; |
606 |
|
1 |
case CLOSE_UTF8: |
607 |
|
1 |
reason_str = "Invalid frame payload data"; |
608 |
|
1 |
break; |
609 |
|
1 |
case CLOSE_POLICY: |
610 |
|
1 |
reason_str = "Policy Violation"; |
611 |
|
1 |
break; |
612 |
|
1 |
case CLOSE_BIG: |
613 |
|
1 |
reason_str = "Message is too big"; |
614 |
|
1 |
break; |
615 |
|
1 |
case CLOSE_EXTENSION: |
616 |
|
1 |
reason_str = "Mandatory extension"; |
617 |
|
1 |
break; |
618 |
|
1 |
case CLOSE_UNEXPECTED: |
619 |
|
1 |
reason_str = "Internal server error"; |
620 |
|
1 |
break; |
621 |
|
1 |
case CLOSE_RESTARTING: |
622 |
|
1 |
reason_str = "Server is restarting"; |
623 |
|
1 |
break; |
624 |
|
1 |
case CLOSE_TRY_AGAIN: |
625 |
|
1 |
reason_str = "Try again later"; |
626 |
|
1 |
break; |
627 |
|
1 |
case CLOSE_INVALID_PROXY_RESPONSE: |
628 |
|
1 |
reason_str = "The server was acting as a gateway or proxy and received an invalid response from the upstream server."; |
629 |
|
1 |
break; |
630 |
|
1 |
case CLOSE_FAILED_TLS_HANDSHAKE: |
631 |
|
1 |
reason_str = "Failed TLS Handshake"; |
632 |
|
1 |
break; |
633 |
|
1 |
default: |
634 |
|
1 |
WSS_log_error("Unknown closing reason"); |
635 |
|
1 |
WSS_free_frame(frame); |
636 |
|
1 |
return NULL; |
637 |
|
|
} |
638 |
|
4 |
} |
639 |
|
19 |
frame->applicationDataLength = strlen(reason_str)+sizeof(uint16_t); |
640 |
✗✓ |
19 |
if ( unlikely(NULL == (frame->payload = WSS_malloc(frame->applicationDataLength+1))) ) { |
641 |
|
|
WSS_log_error("Unable to allocate closing frame application data"); |
642 |
|
|
WSS_free_frame(frame); |
643 |
|
|
return NULL; |
644 |
|
|
} |
645 |
|
19 |
nbo_reason = htons16(reason); |
646 |
|
19 |
memcpy(frame->payload, &nbo_reason, sizeof(uint16_t)); |
647 |
|
19 |
memcpy(frame->payload+sizeof(uint16_t), reason_str, strlen(reason_str)); |
648 |
|
|
|
649 |
|
19 |
frame->payloadLength += frame->extensionDataLength; |
650 |
|
19 |
frame->payloadLength += frame->applicationDataLength; |
651 |
|
|
|
652 |
|
19 |
return frame; |
653 |
|
|
} |
654 |
|
|
|
655 |
|
|
/** |
656 |
|
|
* Creates a ping frame. |
657 |
|
|
* |
658 |
|
|
* @return [wss_frame_t *] "A websocket frame" |
659 |
|
|
*/ |
660 |
|
1 |
wss_frame_t *WSS_ping_frame() { |
661 |
|
1 |
WSS_log_trace("Creating ping frame"); |
662 |
|
|
|
663 |
|
1 |
wss_frame_t *frame; |
664 |
|
|
|
665 |
✗✓ |
1 |
if ( unlikely(NULL == (frame = WSS_malloc(sizeof(wss_frame_t)))) ) { |
666 |
|
|
WSS_log_error("Unable to allocate ping frame"); |
667 |
|
|
return NULL; |
668 |
|
|
} |
669 |
|
|
|
670 |
|
1 |
frame->fin = 1; |
671 |
|
1 |
frame->opcode = PING_FRAME; |
672 |
|
1 |
frame->mask = 0; |
673 |
|
|
|
674 |
|
1 |
frame->applicationDataLength = 120; |
675 |
✗✓ |
1 |
if ( unlikely(NULL == (frame->payload = random_bytes(frame->applicationDataLength))) ) { |
676 |
|
|
WSS_log_error("Unable to allocate ping frame application data"); |
677 |
|
|
WSS_free_frame(frame); |
678 |
|
|
return NULL; |
679 |
|
|
} |
680 |
|
|
|
681 |
|
1 |
frame->payloadLength += frame->extensionDataLength; |
682 |
|
1 |
frame->payloadLength += frame->applicationDataLength; |
683 |
|
|
|
684 |
|
1 |
return frame; |
685 |
|
|
} |
686 |
|
|
|
687 |
|
|
/** |
688 |
|
|
* Creates a pong frame from a received ping frame. |
689 |
|
|
* |
690 |
|
|
* @param ping [wss_frame_t *] "A ping frame" |
691 |
|
|
* @return [wss_frame_t *] "A websocket frame" |
692 |
|
|
*/ |
693 |
|
2 |
wss_frame_t *WSS_pong_frame(wss_frame_t *ping) { |
694 |
|
2 |
WSS_log_trace("Converting ping frame to pong frame"); |
695 |
|
|
|
696 |
✓✓ |
2 |
if ( NULL == ping ) { |
697 |
|
|
return NULL; |
698 |
|
|
} |
699 |
|
|
|
700 |
|
1 |
ping->fin = 1; |
701 |
|
1 |
ping->rsv1 = 0; |
702 |
|
1 |
ping->rsv2 = 0; |
703 |
|
1 |
ping->rsv3 = 0; |
704 |
|
1 |
ping->opcode = PONG_FRAME; |
705 |
|
1 |
ping->mask = 0; |
706 |
|
|
|
707 |
|
1 |
memset(ping->maskingKey, '\0', sizeof(uint32_t)); |
708 |
|
|
|
709 |
|
1 |
return ping; |
710 |
|
|
} |
711 |
|
|
|
712 |
|
|
/** |
713 |
|
|
* Releases memory used by a frame. |
714 |
|
|
* |
715 |
|
|
* @param ping [wss_frame_t *] "The frame that should be freed" |
716 |
|
|
* @return [void] |
717 |
|
|
*/ |
718 |
|
26 |
void WSS_free_frame(wss_frame_t *frame) { |
719 |
✓✓ |
26 |
if ( likely(NULL != frame) ) { |
720 |
|
25 |
WSS_free((void **) &frame->payload); |
721 |
|
|
} |
722 |
|
26 |
WSS_free((void **) &frame); |
723 |
|
26 |
} |