GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/frame.c Lines: 280 319 87.8 %
Date: 2020-12-10 21:44:00 Branches: 99 123 80.5 %

Line Branch Exec Source
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
}