frame.hpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864
  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. #ifndef WEBSOCKETPP_FRAME_HPP
  28. #define WEBSOCKETPP_FRAME_HPP
  29. #include <algorithm>
  30. #include <string>
  31. #include <websocketpp/common/system_error.hpp>
  32. #include <websocketpp/common/network.hpp>
  33. #include <websocketpp/utilities.hpp>
  34. namespace websocketpp {
  35. /// Data structures and utility functions for manipulating WebSocket frames
  36. /**
  37. * namespace frame provides a number of data structures and utility functions
  38. * for reading, writing, and manipulating binary encoded WebSocket frames.
  39. */
  40. namespace frame {
  41. /// Minimum length of a WebSocket frame header.
  42. static unsigned int const BASIC_HEADER_LENGTH = 2;
  43. /// Maximum length of a WebSocket header
  44. static unsigned int const MAX_HEADER_LENGTH = 14;
  45. /// Maximum length of the variable portion of the WebSocket header
  46. static unsigned int const MAX_EXTENDED_HEADER_LENGTH = 12;
  47. /// Two byte conversion union
  48. union uint16_converter {
  49. uint16_t i;
  50. uint8_t c[2];
  51. };
  52. /// Four byte conversion union
  53. union uint32_converter {
  54. uint32_t i;
  55. uint8_t c[4];
  56. };
  57. /// Eight byte conversion union
  58. union uint64_converter {
  59. uint64_t i;
  60. uint8_t c[8];
  61. };
  62. /// Constants and utility functions related to WebSocket opcodes
  63. /**
  64. * WebSocket Opcodes are 4 bits. See RFC6455 section 5.2.
  65. */
  66. namespace opcode {
  67. enum value {
  68. continuation = 0x0,
  69. text = 0x1,
  70. binary = 0x2,
  71. rsv3 = 0x3,
  72. rsv4 = 0x4,
  73. rsv5 = 0x5,
  74. rsv6 = 0x6,
  75. rsv7 = 0x7,
  76. close = 0x8,
  77. ping = 0x9,
  78. pong = 0xA,
  79. control_rsvb = 0xB,
  80. control_rsvc = 0xC,
  81. control_rsvd = 0xD,
  82. control_rsve = 0xE,
  83. control_rsvf = 0xF,
  84. CONTINUATION = 0x0,
  85. TEXT = 0x1,
  86. BINARY = 0x2,
  87. RSV3 = 0x3,
  88. RSV4 = 0x4,
  89. RSV5 = 0x5,
  90. RSV6 = 0x6,
  91. RSV7 = 0x7,
  92. CLOSE = 0x8,
  93. PING = 0x9,
  94. PONG = 0xA,
  95. CONTROL_RSVB = 0xB,
  96. CONTROL_RSVC = 0xC,
  97. CONTROL_RSVD = 0xD,
  98. CONTROL_RSVE = 0xE,
  99. CONTROL_RSVF = 0xF
  100. };
  101. /// Check if an opcode is reserved
  102. /**
  103. * @param v The opcode to test.
  104. * @return Whether or not the opcode is reserved.
  105. */
  106. inline bool reserved(value v) {
  107. return (v >= rsv3 && v <= rsv7) ||
  108. (v >= control_rsvb && v <= control_rsvf);
  109. }
  110. /// Check if an opcode is invalid
  111. /**
  112. * Invalid opcodes are negative or require greater than 4 bits to store.
  113. *
  114. * @param v The opcode to test.
  115. * @return Whether or not the opcode is invalid.
  116. */
  117. inline bool invalid(value v) {
  118. return (v > 0xF || v < 0);
  119. }
  120. /// Check if an opcode is for a control frame
  121. /**
  122. * @param v The opcode to test.
  123. * @return Whether or not the opcode is a control opcode.
  124. */
  125. inline bool is_control(value v) {
  126. return v >= 0x8;
  127. }
  128. }
  129. /// Constants related to frame and payload limits
  130. namespace limits {
  131. /// Minimum length of a WebSocket frame header.
  132. static unsigned int const basic_header_length = 2;
  133. /// Maximum length of a WebSocket header
  134. static unsigned int const max_header_length = 14;
  135. /// Maximum length of the variable portion of the WebSocket header
  136. static unsigned int const max_extended_header_length = 12;
  137. /// Maximum size of a basic WebSocket payload
  138. static uint8_t const payload_size_basic = 125;
  139. /// Maximum size of an extended WebSocket payload (basic payload = 126)
  140. static uint16_t const payload_size_extended = 0xFFFF; // 2^16, 65535
  141. /// Maximum size of a jumbo WebSocket payload (basic payload = 127)
  142. static uint64_t const payload_size_jumbo = 0x7FFFFFFFFFFFFFFFLL;//2^63
  143. /// Maximum size of close frame reason
  144. /**
  145. * This is payload_size_basic - 2 bytes (as first two bytes are used for
  146. * the close code
  147. */
  148. static uint8_t const close_reason_size = 123;
  149. }
  150. // masks for fields in the basic header
  151. static uint8_t const BHB0_OPCODE = 0x0F;
  152. static uint8_t const BHB0_RSV3 = 0x10;
  153. static uint8_t const BHB0_RSV2 = 0x20;
  154. static uint8_t const BHB0_RSV1 = 0x40;
  155. static uint8_t const BHB0_FIN = 0x80;
  156. static uint8_t const BHB1_PAYLOAD = 0x7F;
  157. static uint8_t const BHB1_MASK = 0x80;
  158. static uint8_t const payload_size_code_16bit = 0x7E; // 126
  159. static uint8_t const payload_size_code_64bit = 0x7F; // 127
  160. typedef uint32_converter masking_key_type;
  161. /// The constant size component of a WebSocket frame header
  162. struct basic_header {
  163. basic_header() : b0(0x00),b1(0x00) {}
  164. basic_header(uint8_t p0, uint8_t p1) : b0(p0), b1(p1) {}
  165. basic_header(opcode::value op, uint64_t size, bool fin, bool mask,
  166. bool rsv1 = false, bool rsv2 = false, bool rsv3 = false) : b0(0x00),
  167. b1(0x00)
  168. {
  169. if (fin) {
  170. b0 |= BHB0_FIN;
  171. }
  172. if (rsv1) {
  173. b0 |= BHB0_RSV1;
  174. }
  175. if (rsv2) {
  176. b0 |= BHB0_RSV2;
  177. }
  178. if (rsv3) {
  179. b0 |= BHB0_RSV3;
  180. }
  181. b0 |= (op & BHB0_OPCODE);
  182. if (mask) {
  183. b1 |= BHB1_MASK;
  184. }
  185. uint8_t basic_value;
  186. if (size <= limits::payload_size_basic) {
  187. basic_value = static_cast<uint8_t>(size);
  188. } else if (size <= limits::payload_size_extended) {
  189. basic_value = payload_size_code_16bit;
  190. } else {
  191. basic_value = payload_size_code_64bit;
  192. }
  193. b1 |= basic_value;
  194. }
  195. uint8_t b0;
  196. uint8_t b1;
  197. };
  198. /// The variable size component of a WebSocket frame header
  199. struct extended_header {
  200. extended_header() {
  201. std::fill_n(this->bytes,MAX_EXTENDED_HEADER_LENGTH,0x00);
  202. }
  203. extended_header(uint64_t payload_size) {
  204. std::fill_n(this->bytes,MAX_EXTENDED_HEADER_LENGTH,0x00);
  205. copy_payload(payload_size);
  206. }
  207. extended_header(uint64_t payload_size, uint32_t masking_key) {
  208. std::fill_n(this->bytes,MAX_EXTENDED_HEADER_LENGTH,0x00);
  209. // Copy payload size
  210. int offset = copy_payload(payload_size);
  211. // Copy Masking Key
  212. uint32_converter temp32;
  213. temp32.i = masking_key;
  214. std::copy(temp32.c,temp32.c+4,bytes+offset);
  215. }
  216. uint8_t bytes[MAX_EXTENDED_HEADER_LENGTH];
  217. private:
  218. int copy_payload(uint64_t payload_size) {
  219. int payload_offset = 0;
  220. if (payload_size <= limits::payload_size_basic) {
  221. payload_offset = 8;
  222. } else if (payload_size <= limits::payload_size_extended) {
  223. payload_offset = 6;
  224. }
  225. uint64_converter temp64;
  226. temp64.i = lib::net::_htonll(payload_size);
  227. std::copy(temp64.c+payload_offset,temp64.c+8,bytes);
  228. return 8-payload_offset;
  229. }
  230. };
  231. bool get_fin(basic_header const &h);
  232. void set_fin(basic_header &h, bool value);
  233. bool get_rsv1(basic_header const &h);
  234. void set_rsv1(basic_header &h, bool value);
  235. bool get_rsv2(basic_header const &h);
  236. void set_rsv2(basic_header &h, bool value);
  237. bool get_rsv3(basic_header const &h);
  238. void set_rsv3(basic_header &h, bool value);
  239. opcode::value get_opcode(basic_header const &h);
  240. bool get_masked(basic_header const &h);
  241. void set_masked(basic_header &h, bool value);
  242. uint8_t get_basic_size(basic_header const &);
  243. size_t get_header_len(basic_header const &);
  244. unsigned int get_masking_key_offset(basic_header const &);
  245. std::string write_header(basic_header const &, extended_header const &);
  246. masking_key_type get_masking_key(basic_header const &, extended_header const &);
  247. uint16_t get_extended_size(extended_header const &);
  248. uint64_t get_jumbo_size(extended_header const &);
  249. uint64_t get_payload_size(basic_header const &, extended_header const &);
  250. size_t prepare_masking_key(masking_key_type const & key);
  251. size_t circshift_prepared_key(size_t prepared_key, size_t offset);
  252. // Functions for performing xor based masking and unmasking
  253. template <typename input_iter, typename output_iter>
  254. void byte_mask(input_iter b, input_iter e, output_iter o, masking_key_type
  255. const & key, size_t key_offset = 0);
  256. template <typename iter_type>
  257. void byte_mask(iter_type b, iter_type e, masking_key_type const & key,
  258. size_t key_offset = 0);
  259. void word_mask_exact(uint8_t * input, uint8_t * output, size_t length,
  260. masking_key_type const & key);
  261. void word_mask_exact(uint8_t * data, size_t length, masking_key_type const &
  262. key);
  263. size_t word_mask_circ(uint8_t * input, uint8_t * output, size_t length,
  264. size_t prepared_key);
  265. size_t word_mask_circ(uint8_t * data, size_t length, size_t prepared_key);
  266. /// Check whether the frame's FIN bit is set.
  267. /**
  268. * @param [in] h The basic header to extract from.
  269. * @return True if the header's fin bit is set.
  270. */
  271. inline bool get_fin(basic_header const & h) {
  272. return ((h.b0 & BHB0_FIN) == BHB0_FIN);
  273. }
  274. /// Set the frame's FIN bit
  275. /**
  276. * @param [out] h Header to set.
  277. * @param [in] value Value to set it to.
  278. */
  279. inline void set_fin(basic_header & h, bool value) {
  280. h.b0 = (value ? h.b0 | BHB0_FIN : h.b0 & ~BHB0_FIN);
  281. }
  282. /// check whether the frame's RSV1 bit is set
  283. /**
  284. * @param [in] h The basic header to extract from.
  285. * @return True if the header's RSV1 bit is set.
  286. */
  287. inline bool get_rsv1(const basic_header &h) {
  288. return ((h.b0 & BHB0_RSV1) == BHB0_RSV1);
  289. }
  290. /// Set the frame's RSV1 bit
  291. /**
  292. * @param [out] h Header to set.
  293. * @param [in] value Value to set it to.
  294. */
  295. inline void set_rsv1(basic_header &h, bool value) {
  296. h.b0 = (value ? h.b0 | BHB0_RSV1 : h.b0 & ~BHB0_RSV1);
  297. }
  298. /// check whether the frame's RSV2 bit is set
  299. /**
  300. * @param [in] h The basic header to extract from.
  301. * @return True if the header's RSV2 bit is set.
  302. */
  303. inline bool get_rsv2(const basic_header &h) {
  304. return ((h.b0 & BHB0_RSV2) == BHB0_RSV2);
  305. }
  306. /// Set the frame's RSV2 bit
  307. /**
  308. * @param [out] h Header to set.
  309. * @param [in] value Value to set it to.
  310. */
  311. inline void set_rsv2(basic_header &h, bool value) {
  312. h.b0 = (value ? h.b0 | BHB0_RSV2 : h.b0 & ~BHB0_RSV2);
  313. }
  314. /// check whether the frame's RSV3 bit is set
  315. /**
  316. * @param [in] h The basic header to extract from.
  317. * @return True if the header's RSV3 bit is set.
  318. */
  319. inline bool get_rsv3(const basic_header &h) {
  320. return ((h.b0 & BHB0_RSV3) == BHB0_RSV3);
  321. }
  322. /// Set the frame's RSV3 bit
  323. /**
  324. * @param [out] h Header to set.
  325. * @param [in] value Value to set it to.
  326. */
  327. inline void set_rsv3(basic_header &h, bool value) {
  328. h.b0 = (value ? h.b0 | BHB0_RSV3 : h.b0 & ~BHB0_RSV3);
  329. }
  330. /// Extract opcode from basic header
  331. /**
  332. * @param [in] h The basic header to extract from.
  333. * @return The opcode value of the header.
  334. */
  335. inline opcode::value get_opcode(const basic_header &h) {
  336. return opcode::value(h.b0 & BHB0_OPCODE);
  337. }
  338. /// check whether the frame is masked
  339. /**
  340. * @param [in] h The basic header to extract from.
  341. * @return True if the header mask bit is set.
  342. */
  343. inline bool get_masked(basic_header const & h) {
  344. return ((h.b1 & BHB1_MASK) == BHB1_MASK);
  345. }
  346. /// Set the frame's MASK bit
  347. /**
  348. * @param [out] h Header to set.
  349. * @param value Value to set it to.
  350. */
  351. inline void set_masked(basic_header & h, bool value) {
  352. h.b1 = (value ? h.b1 | BHB1_MASK : h.b1 & ~BHB1_MASK);
  353. }
  354. /// Extracts the raw payload length specified in the basic header
  355. /**
  356. * A basic WebSocket frame header contains a 7 bit value that represents the
  357. * payload size. There are two reserved values that are used to indicate that
  358. * the actual payload size will not fit in 7 bits and that the full payload
  359. * size is included in a separate field. The values are as follows:
  360. *
  361. * PAYLOAD_SIZE_CODE_16BIT (0x7E) indicates that the actual payload is less
  362. * than 16 bit
  363. *
  364. * PAYLOAD_SIZE_CODE_64BIT (0x7F) indicates that the actual payload is less
  365. * than 63 bit
  366. *
  367. * @param [in] h Basic header to read value from.
  368. * @return The exact size encoded in h.
  369. */
  370. inline uint8_t get_basic_size(const basic_header &h) {
  371. return h.b1 & BHB1_PAYLOAD;
  372. }
  373. /// Calculates the full length of the header based on the first bytes.
  374. /**
  375. * A WebSocket frame header always has at least two bytes. Encoded within the
  376. * first two bytes is all the information necessary to calculate the full
  377. * (variable) header length. get_header_len() calculates the full header
  378. * length for the given two byte basic header.
  379. *
  380. * @param h Basic frame header to extract size from.
  381. * @return Full length of the extended header.
  382. */
  383. inline size_t get_header_len(basic_header const & h) {
  384. // TODO: check extensions?
  385. // masking key offset represents the space used for the extended length
  386. // fields
  387. size_t size = BASIC_HEADER_LENGTH + get_masking_key_offset(h);
  388. // If the header is masked there is a 4 byte masking key
  389. if (get_masked(h)) {
  390. size += 4;
  391. }
  392. return size;
  393. }
  394. /// Calculate the offset location of the masking key within the extended header
  395. /**
  396. * Calculate the offset location of the masking key within the extended header
  397. * using information from its corresponding basic header
  398. *
  399. * @param h Corresponding basic header to calculate from.
  400. *
  401. * @return byte offset of the first byte of the masking key
  402. */
  403. inline unsigned int get_masking_key_offset(const basic_header &h) {
  404. if (get_basic_size(h) == payload_size_code_16bit) {
  405. return 2;
  406. } else if (get_basic_size(h) == payload_size_code_64bit) {
  407. return 8;
  408. } else {
  409. return 0;
  410. }
  411. }
  412. /// Generate a properly sized contiguous string that encodes a full frame header
  413. /**
  414. * Copy the basic header h and extended header e into a properly sized
  415. * contiguous frame header string for the purposes of writing out to the wire.
  416. *
  417. * @param h The basic header to include
  418. * @param e The extended header to include
  419. *
  420. * @return A contiguous string containing h and e
  421. */
  422. inline std::string prepare_header(const basic_header &h, const
  423. extended_header &e)
  424. {
  425. std::string ret;
  426. ret.push_back(char(h.b0));
  427. ret.push_back(char(h.b1));
  428. ret.append(
  429. reinterpret_cast<const char*>(e.bytes),
  430. get_header_len(h)-BASIC_HEADER_LENGTH
  431. );
  432. return ret;
  433. }
  434. /// Extract the masking key from a frame header
  435. /**
  436. * Note that while read and written as an integer at times, this value is not
  437. * an integer and should never be interpreted as one. Big and little endian
  438. * machines will generate and store masking keys differently without issue as
  439. * long as the integer values remain irrelivant.
  440. *
  441. * @param h The basic header to extract from
  442. * @param e The extended header to extract from
  443. *
  444. * @return The masking key as an integer.
  445. */
  446. inline masking_key_type get_masking_key(const basic_header &h, const
  447. extended_header &e)
  448. {
  449. masking_key_type temp32;
  450. if (!get_masked(h)) {
  451. temp32.i = 0;
  452. } else {
  453. unsigned int offset = get_masking_key_offset(h);
  454. std::copy(e.bytes+offset,e.bytes+offset+4,temp32.c);
  455. }
  456. return temp32;
  457. }
  458. /// Extract the extended size field from an extended header
  459. /**
  460. * It is the responsibility of the caller to verify that e is a valid extended
  461. * header. This function assumes that e contains an extended payload size.
  462. *
  463. * @param e The extended header to extract from
  464. *
  465. * @return The size encoded in the extended header in host byte order
  466. */
  467. inline uint16_t get_extended_size(const extended_header &e) {
  468. uint16_converter temp16;
  469. std::copy(e.bytes,e.bytes+2,temp16.c);
  470. return ntohs(temp16.i);
  471. }
  472. /// Extract the jumbo size field from an extended header
  473. /**
  474. * It is the responsibility of the caller to verify that e is a valid extended
  475. * header. This function assumes that e contains a jumbo payload size.
  476. *
  477. * @param e The extended header to extract from
  478. *
  479. * @return The size encoded in the extended header in host byte order
  480. */
  481. inline uint64_t get_jumbo_size(const extended_header &e) {
  482. uint64_converter temp64;
  483. std::copy(e.bytes,e.bytes+8,temp64.c);
  484. return lib::net::_ntohll(temp64.i);
  485. }
  486. /// Extract the full payload size field from a WebSocket header
  487. /**
  488. * It is the responsibility of the caller to verify that h and e together
  489. * represent a valid WebSocket frame header. This function assumes only that h
  490. * and e are valid. It uses information in the basic header to determine where
  491. * to look for the payload_size
  492. *
  493. * @param h The basic header to extract from
  494. * @param e The extended header to extract from
  495. *
  496. * @return The size encoded in the combined header in host byte order.
  497. */
  498. inline uint64_t get_payload_size(const basic_header &h, const
  499. extended_header &e)
  500. {
  501. uint8_t val = get_basic_size(h);
  502. if (val <= limits::payload_size_basic) {
  503. return val;
  504. } else if (val == payload_size_code_16bit) {
  505. return get_extended_size(e);
  506. } else {
  507. return get_jumbo_size(e);
  508. }
  509. }
  510. /// Extract a masking key into a value the size of a machine word.
  511. /**
  512. * Machine word size must be 4 or 8.
  513. *
  514. * @param key Masking key to extract from
  515. *
  516. * @return prepared key as a machine word
  517. */
  518. inline size_t prepare_masking_key(const masking_key_type& key) {
  519. size_t low_bits = static_cast<size_t>(key.i);
  520. if (sizeof(size_t) == 8) {
  521. uint64_t high_bits = static_cast<size_t>(key.i);
  522. return static_cast<size_t>((high_bits << 32) | low_bits);
  523. } else {
  524. return low_bits;
  525. }
  526. }
  527. /// circularly shifts the supplied prepared masking key by offset bytes
  528. /**
  529. * Prepared_key must be the output of prepare_masking_key with the associated
  530. * restrictions on the machine word size. offset must be greater than or equal
  531. * to zero and less than sizeof(size_t).
  532. */
  533. inline size_t circshift_prepared_key(size_t prepared_key, size_t offset) {
  534. if (offset == 0) {
  535. return prepared_key;
  536. }
  537. if (lib::net::is_little_endian()) {
  538. size_t temp = prepared_key << (sizeof(size_t)-offset)*8;
  539. return (prepared_key >> offset*8) | temp;
  540. } else {
  541. size_t temp = prepared_key >> (sizeof(size_t)-offset)*8;
  542. return (prepared_key << offset*8) | temp;
  543. }
  544. }
  545. /// Byte by byte mask/unmask
  546. /**
  547. * Iterator based byte by byte masking and unmasking for WebSocket payloads.
  548. * Performs masking in place using the supplied key offset by the supplied
  549. * offset number of bytes.
  550. *
  551. * This function is simple and can be done in place on input with arbitrary
  552. * lengths and does not vary based on machine word size. It is slow.
  553. *
  554. * @param b Beginning iterator to start masking
  555. *
  556. * @param e Ending iterator to end masking
  557. *
  558. * @param o Beginning iterator to store masked results
  559. *
  560. * @param key 32 bit key to mask with.
  561. *
  562. * @param key_offset offset value to start masking at.
  563. */
  564. template <typename input_iter, typename output_iter>
  565. void byte_mask(input_iter first, input_iter last, output_iter result,
  566. masking_key_type const & key, size_t key_offset)
  567. {
  568. size_t key_index = key_offset%4;
  569. while (first != last) {
  570. *result = *first ^ key.c[key_index++];
  571. key_index %= 4;
  572. ++result;
  573. ++first;
  574. }
  575. }
  576. /// Byte by byte mask/unmask (in place)
  577. /**
  578. * Iterator based byte by byte masking and unmasking for WebSocket payloads.
  579. * Performs masking in place using the supplied key offset by the supplied
  580. * offset number of bytes.
  581. *
  582. * This function is simple and can be done in place on input with arbitrary
  583. * lengths and does not vary based on machine word size. It is slow.
  584. *
  585. * @param b Beginning iterator to start masking
  586. *
  587. * @param e Ending iterator to end masking
  588. *
  589. * @param key 32 bit key to mask with.
  590. *
  591. * @param key_offset offset value to start masking at.
  592. */
  593. template <typename iter_type>
  594. void byte_mask(iter_type b, iter_type e, masking_key_type const & key,
  595. size_t key_offset)
  596. {
  597. byte_mask(b,e,b,key,key_offset);
  598. }
  599. /// Exact word aligned mask/unmask
  600. /**
  601. * Balanced combination of byte by byte and circular word by word masking.
  602. * Best used to mask complete messages at once. Has much higher setup costs than
  603. * word_mask_circ but works with exact sized buffers.
  604. *
  605. * Buffer based word by word masking and unmasking for WebSocket payloads.
  606. * Masking is done in word by word chunks with the remainder not divisible by
  607. * the word size done byte by byte.
  608. *
  609. * input and output must both be at least length bytes. Exactly length bytes
  610. * will be written.
  611. *
  612. * @param input buffer to mask or unmask
  613. *
  614. * @param output buffer to store the output. May be the same as input.
  615. *
  616. * @param length length of data buffer
  617. *
  618. * @param key Masking key to use
  619. */
  620. inline void word_mask_exact(uint8_t* input, uint8_t* output, size_t length,
  621. const masking_key_type& key)
  622. {
  623. size_t prepared_key = prepare_masking_key(key);
  624. size_t n = length/sizeof(size_t);
  625. size_t* input_word = reinterpret_cast<size_t*>(input);
  626. size_t* output_word = reinterpret_cast<size_t*>(output);
  627. for (size_t i = 0; i < n; i++) {
  628. output_word[i] = input_word[i] ^ prepared_key;
  629. }
  630. for (size_t i = n*sizeof(size_t); i < length; i++) {
  631. output[i] = input[i] ^ key.c[i%4];
  632. }
  633. }
  634. /// Exact word aligned mask/unmask (in place)
  635. /**
  636. * In place version of word_mask_exact
  637. *
  638. * @see word_mask_exact
  639. *
  640. * @param data buffer to read and write from
  641. *
  642. * @param length length of data buffer
  643. *
  644. * @param key Masking key to use
  645. */
  646. inline void word_mask_exact(uint8_t* data, size_t length, const
  647. masking_key_type& key)
  648. {
  649. word_mask_exact(data,data,length,key);
  650. }
  651. /// Circular word aligned mask/unmask
  652. /**
  653. * Performs a circular mask/unmask in word sized chunks using pre-prepared keys
  654. * that store state between calls. Best for providing streaming masking or
  655. * unmasking of small chunks at a time of a larger message. Requires that the
  656. * underlying allocated size of the data buffer be a multiple of the word size.
  657. * Data in the buffer after `length` will be overwritten only with the same
  658. * values that were originally present.
  659. *
  660. * Buffer based word by word masking and unmasking for WebSocket payloads.
  661. * Performs masking in place using the supplied key. Casts the data buffer to
  662. * an array of size_t's and performs masking word by word. The underlying
  663. * buffer size must be a muliple of the word size.
  664. *
  665. * word_mask returns a copy of prepared_key circularly shifted based on the
  666. * length value. The returned value may be fed back into word_mask when more
  667. * data is available.
  668. *
  669. * input and output must both have length at least:
  670. * ceil(length/sizeof(size_t))*sizeof(size_t)
  671. * Exactly that many bytes will be written, although only exactly length bytes
  672. * will be changed (trailing bytes will be replaced without masking)
  673. *
  674. * @param data Character buffer to mask
  675. *
  676. * @param length Length of data
  677. *
  678. * @param prepared_key Prepared key to use.
  679. *
  680. * @return the prepared_key shifted to account for the input length
  681. */
  682. inline size_t word_mask_circ(uint8_t * input, uint8_t * output, size_t length,
  683. size_t prepared_key)
  684. {
  685. size_t n = length / sizeof(size_t); // whole words
  686. size_t l = length - (n * sizeof(size_t)); // remaining bytes
  687. size_t * input_word = reinterpret_cast<size_t *>(input);
  688. size_t * output_word = reinterpret_cast<size_t *>(output);
  689. // mask word by word
  690. for (size_t i = 0; i < n; i++) {
  691. output_word[i] = input_word[i] ^ prepared_key;
  692. }
  693. // mask partial word at the end
  694. size_t start = length - l;
  695. uint8_t * byte_key = reinterpret_cast<uint8_t *>(&prepared_key);
  696. for (size_t i = 0; i < l; ++i) {
  697. output[start+i] = input[start+i] ^ byte_key[i];
  698. }
  699. return circshift_prepared_key(prepared_key,l);
  700. }
  701. /// Circular word aligned mask/unmask (in place)
  702. /**
  703. * In place version of word_mask_circ
  704. *
  705. * @see word_mask_circ
  706. *
  707. * @param data Character buffer to read from and write to
  708. *
  709. * @param length Length of data
  710. *
  711. * @param prepared_key Prepared key to use.
  712. *
  713. * @return the prepared_key shifted to account for the input length
  714. */
  715. inline size_t word_mask_circ(uint8_t* data, size_t length, size_t prepared_key){
  716. return word_mask_circ(data,data,length,prepared_key);
  717. }
  718. /// Circular byte aligned mask/unmask
  719. /**
  720. * Performs a circular mask/unmask in byte sized chunks using pre-prepared keys
  721. * that store state between calls. Best for providing streaming masking or
  722. * unmasking of small chunks at a time of a larger message. Requires that the
  723. * underlying allocated size of the data buffer be a multiple of the word size.
  724. * Data in the buffer after `length` will be overwritten only with the same
  725. * values that were originally present.
  726. *
  727. * word_mask returns a copy of prepared_key circularly shifted based on the
  728. * length value. The returned value may be fed back into byte_mask when more
  729. * data is available.
  730. *
  731. * @param data Character buffer to mask
  732. *
  733. * @param length Length of data
  734. *
  735. * @param prepared_key Prepared key to use.
  736. *
  737. * @return the prepared_key shifted to account for the input length
  738. */
  739. inline size_t byte_mask_circ(uint8_t * input, uint8_t * output, size_t length,
  740. size_t prepared_key)
  741. {
  742. uint32_converter key;
  743. key.i = prepared_key;
  744. for (size_t i = 0; i < length; ++i) {
  745. output[i] = input[i] ^ key.c[i % 4];
  746. }
  747. return circshift_prepared_key(prepared_key,length % 4);
  748. }
  749. /// Circular byte aligned mask/unmask (in place)
  750. /**
  751. * In place version of byte_mask_circ
  752. *
  753. * @see byte_mask_circ
  754. *
  755. * @param data Character buffer to read from and write to
  756. *
  757. * @param length Length of data
  758. *
  759. * @param prepared_key Prepared key to use.
  760. *
  761. * @return the prepared_key shifted to account for the input length
  762. */
  763. inline size_t byte_mask_circ(uint8_t* data, size_t length, size_t prepared_key){
  764. return byte_mask_circ(data,data,length,prepared_key);
  765. }
  766. } // namespace frame
  767. } // namespace websocketpp
  768. #endif //WEBSOCKETPP_FRAME_HPP