EHS Embedded HTTP Server  1.5.0.132
samples/wsframe.h
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