EHS Embedded HTTP Server
1.5.0.132
|
00001 /* 00002 * This file has been derived from the WebSockets++ project at 00003 * https://github.com/zaphoyd/websocketpp which is licensed under a BSD-license. 00004 * 00005 * Copyright (c) 2011, Peter Thorson. All rights reserved. 00006 * 00007 * Redistribution and use in source and binary forms, with or without 00008 * modification, are permitted provided that the following conditions are met: 00009 * * Redistributions of source code must retain the above copyright 00010 * notice, this list of conditions and the following disclaimer. 00011 * * Redistributions in binary form must reproduce the above copyright 00012 * notice, this list of conditions and the following disclaimer in the 00013 * documentation and/or other materials provided with the distribution. 00014 * * Neither the name of the WebSocket++ Project nor the 00015 * names of its contributors may be used to endorse or promote products 00016 * derived from this software without specific prior written permission. 00017 * 00018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00021 * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY 00022 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00023 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00024 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 00025 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00026 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00027 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00028 * 00029 */ 00030 00031 #ifndef WEBSOCKET_FRAME_HPP 00032 #define WEBSOCKET_FRAME_HPP 00033 00034 #include "wscommon.h" 00035 #include "wsutf8.h" 00036 #include "btexception.h" 00037 00038 #if defined(_WIN32) 00039 #include <winsock2.h> 00040 #else 00041 #include <arpa/inet.h> 00042 #endif 00043 00044 #include <vector> 00045 #include <cstring> 00046 #include <iostream> 00047 #include <algorithm> 00048 00049 static int64_t htonll(int64_t v) { 00050 static int HOST_IS_LE = 0x1234; 00051 if (HOST_IS_LE == 0x1234) 00052 HOST_IS_LE = (htons(1) != 1); 00053 if (HOST_IS_LE) { 00054 union { uint32_t hv[2]; int64_t v; } u; 00055 u.hv[0] = htonl(v >> 32); 00056 u.hv[1] = htonl(v & 0x0FFFFFFFFULL); 00057 return u.v; 00058 } 00059 return v; 00060 } 00061 #define ntohll(x) htonll(x) 00062 00063 namespace tracing { 00064 00070 class wserror : public exception 00071 { 00072 public: 00073 enum { 00074 FATAL_ERROR = 0, // force session end 00075 SOFT_ERROR = 1, // should log and ignore 00076 PROTOCOL_VIOLATION = 2, // must end session 00077 PAYLOAD_VIOLATION = 3, // should end session 00078 INTERNAL_ENDPOINT_ERROR = 4,// cleanly end session 00079 MESSAGE_TOO_BIG = 5, // ??? 00080 OUT_OF_MESSAGES = 6 00081 }; 00082 00088 explicit wserror(const std::string& __arg, int code = wserror::FATAL_ERROR) 00089 : exception(), msg(__arg) , ecode(code) { } 00091 virtual ~wserror() throw() { } 00096 virtual const char* what() const throw() 00097 { return msg.c_str(); } 00102 virtual int code() const { return ecode; } 00103 00104 private: 00105 std::string msg; 00106 int ecode; 00107 }; 00108 } 00109 00110 namespace wspp { 00111 00115 class simple_rng { 00116 public: 00118 simple_rng() : seed(::time(NULL)) { } 00123 int32_t gen() { 00124 #ifdef _WIN32 00125 return ::rand(); 00126 #else 00127 return ::rand_r(&seed); 00128 #endif 00129 } 00130 private: 00131 unsigned int seed; 00132 }; 00133 00134 namespace frame { 00135 00136 /* policies to abstract out 00137 00138 - random number generation 00139 - utf8 validation 00140 00141 rng 00142 int32_t gen() 00143 00144 00145 class boost_random { 00146 public: 00147 boost_random() 00148 int32_t gen(); 00149 private: 00150 boost::random::random_device m_rng; 00151 boost::random::variate_generator<boost::random::random_device&,boost::random::uniform_int_distribution<> > m_gen; 00152 } 00153 00154 */ 00155 00156 template <class rng_policy> 00160 class parser { 00161 private: 00162 // basic payload byte flags 00163 static const uint8_t BPB0_OPCODE = 0x0F; 00164 static const uint8_t BPB0_RSV3 = 0x10; 00165 static const uint8_t BPB0_RSV2 = 0x20; 00166 static const uint8_t BPB0_RSV1 = 0x40; 00167 static const uint8_t BPB0_FIN = 0x80; 00168 static const uint8_t BPB1_PAYLOAD = 0x7F; 00169 static const uint8_t BPB1_MASK = 0x80; 00170 00171 static const uint8_t BASIC_PAYLOAD_16BIT_CODE = 0x7E; // 126 00172 static const uint8_t BASIC_PAYLOAD_64BIT_CODE = 0x7F; // 127 00173 00174 static const unsigned int BASIC_HEADER_LENGTH = 2; 00175 static const unsigned int MAX_HEADER_LENGTH = 14; 00176 static const uint8_t extended_header_length = 12; 00177 static const uint64_t max_payload_size = 100000000; // 100MB 00178 00179 public: 00184 parser(rng_policy& rng) 00185 : m_state(STATE_BASIC_HEADER) 00186 , m_bytes_needed(BASIC_HEADER_LENGTH) 00187 , m_degraded(false) 00188 , m_payload(std::vector<unsigned char>()) 00189 , m_rng(rng) 00190 { 00191 reset(); 00192 } 00193 00198 bool ready() const { 00199 return (m_state == STATE_READY); 00200 } 00201 00205 void reset() { 00206 m_state = STATE_BASIC_HEADER; 00207 m_bytes_needed = BASIC_HEADER_LENGTH; 00208 m_degraded = false; 00209 m_payload.clear(); 00210 std::fill(m_header,m_header+MAX_HEADER_LENGTH,0); 00211 } 00212 00222 void consume(std::istream &s) { 00223 try { 00224 switch (m_state) { 00225 case STATE_BASIC_HEADER: 00226 s.read(&m_header[BASIC_HEADER_LENGTH-m_bytes_needed],m_bytes_needed); 00227 00228 m_bytes_needed -= s.gcount(); 00229 00230 if (m_bytes_needed == 0) { 00231 process_basic_header(); 00232 00233 validate_basic_header(); 00234 00235 if (m_bytes_needed > 0) { 00236 m_state = STATE_EXTENDED_HEADER; 00237 } else { 00238 process_extended_header(); 00239 00240 if (m_bytes_needed == 0) { 00241 m_state = STATE_READY; 00242 process_payload(); 00243 00244 } else { 00245 m_state = STATE_PAYLOAD; 00246 } 00247 } 00248 } 00249 break; 00250 case STATE_EXTENDED_HEADER: 00251 s.read(&m_header[get_header_len()-m_bytes_needed],m_bytes_needed); 00252 00253 m_bytes_needed -= s.gcount(); 00254 00255 if (m_bytes_needed == 0) { 00256 process_extended_header(); 00257 if (m_bytes_needed == 0) { 00258 m_state = STATE_READY; 00259 process_payload(); 00260 } else { 00261 m_state = STATE_PAYLOAD; 00262 } 00263 } 00264 break; 00265 case STATE_PAYLOAD: 00266 s.read(reinterpret_cast<char *>(&m_payload[m_payload.size()-m_bytes_needed]), 00267 m_bytes_needed); 00268 00269 m_bytes_needed -= s.gcount(); 00270 00271 if (m_bytes_needed == 0) { 00272 m_state = STATE_READY; 00273 process_payload(); 00274 } 00275 break; 00276 case STATE_RECOVERY: 00277 // Recovery state discards all bytes that are not the first byte 00278 // of a close frame. 00279 do { 00280 s.read(reinterpret_cast<char *>(&m_header[0]),1); 00281 if (int(static_cast<unsigned char>(m_header[0])) == 0x88) { 00282 //(BPB0_FIN && CONNECTION_CLOSE) 00283 m_bytes_needed--; 00284 m_state = STATE_BASIC_HEADER; 00285 break; 00286 } 00287 } while (s.gcount() > 0); 00288 break; 00289 default: 00290 break; 00291 } 00292 00293 } catch (const std::exception & e) { 00294 // After this point all non-close frames must be considered garbage, 00295 // including the current one. Reset it and put the reading frame into 00296 // a recovery state. 00297 if (m_degraded == true) { 00298 throw tracing::wserror("An error occurred while trying to gracefully recover from a less serious frame error."); 00299 } else { 00300 reset(); 00301 m_state = STATE_RECOVERY; 00302 m_degraded = true; 00303 00304 throw e; 00305 } 00306 } 00307 } 00308 00313 std::string get_header_str() { 00314 return std::string(m_header, get_header_len()); 00315 } 00316 00321 std::string get_payload_str() const { 00322 return std::string(m_payload.begin(), m_payload.end()); 00323 } 00324 00329 std::vector<unsigned char> &get_payload() { 00330 return m_payload; 00331 } 00332 00337 bool is_control() const { 00338 return (opcode::is_control(get_opcode())); 00339 } 00340 00345 void set_fin(bool fin) { 00346 if (fin) { 00347 m_header[0] |= BPB0_FIN; 00348 } else { 00349 m_header[0] &= (0xFF ^ BPB0_FIN); 00350 } 00351 } 00352 00357 opcode::value get_opcode() const { 00358 return frame::opcode::value(m_header[0] & BPB0_OPCODE); 00359 } 00360 00365 void set_opcode(opcode::value op) { 00366 if (opcode::reserved(op)) { 00367 throw tracing::wserror("reserved opcode",tracing::wserror::PROTOCOL_VIOLATION); 00368 } 00369 00370 if (opcode::invalid(op)) { 00371 throw tracing::wserror("invalid opcode",tracing::wserror::PROTOCOL_VIOLATION); 00372 } 00373 00374 if (is_control() && get_basic_size() > limits::PAYLOAD_SIZE_BASIC) { 00375 throw tracing::wserror("control frames can't have large payloads",tracing::wserror::PROTOCOL_VIOLATION); 00376 } 00377 00378 m_header[0] &= (0xFF ^ BPB0_OPCODE); // clear op bits 00379 m_header[0] |= op; // set op bits 00380 } 00381 00386 void set_masked(bool masked) { 00387 if (masked) { 00388 m_header[1] |= BPB1_MASK; 00389 generate_masking_key(); 00390 } else { 00391 m_header[1] &= (0xFF ^ BPB1_MASK); 00392 clear_masking_key(); 00393 } 00394 } 00395 00400 void set_payload(const std::string& source) { 00401 set_payload_helper(source.size()); 00402 00403 std::copy(source.begin(),source.end(),m_payload.begin()); 00404 } 00405 00410 void set_payload(const std::vector<unsigned char>& source) { 00411 set_payload_helper(source.size()); 00412 00413 std::copy(source.begin(),source.end(),m_payload.begin()); 00414 } 00415 00420 close::status::value get_close_code() const { 00421 if (m_payload.size() == 0) { 00422 return close::status::NO_STATUS; 00423 } else { 00424 return close::status::value(get_raw_close_code()); 00425 } 00426 } 00427 00432 std::string get_close_reason() const { 00433 if (m_payload.size() > 2) { 00434 return get_payload_str().substr(2); 00435 } else { 00436 return std::string(); 00437 } 00438 } 00439 00440 private: 00446 uint64_t get_bytes_needed() const { 00447 return m_bytes_needed; 00448 } 00449 00450 // get pointers to underlying buffers 00451 char* get_header() { 00452 return m_header; 00453 } 00454 char* get_extended_header() { 00455 return m_header+BASIC_HEADER_LENGTH; 00456 } 00457 unsigned int get_header_len() const { 00458 unsigned int temp = 2; 00459 00460 if (get_masked()) { 00461 temp += 4; 00462 } 00463 00464 if (get_basic_size() == 126) { 00465 temp += 2; 00466 } else if (get_basic_size() == 127) { 00467 temp += 8; 00468 } 00469 00470 return temp; 00471 } 00472 00473 char* get_masking_key() { 00474 return &m_header[get_header_len()-4]; 00475 } 00476 00477 // get and set header bits 00478 bool get_fin() const { 00479 return ((m_header[0] & BPB0_FIN) == BPB0_FIN); 00480 } 00481 bool get_rsv1() const { 00482 return ((m_header[0] & BPB0_RSV1) == BPB0_RSV1); 00483 } 00484 void set_rsv1(bool b) { 00485 if (b) { 00486 m_header[0] |= BPB0_RSV1; 00487 } else { 00488 m_header[0] &= (0xFF ^ BPB0_RSV1); 00489 } 00490 } 00491 00492 bool get_rsv2() const { 00493 return ((m_header[0] & BPB0_RSV2) == BPB0_RSV2); 00494 } 00495 void set_rsv2(bool b) { 00496 if (b) { 00497 m_header[0] |= BPB0_RSV2; 00498 } else { 00499 m_header[0] &= (0xFF ^ BPB0_RSV2); 00500 } 00501 } 00502 00503 bool get_rsv3() const { 00504 return ((m_header[0] & BPB0_RSV3) == BPB0_RSV3); 00505 } 00506 void set_rsv3(bool b) { 00507 if (b) { 00508 m_header[0] |= BPB0_RSV3; 00509 } else { 00510 m_header[0] &= (0xFF ^ BPB0_RSV3); 00511 } 00512 } 00513 00514 bool get_masked() const { 00515 return ((m_header[1] & BPB1_MASK) == BPB1_MASK); 00516 } 00517 uint8_t get_basic_size() const { 00518 return m_header[1] & BPB1_PAYLOAD; 00519 } 00520 size_t get_payload_size() const { 00521 if (m_state != STATE_READY && m_state != STATE_PAYLOAD) { 00522 // TODO: how to handle errors like this? 00523 throw "attempted to get payload size before reading full header"; 00524 } 00525 00526 return m_payload.size(); 00527 } 00528 00529 close::status::value get_close_status() const { 00530 if (get_payload_size() == 0) { 00531 return close::status::NO_STATUS; 00532 } else if (get_payload_size() >= 2) { 00533 char val[2] = { m_payload[0], m_payload[1] }; 00534 uint16_t code; 00535 00536 std::copy(val,val+sizeof(code),&code); 00537 code = ntohs(code); 00538 00539 return close::status::value(code); 00540 } else { 00541 return close::status::PROTOCOL_ERROR; 00542 } 00543 } 00544 std::string get_close_msg() const { 00545 if (get_payload_size() > 2) { 00546 uint32_t state = utf8_validator::UTF8_ACCEPT; 00547 uint32_t codep = 0; 00548 validate_utf8(&state,&codep,2); 00549 if (state != utf8_validator::UTF8_ACCEPT) { 00550 throw tracing::wserror("Invalid UTF-8 Data",tracing::wserror::PAYLOAD_VIOLATION); 00551 } 00552 return std::string(m_payload.begin()+2,m_payload.end()); 00553 } else { 00554 return std::string(); 00555 } 00556 } 00557 00558 void set_payload_helper(uint64_t s) { 00559 if (s > max_payload_size) { 00560 throw tracing::wserror("requested payload is over implementation defined limit",tracing::wserror::MESSAGE_TOO_BIG); 00561 } 00562 00563 // limits imposed by the websocket spec 00564 if (is_control() && s > limits::PAYLOAD_SIZE_BASIC) { 00565 throw tracing::wserror("control frames can't have large payloads",tracing::wserror::PROTOCOL_VIOLATION); 00566 } 00567 00568 bool masked = get_masked(); 00569 00570 if (s <= limits::PAYLOAD_SIZE_BASIC) { 00571 m_header[1] = s; 00572 } else if (s <= limits::PAYLOAD_SIZE_EXTENDED) { 00573 m_header[1] = BASIC_PAYLOAD_16BIT_CODE; 00574 00575 // this reinterprets the second pair of bytes in m_header as a 00576 // 16 bit int and writes the payload size there as an integer 00577 // in network byte order 00578 *reinterpret_cast<uint16_t*>(&m_header[BASIC_HEADER_LENGTH]) = htons(s); 00579 } else if (s <= limits::PAYLOAD_SIZE_JUMBO) { 00580 m_header[1] = BASIC_PAYLOAD_64BIT_CODE; 00581 *reinterpret_cast<uint64_t*>(&m_header[BASIC_HEADER_LENGTH]) = htonll(s); 00582 } else { 00583 throw tracing::wserror("payload size limit is 63 bits",tracing::wserror::PROTOCOL_VIOLATION); 00584 } 00585 00586 if (masked) { 00587 m_header[1] |= BPB1_MASK; 00588 } 00589 00590 m_payload.resize(s); 00591 } 00592 00593 void set_status(close::status::value status,const std::string message = "") { 00594 // check for valid statuses 00595 if (close::status::invalid(status)) { 00596 std::stringstream err; 00597 err << "Status code " << status << " is invalid"; 00598 throw tracing::wserror(err.str()); 00599 } 00600 00601 if (close::status::reserved(status)) { 00602 std::stringstream err; 00603 err << "Status code " << status << " is reserved"; 00604 throw tracing::wserror(err.str()); 00605 } 00606 00607 m_payload.resize(2+message.size()); 00608 00609 char val[2]; 00610 00611 *reinterpret_cast<uint16_t*>(&val[0]) = htons(status); 00612 00613 bool masked = get_masked(); 00614 00615 m_header[1] = message.size()+2; 00616 00617 if (masked) { 00618 m_header[1] |= BPB1_MASK; 00619 } 00620 00621 m_payload[0] = val[0]; 00622 m_payload[1] = val[1]; 00623 00624 std::copy(message.begin(),message.end(),m_payload.begin()+2); 00625 } 00626 00627 std::string print_frame() const { 00628 std::stringstream f; 00629 00630 unsigned int len = get_header_len(); 00631 00632 f << "frame: "; 00633 // print header 00634 for (unsigned int i = 0; i < len; i++) { 00635 f << std::hex << (unsigned short)m_header[i] << " "; 00636 } 00637 // print message 00638 if (m_payload.size() > 50) { 00639 f << "[payload of " << m_payload.size() << " bytes]"; 00640 } else { 00641 std::vector<unsigned char>::const_iterator it; 00642 for (it = m_payload.begin(); it != m_payload.end(); it++) { 00643 f << *it; 00644 } 00645 } 00646 return f.str(); 00647 } 00648 00649 // reads basic header, sets and returns m_header_bits_needed 00650 void process_basic_header() { 00651 m_bytes_needed = get_header_len() - BASIC_HEADER_LENGTH; 00652 } 00653 void process_extended_header() { 00654 uint8_t s = get_basic_size(); 00655 uint64_t payload_size; 00656 int mask_index = BASIC_HEADER_LENGTH; 00657 00658 if (s <= limits::PAYLOAD_SIZE_BASIC) { 00659 payload_size = s; 00660 } else if (s == BASIC_PAYLOAD_16BIT_CODE) { 00661 // reinterpret the second two bytes as a 16 bit integer in network 00662 // byte order. Convert to host byte order and store locally. 00663 payload_size = ntohs(*( 00664 reinterpret_cast<uint16_t*>(&m_header[BASIC_HEADER_LENGTH]) 00665 )); 00666 00667 if (payload_size < s) { 00668 std::stringstream err; 00669 err << "payload length not minimally encoded. Using 16 bit form for payload size: " << payload_size; 00670 m_bytes_needed = payload_size; 00671 throw tracing::wserror(err.str(),tracing::wserror::PROTOCOL_VIOLATION); 00672 } 00673 00674 mask_index += 2; 00675 } else if (s == BASIC_PAYLOAD_64BIT_CODE) { 00676 // reinterpret the second eight bytes as a 64 bit integer in 00677 // network byte order. Convert to host byte order and store. 00678 payload_size = ntohll(*( 00679 reinterpret_cast<uint64_t*>(&m_header[BASIC_HEADER_LENGTH]) 00680 )); 00681 00682 if (payload_size <= limits::PAYLOAD_SIZE_EXTENDED) { 00683 m_bytes_needed = payload_size; 00684 throw tracing::wserror("payload length not minimally encoded", 00685 tracing::wserror::PROTOCOL_VIOLATION); 00686 } 00687 00688 mask_index += 8; 00689 } else { 00690 // TODO: shouldn't be here how to handle? 00691 throw tracing::wserror("invalid get_basic_size in process_extended_header"); 00692 } 00693 00694 if (get_masked() == 0) { 00695 clear_masking_key(); 00696 } else { 00697 // TODO: this should be removed entirely once it is confirmed to not 00698 // be used by anything. 00699 // std::copy(m_header[mask_index],m_header[mask_index+4],m_masking_key); 00700 /*m_masking_key[0] = m_header[mask_index+0]; 00701 m_masking_key[1] = m_header[mask_index+1]; 00702 m_masking_key[2] = m_header[mask_index+2]; 00703 m_masking_key[3] = m_header[mask_index+3];*/ 00704 } 00705 00706 if (payload_size > max_payload_size) { 00707 // TODO: frame/message size limits 00708 // TODO: find a way to throw a server error without coupling frame 00709 // with server 00710 // throw wspp::server_error("got frame with payload greater than maximum frame buffer size."); 00711 throw "Got frame with payload greater than maximum frame buffer size."; 00712 } 00713 m_payload.resize(payload_size); 00714 m_bytes_needed = payload_size; 00715 } 00716 00717 void process_payload() { 00718 if (get_masked()) { 00719 char *masking_key = get_masking_key(); 00720 00721 for (uint64_t i = 0; i < m_payload.size(); i++) { 00722 m_payload[i] = (m_payload[i] ^ masking_key[i%4]); 00723 } 00724 } 00725 } 00726 00727 // experiment with more efficient masking code. 00728 void process_payload2() { 00729 // unmask payload one byte at a time 00730 00731 //uint64_t key = (*((uint32_t*)m_masking_key;)) << 32; 00732 //key += *((uint32_t*)m_masking_key); 00733 00734 // might need to switch byte order 00735 /*uint32_t key = *((uint32_t*)m_masking_key); 00736 00737 // 4 00738 00739 uint64_t i = 0; 00740 uint64_t s = (m_payload.size() / 4); 00741 00742 // chunks of 4 00743 for (i = 0; i < s; i+=4) { 00744 ((uint32_t*)(&m_payload[0]))[i] = (((uint32_t*)(&m_payload[0]))[i] ^ key); 00745 } 00746 00747 // finish the last few 00748 for (i = s; i < m_payload.size(); i++) { 00749 m_payload[i] = (m_payload[i] ^ m_masking_key[i%4]); 00750 }*/ 00751 } 00752 00753 void validate_utf8(uint32_t* state,uint32_t* codep,size_t offset = 0) const { 00754 for (size_t i = offset; i < m_payload.size(); i++) { 00755 using utf8_validator::decode; 00756 00757 if (decode(state,codep,m_payload[i]) == utf8_validator::UTF8_REJECT) { 00758 throw tracing::wserror("Invalid UTF-8 Data",tracing::wserror::PAYLOAD_VIOLATION); 00759 } 00760 } 00761 } 00762 void validate_basic_header() const { 00763 // check for control frame size 00764 if (is_control() && get_basic_size() > limits::PAYLOAD_SIZE_BASIC) { 00765 throw tracing::wserror("Control Frame is too large",tracing::wserror::PROTOCOL_VIOLATION); 00766 } 00767 00768 // check for reserved bits 00769 if (get_rsv1() || get_rsv2() || get_rsv3()) { 00770 throw tracing::wserror("Reserved bit used",tracing::wserror::PROTOCOL_VIOLATION); 00771 } 00772 00773 // check for reserved opcodes 00774 if (opcode::reserved(get_opcode())) { 00775 throw tracing::wserror("Reserved opcode used",tracing::wserror::PROTOCOL_VIOLATION); 00776 } 00777 00778 // check for fragmented control message 00779 if (is_control() && !get_fin()) { 00780 throw tracing::wserror("Fragmented control message",tracing::wserror::PROTOCOL_VIOLATION); 00781 } 00782 } 00783 00784 void generate_masking_key() { 00785 *(reinterpret_cast<int32_t *>(&m_header[get_header_len()-4])) = m_rng.gen(); 00786 } 00787 void clear_masking_key() { 00788 // this is a no-op as clearing the mask bit also changes the get_header_len 00789 // method to not include these byte ranges. Whenever the masking bit is re- 00790 // set a new key is generated anyways. 00791 } 00792 00793 00794 private: 00795 uint16_t get_raw_close_code() const { 00796 if (m_payload.size() <= 1) { 00797 throw tracing::wserror("get_raw_close_code called with invalid size",tracing::wserror::FATAL_ERROR); 00798 } 00799 00800 union {uint16_t i;char c[2];} val; 00801 00802 val.c[0] = m_payload[0]; 00803 val.c[1] = m_payload[1]; 00804 00805 return ntohs(val.i); 00806 } 00807 00808 static const uint8_t STATE_BASIC_HEADER = 1; 00809 static const uint8_t STATE_EXTENDED_HEADER = 2; 00810 static const uint8_t STATE_PAYLOAD = 3; 00811 static const uint8_t STATE_READY = 4; 00812 static const uint8_t STATE_RECOVERY = 5; 00813 00814 uint8_t m_state; 00815 uint64_t m_bytes_needed; 00816 bool m_degraded; 00817 00818 char m_header[MAX_HEADER_LENGTH]; 00819 std::vector<unsigned char> m_payload; 00820 00821 rng_policy& m_rng; 00822 }; 00823 00824 } 00825 } 00826 00827 #endif // WEBSOCKET_FRAME_HPP