modify build setup
[c11concurrency-benchmarks.git] / gdax-orderbook-hpp / demo / dependencies / websocketpp-0.7.0 / websocketpp / 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
39 namespace websocketpp {
40 /// Data structures and utility functions for manipulating WebSocket frames
41 /**
42  * namespace frame provides a number of data structures and utility functions
43  * for reading, writing, and manipulating binary encoded WebSocket frames.
44  */
45 namespace frame {
46
47 /// Minimum length of a WebSocket frame header.
48 static unsigned int const BASIC_HEADER_LENGTH = 2;
49 /// Maximum length of a WebSocket header
50 static unsigned int const MAX_HEADER_LENGTH = 14;
51 /// Maximum length of the variable portion of the WebSocket header
52 static unsigned int const MAX_EXTENDED_HEADER_LENGTH = 12;
53
54 /// Two byte conversion union
55 union uint16_converter {
56     uint16_t i;
57     uint8_t  c[2];
58 };
59
60 /// Four byte conversion union
61 union uint32_converter {
62     uint32_t i;
63     uint8_t c[4];
64 };
65
66 /// Eight byte conversion union
67 union uint64_converter {
68     uint64_t i;
69     uint8_t  c[8];
70 };
71
72 /// Constants and utility functions related to WebSocket opcodes
73 /**
74  * WebSocket Opcodes are 4 bits. See RFC6455 section 5.2.
75  */
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,
106         CONTROL_RSVB = 0xB,
107         CONTROL_RSVC = 0xC,
108         CONTROL_RSVD = 0xD,
109         CONTROL_RSVE = 0xE,
110         CONTROL_RSVF = 0xF
111     };
112
113     /// Check if an opcode is reserved
114     /**
115      * @param v The opcode to test.
116      * @return Whether or not the opcode is reserved.
117      */
118     inline bool reserved(value v) {
119         return (v >= rsv3 && v <= rsv7) ||
120                (v >= control_rsvb && v <= control_rsvf);
121     }
122
123     /// Check if an opcode is invalid
124     /**
125      * Invalid opcodes are negative or require greater than 4 bits to store.
126      *
127      * @param v The opcode to test.
128      * @return Whether or not the opcode is invalid.
129      */
130     inline bool invalid(value v) {
131         return (v > 0xF || v < 0);
132     }
133
134     /// Check if an opcode is for a control frame
135     /**
136      * @param v The opcode to test.
137      * @return Whether or not the opcode is a control opcode.
138      */
139     inline bool is_control(value v) {
140         return v >= 0x8;
141     }
142 }
143
144 /// Constants related to frame and payload limits
145 namespace limits {
146     /// Minimum length of a WebSocket frame header.
147     static unsigned int const basic_header_length = 2;
148
149     /// Maximum length of a WebSocket header
150     static unsigned int const max_header_length = 14;
151
152     /// Maximum length of the variable portion of the WebSocket header
153     static unsigned int const max_extended_header_length = 12;
154
155     /// Maximum size of a basic WebSocket payload
156     static uint8_t const payload_size_basic = 125;
157
158     /// Maximum size of an extended WebSocket payload (basic payload = 126)
159     static uint16_t const payload_size_extended = 0xFFFF; // 2^16, 65535
160
161     /// Maximum size of a jumbo WebSocket payload (basic payload = 127)
162     static uint64_t const payload_size_jumbo = 0x7FFFFFFFFFFFFFFFLL;//2^63
163
164     /// Maximum size of close frame reason
165     /**
166      * This is payload_size_basic - 2 bytes (as first two bytes are used for
167      * the close code
168      */
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
186 typedef uint32_converter masking_key_type;
187
188 /// The constant size component of a WebSocket frame header
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
234 /// The variable size component of a WebSocket frame header
235 struct extended_header {
236     extended_header() {
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];
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);
285 opcode::value get_opcode(basic_header const &h);
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
316 /// Check whether the frame's FIN bit is set.
317 /**
318  * @param [in] h The basic header to extract from.
319  * @return True if the header's fin bit is set.
320  */
321 inline bool get_fin(basic_header const & h) {
322     return ((h.b0 & BHB0_FIN) == BHB0_FIN);
323 }
324
325 /// Set the frame's FIN bit
326 /**
327  * @param [out] h Header to set.
328  * @param [in] value Value to set it to.
329  */
330 inline void set_fin(basic_header & h, bool value) {
331     h.b0 = (value ? h.b0 | BHB0_FIN : h.b0 & ~BHB0_FIN);
332 }
333
334 /// check whether the frame's RSV1 bit is set
335 /**
336  * @param [in] h The basic header to extract from.
337  * @return True if the header's RSV1 bit is set.
338  */
339 inline bool get_rsv1(const basic_header &h) {
340     return ((h.b0 & BHB0_RSV1) == BHB0_RSV1);
341 }
342
343 /// Set the frame's RSV1 bit
344 /**
345  * @param [out] h Header to set.
346  * @param [in] value Value to set it to.
347  */
348 inline void set_rsv1(basic_header &h, bool value) {
349     h.b0 = (value ? h.b0 | BHB0_RSV1 : h.b0 & ~BHB0_RSV1);
350 }
351
352 /// check whether the frame's RSV2 bit is set
353 /**
354  * @param [in] h The basic header to extract from.
355  * @return True if the header's RSV2 bit is set.
356  */
357 inline bool get_rsv2(const basic_header &h) {
358     return ((h.b0 & BHB0_RSV2) == BHB0_RSV2);
359 }
360
361 /// Set the frame's RSV2 bit
362 /**
363  * @param [out] h Header to set.
364  * @param [in] value Value to set it to.
365  */
366 inline void set_rsv2(basic_header &h, bool value) {
367     h.b0 = (value ? h.b0 | BHB0_RSV2 : h.b0 & ~BHB0_RSV2);
368 }
369
370 /// check whether the frame's RSV3 bit is set
371 /**
372  * @param [in] h The basic header to extract from.
373  * @return True if the header's RSV3 bit is set.
374  */
375 inline bool get_rsv3(const basic_header &h) {
376     return ((h.b0 & BHB0_RSV3) == BHB0_RSV3);
377 }
378
379 /// Set the frame's RSV3 bit
380 /**
381  * @param [out] h Header to set.
382  * @param [in] value Value to set it to.
383  */
384 inline void set_rsv3(basic_header &h, bool value) {
385     h.b0 = (value ? h.b0 | BHB0_RSV3 : h.b0 & ~BHB0_RSV3);
386 }
387
388 /// Extract opcode from basic header
389 /**
390  * @param [in] h The basic header to extract from.
391  * @return The opcode value of the header.
392  */
393 inline opcode::value get_opcode(const basic_header &h) {
394     return opcode::value(h.b0 & BHB0_OPCODE);
395 }
396
397 /// check whether the frame is masked
398 /**
399  * @param [in] h The basic header to extract from.
400  * @return True if the header mask bit is set.
401  */
402 inline bool get_masked(basic_header const & h) {
403     return ((h.b1 & BHB1_MASK) == BHB1_MASK);
404 }
405
406 /// Set the frame's MASK bit
407 /**
408  * @param [out] h Header to set.
409  * @param value Value to set it to.
410  */
411 inline void set_masked(basic_header & h, bool value) {
412     h.b1 = (value ? h.b1 | BHB1_MASK : h.b1 & ~BHB1_MASK);
413 }
414
415 /// Extracts the raw payload length specified in the basic header
416 /**
417  * A basic WebSocket frame header contains a 7 bit value that represents the
418  * payload size. There are two reserved values that are used to indicate that
419  * the actual payload size will not fit in 7 bits and that the full payload
420  * size is included in a separate field. The values are as follows:
421  *
422  * PAYLOAD_SIZE_CODE_16BIT (0x7E) indicates that the actual payload is less
423  * than 16 bit
424  *
425  * PAYLOAD_SIZE_CODE_64BIT (0x7F) indicates that the actual payload is less
426  * than 63 bit
427  *
428  * @param [in] h Basic header to read value from.
429  * @return The exact size encoded in h.
430  */
431 inline uint8_t get_basic_size(const basic_header &h) {
432     return h.b1 & BHB1_PAYLOAD;
433 }
434
435 /// Calculates the full length of the header based on the first bytes.
436 /**
437  * A WebSocket frame header always has at least two bytes. Encoded within the
438  * first two bytes is all the information necessary to calculate the full
439  * (variable) header length. get_header_len() calculates the full header
440  * length for the given two byte basic header.
441  *
442  * @param h Basic frame header to extract size from.
443  * @return Full length of the extended header.
444  */
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
460 /// Calculate the offset location of the masking key within the extended header
461 /**
462  * Calculate the offset location of the masking key within the extended header
463  * using information from its corresponding basic header
464  *
465  * @param h Corresponding basic header to calculate from.
466  *
467  * @return byte offset of the first byte of the masking key
468  */
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
479 /// Generate a properly sized contiguous string that encodes a full frame header
480 /**
481  * Copy the basic header h and extended header e into a properly sized
482  * contiguous frame header string for the purposes of writing out to the wire.
483  *
484  * @param h The basic header to include
485  * @param e The extended header to include
486  *
487  * @return A contiguous string containing h and e
488  */
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
504 /// Extract the masking key from a frame header
505 /**
506  * Note that while read and written as an integer at times, this value is not
507  * an integer and should never be interpreted as one. Big and little endian
508  * machines will generate and store masking keys differently without issue as
509  * long as the integer values remain irrelivant.
510  *
511  * @param h The basic header to extract from
512  * @param e The extended header to extract from
513  *
514  * @return The masking key as an integer.
515  */
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
531 /// Extract the extended size field from an extended header
532 /**
533  * It is the responsibility of the caller to verify that e is a valid extended
534  * header. This function assumes that e contains an extended payload size.
535  *
536  * @param e The extended header to extract from
537  *
538  * @return The size encoded in the extended header in host byte order
539  */
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
546 /// Extract the jumbo size field from an extended header
547 /**
548  * It is the responsibility of the caller to verify that e is a valid extended
549  * header. This function assumes that e contains a jumbo payload size.
550  *
551  * @param e The extended header to extract from
552  *
553  * @return The size encoded in the extended header in host byte order
554  */
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
561 /// Extract the full payload size field from a WebSocket header
562 /**
563  * It is the responsibility of the caller to verify that h and e together
564  * represent a valid WebSocket frame header. This function assumes only that h
565  * and e are valid. It uses information in the basic header to determine where
566  * to look for the payload_size
567  *
568  * @param h The basic header to extract from
569  * @param e The extended header to extract from
570  *
571  * @return The size encoded in the combined header in host byte order.
572  */
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
587 /// Extract a masking key into a value the size of a machine word.
588 /**
589  * Machine word size must be 4 or 8.
590  *
591  * @param key Masking key to extract from
592  *
593  * @return prepared key as a machine word
594  */
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
606 /// circularly shifts the supplied prepared masking key by offset bytes
607 /**
608  * Prepared_key must be the output of prepare_masking_key with the associated
609  * restrictions on the machine word size. offset must be greater than or equal
610  * to zero and less than sizeof(size_t).
611  */
612 inline size_t circshift_prepared_key(size_t prepared_key, size_t offset) {
613     if (lib::net::is_little_endian()) {
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
622 /// Byte by byte mask/unmask
623 /**
624  * Iterator based byte by byte masking and unmasking for WebSocket payloads.
625  * Performs masking in place using the supplied key offset by the supplied
626  * offset number of bytes.
627  *
628  * This function is simple and can be done in place on input with arbitrary
629  * lengths and does not vary based on machine word size. It is slow.
630  *
631  * @param b Beginning iterator to start masking
632  *
633  * @param e Ending iterator to end masking
634  *
635  * @param o Beginning iterator to store masked results
636  *
637  * @param key 32 bit key to mask with.
638  *
639  * @param key_offset offset value to start masking at.
640  */
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
654 /// Byte by byte mask/unmask (in place)
655 /**
656  * Iterator based byte by byte masking and unmasking for WebSocket payloads.
657  * Performs masking in place using the supplied key offset by the supplied
658  * offset number of bytes.
659  *
660  * This function is simple and can be done in place on input with arbitrary
661  * lengths and does not vary based on machine word size. It is slow.
662  *
663  * @param b Beginning iterator to start masking
664  *
665  * @param e Ending iterator to end masking
666  *
667  * @param key 32 bit key to mask with.
668  *
669  * @param key_offset offset value to start masking at.
670  */
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
678 /// Exact word aligned mask/unmask
679 /**
680  * Balanced combination of byte by byte and circular word by word masking.
681  * Best used to mask complete messages at once. Has much higher setup costs than
682  * word_mask_circ but works with exact sized buffers.
683  *
684  * Buffer based word by word masking and unmasking for WebSocket payloads.
685  * Masking is done in word by word chunks with the remainder not divisible by
686  * the word size done byte by byte.
687  *
688  * input and output must both be at least length bytes. Exactly length bytes
689  * will be written.
690  *
691  * @param input buffer to mask or unmask
692  *
693  * @param output buffer to store the output. May be the same as input.
694  *
695  * @param length length of data buffer
696  *
697  * @param key Masking key to use
698  */
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
716 /// Exact word aligned mask/unmask (in place)
717 /**
718  * In place version of word_mask_exact
719  *
720  * @see word_mask_exact
721  *
722  * @param data buffer to read and write from
723  *
724  * @param length length of data buffer
725  *
726  * @param key Masking key to use
727  */
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
734 /// Circular word aligned mask/unmask
735 /**
736  * Performs a circular mask/unmask in word sized chunks using pre-prepared keys
737  * that store state between calls. Best for providing streaming masking or
738  * unmasking of small chunks at a time of a larger message. Requires that the
739  * underlying allocated size of the data buffer be a multiple of the word size.
740  * Data in the buffer after `length` will be overwritten only with the same
741  * values that were originally present.
742  *
743  * Buffer based word by word masking and unmasking for WebSocket payloads.
744  * Performs masking in place using the supplied key. Casts the data buffer to
745  * an array of size_t's and performs masking word by word. The underlying
746  * buffer size must be a muliple of the word size.
747  *
748  * word_mask returns a copy of prepared_key circularly shifted based on the
749  * length value. The returned value may be fed back into word_mask when more
750  * data is available.
751  *
752  * input and output must both have length at least:
753  *    ceil(length/sizeof(size_t))*sizeof(size_t)
754  * Exactly that many bytes will be written, although only exactly length bytes
755  * will be changed (trailing bytes will be replaced without masking)
756  *
757  * @param data Character buffer to mask
758  *
759  * @param length Length of data
760  *
761  * @param prepared_key Prepared key to use.
762  *
763  * @return the prepared_key shifted to account for the input length
764  */
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
788 /// Circular word aligned mask/unmask (in place)
789 /**
790  * In place version of word_mask_circ
791  *
792  * @see word_mask_circ
793  *
794  * @param data Character buffer to read from and write to
795  *
796  * @param length Length of data
797  *
798  * @param prepared_key Prepared key to use.
799  *
800  * @return the prepared_key shifted to account for the input length
801  */
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
806 /// Circular byte aligned mask/unmask
807 /**
808  * Performs a circular mask/unmask in byte sized chunks using pre-prepared keys
809  * that store state between calls. Best for providing streaming masking or
810  * unmasking of small chunks at a time of a larger message. Requires that the
811  * underlying allocated size of the data buffer be a multiple of the word size.
812  * Data in the buffer after `length` will be overwritten only with the same
813  * values that were originally present.
814  *
815  * word_mask returns a copy of prepared_key circularly shifted based on the
816  * length value. The returned value may be fed back into byte_mask when more
817  * data is available.
818  *
819  * @param data Character buffer to mask
820  *
821  * @param length Length of data
822  *
823  * @param prepared_key Prepared key to use.
824  *
825  * @return the prepared_key shifted to account for the input length
826  */
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
840 /// Circular byte aligned mask/unmask (in place)
841 /**
842  * In place version of byte_mask_circ
843  *
844  * @see byte_mask_circ
845  *
846  * @param data Character buffer to read from and write to
847  *
848  * @param length Length of data
849  *
850  * @param prepared_key Prepared key to use.
851  *
852  * @return the prepared_key shifted to account for the input length
853  */
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