NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.3: NDN, CCN, CCNx, content centric networks
API Documentation
frame.hpp
Go to the documentation of this file.
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 
36 
38 
39 namespace websocketpp {
41 
45 namespace frame {
46 
48 static unsigned int const BASIC_HEADER_LENGTH = 2;
50 static unsigned int const MAX_HEADER_LENGTH = 14;
52 static 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 
76 namespace 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,
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 
145 namespace 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
174 static uint8_t const BHB0_OPCODE = 0x0F;
175 static uint8_t const BHB0_RSV3 = 0x10;
176 static uint8_t const BHB0_RSV2 = 0x20;
177 static uint8_t const BHB0_RSV1 = 0x40;
178 static uint8_t const BHB0_FIN = 0x80;
179 
180 static uint8_t const BHB1_PAYLOAD = 0x7F;
181 static uint8_t const BHB1_MASK = 0x80;
182 
183 static uint8_t const payload_size_code_16bit = 0x7E; // 126
184 static uint8_t const payload_size_code_64bit = 0x7F; // 127
185 
187 
189 struct basic_header {
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 
259 private:
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 
277 bool get_fin(basic_header const &h);
278 void set_fin(basic_header &h, bool value);
279 bool get_rsv1(basic_header const &h);
280 void set_rsv1(basic_header &h, bool value);
281 bool get_rsv2(basic_header const &h);
282 void set_rsv2(basic_header &h, bool value);
283 bool get_rsv3(basic_header const &h);
284 void set_rsv3(basic_header &h, bool value);
286 bool get_masked(basic_header const &h);
287 void set_masked(basic_header &h, bool value);
288 uint8_t get_basic_size(basic_header const &);
289 size_t get_header_len(basic_header const &);
290 unsigned int get_masking_key_offset(basic_header const &);
291 
292 std::string write_header(basic_header const &, extended_header const &);
293 masking_key_type get_masking_key(basic_header const &, extended_header const &);
294 uint16_t get_extended_size(extended_header const &);
295 uint64_t get_jumbo_size(extended_header const &);
296 uint64_t get_payload_size(basic_header const &, extended_header const &);
297 
298 size_t prepare_masking_key(masking_key_type const & key);
299 size_t circshift_prepared_key(size_t prepared_key, size_t offset);
300 
301 // Functions for performing xor based masking and unmasking
302 template <typename input_iter, typename output_iter>
303 void byte_mask(input_iter b, input_iter e, output_iter o, masking_key_type
304  const & key, size_t key_offset = 0);
305 template <typename iter_type>
306 void byte_mask(iter_type b, iter_type e, masking_key_type const & key,
307  size_t key_offset = 0);
308 void word_mask_exact(uint8_t * input, uint8_t * output, size_t length,
309  masking_key_type const & key);
310 void word_mask_exact(uint8_t * data, size_t length, masking_key_type const &
311  key);
312 size_t word_mask_circ(uint8_t * input, uint8_t * output, size_t length,
313  size_t prepared_key);
314 size_t word_mask_circ(uint8_t * data, size_t length, size_t prepared_key);
315 
317 
321 inline bool get_fin(basic_header const & h) {
322  return ((h.b0 & BHB0_FIN) == BHB0_FIN);
323 }
324 
326 
330 inline void set_fin(basic_header & h, bool value) {
331  h.b0 = (value ? h.b0 | BHB0_FIN : h.b0 & ~BHB0_FIN);
332 }
333 
335 
339 inline bool get_rsv1(const basic_header &h) {
340  return ((h.b0 & BHB0_RSV1) == BHB0_RSV1);
341 }
342 
344 
348 inline void set_rsv1(basic_header &h, bool value) {
349  h.b0 = (value ? h.b0 | BHB0_RSV1 : h.b0 & ~BHB0_RSV1);
350 }
351 
353 
357 inline bool get_rsv2(const basic_header &h) {
358  return ((h.b0 & BHB0_RSV2) == BHB0_RSV2);
359 }
360 
362 
366 inline void set_rsv2(basic_header &h, bool value) {
367  h.b0 = (value ? h.b0 | BHB0_RSV2 : h.b0 & ~BHB0_RSV2);
368 }
369 
371 
375 inline bool get_rsv3(const basic_header &h) {
376  return ((h.b0 & BHB0_RSV3) == BHB0_RSV3);
377 }
378 
380 
384 inline void set_rsv3(basic_header &h, bool value) {
385  h.b0 = (value ? h.b0 | BHB0_RSV3 : h.b0 & ~BHB0_RSV3);
386 }
387 
389 
394  return opcode::value(h.b0 & BHB0_OPCODE);
395 }
396 
398 
402 inline bool get_masked(basic_header const & h) {
403  return ((h.b1 & BHB1_MASK) == BHB1_MASK);
404 }
405 
407 
411 inline void set_masked(basic_header & h, bool value) {
412  h.b1 = (value ? h.b1 | BHB1_MASK : h.b1 & ~BHB1_MASK);
413 }
414 
416 
431 inline uint8_t get_basic_size(const basic_header &h) {
432  return h.b1 & BHB1_PAYLOAD;
433 }
434 
436 
445 inline 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
450  size_t size = BASIC_HEADER_LENGTH + get_masking_key_offset(h);
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 
469 inline 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 
489 inline std::string prepare_header(const basic_header &h, const
490  extended_header &e)
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),
498  get_header_len(h)-BASIC_HEADER_LENGTH
499  );
500 
501  return ret;
502 }
503 
505 
516 inline masking_key_type get_masking_key(const basic_header &h, const
517  extended_header &e)
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 
540 inline 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 
555 inline 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 
573 inline uint64_t get_payload_size(const basic_header &h, const
574  extended_header &e)
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 
595 inline 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 
612 inline size_t circshift_prepared_key(size_t prepared_key, size_t offset) {
614  size_t temp = prepared_key << (sizeof(size_t)-offset)*8;
615  return (prepared_key >> offset*8) | temp;
616  } else {
617  size_t temp = prepared_key >> (sizeof(size_t)-offset)*8;
618  return (prepared_key << offset*8) | temp;
619  }
620 }
621 
623 
641 template <typename input_iter, typename output_iter>
642 void byte_mask(input_iter first, input_iter last, output_iter result,
643  masking_key_type const & key, size_t key_offset)
644 {
645  size_t key_index = key_offset%4;
646  while (first != last) {
647  *result = *first ^ key.c[key_index++];
648  key_index %= 4;
649  ++result;
650  ++first;
651  }
652 }
653 
655 
671 template <typename iter_type>
672 void byte_mask(iter_type b, iter_type e, masking_key_type const & key,
673  size_t key_offset)
674 {
675  byte_mask(b,e,b,key,key_offset);
676 }
677 
679 
699 inline void word_mask_exact(uint8_t* input, uint8_t* output, size_t length,
700  const masking_key_type& key)
701 {
702  size_t prepared_key = prepare_masking_key(key);
703  size_t n = length/sizeof(size_t);
704  size_t* input_word = reinterpret_cast<size_t*>(input);
705  size_t* output_word = reinterpret_cast<size_t*>(output);
706 
707  for (size_t i = 0; i < n; i++) {
708  output_word[i] = input_word[i] ^ prepared_key;
709  }
710 
711  for (size_t i = n*sizeof(size_t); i < length; i++) {
712  output[i] = input[i] ^ key.c[i%4];
713  }
714 }
715 
717 
728 inline void word_mask_exact(uint8_t* data, size_t length, const
729  masking_key_type& key)
730 {
731  word_mask_exact(data,data,length,key);
732 }
733 
735 
765 inline size_t word_mask_circ(uint8_t * input, uint8_t * output, size_t length,
766  size_t prepared_key)
767 {
768  size_t n = length / sizeof(size_t); // whole words
769  size_t l = length - (n * sizeof(size_t)); // remaining bytes
770  size_t * input_word = reinterpret_cast<size_t *>(input);
771  size_t * output_word = reinterpret_cast<size_t *>(output);
772 
773  // mask word by word
774  for (size_t i = 0; i < n; i++) {
775  output_word[i] = input_word[i] ^ prepared_key;
776  }
777 
778  // mask partial word at the end
779  size_t start = length - l;
780  uint8_t * byte_key = reinterpret_cast<uint8_t *>(&prepared_key);
781  for (size_t i = 0; i < l; ++i) {
782  output[start+i] = input[start+i] ^ byte_key[i];
783  }
784 
785  return circshift_prepared_key(prepared_key,l);
786 }
787 
789 
802 inline size_t word_mask_circ(uint8_t* data, size_t length, size_t prepared_key){
803  return word_mask_circ(data,data,length,prepared_key);
804 }
805 
807 
827 inline size_t byte_mask_circ(uint8_t * input, uint8_t * output, size_t length,
828  size_t prepared_key)
829 {
830  uint32_converter key;
831  key.i = prepared_key;
832 
833  for (size_t i = 0; i < length; ++i) {
834  output[i] = input[i] ^ key.c[i % 4];
835  }
836 
837  return circshift_prepared_key(prepared_key,length % 4);
838 }
839 
841 
854 inline size_t byte_mask_circ(uint8_t* data, size_t length, size_t prepared_key){
855  return byte_mask_circ(data,data,length,prepared_key);
856 }
857 
858 } // namespace frame
859 } // namespace websocketpp
860 
861 #endif //WEBSOCKETPP_FRAME_HPP
bool is_control(value v)
Check if an opcode is for a control frame.
Definition: frame.hpp:139
bool invalid(value v)
Check if an opcode is invalid.
Definition: frame.hpp:130
static uint8_t const payload_size_code_16bit
Definition: frame.hpp:183
static uint8_t const BHB0_RSV2
Definition: frame.hpp:176
bool get_rsv1(basic_header const &h)
check whether the frame&#39;s RSV1 bit is set
Definition: frame.hpp:339
void set_rsv1(basic_header &h, bool value)
Set the frame&#39;s RSV1 bit.
Definition: frame.hpp:348
static uint8_t const BHB0_RSV3
Definition: frame.hpp:175
bool get_rsv3(basic_header const &h)
check whether the frame&#39;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
std::string write_header(basic_header const &, extended_header const &)
static uint8_t const BHB1_MASK
Definition: frame.hpp:181
uint16_t get_extended_size(extended_header const &)
Extract the extended size field from an extended header.
Definition: frame.hpp:540
extended_header(uint64_t payload_size, uint32_t masking_key)
Definition: frame.hpp:246
bool get_rsv2(basic_header const &h)
check whether the frame&#39;s RSV2 bit is set
Definition: frame.hpp:357
static uint8_t const BHB1_PAYLOAD
Definition: frame.hpp:180
static unsigned int const max_header_length
Maximum length of a WebSocket header.
Definition: frame.hpp:150
opcode::value get_opcode(basic_header const &h)
Extract opcode from basic header.
Definition: frame.hpp:393
uint64_t _htonll(uint64_t src)
Convert 64 bit value to network byte order.
Definition: network.hpp:66
static uint8_t const payload_size_basic
Maximum size of a basic WebSocket payload.
Definition: frame.hpp:156
basic_header(uint8_t p0, uint8_t p1)
Definition: frame.hpp:192
basic_header(opcode::value op, uint64_t size, bool fin, bool mask, bool rsv1=false, bool rsv2=false, bool rsv3=false)
Definition: frame.hpp:194
masking_key_type get_masking_key(basic_header const &, extended_header const &)
Extract the masking key from a frame header.
Definition: frame.hpp:516
Eight byte conversion union.
Definition: frame.hpp:67
Two byte conversion union.
Definition: frame.hpp:55
Four byte conversion union.
Definition: frame.hpp:61
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:642
static uint64_t const payload_size_jumbo
Maximum size of a jumbo WebSocket payload (basic payload = 127)
Definition: frame.hpp:162
size_t get_header_len(basic_header const &)
Calculates the full length of the header based on the first bytes.
Definition: frame.hpp:445
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
static unsigned int const basic_header_length
Minimum length of a WebSocket frame header.
Definition: frame.hpp:147
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:765
static uint8_t const BHB0_OPCODE
Definition: frame.hpp:174
uint64_t _ntohll(uint64_t src)
Convert 64 bit value to host byte order.
Definition: network.hpp:98
The constant size component of a WebSocket frame header.
Definition: frame.hpp:189
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:699
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
uint32_converter masking_key_type
Definition: frame.hpp:186
uint8_t get_basic_size(basic_header const &)
Extracts the raw payload length specified in the basic header.
Definition: frame.hpp:431
uint64_t get_jumbo_size(extended_header const &)
Extract the jumbo size field from an extended header.
Definition: frame.hpp:555
Namespace for the WebSocket++ project.
Definition: base64.hpp:41
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
static unsigned int const MAX_EXTENDED_HEADER_LENGTH
Maximum length of the variable portion of the WebSocket header.
Definition: frame.hpp:52
void close(T *e, websocketpp::connection_hdl hdl)
static uint8_t const payload_size_code_64bit
Definition: frame.hpp:184
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
The variable size component of a WebSocket frame header.
Definition: frame.hpp:235
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:50
void set_masked(basic_header &h, bool value)
Set the frame&#39;s MASK bit.
Definition: frame.hpp:411
extended_header(uint64_t payload_size)
Definition: frame.hpp:240
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
static uint16_t const payload_size_extended
Maximum size of an extended WebSocket payload (basic payload = 126)
Definition: frame.hpp:159
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:827
static uint8_t const close_reason_size
Maximum size of close frame reason.
Definition: frame.hpp:169
static uint8_t const BHB0_FIN
Definition: frame.hpp:178
void set_fin(basic_header &h, bool value)
Set the frame&#39;s FIN bit.
Definition: frame.hpp:330
bool reserved(value v)
Check if an opcode is reserved.
Definition: frame.hpp:118
bool get_fin(basic_header const &h)
Check whether the frame&#39;s FIN bit is set.
Definition: frame.hpp:321
static uint8_t const BHB0_RSV1
Definition: frame.hpp:177
void set_rsv2(basic_header &h, bool value)
Set the frame&#39;s RSV2 bit.
Definition: frame.hpp:366
static unsigned int const BASIC_HEADER_LENGTH
Minimum length of a WebSocket frame header.
Definition: frame.hpp:48
uint8_t bytes[MAX_EXTENDED_HEADER_LENGTH]
Definition: frame.hpp:258
void set_rsv3(basic_header &h, bool value)
Set the frame&#39;s RSV3 bit.
Definition: frame.hpp:384