WebSocket++ 0.8.2
C++ websocket client/server library
Loading...
Searching...
No Matches
frame.hpp
1/*
2 * Copyright (c) 2014, Peter Thorson. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution.
11 * * Neither the name of the WebSocket++ Project nor the
12 * names of its contributors may be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 */
27
28#ifndef WEBSOCKETPP_FRAME_HPP
29#define WEBSOCKETPP_FRAME_HPP
30
31#include <algorithm>
32#include <string>
33
34#include <websocketpp/common/system_error.hpp>
35#include <websocketpp/common/network.hpp>
36
37#include <websocketpp/utilities.hpp>
38
39namespace websocketpp {
41
45namespace frame {
46
48static unsigned int const BASIC_HEADER_LENGTH = 2;
50static unsigned int const MAX_HEADER_LENGTH = 14;
52static unsigned int const MAX_EXTENDED_HEADER_LENGTH = 12;
53
56 uint16_t i;
57 uint8_t c[2];
58};
59
62 uint32_t i;
63 uint8_t c[4];
64};
65
68 uint64_t i;
69 uint8_t c[8];
70};
71
73
76namespace opcode {
77 enum value {
78 continuation = 0x0,
79 text = 0x1,
80 binary = 0x2,
81 rsv3 = 0x3,
82 rsv4 = 0x4,
83 rsv5 = 0x5,
84 rsv6 = 0x6,
85 rsv7 = 0x7,
86 close = 0x8,
87 ping = 0x9,
88 pong = 0xA,
89 control_rsvb = 0xB,
90 control_rsvc = 0xC,
91 control_rsvd = 0xD,
92 control_rsve = 0xE,
93 control_rsvf = 0xF,
94
95 CONTINUATION = 0x0,
96 TEXT = 0x1,
97 BINARY = 0x2,
98 RSV3 = 0x3,
99 RSV4 = 0x4,
100 RSV5 = 0x5,
101 RSV6 = 0x6,
102 RSV7 = 0x7,
103 CLOSE = 0x8,
104 PING = 0x9,
105 PONG = 0xA,
106 CONTROL_RSVB = 0xB,
107 CONTROL_RSVC = 0xC,
108 CONTROL_RSVD = 0xD,
109 CONTROL_RSVE = 0xE,
110 CONTROL_RSVF = 0xF
111 };
112
114
118 inline bool reserved(value v) {
119 return (v >= rsv3 && v <= rsv7) ||
120 (v >= control_rsvb && v <= control_rsvf);
121 }
122
124
130 inline bool invalid(value v) {
131 return (v > 0xF || v < 0);
132 }
133
135
139 inline bool is_control(value v) {
140 return v >= 0x8;
141 }
142}
143
145namespace limits {
147 static unsigned int const basic_header_length = 2;
148
150 static unsigned int const max_header_length = 14;
151
153 static unsigned int const max_extended_header_length = 12;
154
156 static uint8_t const payload_size_basic = 125;
157
159 static uint16_t const payload_size_extended = 0xFFFF; // 2^16, 65535
160
162 static uint64_t const payload_size_jumbo = 0x7FFFFFFFFFFFFFFFLL;//2^63
163
165
169 static uint8_t const close_reason_size = 123;
170}
171
172
173// masks for fields in the basic header
174static uint8_t const BHB0_OPCODE = 0x0F;
175static uint8_t const BHB0_RSV3 = 0x10;
176static uint8_t const BHB0_RSV2 = 0x20;
177static uint8_t const BHB0_RSV1 = 0x40;
178static uint8_t const BHB0_FIN = 0x80;
179
180static uint8_t const BHB1_PAYLOAD = 0x7F;
181static uint8_t const BHB1_MASK = 0x80;
182
183static uint8_t const payload_size_code_16bit = 0x7E; // 126
184static uint8_t const payload_size_code_64bit = 0x7F; // 127
185
187
190 basic_header() : b0(0x00),b1(0x00) {}
191
192 basic_header(uint8_t p0, uint8_t p1) : b0(p0), b1(p1) {}
193
194 basic_header(opcode::value op, uint64_t size, bool fin, bool mask,
195 bool rsv1 = false, bool rsv2 = false, bool rsv3 = false) : b0(0x00),
196 b1(0x00)
197 {
198 if (fin) {
199 b0 |= BHB0_FIN;
200 }
201 if (rsv1) {
202 b0 |= BHB0_RSV1;
203 }
204 if (rsv2) {
205 b0 |= BHB0_RSV2;
206 }
207 if (rsv3) {
208 b0 |= BHB0_RSV3;
209 }
210 b0 |= (op & BHB0_OPCODE);
211
212 if (mask) {
213 b1 |= BHB1_MASK;
214 }
215
216 uint8_t basic_value;
217
218 if (size <= limits::payload_size_basic) {
219 basic_value = static_cast<uint8_t>(size);
220 } else if (size <= limits::payload_size_extended) {
221 basic_value = payload_size_code_16bit;
222 } else {
223 basic_value = payload_size_code_64bit;
224 }
225
226
227 b1 |= basic_value;
228 }
229
230 uint8_t b0;
231 uint8_t b1;
232};
233
237 std::fill_n(this->bytes,MAX_EXTENDED_HEADER_LENGTH,0x00);
238 }
239
240 extended_header(uint64_t payload_size) {
241 std::fill_n(this->bytes,MAX_EXTENDED_HEADER_LENGTH,0x00);
242
243 copy_payload(payload_size);
244 }
245
246 extended_header(uint64_t payload_size, uint32_t masking_key) {
247 std::fill_n(this->bytes,MAX_EXTENDED_HEADER_LENGTH,0x00);
248
249 // Copy payload size
250 int offset = copy_payload(payload_size);
251
252 // Copy Masking Key
253 uint32_converter temp32;
254 temp32.i = masking_key;
255 std::copy(temp32.c,temp32.c+4,bytes+offset);
256 }
257
258 uint8_t bytes[MAX_EXTENDED_HEADER_LENGTH];
259private:
260 int copy_payload(uint64_t payload_size) {
261 int payload_offset = 0;
262
263 if (payload_size <= limits::payload_size_basic) {
264 payload_offset = 8;
265 } else if (payload_size <= limits::payload_size_extended) {
266 payload_offset = 6;
267 }
268
269 uint64_converter temp64;
270 temp64.i = lib::net::_htonll(payload_size);
271 std::copy(temp64.c+payload_offset,temp64.c+8,bytes);
272
273 return 8-payload_offset;
274 }
275};
276
277bool get_fin(basic_header const &h);
278void set_fin(basic_header &h, bool value);
279bool get_rsv1(basic_header const &h);
280void set_rsv1(basic_header &h, bool value);
281bool get_rsv2(basic_header const &h);
282void set_rsv2(basic_header &h, bool value);
283bool get_rsv3(basic_header const &h);
284void set_rsv3(basic_header &h, bool value);
285opcode::value get_opcode(basic_header const &h);
286bool get_masked(basic_header const &h);
287void set_masked(basic_header &h, bool value);
288uint8_t get_basic_size(basic_header const &);
289size_t get_header_len(basic_header const &);
290unsigned int get_masking_key_offset(basic_header const &);
291
292std::string write_header(basic_header const &, extended_header const &);
294uint16_t get_extended_size(extended_header const &);
295uint64_t get_jumbo_size(extended_header const &);
296uint64_t get_payload_size(basic_header const &, extended_header const &);
297
298size_t prepare_masking_key(masking_key_type const & key);
299size_t circshift_prepared_key(size_t prepared_key, size_t offset);
300
301// Functions for performing xor based masking and unmasking
302template <typename input_iter, typename output_iter>
303void byte_mask(input_iter b, input_iter e, output_iter o, masking_key_type
304 const & key, size_t key_offset = 0);
305template <typename iter_type>
306void byte_mask(iter_type b, iter_type e, masking_key_type const & key,
307 size_t key_offset = 0);
308void word_mask_exact(uint8_t * input, uint8_t * output, size_t length,
309 masking_key_type const & key);
310void word_mask_exact(uint8_t * data, size_t length, masking_key_type const &
311 key);
312size_t word_mask_circ(uint8_t * input, uint8_t * output, size_t length,
313 size_t prepared_key);
314size_t word_mask_circ(uint8_t * data, size_t length, size_t prepared_key);
315
317
321inline bool get_fin(basic_header const & h) {
322 return ((h.b0 & BHB0_FIN) == BHB0_FIN);
323}
324
326
330inline void set_fin(basic_header & h, bool value) {
331 h.b0 = (value ? h.b0 | BHB0_FIN : h.b0 & ~BHB0_FIN);
332}
333
335
339inline bool get_rsv1(const basic_header &h) {
340 return ((h.b0 & BHB0_RSV1) == BHB0_RSV1);
341}
342
344
348inline void set_rsv1(basic_header &h, bool value) {
349 h.b0 = (value ? h.b0 | BHB0_RSV1 : h.b0 & ~BHB0_RSV1);
350}
351
353
357inline bool get_rsv2(const basic_header &h) {
358 return ((h.b0 & BHB0_RSV2) == BHB0_RSV2);
359}
360
362
366inline void set_rsv2(basic_header &h, bool value) {
367 h.b0 = (value ? h.b0 | BHB0_RSV2 : h.b0 & ~BHB0_RSV2);
368}
369
371
375inline bool get_rsv3(const basic_header &h) {
376 return ((h.b0 & BHB0_RSV3) == BHB0_RSV3);
377}
378
380
384inline void set_rsv3(basic_header &h, bool value) {
385 h.b0 = (value ? h.b0 | BHB0_RSV3 : h.b0 & ~BHB0_RSV3);
386}
387
389
393inline opcode::value get_opcode(const basic_header &h) {
394 return opcode::value(h.b0 & BHB0_OPCODE);
395}
396
398
402inline bool get_masked(basic_header const & h) {
403 return ((h.b1 & BHB1_MASK) == BHB1_MASK);
404}
405
407
411inline void set_masked(basic_header & h, bool value) {
412 h.b1 = (value ? h.b1 | BHB1_MASK : h.b1 & ~BHB1_MASK);
413}
414
416
431inline uint8_t get_basic_size(const basic_header &h) {
432 return h.b1 & BHB1_PAYLOAD;
433}
434
436
445inline size_t get_header_len(basic_header const & h) {
446 // TODO: check extensions?
447
448 // masking key offset represents the space used for the extended length
449 // fields
451
452 // If the header is masked there is a 4 byte masking key
453 if (get_masked(h)) {
454 size += 4;
455 }
456
457 return size;
458}
459
461
469inline unsigned int get_masking_key_offset(const basic_header &h) {
470 if (get_basic_size(h) == payload_size_code_16bit) {
471 return 2;
472 } else if (get_basic_size(h) == payload_size_code_64bit) {
473 return 8;
474 } else {
475 return 0;
476 }
477}
478
480
489inline std::string prepare_header(const basic_header &h, const
491{
492 std::string ret;
493
494 ret.push_back(char(h.b0));
495 ret.push_back(char(h.b1));
496 ret.append(
497 reinterpret_cast<const char*>(e.bytes),
499 );
500
501 return ret;
502}
503
505
518{
519 masking_key_type temp32;
520
521 if (!get_masked(h)) {
522 temp32.i = 0;
523 } else {
524 unsigned int offset = get_masking_key_offset(h);
525 std::copy(e.bytes+offset,e.bytes+offset+4,temp32.c);
526 }
527
528 return temp32;
529}
530
532
540inline uint16_t get_extended_size(const extended_header &e) {
541 uint16_converter temp16;
542 std::copy(e.bytes,e.bytes+2,temp16.c);
543 return ntohs(temp16.i);
544}
545
547
555inline uint64_t get_jumbo_size(const extended_header &e) {
556 uint64_converter temp64;
557 std::copy(e.bytes,e.bytes+8,temp64.c);
558 return lib::net::_ntohll(temp64.i);
559}
560
562
573inline uint64_t get_payload_size(const basic_header &h, const
575{
576 uint8_t val = get_basic_size(h);
577
578 if (val <= limits::payload_size_basic) {
579 return val;
580 } else if (val == payload_size_code_16bit) {
581 return get_extended_size(e);
582 } else {
583 return get_jumbo_size(e);
584 }
585}
586
588
595inline size_t prepare_masking_key(const masking_key_type& key) {
596 size_t low_bits = static_cast<size_t>(key.i);
597
598 if (sizeof(size_t) == 8) {
599 uint64_t high_bits = static_cast<size_t>(key.i);
600 return static_cast<size_t>((high_bits << 32) | low_bits);
601 } else {
602 return low_bits;
603 }
604}
605
607
612inline size_t circshift_prepared_key(size_t prepared_key, size_t offset) {
613 if (offset == 0) {
614 return prepared_key;
615 }
616 if (lib::net::is_little_endian()) {
617 size_t temp = prepared_key << (sizeof(size_t)-offset)*8;
618 return (prepared_key >> offset*8) | temp;
619 } else {
620 size_t temp = prepared_key >> (sizeof(size_t)-offset)*8;
621 return (prepared_key << offset*8) | temp;
622 }
623}
624
626
644template <typename input_iter, typename output_iter>
645void byte_mask(input_iter first, input_iter last, output_iter result,
646 masking_key_type const & key, size_t key_offset)
647{
648 size_t key_index = key_offset%4;
649 while (first != last) {
650 *result = *first ^ key.c[key_index++];
651 key_index %= 4;
652 ++result;
653 ++first;
654 }
655}
656
658
674template <typename iter_type>
675void byte_mask(iter_type b, iter_type e, masking_key_type const & key,
676 size_t key_offset)
677{
678 byte_mask(b,e,b,key,key_offset);
679}
680
682
702inline void word_mask_exact(uint8_t* input, uint8_t* output, size_t length,
703 const masking_key_type& key)
704{
705 size_t prepared_key = prepare_masking_key(key);
706 size_t n = length/sizeof(size_t);
707 size_t* input_word = reinterpret_cast<size_t*>(input);
708 size_t* output_word = reinterpret_cast<size_t*>(output);
709
710 for (size_t i = 0; i < n; i++) {
711 output_word[i] = input_word[i] ^ prepared_key;
712 }
713
714 for (size_t i = n*sizeof(size_t); i < length; i++) {
715 output[i] = input[i] ^ key.c[i%4];
716 }
717}
718
720
731inline void word_mask_exact(uint8_t* data, size_t length, const
732 masking_key_type& key)
733{
734 word_mask_exact(data,data,length,key);
735}
736
738
768inline size_t word_mask_circ(uint8_t * input, uint8_t * output, size_t length,
769 size_t prepared_key)
770{
771 size_t n = length / sizeof(size_t); // whole words
772 size_t l = length - (n * sizeof(size_t)); // remaining bytes
773 size_t * input_word = reinterpret_cast<size_t *>(input);
774 size_t * output_word = reinterpret_cast<size_t *>(output);
775
776 // mask word by word
777 for (size_t i = 0; i < n; i++) {
778 output_word[i] = input_word[i] ^ prepared_key;
779 }
780
781 // mask partial word at the end
782 size_t start = length - l;
783 uint8_t * byte_key = reinterpret_cast<uint8_t *>(&prepared_key);
784 for (size_t i = 0; i < l; ++i) {
785 output[start+i] = input[start+i] ^ byte_key[i];
786 }
787
788 return circshift_prepared_key(prepared_key,l);
789}
790
792
805inline size_t word_mask_circ(uint8_t* data, size_t length, size_t prepared_key){
806 return word_mask_circ(data,data,length,prepared_key);
807}
808
810
830inline size_t byte_mask_circ(uint8_t * input, uint8_t * output, size_t length,
831 size_t prepared_key)
832{
834 key.i = prepared_key;
835
836 for (size_t i = 0; i < length; ++i) {
837 output[i] = input[i] ^ key.c[i % 4];
838 }
839
840 return circshift_prepared_key(prepared_key,length % 4);
841}
842
844
857inline size_t byte_mask_circ(uint8_t* data, size_t length, size_t prepared_key){
858 return byte_mask_circ(data,data,length,prepared_key);
859}
860
861} // namespace frame
862} // namespace websocketpp
863
864#endif //WEBSOCKETPP_FRAME_HPP
static uint8_t const close_reason_size
Maximum size of close frame reason.
Definition frame.hpp:169
static uint64_t const payload_size_jumbo
Maximum size of a jumbo WebSocket payload (basic payload = 127)
Definition frame.hpp:162
static unsigned int const max_extended_header_length
Maximum length of the variable portion of the WebSocket header.
Definition frame.hpp:153
static unsigned int const max_header_length
Maximum length of a WebSocket header.
Definition frame.hpp:150
static uint16_t const payload_size_extended
Maximum size of an extended WebSocket payload (basic payload = 126)
Definition frame.hpp:159
static uint8_t const payload_size_basic
Maximum size of a basic WebSocket payload.
Definition frame.hpp:156
static unsigned int const basic_header_length
Minimum length of a WebSocket frame header.
Definition frame.hpp:147
bool invalid(value v)
Check if an opcode is invalid.
Definition frame.hpp:130
bool reserved(value v)
Check if an opcode is reserved.
Definition frame.hpp:118
bool is_control(value v)
Check if an opcode is for a control frame.
Definition frame.hpp:139
unsigned int get_masking_key_offset(basic_header const &)
Calculate the offset location of the masking key within the extended header.
Definition frame.hpp:469
void set_rsv2(basic_header &h, bool value)
Set the frame's RSV2 bit.
Definition frame.hpp:366
static unsigned int const MAX_HEADER_LENGTH
Maximum length of a WebSocket header.
Definition frame.hpp:50
opcode::value get_opcode(basic_header const &h)
Extract opcode from basic header.
Definition frame.hpp:393
void set_rsv3(basic_header &h, bool value)
Set the frame's RSV3 bit.
Definition frame.hpp:384
uint64_t get_payload_size(basic_header const &, extended_header const &)
Extract the full payload size field from a WebSocket header.
Definition frame.hpp:573
uint8_t get_basic_size(basic_header const &)
Extracts the raw payload length specified in the basic header.
Definition frame.hpp:431
size_t byte_mask_circ(uint8_t *input, uint8_t *output, size_t length, size_t prepared_key)
Circular byte aligned mask/unmask.
Definition frame.hpp:830
void byte_mask(input_iter b, input_iter e, output_iter o, masking_key_type const &key, size_t key_offset=0)
Byte by byte mask/unmask.
Definition frame.hpp:645
static unsigned int const MAX_EXTENDED_HEADER_LENGTH
Maximum length of the variable portion of the WebSocket header.
Definition frame.hpp:52
bool get_rsv3(basic_header const &h)
check whether the frame's RSV3 bit is set
Definition frame.hpp:375
bool get_masked(basic_header const &h)
check whether the frame is masked
Definition frame.hpp:402
bool get_rsv2(basic_header const &h)
check whether the frame's RSV2 bit is set
Definition frame.hpp:357
uint16_t get_extended_size(extended_header const &)
Extract the extended size field from an extended header.
Definition frame.hpp:540
bool get_fin(basic_header const &h)
Check whether the frame's FIN bit is set.
Definition frame.hpp:321
size_t circshift_prepared_key(size_t prepared_key, size_t offset)
circularly shifts the supplied prepared masking key by offset bytes
Definition frame.hpp:612
bool get_rsv1(basic_header const &h)
check whether the frame's RSV1 bit is set
Definition frame.hpp:339
void set_masked(basic_header &h, bool value)
Set the frame's MASK bit.
Definition frame.hpp:411
size_t word_mask_circ(uint8_t *input, uint8_t *output, size_t length, size_t prepared_key)
Circular word aligned mask/unmask.
Definition frame.hpp:768
void set_rsv1(basic_header &h, bool value)
Set the frame's RSV1 bit.
Definition frame.hpp:348
size_t get_header_len(basic_header const &)
Calculates the full length of the header based on the first bytes.
Definition frame.hpp:445
void set_fin(basic_header &h, bool value)
Set the frame's FIN bit.
Definition frame.hpp:330
uint64_t get_jumbo_size(extended_header const &)
Extract the jumbo size field from an extended header.
Definition frame.hpp:555
void word_mask_exact(uint8_t *input, uint8_t *output, size_t length, masking_key_type const &key)
Exact word aligned mask/unmask.
Definition frame.hpp:702
std::string prepare_header(const basic_header &h, const extended_header &e)
Generate a properly sized contiguous string that encodes a full frame header.
Definition frame.hpp:489
masking_key_type get_masking_key(basic_header const &, extended_header const &)
Extract the masking key from a frame header.
Definition frame.hpp:516
static unsigned int const BASIC_HEADER_LENGTH
Minimum length of a WebSocket frame header.
Definition frame.hpp:48
size_t prepare_masking_key(masking_key_type const &key)
Extract a masking key into a value the size of a machine word.
Definition frame.hpp:595
Namespace for the WebSocket++ project.
Definition base64.hpp:41
The constant size component of a WebSocket frame header.
Definition frame.hpp:189
The variable size component of a WebSocket frame header.
Definition frame.hpp:235
Two byte conversion union.
Definition frame.hpp:55
Four byte conversion union.
Definition frame.hpp:61
Eight byte conversion union.
Definition frame.hpp:67