diff --git a/src/third_party/websocketpp/COPYING b/src/third_party/websocketpp/COPYING index 7eeeb8f3..f8cc5ba1 100644 --- a/src/third_party/websocketpp/COPYING +++ b/src/third_party/websocketpp/COPYING @@ -1,6 +1,6 @@ Main Library: -Copyright (c) 2013, Peter Thorson. All rights reserved. +Copyright (c) 2014, Peter Thorson. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/src/third_party/websocketpp/websocketpp/base64/base64.hpp b/src/third_party/websocketpp/websocketpp/base64/base64.hpp index 6572c495..ff1561d1 100644 --- a/src/third_party/websocketpp/websocketpp/base64/base64.hpp +++ b/src/third_party/websocketpp/websocketpp/base64/base64.hpp @@ -45,6 +45,11 @@ static std::string const base64_chars = "abcdefghijklmnopqrstuvwxyz" "0123456789+/"; +/// Test whether a character is a valid base64 character +/** + * @param c The character to test + * @return true if c is a valid base64 character + */ static inline bool is_base64(unsigned char c) { return (c == 43 || // + (c >= 47 && c <= 57) || // /-9 @@ -52,17 +57,21 @@ static inline bool is_base64(unsigned char c) { (c >= 97 && c <= 122)); // a-z } -inline std::string base64_encode(unsigned char const * bytes_to_encode, unsigned - int in_len) -{ +/// Encode a char buffer into a base64 string +/** + * @param input The input data + * @param len The length of input in bytes + * @return A base64 encoded string representing input + */ +inline std::string base64_encode(unsigned char const * input, size_t len) { std::string ret; int i = 0; int j = 0; unsigned char char_array_3[3]; unsigned char char_array_4[4]; - while (in_len--) { - char_array_3[i++] = *(bytes_to_encode++); + while (len--) { + char_array_3[i++] = *(input++); if (i == 3) { char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + @@ -97,25 +106,38 @@ inline std::string base64_encode(unsigned char const * bytes_to_encode, unsigned while((i++ < 3)) { ret += '='; } - } + } - return ret; + return ret; } -inline std::string base64_encode(std::string const & data) { - return base64_encode(reinterpret_cast(data.data()),data.size()); +/// Encode a string into a base64 string +/** + * @param input The input data + * @return A base64 encoded string representing input + */ +inline std::string base64_encode(std::string const & input) { + return base64_encode( + reinterpret_cast(input.data()), + input.size() + ); } -inline std::string base64_decode(std::string const & encoded_string) { - size_t in_len = encoded_string.size(); +/// Decode a base64 encoded string into a string of raw bytes +/** + * @param input The base64 encoded input data + * @return A string representing the decoded raw bytes + */ +inline std::string base64_decode(std::string const & input) { + size_t in_len = input.size(); int i = 0; int j = 0; int in_ = 0; unsigned char char_array_4[4], char_array_3[3]; std::string ret; - while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { - char_array_4[i++] = encoded_string[in_]; in_++; + while (in_len-- && ( input[in_] != '=') && is_base64(input[in_])) { + char_array_4[i++] = input[in_]; in_++; if (i ==4) { for (i = 0; i <4; i++) { char_array_4[i] = static_cast(base64_chars.find(char_array_4[i])); diff --git a/src/third_party/websocketpp/websocketpp/client.hpp b/src/third_party/websocketpp/websocketpp/client.hpp index 45268be3..8782d7e4 100644 --- a/src/third_party/websocketpp/websocketpp/client.hpp +++ b/src/third_party/websocketpp/websocketpp/client.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/third_party/websocketpp/websocketpp/close.hpp b/src/third_party/websocketpp/websocketpp/close.hpp index eee44f61..53ad4f1c 100644 --- a/src/third_party/websocketpp/websocketpp/close.hpp +++ b/src/third_party/websocketpp/websocketpp/close.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -199,6 +199,46 @@ namespace status { code == policy_violation || code == message_too_big || code == internal_endpoint_error); } + + /// Return a human readable interpretation of a WebSocket close code + /** + * See https://tools.ietf.org/html/rfc6455#section-7.4 for more details. + * + * @since 0.3.0 + * + * @param [in] code The code to look up. + * @return A human readable interpretation of the code. + */ + inline std::string get_string(value code) { + switch (code) { + case normal: + return "Normal close"; + case going_away: + return "Going away"; + case protocol_error: + return "Protocol error"; + case unsupported_data: + return "Unsupported data"; + case no_status: + return "No status set"; + case abnormal_close: + return "Abnormal close"; + case invalid_payload: + return "Invalid payload"; + case policy_violation: + return "Policy violoation"; + case message_too_big: + return "Message too big"; + case extension_required: + return "Extension required"; + case internal_endpoint_error: + return "Internal endpoint error"; + case tls_handshake: + return "TLS handshake failure"; + default: + return "Unknown"; + } + } } // namespace status /// Type used to convert close statuses between integer and wire representations diff --git a/src/third_party/websocketpp/websocketpp/common/chrono.hpp b/src/third_party/websocketpp/websocketpp/common/chrono.hpp index 731d7703..c536a365 100644 --- a/src/third_party/websocketpp/websocketpp/common/chrono.hpp +++ b/src/third_party/websocketpp/websocketpp/common/chrono.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/third_party/websocketpp/websocketpp/common/connection_hdl.hpp b/src/third_party/websocketpp/websocketpp/common/connection_hdl.hpp index 71f490cf..1044c88e 100644 --- a/src/third_party/websocketpp/websocketpp/common/connection_hdl.hpp +++ b/src/third_party/websocketpp/websocketpp/common/connection_hdl.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -34,7 +34,7 @@ namespace websocketpp { /// A handle to uniquely identify a connection. /** - * This type uniquely identifies a connection. It is implimented as a weak + * This type uniquely identifies a connection. It is implemented as a weak * pointer to the connection in question. This provides uniqueness across * multiple endpoints and ensures that IDs never conflict or run out. * diff --git a/src/third_party/websocketpp/websocketpp/common/cpp11.hpp b/src/third_party/websocketpp/websocketpp/common/cpp11.hpp index 2a638dce..c317e9a4 100644 --- a/src/third_party/websocketpp/websocketpp/common/cpp11.hpp +++ b/src/third_party/websocketpp/websocketpp/common/cpp11.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -40,10 +40,29 @@ #define __has_extension __has_feature // Compatibility with pre-3.0 compilers. #endif +// The code below attempts to use information provided by the build system or +// user supplied defines to selectively enable C++11 language and library +// features. In most cases features that are targeted individually may also be +// selectively disabled via an associated _WEBSOCKETPP_NOXXX_ define. -#ifdef _WEBSOCKETPP_CPP11_STL_ - // This flag indicates that all of the C++11 language features are available - // to us. +#if defined(_WEBSOCKETPP_CPP11_STL_) || __cplusplus >= 201103L || defined(_WEBSOCKETPP_CPP11_STRICT_) + // This check tests for blanket c++11 coverage. It can be activated in one + // of three ways. Either the compiler itself reports that it is a full + // C++11 compiler via the __cplusplus macro or the user/build system + // supplies one of the two preprocessor defines below: + + // _WEBSOCKETPP_CPP11_STRICT_ + // + // This define reports to WebSocket++ that 100% of the language and library + // features of C++11 are available. Using this define on a non-C++11 + // compiler will result in problems. + + // _WEBSOCKETPP_CPP11_STL_ + // + // This define enables *most* C++11 options that were implemented early on + // by compilers. It is typically used for compilers that have many, but not + // all C++11 features. It should be safe to use on GCC 4.7-4.8 and perhaps + // earlier. #ifndef _WEBSOCKETPP_NOEXCEPT_TOKEN_ #define _WEBSOCKETPP_NOEXCEPT_TOKEN_ noexcept #endif @@ -53,7 +72,19 @@ #ifndef _WEBSOCKETPP_INITIALIZER_LISTS_ #define _WEBSOCKETPP_INITIALIZER_LISTS_ #endif + #ifndef _WEBSOCKETPP_NULLPTR_TOKEN_ + #define _WEBSOCKETPP_NULLPTR_TOKEN_ nullptr + #endif + + #ifndef __GNUC__ + // GCC as of version 4.9 (latest) does not support std::put_time yet. + // so ignore it + #define _WEBSOCKETPP_PUTTIME_ + #endif #else + // In the absence of a blanket define, try to use compiler versions or + // feature testing macros to selectively enable what we can. + // Test for noexcept #ifndef _WEBSOCKETPP_NOEXCEPT_TOKEN_ #ifdef _WEBSOCKETPP_NOEXCEPT_ @@ -90,6 +121,25 @@ #if __has_feature(cxx_generalized_initializers) && !defined(_WEBSOCKETPP_INITIALIZER_LISTS_) #define _WEBSOCKETPP_INITIALIZER_LISTS_ #endif + + // Test for nullptr + #ifndef _WEBSOCKETPP_NULLPTR_TOKEN_ + #ifdef _WEBSOCKETPP_NULLPTR_ + // build system says we have nullptr + #define _WEBSOCKETPP_NULLPTR_TOKEN_ nullptr + #else + #if __has_feature(cxx_nullptr) + // clang feature detect says we have nullptr + #define _WEBSOCKETPP_NULLPTR_TOKEN_ nullptr + #elif _MSC_VER >= 1600 + // Visual Studio version that has nullptr + #define _WEBSOCKETPP_NULLPTR_TOKEN_ nullptr + #else + // assume we don't have nullptr + #define _WEBSOCKETPP_NULLPTR_TOKEN_ 0 + #endif + #endif + #endif #endif #endif // WEBSOCKETPP_COMMON_CPP11_HPP diff --git a/src/third_party/websocketpp/websocketpp/common/functional.hpp b/src/third_party/websocketpp/websocketpp/common/functional.hpp index 8c52c08c..cc451bfa 100644 --- a/src/third_party/websocketpp/websocketpp/common/functional.hpp +++ b/src/third_party/websocketpp/websocketpp/common/functional.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -39,8 +39,11 @@ #else #include #include + #include #endif + + namespace websocketpp { namespace lib { @@ -49,6 +52,18 @@ namespace lib { using std::bind; using std::ref; namespace placeholders = std::placeholders; + + // There are some cases where a C++11 compiler balks at using std::ref + // but a C++03 compiler using boost function requires boost::ref. As such + // lib::ref is not useful in these cases. Instead this macro allows the use + // of boost::ref in the case of a boost compile or no reference wrapper at + // all in the case of a C++11 compile + #define _WEBSOCKETPP_REF(x) x + + template + void clear_function(T & x) { + x = nullptr; + } #else using boost::function; using boost::bind; @@ -58,6 +73,14 @@ namespace lib { using ::_1; using ::_2; } + + // See above definition for more details on what this is and why it exists + #define _WEBSOCKETPP_REF(x) boost::ref(x) + + template + void clear_function(T & x) { + x.clear(); + } #endif } // namespace lib diff --git a/src/third_party/websocketpp/websocketpp/common/md5.hpp b/src/third_party/websocketpp/websocketpp/common/md5.hpp index ed48e992..279725f4 100644 --- a/src/third_party/websocketpp/websocketpp/common/md5.hpp +++ b/src/third_party/websocketpp/websocketpp/common/md5.hpp @@ -34,7 +34,7 @@ This code implements the MD5 Algorithm defined in RFC 1321, whose text is available at - http://www.ietf.org/rfc/rfc1321.txt + http://www.ietf.org/rfc/rfc1321.txt The code is derived from the text of the RFC, including the test suite (section A.5) but excluding the rest of Appendix A. It does not include any code or documentation that is identified in the RFC as being @@ -45,12 +45,12 @@ that follows (in reverse chronological order): 2002-04-13 lpd Removed support for non-ANSI compilers; removed - references to Ghostscript; clarified derivation from RFC 1321; - now handles byte order either statically or dynamically. + references to Ghostscript; clarified derivation from RFC 1321; + now handles byte order either statically or dynamically. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); - added conditionalization for C++ compilation from Martin - Purschke . + added conditionalization for C++ compilation from Martin + Purschke . 1999-05-03 lpd Original version. */ @@ -80,9 +80,9 @@ typedef unsigned int md5_word_t; /* 32-bit word */ /* Define the state of the MD5 Algorithm. */ typedef struct md5_state_s { - md5_word_t count[2]; /* message length in bits, lsw first */ - md5_word_t abcd[4]; /* digest buffer */ - md5_byte_t buf[64]; /* accumulate block */ + md5_word_t count[2]; /* message length in bits, lsw first */ + md5_word_t abcd[4]; /* digest buffer */ + md5_byte_t buf[64]; /* accumulate block */ } md5_state_t; /* Initialize the algorithm. */ @@ -94,7 +94,7 @@ inline void md5_append(md5_state_t *pms, md5_byte_t const * data, size_t nbytes) /* Finish the message and return the digest. */ inline void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); -#undef ZSW_MD5_BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ +#undef ZSW_MD5_BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ #ifdef ARCH_IS_BIG_ENDIAN # define ZSW_MD5_BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) #else @@ -169,8 +169,8 @@ inline void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); static void md5_process(md5_state_t *pms, md5_byte_t const * data /*[64]*/) { md5_word_t - a = pms->abcd[0], b = pms->abcd[1], - c = pms->abcd[2], d = pms->abcd[3]; + a = pms->abcd[0], b = pms->abcd[1], + c = pms->abcd[2], d = pms->abcd[3]; md5_word_t t; #if ZSW_MD5_BYTE_ORDER > 0 /* Define storage only for big-endian CPUs. */ @@ -183,51 +183,51 @@ static void md5_process(md5_state_t *pms, md5_byte_t const * data /*[64]*/) { { #if ZSW_MD5_BYTE_ORDER == 0 - /* - * Determine dynamically whether this is a big-endian or - * little-endian machine, since we can use a more efficient - * algorithm on the latter. - */ - static int const w = 1; + /* + * Determine dynamically whether this is a big-endian or + * little-endian machine, since we can use a more efficient + * algorithm on the latter. + */ + static int const w = 1; - if (*((md5_byte_t const *)&w)) /* dynamic little-endian */ + if (*((md5_byte_t const *)&w)) /* dynamic little-endian */ #endif -#if ZSW_MD5_BYTE_ORDER <= 0 /* little-endian */ - { - /* - * On little-endian machines, we can process properly aligned - * data without copying it. - */ - if (!((data - (md5_byte_t const *)0) & 3)) { - /* data are properly aligned */ - X = (md5_word_t const *)data; - } else { - /* not aligned */ - std::memcpy(xbuf, data, 64); - X = xbuf; - } - } +#if ZSW_MD5_BYTE_ORDER <= 0 /* little-endian */ + { + /* + * On little-endian machines, we can process properly aligned + * data without copying it. + */ + if (!((data - (md5_byte_t const *)0) & 3)) { + /* data are properly aligned */ + X = (md5_word_t const *)data; + } else { + /* not aligned */ + std::memcpy(xbuf, data, 64); + X = xbuf; + } + } #endif #if ZSW_MD5_BYTE_ORDER == 0 - else /* dynamic big-endian */ + else /* dynamic big-endian */ #endif -#if ZSW_MD5_BYTE_ORDER >= 0 /* big-endian */ - { - /* - * On big-endian machines, we must arrange the bytes in the - * right order. - */ - const md5_byte_t *xp = data; - int i; +#if ZSW_MD5_BYTE_ORDER >= 0 /* big-endian */ + { + /* + * On big-endian machines, we must arrange the bytes in the + * right order. + */ + const md5_byte_t *xp = data; + int i; # if ZSW_MD5_BYTE_ORDER == 0 - X = xbuf; /* (dynamic only) */ + X = xbuf; /* (dynamic only) */ # else -# define xbuf X /* (static only) */ +# define xbuf X /* (static only) */ # endif - for (i = 0; i < 16; ++i, xp += 4) - xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); - } + for (i = 0; i < 16; ++i, xp += 4) + xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + } #endif } @@ -361,71 +361,71 @@ void md5_append(md5_state_t *pms, md5_byte_t const * data, size_t nbytes) { md5_word_t nbits = (md5_word_t)(nbytes << 3); if (nbytes <= 0) - return; + return; /* Update the message length. */ pms->count[1] += nbytes >> 29; pms->count[0] += nbits; if (pms->count[0] < nbits) - pms->count[1]++; + pms->count[1]++; /* Process an initial partial block. */ if (offset) { - int copy = (offset + nbytes > 64 ? 64 - offset : static_cast(nbytes)); + int copy = (offset + nbytes > 64 ? 64 - offset : static_cast(nbytes)); - std::memcpy(pms->buf + offset, p, copy); - if (offset + copy < 64) - return; - p += copy; - left -= copy; - md5_process(pms, pms->buf); + std::memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); } /* Process full blocks. */ for (; left >= 64; p += 64, left -= 64) - md5_process(pms, p); + md5_process(pms, p); /* Process a final partial block. */ if (left) - std::memcpy(pms->buf, p, left); + std::memcpy(pms->buf, p, left); } void md5_finish(md5_state_t *pms, md5_byte_t digest[16]) { static md5_byte_t const pad[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; md5_byte_t data[8]; int i; /* Save the length before padding. */ for (i = 0; i < 8; ++i) - data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); /* Pad to 56 bytes mod 64. */ md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); /* Append the length. */ md5_append(pms, data, 8); for (i = 0; i < 16; ++i) - digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); + digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); } // some convenience c++ functions inline std::string md5_hash_string(std::string const & s) { - char digest[16]; + char digest[16]; - md5_state_t state; + md5_state_t state; - md5_init(&state); - md5_append(&state, (md5_byte_t const *)s.c_str(), s.size()); - md5_finish(&state, (md5_byte_t *)digest); + md5_init(&state); + md5_append(&state, (md5_byte_t const *)s.c_str(), s.size()); + md5_finish(&state, (md5_byte_t *)digest); std::string ret; ret.resize(16); std::copy(digest,digest+16,ret.begin()); - return ret; + return ret; } const char hexval[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; diff --git a/src/third_party/websocketpp/websocketpp/common/memory.hpp b/src/third_party/websocketpp/websocketpp/common/memory.hpp index 65a5b906..fba4c607 100644 --- a/src/third_party/websocketpp/websocketpp/common/memory.hpp +++ b/src/third_party/websocketpp/websocketpp/common/memory.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -38,6 +38,7 @@ #include #else #include + #include #include #include #include @@ -51,6 +52,7 @@ namespace lib { using std::weak_ptr; using std::enable_shared_from_this; using std::static_pointer_cast; + using std::make_shared; typedef std::unique_ptr unique_ptr_uchar_array; #else @@ -58,6 +60,7 @@ namespace lib { using boost::weak_ptr; using boost::enable_shared_from_this; using boost::static_pointer_cast; + using boost::make_shared; typedef boost::scoped_array unique_ptr_uchar_array; #endif diff --git a/src/third_party/websocketpp/websocketpp/common/network.hpp b/src/third_party/websocketpp/websocketpp/common/network.hpp index 6a01f140..ac906440 100644 --- a/src/third_party/websocketpp/websocketpp/common/network.hpp +++ b/src/third_party/websocketpp/websocketpp/common/network.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -29,7 +29,7 @@ #define WEBSOCKETPP_COMMON_NETWORK_HPP // For ntohs and htons -#if defined(WIN32) +#if defined(_WIN32) #include #else //#include @@ -50,7 +50,18 @@ inline bool is_little_endian() { #define TYP_SMLE 1 #define TYP_BIGE 2 -inline uint64_t htonll(uint64_t src) { +/// Convert 64 bit value to network byte order +/** + * This method is prefixed to avoid conflicts with operating system level + * macros for this functionality. + * + * TODO: figure out if it would be beneficial to use operating system level + * macros for this. + * + * @param src The integer in host byte order + * @return src converted to network byte order + */ +inline uint64_t _htonll(uint64_t src) { static int typ = TYP_INIT; unsigned char c; union { @@ -71,8 +82,19 @@ inline uint64_t htonll(uint64_t src) { return x.ull; } -inline uint64_t ntohll(uint64_t src) { - return htonll(src); +/// Convert 64 bit value to host byte order +/** + * This method is prefixed to avoid conflicts with operating system level + * macros for this functionality. + * + * TODO: figure out if it would be beneficial to use operating system level + * macros for this. + * + * @param src The integer in network byte order + * @return src converted to host byte order + */ +inline uint64_t _ntohll(uint64_t src) { + return _htonll(src); } } // net diff --git a/src/third_party/websocketpp/websocketpp/common/platforms.hpp b/src/third_party/websocketpp/websocketpp/common/platforms.hpp index 4e031aa3..d934a039 100644 --- a/src/third_party/websocketpp/websocketpp/common/platforms.hpp +++ b/src/third_party/websocketpp/websocketpp/common/platforms.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -33,7 +33,7 @@ * don't fit somewhere else better. */ -#if defined(WIN32) && !defined(NOMINMAX) +#if defined(_WIN32) && !defined(NOMINMAX) // don't define min and max macros that conflict with std::min and std::max #define NOMINMAX #endif diff --git a/src/third_party/websocketpp/websocketpp/common/random.hpp b/src/third_party/websocketpp/websocketpp/common/random.hpp index fe139516..fd29c42d 100644 --- a/src/third_party/websocketpp/websocketpp/common/random.hpp +++ b/src/third_party/websocketpp/websocketpp/common/random.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/third_party/websocketpp/websocketpp/common/regex.hpp b/src/third_party/websocketpp/websocketpp/common/regex.hpp index b85cd709..326635de 100644 --- a/src/third_party/websocketpp/websocketpp/common/regex.hpp +++ b/src/third_party/websocketpp/websocketpp/common/regex.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/third_party/websocketpp/websocketpp/common/stdint.hpp b/src/third_party/websocketpp/websocketpp/common/stdint.hpp index 233e36f5..ec48ea75 100644 --- a/src/third_party/websocketpp/websocketpp/common/stdint.hpp +++ b/src/third_party/websocketpp/websocketpp/common/stdint.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -32,7 +32,7 @@ #define __STDC_LIMIT_MACROS 1 #endif -#if WIN32 && (_MSC_VER < 1600) +#if defined (_WIN32) && defined (_MSC_VER) && (_MSC_VER < 1600) #include using boost::int8_t; diff --git a/src/third_party/websocketpp/websocketpp/common/system_error.hpp b/src/third_party/websocketpp/websocketpp/common/system_error.hpp index fff3dfe9..4bfa73dc 100644 --- a/src/third_party/websocketpp/websocketpp/common/system_error.hpp +++ b/src/third_party/websocketpp/websocketpp/common/system_error.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/third_party/websocketpp/websocketpp/common/thread.hpp b/src/third_party/websocketpp/websocketpp/common/thread.hpp index e02a6582..30fb6a42 100644 --- a/src/third_party/websocketpp/websocketpp/common/thread.hpp +++ b/src/third_party/websocketpp/websocketpp/common/thread.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/third_party/websocketpp/websocketpp/common/time.hpp b/src/third_party/websocketpp/websocketpp/common/time.hpp new file mode 100644 index 00000000..1f01c311 --- /dev/null +++ b/src/third_party/websocketpp/websocketpp/common/time.hpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2014, Peter Thorson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the WebSocket++ Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef WEBSOCKETPP_COMMON_TIME_HPP +#define WEBSOCKETPP_COMMON_TIME_HPP + +#include + +namespace websocketpp { +namespace lib { + +// Code in this header was inspired by the following article and includes some +// code from the related project g2log. The g2log code is public domain licensed +// http://kjellkod.wordpress.com/2013/01/22/exploring-c11-part-2-localtime-and-time-again/ + +/// Thread safe cross platform localtime +inline std::tm localtime(std::time_t const & time) { + std::tm tm_snapshot; +#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) + localtime_s(&tm_snapshot, &time); +#else + localtime_r(&time, &tm_snapshot); // POSIX +#endif + return tm_snapshot; +} + +} // lib +} // websocketpp + +#endif // WEBSOCKETPP_COMMON_TIME_HPP diff --git a/src/third_party/websocketpp/websocketpp/concurrency/basic.hpp b/src/third_party/websocketpp/websocketpp/concurrency/basic.hpp index 84e61b36..1943ad77 100644 --- a/src/third_party/websocketpp/websocketpp/concurrency/basic.hpp +++ b/src/third_party/websocketpp/websocketpp/concurrency/basic.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/third_party/websocketpp/websocketpp/concurrency/none.hpp b/src/third_party/websocketpp/websocketpp/concurrency/none.hpp index 9d19d64c..da9aa411 100644 --- a/src/third_party/websocketpp/websocketpp/concurrency/none.hpp +++ b/src/third_party/websocketpp/websocketpp/concurrency/none.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -29,26 +29,48 @@ #define WEBSOCKETPP_CONCURRENCY_NONE_HPP namespace websocketpp { + +/// Concurrency handling support namespace concurrency { +/// Implementation for no-op locking primitives namespace none_impl { +/// A fake mutex implementation that does nothing class fake_mutex { public: fake_mutex() {} ~fake_mutex() {} }; +/// A fake lock guard implementation that does nothing class fake_lock_guard { public: - explicit fake_lock_guard(fake_mutex foo) {} + explicit fake_lock_guard(fake_mutex) {} ~fake_lock_guard() {} }; } // namespace none_impl -/// Stub Concurrency policy to remove locking in single threaded projects +/// Stub concurrency policy that implements the interface using no-ops. +/** + * This policy documents the concurrency policy interface using no-ops. It can + * be used as a reference or base for building a new concurrency policy. It can + * also be used as is to disable all locking for endpoints used in purely single + * threaded programs. + */ class none { public: + /// The type of a mutex primitive + /** + * std::mutex is an example. + */ typedef none_impl::fake_mutex mutex_type; + + /// The type of a scoped/RAII lock primitive. + /** + * The scoped lock constructor should take a mutex_type as a parameter, + * acquire that lock, and release it in its destructor. std::lock_guard is + * an example. + */ typedef none_impl::fake_lock_guard scoped_lock_type; }; diff --git a/src/third_party/websocketpp/websocketpp/config/asio.hpp b/src/third_party/websocketpp/websocketpp/config/asio.hpp index b2070edb..d28d0fb8 100644 --- a/src/third_party/websocketpp/websocketpp/config/asio.hpp +++ b/src/third_party/websocketpp/websocketpp/config/asio.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/third_party/websocketpp/websocketpp/config/asio_client.hpp b/src/third_party/websocketpp/websocketpp/config/asio_client.hpp index 26d4c4db..1cb594d0 100644 --- a/src/third_party/websocketpp/websocketpp/config/asio_client.hpp +++ b/src/third_party/websocketpp/websocketpp/config/asio_client.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/third_party/websocketpp/websocketpp/config/asio_no_tls.hpp b/src/third_party/websocketpp/websocketpp/config/asio_no_tls.hpp index a40e99a8..6c1357fb 100644 --- a/src/third_party/websocketpp/websocketpp/config/asio_no_tls.hpp +++ b/src/third_party/websocketpp/websocketpp/config/asio_no_tls.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/third_party/websocketpp/websocketpp/config/asio_no_tls_client.hpp b/src/third_party/websocketpp/websocketpp/config/asio_no_tls_client.hpp index 8b9635f8..6e3f7ba0 100644 --- a/src/third_party/websocketpp/websocketpp/config/asio_no_tls_client.hpp +++ b/src/third_party/websocketpp/websocketpp/config/asio_no_tls_client.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/third_party/websocketpp/websocketpp/config/boost_config.hpp b/src/third_party/websocketpp/websocketpp/config/boost_config.hpp index 19c89053..57671ccd 100644 --- a/src/third_party/websocketpp/websocketpp/config/boost_config.hpp +++ b/src/third_party/websocketpp/websocketpp/config/boost_config.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -25,9 +25,9 @@ * */ - // This header defines WebSocket++ macros for C++11 compatibility based on the Boost.Config library. - // This will correctly configure most target platforms simply by including this header before - // any other WebSocket++ header. + // This header defines WebSocket++ macros for C++11 compatibility based on the + // Boost.Config library. This will correctly configure most target platforms + // simply by including this header before any other WebSocket++ header. #ifndef WEBSOCKETPP_CONFIG_BOOST_CONFIG_HPP #define WEBSOCKETPP_CONFIG_BOOST_CONFIG_HPP @@ -41,7 +41,7 @@ #define _WEBSOCKETPP_CPP11_FUNCTIONAL_ #endif -#ifndef BOOST_ASIO_HAS_STD_CHRONO +#ifdef BOOST_ASIO_HAS_STD_CHRONO #define _WEBSOCKETPP_CPP11_CHRONO_ #endif @@ -67,5 +67,6 @@ #define _WEBSOCKETPP_NOEXCEPT_TOKEN_ BOOST_NOEXCEPT #define _WEBSOCKETPP_CONSTEXPR_TOKEN_ BOOST_CONSTEXPR +// TODO: nullptr support #endif // WEBSOCKETPP_CONFIG_BOOST_CONFIG_HPP diff --git a/src/third_party/websocketpp/websocketpp/config/core.hpp b/src/third_party/websocketpp/websocketpp/config/core.hpp index e400da50..c35bff76 100644 --- a/src/third_party/websocketpp/websocketpp/config/core.hpp +++ b/src/third_party/websocketpp/websocketpp/config/core.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -215,6 +215,18 @@ struct core { */ static const bool silent_close = false; + /// Default maximum message size + /** + * Default value for the processor's maximum message size. Maximum message size + * determines the point at which the library will fail a connection with the + * message_too_big protocol error. + * + * The default is 32MB + * + * @since 0.3.0 + */ + static const size_t max_message_size = 32000000; + /// Global flag for enabling/disabling extensions static const bool enable_extensions = true; diff --git a/src/third_party/websocketpp/websocketpp/config/core_client.hpp b/src/third_party/websocketpp/websocketpp/config/core_client.hpp index 328bcc86..fcbac10a 100644 --- a/src/third_party/websocketpp/websocketpp/config/core_client.hpp +++ b/src/third_party/websocketpp/websocketpp/config/core_client.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -34,7 +34,11 @@ #include // Concurrency +#ifndef _WEBSOCKETPP_NO_THREADING_ #include +#else +#include +#endif // Transport #include @@ -68,7 +72,11 @@ struct core_client { typedef core_client type; // Concurrency policy +#ifndef _WEBSOCKETPP_NO_THREADING_ typedef websocketpp::concurrency::basic concurrency_type; +#else + typedef websocketpp::concurrency::none concurrency_type; +#endif // HTTP Parser Policies typedef http::parser::request request_type; @@ -216,6 +224,18 @@ struct core_client { */ static const bool silent_close = false; + /// Default maximum message size + /** + * Default value for the processor's maximum message size. Maximum message size + * determines the point at which the library will fail a connection with the + * message_too_big protocol error. + * + * The default is 32MB + * + * @since 0.3.0 + */ + static const size_t max_message_size = 32000000; + /// Global flag for enabling/disabling extensions static const bool enable_extensions = true; diff --git a/src/third_party/websocketpp/websocketpp/config/debug.hpp b/src/third_party/websocketpp/websocketpp/config/debug.hpp index 691229a6..9f90360a 100644 --- a/src/third_party/websocketpp/websocketpp/config/debug.hpp +++ b/src/third_party/websocketpp/websocketpp/config/debug.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -216,6 +216,18 @@ struct debug_core { */ static const bool silent_close = false; + /// Default maximum message size + /** + * Default value for the processor's maximum message size. Maximum message size + * determines the point at which the library will fail a connection with the + * message_too_big protocol error. + * + * The default is 32MB + * + * @since 0.3.0 + */ + static const size_t max_message_size = 32000000; + /// Global flag for enabling/disabling extensions static const bool enable_extensions = true; diff --git a/src/third_party/websocketpp/websocketpp/config/debug_asio.hpp b/src/third_party/websocketpp/websocketpp/config/debug_asio.hpp index 66a65fdd..a57c736c 100644 --- a/src/third_party/websocketpp/websocketpp/config/debug_asio.hpp +++ b/src/third_party/websocketpp/websocketpp/config/debug_asio.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/third_party/websocketpp/websocketpp/config/debug_asio_no_tls.hpp b/src/third_party/websocketpp/websocketpp/config/debug_asio_no_tls.hpp index 7437650a..b3dc83b4 100644 --- a/src/third_party/websocketpp/websocketpp/config/debug_asio_no_tls.hpp +++ b/src/third_party/websocketpp/websocketpp/config/debug_asio_no_tls.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/third_party/websocketpp/websocketpp/config/minimal_client.hpp b/src/third_party/websocketpp/websocketpp/config/minimal_client.hpp new file mode 100644 index 00000000..72528cde --- /dev/null +++ b/src/third_party/websocketpp/websocketpp/config/minimal_client.hpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2014, Peter Thorson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the WebSocket++ Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef WEBSOCKETPP_CONFIG_MINIMAL_CLIENT_HPP +#define WEBSOCKETPP_CONFIG_MINIMAL_CLIENT_HPP + +#include + +namespace websocketpp { +namespace config { + +/// Client config with minimal dependencies +/** + * This config strips out as many dependencies as possible. It is suitable for + * use as a base class for custom configs that want to implement or choose their + * own policies for components that even the core config includes. + * + * NOTE: this config stubs out enough that it cannot be used directly. You must + * supply at least a transport policy and a cryptographically secure random + * number generation policy for a config based on `minimal_client` to do + * anything useful. + * + * Present dependency list for minimal_server config: + * + * C++98 STL: + * + * + * + * + * + * + * C++11 STL or Boost + * + * + * + * + * Operating System: + * or + * or (for ntohl.. could potentially bundle this) + * + * @since 0.4.0-dev + */ +typedef minimal_server minimal_client; + +} // namespace config +} // namespace websocketpp + +#endif // WEBSOCKETPP_CONFIG_MINIMAL_CLIENT_HPP diff --git a/src/third_party/websocketpp/websocketpp/config/minimal_server.hpp b/src/third_party/websocketpp/websocketpp/config/minimal_server.hpp new file mode 100644 index 00000000..f689da9e --- /dev/null +++ b/src/third_party/websocketpp/websocketpp/config/minimal_server.hpp @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2014, Peter Thorson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the WebSocket++ Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef WEBSOCKETPP_CONFIG_MINIMAL_HPP +#define WEBSOCKETPP_CONFIG_MINIMAL_HPP + +// Non-Policy common stuff +#include +#include +#include + +// Concurrency +#include + +// Transport +#include + +// HTTP +#include +#include + +// Messages +#include +#include + +// Loggers +#include + +// RNG +#include + +// User stub base classes +#include +#include + +// Extensions +#include + +namespace websocketpp { +namespace config { + +/// Server config with minimal dependencies +/** + * This config strips out as many dependencies as possible. It is suitable for + * use as a base class for custom configs that want to implement or choose their + * own policies for components that even the core config includes. + * + * NOTE: this config stubs out enough that it cannot be used directly. You must + * supply at least a transport policy for a config based on `minimal_server` to + * do anything useful. + * + * Present dependency list for minimal_server config: + * + * C++98 STL: + * + * + * + * + * + * + * C++11 STL or Boost + * + * + * + * + * Operating System: + * or + * or (for ntohl.. could potentially bundle this) + * + * @since 0.4.0-dev + */ +struct minimal_server { + typedef minimal_server type; + + // Concurrency policy + typedef websocketpp::concurrency::none concurrency_type; + + // HTTP Parser Policies + typedef http::parser::request request_type; + typedef http::parser::response response_type; + + // Message Policies + typedef message_buffer::message + message_type; + typedef message_buffer::alloc::con_msg_manager + con_msg_manager_type; + typedef message_buffer::alloc::endpoint_msg_manager + endpoint_msg_manager_type; + + /// Logging policies + typedef websocketpp::log::stub elog_type; + typedef websocketpp::log::stub alog_type; + + /// RNG policies + typedef websocketpp::random::none::int_generator rng_type; + + /// Controls compile time enabling/disabling of thread syncronization + /// code Disabling can provide a minor performance improvement to single + /// threaded applications + static bool const enable_multithreading = true; + + struct transport_config { + typedef type::concurrency_type concurrency_type; + typedef type::elog_type elog_type; + typedef type::alog_type alog_type; + typedef type::request_type request_type; + typedef type::response_type response_type; + + /// Controls compile time enabling/disabling of thread syncronization + /// code Disabling can provide a minor performance improvement to single + /// threaded applications + static bool const enable_multithreading = true; + + /// Default timer values (in ms) + + /// Length of time to wait for socket pre-initialization + /** + * Exactly what this includes depends on the socket policy in use + */ + static const long timeout_socket_pre_init = 5000; + + /// Length of time to wait before a proxy handshake is aborted + static const long timeout_proxy = 5000; + + /// Length of time to wait for socket post-initialization + /** + * Exactly what this includes depends on the socket policy in use. + * Often this means the TLS handshake + */ + static const long timeout_socket_post_init = 5000; + + /// Length of time to wait for dns resolution + static const long timeout_dns_resolve = 5000; + + /// Length of time to wait for TCP connect + static const long timeout_connect = 5000; + + /// Length of time to wait for socket shutdown + static const long timeout_socket_shutdown = 5000; + }; + + /// Transport Endpoint Component + typedef websocketpp::transport::stub::endpoint + transport_type; + + /// User overridable Endpoint base class + typedef websocketpp::endpoint_base endpoint_base; + /// User overridable Connection base class + typedef websocketpp::connection_base connection_base; + + /// Default timer values (in ms) + + /// Length of time before an opening handshake is aborted + static const long timeout_open_handshake = 5000; + /// Length of time before a closing handshake is aborted + static const long timeout_close_handshake = 5000; + /// Length of time to wait for a pong after a ping + static const long timeout_pong = 5000; + + /// WebSocket Protocol version to use as a client + /** + * What version of the WebSocket Protocol to use for outgoing client + * connections. Setting this to a value other than 13 (RFC6455) is not + * recommended. + */ + static const int client_version = 13; // RFC6455 + + /// Default static error logging channels + /** + * Which error logging channels to enable at compile time. Channels not + * enabled here will be unable to be selected by programs using the library. + * This option gives an optimizing compiler the ability to remove entirely + * code to test whether or not to print out log messages on a certain + * channel + * + * Default is all except for development/debug level errors + */ + static const websocketpp::log::level elog_level = + websocketpp::log::elevel::none; + + /// Default static access logging channels + /** + * Which access logging channels to enable at compile time. Channels not + * enabled here will be unable to be selected by programs using the library. + * This option gives an optimizing compiler the ability to remove entirely + * code to test whether or not to print out log messages on a certain + * channel + * + * Default is all except for development/debug level access messages + */ + static const websocketpp::log::level alog_level = + websocketpp::log::alevel::none; + + /// + static const size_t connection_read_buffer_size = 16384; + + /// Drop connections immediately on protocol error. + /** + * Drop connections on protocol error rather than sending a close frame. + * Off by default. This may result in legit messages near the error being + * dropped as well. It may free up resources otherwise spent dealing with + * misbehaving clients. + */ + static const bool drop_on_protocol_error = false; + + /// Suppresses the return of detailed connection close information + /** + * Silence close suppresses the return of detailed connection close + * information during the closing handshake. This information is useful + * for debugging and presenting useful errors to end users but may be + * undesirable for security reasons in some production environments. + * Close reasons could be used by an attacker to confirm that the endpoint + * is out of resources or be used to identify the WebSocket implementation + * in use. + * + * Note: this will suppress *all* close codes, including those explicitly + * sent by local applications. + */ + static const bool silent_close = false; + + /// Default maximum message size + /** + * Default value for the processor's maximum message size. Maximum message size + * determines the point at which the library will fail a connection with the + * message_too_big protocol error. + * + * The default is 32MB + * + * @since 0.4.0-alpha1 + */ + static const size_t max_message_size = 32000000; + + /// Global flag for enabling/disabling extensions + static const bool enable_extensions = true; + + /// Extension specific settings: + + /// permessage_compress extension + struct permessage_deflate_config { + typedef core::request_type request_type; + + /// If the remote endpoint requests that we reset the compression + /// context after each message should we honor the request? + static const bool allow_disabling_context_takeover = true; + + /// If the remote endpoint requests that we reduce the size of the + /// LZ77 sliding window size this is the lowest value that will be + /// allowed. Values range from 8 to 15. A value of 8 means we will + /// allow any possible window size. A value of 15 means do not allow + /// negotiation of the window size (ie require the default). + static const uint8_t minimum_outgoing_window_bits = 8; + }; + + typedef websocketpp::extensions::permessage_deflate::disabled + permessage_deflate_type; + + /// Autonegotiate permessage-deflate + /** + * Automatically enables the permessage-deflate extension. + * + * For clients this results in a permessage-deflate extension request being + * sent with every request rather than requiring it to be requested manually + * + * For servers this results in accepting the first set of extension settings + * requested by the client that we understand being used. The alternative is + * requiring the extension to be manually negotiated in `validate`. With + * auto-negotiate on, you may still override the auto-negotiate manually if + * needed. + */ + //static const bool autonegotiate_compression = false; +}; + +} // namespace config +} // namespace websocketpp + +#endif // WEBSOCKETPP_CONFIG_MINIMAL_HPP diff --git a/src/third_party/websocketpp/websocketpp/connection.hpp b/src/third_party/websocketpp/websocketpp/connection.hpp index c8be3633..37880ce1 100644 --- a/src/third_party/websocketpp/websocketpp/connection.hpp +++ b/src/third_party/websocketpp/websocketpp/connection.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -279,9 +280,9 @@ private: }; public: - explicit connection(bool is_server, std::string const & ua, alog_type& alog, + explicit connection(bool p_is_server, std::string const & ua, alog_type& alog, elog_type& elog, rng_type & rng) - : transport_con_type(is_server,alog,elog) + : transport_con_type(p_is_server, alog, elog) , m_handle_read_frame(lib::bind( &type::handle_read_frame, this, @@ -297,12 +298,14 @@ public: , m_open_handshake_timeout_dur(config::timeout_open_handshake) , m_close_handshake_timeout_dur(config::timeout_close_handshake) , m_pong_timeout_dur(config::timeout_pong) + , m_max_message_size(config::max_message_size) , m_state(session::state::connecting) , m_internal_state(session::internal_state::USER_INIT) , m_msg_manager(new con_msg_manager_type()) , m_send_buffer_size(0) , m_write_flag(false) - , m_is_server(is_server) + , m_read_flag(true) + , m_is_server(p_is_server) , m_alog(alog) , m_elog(elog) , m_rng(rng) @@ -455,9 +458,9 @@ public: m_message_handler = h; } - ///////////////////////// - // Connection timeouts // - ///////////////////////// + ////////////////////////////////////////// + // Connection timeouts and other limits // + ////////////////////////////////////////// /// Set open handshake timeout /** @@ -528,6 +531,38 @@ public: m_pong_timeout_dur = dur; } + /// Get maximum message size + /** + * Get maximum message size. Maximum message size determines the point at which the + * connection will fail a connection with the message_too_big protocol error. + * + * The default is set by the endpoint that creates the connection. + * + * @since 0.3.0 + */ + size_t get_max_message_size() const { + return m_max_message_size; + } + + /// Set maximum message size + /** + * Set maximum message size. Maximum message size determines the point at which the + * connection will fail a connection with the message_too_big protocol error. This + * value may be changed during the connection. + * + * The default is set by the endpoint that creates the connection. + * + * @since 0.3.0 + * + * @param new_value The value to set as the maximum message size. + */ + void set_max_message_size(size_t new_value) { + m_max_message_size = new_value; + if (m_processor) { + m_processor->set_max_message_size(new_value); + } + } + ////////////////////////////////// // Uncategorized public methods // ////////////////////////////////// @@ -615,9 +650,46 @@ public: * @return An error code */ lib::error_code interrupt(); - + /// Transport inturrupt callback void handle_interrupt(); + + /// Pause reading of new data + /** + * Signals to the connection to halt reading of new data. While reading is paused, + * the connection will stop reading from its associated socket. In turn this will + * result in TCP based flow control kicking in and slowing data flow from the remote + * endpoint. + * + * This is useful for applications that push new requests to a queue to be processed + * by another thread and need a way to signal when their request queue is full without + * blocking the network processing thread. + * + * Use `resume_reading()` to resume. + * + * If supported by the transport this is done asynchronously. As such reading may not + * stop until the current read operation completes. Typically you can expect to + * receive no more bytes after initiating a read pause than the size of the read + * buffer. + * + * If reading is paused for this connection already nothing is changed. + */ + lib::error_code pause_reading(); + + /// Pause reading callback + void handle_pause_reading(); + + /// Resume reading of new data + /** + * Signals to the connection to resume reading of new data after it was paused by + * `pause_reading()`. + * + * If reading is not paused for this connection already nothing is changed. + */ + lib::error_code resume_reading(); + + /// Resume reading callback + void handle_resume_reading(); /// Send a ping /** @@ -1092,8 +1164,8 @@ public: void handle_open_handshake_timeout(lib::error_code const & ec); void handle_close_handshake_timeout(lib::error_code const & ec); - void handle_read_frame(lib::error_code const & ec, - size_t bytes_transferred); + void handle_read_frame(lib::error_code const & ec, size_t bytes_transferred); + void read_frame(); /// Get array of WebSocket protocol versions that this connection supports. const std::vector& get_supported_versions() const; @@ -1281,6 +1353,14 @@ private: */ void log_fail_result(); + /// Prints information about an arbitrary error code on the specified channel + template + void log_err(log::level l, char const * msg, error_type const & ec) { + std::stringstream s; + s << msg << " error: " << ec << " (" << ec.message() << ")"; + m_elog.write(l, s.str()); + } + // internal handler functions read_handler m_handle_read_frame; write_frame_handler m_write_frame_handler; @@ -1307,6 +1387,7 @@ private: long m_open_handshake_timeout_dur; long m_close_handshake_timeout_dur; long m_pong_timeout_dur; + size_t m_max_message_size; /// External connection state /** @@ -1370,9 +1451,9 @@ private: */ std::vector m_send_buffer; - /// a pointer to hold on to the current message being written to keep it + /// a list of pointers to hold on to the messages being written to keep them /// from going out of scope before the write is complete. - message_ptr m_current_msg; + std::vector m_current_msgs; /// True if there is currently an outstanding transport write /** @@ -1380,6 +1461,9 @@ private: */ bool m_write_flag; + /// True if this connection is presently reading new data + bool m_read_flag; + // connection data request_type m_request; response_type m_response; diff --git a/src/third_party/websocketpp/websocketpp/connection_base.hpp b/src/third_party/websocketpp/websocketpp/connection_base.hpp index f780da7b..2e700962 100644 --- a/src/third_party/websocketpp/websocketpp/connection_base.hpp +++ b/src/third_party/websocketpp/websocketpp/connection_base.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/third_party/websocketpp/websocketpp/endpoint.hpp b/src/third_party/websocketpp/websocketpp/endpoint.hpp index 2df806a3..3bbe9da1 100644 --- a/src/third_party/websocketpp/websocketpp/endpoint.hpp +++ b/src/third_party/websocketpp/websocketpp/endpoint.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -32,7 +32,6 @@ #include #include -#include #include namespace websocketpp { @@ -87,21 +86,22 @@ public: typedef lib::shared_ptr hdl_type; - explicit endpoint(bool is_server) - : m_alog(config::alog_level, &std::cout) - , m_elog(config::elog_level, &std::cerr) + explicit endpoint(bool p_is_server) + : m_alog(config::alog_level, log::channel_type_hint::access) + , m_elog(config::elog_level, log::channel_type_hint::error) , m_user_agent(::websocketpp::user_agent) , m_open_handshake_timeout_dur(config::timeout_open_handshake) , m_close_handshake_timeout_dur(config::timeout_close_handshake) , m_pong_timeout_dur(config::timeout_pong) - , m_is_server(is_server) + , m_max_message_size(config::max_message_size) + , m_is_server(p_is_server) { m_alog.set_channels(config::alog_level); m_elog.set_channels(config::elog_level); - m_alog.write(log::alevel::devel,"endpoint constructor"); + m_alog.write(log::alevel::devel, "endpoint constructor"); - transport_type::init_logging(&m_alog,&m_elog); + transport_type::init_logging(&m_alog, &m_elog); } /// Returns the user agent string that this endpoint will use @@ -272,9 +272,9 @@ public: m_message_handler = h; } - ///////////////////////// - // Connection timeouts // - ///////////////////////// + ////////////////////////////////////////// + // Connection timeouts and other limits // + ////////////////////////////////////////// /// Set open handshake timeout /** @@ -348,6 +348,36 @@ public: m_pong_timeout_dur = dur; } + /// Get default maximum message size + /** + * Get the default maximum message size that will be used for new connections created + * by this endpoint. The maximum message size determines the point at which the + * connection will fail a connection with the message_too_big protocol error. + * + * The default is set by the max_message_size value from the template config + * + * @since 0.3.0 + */ + size_t get_max_message_size() const { + return m_max_message_size; + } + + /// Set default maximum message size + /** + * Set the default maximum message size that will be used for new connections created + * by this endpoint. Maximum message size determines the point at which the connection + * will fail a connection with the message_too_big protocol error. + * + * The default is set by the max_message_size value from the template config + * + * @since 0.3.0 + * + * @param new_value The value to set as the maximum message size. + */ + void set_max_message_size(size_t new_value) { + m_max_message_size = new_value; + } + /*************************************/ /* Connection pass through functions */ /*************************************/ @@ -363,6 +393,43 @@ public: void interrupt(connection_hdl hdl, lib::error_code & ec); void interrupt(connection_hdl hdl); + /// Pause reading of new data (exception free) + /** + * Signals to the connection to halt reading of new data. While reading is paused, + * the connection will stop reading from its associated socket. In turn this will + * result in TCP based flow control kicking in and slowing data flow from the remote + * endpoint. + * + * This is useful for applications that push new requests to a queue to be processed + * by another thread and need a way to signal when their request queue is full without + * blocking the network processing thread. + * + * Use `resume_reading()` to resume. + * + * If supported by the transport this is done asynchronously. As such reading may not + * stop until the current read operation completes. Typically you can expect to + * receive no more bytes after initiating a read pause than the size of the read + * buffer. + * + * If reading is paused for this connection already nothing is changed. + */ + void pause_reading(connection_hdl hdl, lib::error_code & ec); + + /// Pause reading of new data + void pause_reading(connection_hdl hdl); + + /// Resume reading of new data (exception free) + /** + * Signals to the connection to resume reading of new data after it was paused by + * `pause_reading()`. + * + * If reading is not paused for this connection already nothing is changed. + */ + void resume_reading(connection_hdl hdl, lib::error_code & ec); + + /// Resume reading of new data + void resume_reading(connection_hdl hdl); + /// Create a message and add it to the outgoing send queue (exception free) /** * Convenience method to send a message given a payload string and an opcode @@ -470,7 +537,7 @@ public: lib::error_code ec; connection_ptr con = this->get_con_from_hdl(hdl,ec); if (ec) { - throw ec; + throw exception(ec); } return con; } @@ -497,6 +564,7 @@ private: long m_open_handshake_timeout_dur; long m_close_handshake_timeout_dur; long m_pong_timeout_dur; + size_t m_max_message_size; rng_type m_rng; diff --git a/src/third_party/websocketpp/websocketpp/endpoint_base.hpp b/src/third_party/websocketpp/websocketpp/endpoint_base.hpp index c6f26285..1ad1a44d 100644 --- a/src/third_party/websocketpp/websocketpp/endpoint_base.hpp +++ b/src/third_party/websocketpp/websocketpp/endpoint_base.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/third_party/websocketpp/websocketpp/error.hpp b/src/third_party/websocketpp/websocketpp/error.hpp index d699075d..6fff5307 100644 --- a/src/third_party/websocketpp/websocketpp/error.hpp +++ b/src/third_party/websocketpp/websocketpp/error.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -38,7 +38,7 @@ namespace websocketpp { /// Combination error code / string type for returning two values typedef std::pair err_str_pair; -// setup for errors that should be propogated back to the user. +/// Library level error codes namespace error { enum value { /// Catch-all library error @@ -86,7 +86,8 @@ enum value { /// Invalid subprotocol invalid_subprotocol, - /// Bad or unknown connection + /// An operation was attempted on a connection that did not exist or was + /// already deleted. bad_connection, /// Unit testing utility error code @@ -114,7 +115,14 @@ enum value { close_handshake_timeout, /// Invalid port in URI - invalid_port + invalid_port, + + /// An async accept operation failed because the underlying transport has been + /// requested to not listen for new connections anymore. + async_accept_not_listening, + + /// The requested operation was canceled + operation_canceled }; // enum value @@ -176,6 +184,10 @@ public: return "The closing handshake timed out"; case error::invalid_port: return "Invalid URI port"; + case error::async_accept_not_listening: + return "Async Accept not listening"; + case error::operation_canceled: + return "Operation canceled"; default: return "Unknown"; } @@ -205,21 +217,30 @@ namespace websocketpp { class exception : public std::exception { public: - exception(std::string const & msg, - error::value code = error::general) - : m_msg(msg),m_code(code) {} + exception(std::string const & msg, lib::error_code ec = make_error_code(error::general)) + : m_msg(msg), m_code(ec) + {} + + explicit exception(lib::error_code ec) + : m_code(ec) + {} + ~exception() throw() {} virtual char const * what() const throw() { - return m_msg.c_str(); + if (m_msg.empty()) { + return m_code.message().c_str(); + } else { + return m_msg.c_str(); + } } - error::value code() const throw() { + lib::error_code code() const throw() { return m_code; } std::string m_msg; - error::value m_code; + lib::error_code m_code; }; } // namespace websocketpp diff --git a/src/third_party/websocketpp/websocketpp/error_container.hpp b/src/third_party/websocketpp/websocketpp/error_container.hpp index b7c75ac9..5a84f7aa 100644 --- a/src/third_party/websocketpp/websocketpp/error_container.hpp +++ b/src/third_party/websocketpp/websocketpp/error_container.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -36,34 +36,34 @@ namespace websocketpp { */ class error_msg { public: - const std::string& get_msg() const { - return m_error_msg; - } + const std::string& get_msg() const { + return m_error_msg; + } - void set_msg(const std::string& msg) { - m_error_msg = msg; - } + void set_msg(const std::string& msg) { + m_error_msg = msg; + } - void append_msg(const std::string& msg) { - m_error_msg.append(msg); - } + void append_msg(const std::string& msg) { + m_error_msg.append(msg); + } - template - void set_msg(const T& thing) { - std::stringsteam val; - val << thing; - this->set_msg(val.str()); - } + template + void set_msg(const T& thing) { + std::stringsteam val; + val << thing; + this->set_msg(val.str()); + } - template - void append_msg(const T& thing) { - std::stringsteam val; - val << thing; - this->append_msg(val.str()); - } + template + void append_msg(const T& thing) { + std::stringsteam val; + val << thing; + this->append_msg(val.str()); + } private: - // error resources - std::string m_error_msg; + // error resources + std::string m_error_msg; }; } // namespace websocketpp diff --git a/src/third_party/websocketpp/websocketpp/extensions/extension.hpp b/src/third_party/websocketpp/websocketpp/extensions/extension.hpp index 104ea704..4d2ba745 100644 --- a/src/third_party/websocketpp/websocketpp/extensions/extension.hpp +++ b/src/third_party/websocketpp/websocketpp/extensions/extension.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/third_party/websocketpp/websocketpp/extensions/permessage_deflate/disabled.hpp b/src/third_party/websocketpp/websocketpp/extensions/permessage_deflate/disabled.hpp index 3a5da7fd..c76bf936 100644 --- a/src/third_party/websocketpp/websocketpp/extensions/permessage_deflate/disabled.hpp +++ b/src/third_party/websocketpp/websocketpp/extensions/permessage_deflate/disabled.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -53,7 +53,15 @@ class disabled { typedef std::pair err_str_pair; public: - err_str_pair negotiate(http::attribute_list const & attributes) { + /// Negotiate extension + /** + * The disabled extension always fails the negotiation with a disabled + * error. + * + * @param offer Attribute from client's offer + * @return Status code and value to return to remote endpoint + */ + err_str_pair negotiate(http::attribute_list const &) { return make_pair(make_error_code(error::disabled),std::string()); } @@ -69,17 +77,24 @@ public: return false; } - lib::error_code compress(std::string const & in, std::string & out) { + /// Compress bytes + /** + * @param [in] in String to compress + * @param [out] out String to append compressed bytes to + * @return Error or status code + */ + lib::error_code compress(std::string const &, std::string &) { return make_error_code(error::disabled); } - lib::error_code decompress(uint8_t const * buf, size_t len, - std::string & out) - { - return make_error_code(error::disabled); - } - - lib::error_code decompress(std::string const & in, std::string & out) { + /// Decompress bytes + /** + * @param buf Byte buffer to decompress + * @param len Length of buf + * @param out String to append decompressed bytes to + * @return Error or status code + */ + lib::error_code decompress(uint8_t const *, size_t, std::string &) { return make_error_code(error::disabled); } }; diff --git a/src/third_party/websocketpp/websocketpp/extensions/permessage_deflate/enabled.hpp b/src/third_party/websocketpp/websocketpp/extensions/permessage_deflate/enabled.hpp index 092690c2..00a255d9 100644 --- a/src/third_party/websocketpp/websocketpp/extensions/permessage_deflate/enabled.hpp +++ b/src/third_party/websocketpp/websocketpp/extensions/permessage_deflate/enabled.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -28,8 +28,10 @@ #ifndef WEBSOCKETPP_PROCESSOR_EXTENSION_PERMESSAGEDEFLATE_HPP #define WEBSOCKETPP_PROCESSOR_EXTENSION_PERMESSAGEDEFLATE_HPP + #include #include +#include #include #include @@ -48,8 +50,8 @@ namespace extensions { /** * ### permessage-deflate interface * - * **is_implimented**\n - * `bool is_implimented()`\n + * **is_implemented**\n + * `bool is_implemented()`\n * Returns whether or not the object impliments the extension or not * * **is_enabled**\n @@ -432,8 +434,8 @@ public: * @param response The server response attribute list to validate * @return Validation error or 0 on success */ - lib::error_code validate_offer(http::attribute_list const & response) { - + lib::error_code validate_offer(http::attribute_list const &) { + return make_error_code(error::general); } /// Negotiate extension @@ -487,7 +489,6 @@ public: } size_t output; - int ret; m_dstate.avail_out = m_compress_buffer_size; m_dstate.next_in = (unsigned char *)(const_cast(in.data())); @@ -497,7 +498,7 @@ public: m_dstate.avail_out = m_compress_buffer_size; m_dstate.next_out = m_compress_buffer.get(); - ret = deflate(&m_dstate, Z_SYNC_FLUSH); + deflate(&m_dstate, Z_SYNC_FLUSH); output = m_compress_buffer_size - m_dstate.avail_out; @@ -642,7 +643,7 @@ private: m_s2c_max_window_bits = bits; break; case mode::largest: - m_s2c_max_window_bits = std::min(bits,m_s2c_max_window_bits); + m_s2c_max_window_bits = (std::min)(bits,m_s2c_max_window_bits); break; case mode::smallest: m_s2c_max_window_bits = min_s2c_max_window_bits; diff --git a/src/third_party/websocketpp/websocketpp/frame.hpp b/src/third_party/websocketpp/websocketpp/frame.hpp index 32b50a64..c22d3584 100644 --- a/src/third_party/websocketpp/websocketpp/frame.hpp +++ b/src/third_party/websocketpp/websocketpp/frame.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -266,7 +266,7 @@ private: } uint64_converter temp64; - temp64.i = lib::net::htonll(payload_size); + temp64.i = lib::net::_htonll(payload_size); std::copy(temp64.c+payload_offset,temp64.c+8,bytes); return 8-payload_offset; @@ -456,35 +456,6 @@ inline size_t get_header_len(basic_header const & h) { return size; } -/// Set the frame's size -/** - * @param [out] h The basic header to set. - * @param [out] eh The extended header to set. - * @param [in] The size to set. - * @return What error occurred, if any. - */ -inline lib::error_code set_size(basic_header & h, extended_header & eh, uint64_t - size) -{ - // make sure value isn't too big - uint8_t basic_value; - - if (size <= limits::payload_size_basic) { - basic_value = static_cast(size); - } else if (size <= limits::payload_size_extended) { - basic_value = payload_size_code_16bit; - } else if (size <= limits::payload_size_jumbo) { - basic_value = payload_size_code_64bit; - } else { - // error - return lib::error_code(); - } - - h.b1 = (basic_value & BHB1_PAYLOAD) | (h.b1 & BHB1_MASK); - - return lib::error_code(); -} - /// Calculate the offset location of the masking key within the extended header /** * Calculate the offset location of the masking key within the extended header @@ -583,7 +554,7 @@ inline uint16_t get_extended_size(const extended_header &e) { inline uint64_t get_jumbo_size(const extended_header &e) { uint64_converter temp64; std::copy(e.bytes,e.bytes+8,temp64.c); - return lib::net::ntohll(temp64.i); + return lib::net::_ntohll(temp64.i); } /// Extract the full payload size field from a WebSocket header diff --git a/src/third_party/websocketpp/websocketpp/http/constants.hpp b/src/third_party/websocketpp/websocketpp/http/constants.hpp index be3006aa..22af5f2c 100644 --- a/src/third_party/websocketpp/websocketpp/http/constants.hpp +++ b/src/third_party/websocketpp/websocketpp/http/constants.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -33,6 +33,7 @@ #include namespace websocketpp { +/// HTTP handling support namespace http { /// The type of an HTTP attribute list /** @@ -255,7 +256,7 @@ namespace http { case internal_server_error: return "Internal Server Error"; case not_implemented: - return "Not Implimented"; + return "Not Implemented"; case bad_gateway: return "Bad Gateway"; case service_unavailable: diff --git a/src/third_party/websocketpp/websocketpp/http/impl/parser.hpp b/src/third_party/websocketpp/websocketpp/http/impl/parser.hpp index d1d90813..a8f8d665 100644 --- a/src/third_party/websocketpp/websocketpp/http/impl/parser.hpp +++ b/src/third_party/websocketpp/websocketpp/http/impl/parser.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/third_party/websocketpp/websocketpp/http/impl/request.hpp b/src/third_party/websocketpp/websocketpp/http/impl/request.hpp index 804a7faf..f7cad4f5 100644 --- a/src/third_party/websocketpp/websocketpp/http/impl/request.hpp +++ b/src/third_party/websocketpp/websocketpp/http/impl/request.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -38,15 +38,15 @@ namespace http { namespace parser { inline bool request::parse_complete(std::istream& s) { - std::string request; + std::string req; // get status line - std::getline(s, request); + std::getline(s, req); - if (request[request.size()-1] == '\r') { - request.erase(request.end()-1); + if (req[req.size()-1] == '\r') { + req.erase(req.end()-1); - std::stringstream ss(request); + std::stringstream ss(req); std::string val; ss >> val; @@ -127,18 +127,18 @@ inline size_t request::consume(const char *buf, size_t len) { } } - begin = end+sizeof(header_delimiter)-1; + begin = end+(sizeof(header_delimiter)-1); } } inline std::string request::raw() { // TODO: validation. Make sure all required fields have been set? - std::stringstream raw; + std::stringstream ret; - raw << m_method << " " << m_uri << " " << get_version() << "\r\n"; - raw << raw_headers() << "\r\n" << m_body; + ret << m_method << " " << m_uri << " " << get_version() << "\r\n"; + ret << raw_headers() << "\r\n" << m_body; - return raw.str(); + return ret.str(); } inline void request::set_method(const std::string& method) { diff --git a/src/third_party/websocketpp/websocketpp/http/impl/response.hpp b/src/third_party/websocketpp/websocketpp/http/impl/response.hpp index bcddd176..6a99e81c 100644 --- a/src/third_party/websocketpp/websocketpp/http/impl/response.hpp +++ b/src/third_party/websocketpp/websocketpp/http/impl/response.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -172,15 +172,15 @@ inline size_t response::consume(std::istream & s) { inline bool response::parse_complete(std::istream& s) { // parse a complete header (ie \r\n\r\n MUST be in the input stream) - std::string response; + std::string line; // get status line - std::getline(s, response); + std::getline(s, line); - if (response[response.size()-1] == '\r') { - response.erase(response.end()-1); + if (line[line.size()-1] == '\r') { + line.erase(line.end()-1); - std::stringstream ss(response); + std::stringstream ss(line); std::string str_val; int int_val; char char_val[256]; @@ -201,14 +201,14 @@ inline bool response::parse_complete(std::istream& s) { inline std::string response::raw() const { // TODO: validation. Make sure all required fields have been set? - std::stringstream raw; + std::stringstream ret; - raw << get_version() << " " << m_status_code << " " << m_status_msg; - raw << "\r\n" << raw_headers() << "\r\n"; + ret << get_version() << " " << m_status_code << " " << m_status_msg; + ret << "\r\n" << raw_headers() << "\r\n"; - raw << m_body; + ret << m_body; - return raw.str(); + return ret.str(); } inline void response::set_status(status_code::value code) { diff --git a/src/third_party/websocketpp/websocketpp/http/parser.hpp b/src/third_party/websocketpp/websocketpp/http/parser.hpp index 771c5397..cc81f63c 100644 --- a/src/third_party/websocketpp/websocketpp/http/parser.hpp +++ b/src/third_party/websocketpp/websocketpp/http/parser.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -369,6 +369,9 @@ InputIterator extract_parameters(InputIterator begin, InputIterator end, inline std::string strip_lws(std::string const & input) { std::string::const_iterator begin = extract_all_lws(input.begin(),input.end()); + if (begin == input.end()) { + return std::string(); + } std::string::const_reverse_iterator end = extract_all_lws(input.rbegin(),input.rend()); return std::string(begin,end.base()); diff --git a/src/third_party/websocketpp/websocketpp/http/request.hpp b/src/third_party/websocketpp/websocketpp/http/request.hpp index 1b8c3e2a..4a5990ac 100644 --- a/src/third_party/websocketpp/websocketpp/http/request.hpp +++ b/src/third_party/websocketpp/websocketpp/http/request.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -51,7 +51,7 @@ public: typedef lib::shared_ptr ptr; request() - : m_buf(new std::string()) + : m_buf(lib::make_shared()) , m_ready(false) {} /// DEPRECATED parse a complete header (\r\n\r\n MUST be in the istream) diff --git a/src/third_party/websocketpp/websocketpp/http/response.hpp b/src/third_party/websocketpp/websocketpp/http/response.hpp index 1ee622b1..3825a558 100644 --- a/src/third_party/websocketpp/websocketpp/http/response.hpp +++ b/src/third_party/websocketpp/websocketpp/http/response.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -58,7 +58,7 @@ public: response() : m_read(0) - , m_buf(new std::string()) + , m_buf(lib::make_shared()) , m_status_code(status_code::uninitialized) , m_state(RESPONSE_LINE) {} diff --git a/src/third_party/websocketpp/websocketpp/impl/connection_impl.hpp b/src/third_party/websocketpp/websocketpp/impl/connection_impl.hpp index 0449e746..1f29f4ef 100644 --- a/src/third_party/websocketpp/websocketpp/impl/connection_impl.hpp +++ b/src/third_party/websocketpp/websocketpp/impl/connection_impl.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -28,6 +28,7 @@ #ifndef WEBSOCKETPP_CONNECTION_IMPL_HPP #define WEBSOCKETPP_CONNECTION_IMPL_HPP +#include #include #include @@ -94,7 +95,9 @@ lib::error_code connection::send(const void* payload, size_t len, template lib::error_code connection::send(typename config::message_type::ptr msg) { - m_alog.write(log::alevel::devel,"connection send"); + if (m_alog.static_test(log::alevel::devel)) { + m_alog.write(log::alevel::devel,"connection send"); + } // TODO: if (m_state != session::state::open) { @@ -140,7 +143,9 @@ lib::error_code connection::send(typename config::message_type::ptr msg) template void connection::ping(const std::string& payload, lib::error_code& ec) { - m_alog.write(log::alevel::devel,"connection ping"); + if (m_alog.static_test(log::alevel::devel)) { + m_alog.write(log::alevel::devel,"connection ping"); + } if (m_state != session::state::open) { ec = error::make_error_code(error::invalid_state); @@ -200,17 +205,17 @@ void connection::ping(const std::string& payload, lib::error_code& ec) { } template -void connection::ping(const std::string& payload) { +void connection::ping(std::string const & payload) { lib::error_code ec; ping(payload,ec); if (ec) { - throw ec; + throw exception(ec); } } template -void connection::handle_pong_timeout(std::string payload, const lib::error_code & - ec) +void connection::handle_pong_timeout(std::string payload, + lib::error_code const & ec) { if (ec) { if (ec == transport::error::operation_aborted) { @@ -229,7 +234,9 @@ void connection::handle_pong_timeout(std::string payload, const lib::err template void connection::pong(const std::string& payload, lib::error_code& ec) { - m_alog.write(log::alevel::devel,"connection pong"); + if (m_alog.static_test(log::alevel::devel)) { + m_alog.write(log::alevel::devel,"connection pong"); + } if (m_state != session::state::open) { ec = error::make_error_code(error::invalid_state); @@ -263,11 +270,11 @@ void connection::pong(const std::string& payload, lib::error_code& ec) { } template -void connection::pong(const std::string& payload) { +void connection::pong(std::string const & payload) { lib::error_code ec; pong(payload,ec); if (ec) { - throw ec; + throw exception(ec); } } @@ -275,7 +282,9 @@ template void connection::close(close::status::value const code, std::string const & reason, lib::error_code & ec) { - m_alog.write(log::alevel::devel,"connection close"); + if (m_alog.static_test(log::alevel::devel)) { + m_alog.write(log::alevel::devel,"connection close"); + } if (m_state != session::state::open) { ec = error::make_error_code(error::invalid_state); @@ -296,7 +305,7 @@ void connection::close(close::status::value const code, lib::error_code ec; close(code,reason,ec); if (ec) { - throw ec; + throw exception(ec); } } @@ -323,6 +332,41 @@ void connection::handle_interrupt() { } } +template +lib::error_code connection::pause_reading() { + m_alog.write(log::alevel::devel,"connection connection::pause_reading"); + return transport_con_type::dispatch( + lib::bind( + &type::handle_pause_reading, + type::get_shared() + ) + ); +} + +/// Pause reading handler. Not safe to call directly +template +void connection::handle_pause_reading() { + m_alog.write(log::alevel::devel,"connection connection::handle_pause_reading"); + m_read_flag = false; +} + +template +lib::error_code connection::resume_reading() { + m_alog.write(log::alevel::devel,"connection connection::resume_reading"); + return transport_con_type::dispatch( + lib::bind( + &type::handle_resume_reading, + type::get_shared() + ) + ); +} + +/// Resume reading helper method. Not safe to call directly +template +void connection::handle_resume_reading() { + m_read_flag = true; + read_frame(); +} @@ -387,7 +431,7 @@ connection::get_requested_subprotocols() const { } template -void connection::add_subprotocol(const std::string & value, +void connection::add_subprotocol(std::string const & value, lib::error_code & ec) { if (m_is_server) { @@ -407,17 +451,17 @@ void connection::add_subprotocol(const std::string & value, } template -void connection::add_subprotocol(const std::string & value) { +void connection::add_subprotocol(std::string const & value) { lib::error_code ec; this->add_subprotocol(value,ec); if (ec) { - throw ec; + throw exception(ec); } } template -void connection::select_subprotocol(const std::string & value, +void connection::select_subprotocol(std::string const & value, lib::error_code & ec) { if (!m_is_server) { @@ -445,24 +489,24 @@ void connection::select_subprotocol(const std::string & value, } template -void connection::select_subprotocol(const std::string & value) { +void connection::select_subprotocol(std::string const & value) { lib::error_code ec; this->select_subprotocol(value,ec); if (ec) { - throw ec; + throw exception(ec); } } template const std::string & -connection::get_request_header(const std::string &key) { +connection::get_request_header(std::string const & key) { return m_request.get_header(key); } template const std::string & -connection::get_response_header(const std::string &key) { +connection::get_response_header(std::string const & key) { return m_response.get_header(key); } @@ -472,9 +516,8 @@ void connection::set_status(http::status_code::value code) //scoped_lock_type lock(m_connection_state_lock); if (m_internal_state != istate::PROCESS_HTTP_REQUEST) { - throw error::make_error_code(error::invalid_state); - //throw exception("Call to set_status from invalid state", - // error::INVALID_STATE); + throw exception("Call to set_status from invalid state", + error::make_error_code(error::invalid_state)); } m_response.set_status(code); @@ -486,9 +529,8 @@ void connection::set_status(http::status_code::value code, //scoped_lock_type lock(m_connection_state_lock); if (m_internal_state != istate::PROCESS_HTTP_REQUEST) { - throw error::make_error_code(error::invalid_state); - //throw exception("Call to set_status from invalid state", - // error::INVALID_STATE); + throw exception("Call to set_status from invalid state", + error::make_error_code(error::invalid_state)); } m_response.set_status(code,msg); @@ -498,9 +540,8 @@ void connection::set_body(std::string const & value) { //scoped_lock_type lock(m_connection_state_lock); if (m_internal_state != istate::PROCESS_HTTP_REQUEST) { - throw error::make_error_code(error::invalid_state); - //throw exception("Call to set_status from invalid state", - // error::INVALID_STATE); + throw exception("Call to set_status from invalid state", + error::make_error_code(error::invalid_state)); } m_response.set_body(value); @@ -517,14 +558,16 @@ void connection::append_header(std::string const & key, // we are setting response headers for an incoming server connection m_response.append_header(key,val); } else { - throw error::make_error_code(error::invalid_state); + throw exception("Call to append_header from invalid state", + error::make_error_code(error::invalid_state)); } } else { if (m_internal_state == istate::USER_INIT) { // we are setting initial headers for an outgoing client connection m_request.append_header(key,val); } else { - throw error::make_error_code(error::invalid_state); + throw exception("Call to append_header from invalid state", + error::make_error_code(error::invalid_state)); } } } @@ -539,14 +582,16 @@ void connection::replace_header(std::string const & key, // we are setting response headers for an incoming server connection m_response.replace_header(key,val); } else { - throw error::make_error_code(error::invalid_state); + throw exception("Call to replace_header from invalid state", + error::make_error_code(error::invalid_state)); } } else { if (m_internal_state == istate::USER_INIT) { // we are setting initial headers for an outgoing client connection m_request.replace_header(key,val); } else { - throw error::make_error_code(error::invalid_state); + throw exception("Call to replace_header from invalid state", + error::make_error_code(error::invalid_state)); } } } @@ -560,14 +605,16 @@ void connection::remove_header(std::string const & key) // we are setting response headers for an incoming server connection m_response.remove_header(key); } else { - throw error::make_error_code(error::invalid_state); + throw exception("Call to remove_header from invalid state", + error::make_error_code(error::invalid_state)); } } else { if (m_internal_state == istate::USER_INIT) { // we are setting initial headers for an outgoing client connection m_request.remove_header(key); } else { - throw error::make_error_code(error::invalid_state); + throw exception("Call to remove_header from invalid state", + error::make_error_code(error::invalid_state)); } } } @@ -609,9 +656,8 @@ void connection::handle_transport_init(lib::error_code const & ec) { scoped_lock_type lock(m_connection_state_lock); if (m_internal_state != istate::TRANSPORT_INIT) { - throw error::make_error_code(error::invalid_state); - //throw exception("handle_transport_init must be called from transport init state", - // error::INVALID_STATE); + throw exception("handle_transport_init must be called from transport init state", + error::make_error_code(error::invalid_state)); } if (!ec) { @@ -648,14 +694,16 @@ template void connection::read_handshake(size_t num_bytes) { m_alog.write(log::alevel::devel,"connection read"); - m_handshake_timer = transport_con_type::set_timer( - config::timeout_open_handshake, - lib::bind( - &type::handle_open_handshake_timeout, - type::get_shared(), - lib::placeholders::_1 - ) - ); + if (m_open_handshake_timeout_dur > 0) { + m_handshake_timer = transport_con_type::set_timer( + m_open_handshake_timeout_dur, + lib::bind( + &type::handle_open_handshake_timeout, + type::get_shared(), + lib::placeholders::_1 + ) + ); + } transport_con_type::async_read_at_least( num_bytes, @@ -673,7 +721,7 @@ void connection::read_handshake(size_t num_bytes) { // All exit paths for this function need to call send_http_response() or submit // a new read request with this function as the handler. template -void connection::handle_read_handshake(const lib::error_code& ec, +void connection::handle_read_handshake(lib::error_code const & ec, size_t bytes_transferred) { m_alog.write(log::alevel::devel,"connection handle_read_handshake"); @@ -813,7 +861,7 @@ void connection::send_http_response_error() { // All exit paths for this function need to call send_http_response() or submit // a new read request with this function as the handler. template -void connection::handle_read_frame(const lib::error_code& ec, +void connection::handle_read_frame(lib::error_code const & ec, size_t bytes_transferred) { //m_alog.write(log::alevel::devel,"connection handle_read_frame"); @@ -824,6 +872,8 @@ void connection::handle_read_frame(const lib::error_code& ec, ); if (ec) { + log::level echannel = log::elevel::fatal; + if (ec == transport::error::eof) { if (m_state == session::state::closed) { // we expect to get eof if the connection is closed already @@ -839,14 +889,19 @@ void connection::handle_read_frame(const lib::error_code& ec, } } if (ec == transport::error::tls_short_read) { - m_elog.write(log::elevel::rerror,"got TLS short read, killing connection for now"); - this->terminate(ec); - return; + if (m_state == session::state::closed) { + // We expect to get a TLS short read if we try to read after the + // connection is closed. If this happens ignore and exit the + // read frame path. + terminate(lib::error_code()); + return; + } + echannel = log::elevel::rerror; + } else if (ec == transport::error::action_after_shutdown) { + echannel = log::elevel::info; } - - std::stringstream s; - s << "error in handle_read_frame: " << ec.message() << " (" << ec << ")"; - m_elog.write(log::elevel::fatal,s.str()); + + log_err(echannel, "handle_read_frame", ec); this->terminate(ec); return; } @@ -873,12 +928,12 @@ void connection::handle_read_frame(const lib::error_code& ec, m_alog.write(log::alevel::devel,s.str()); } - lib::error_code ec; + lib::error_code consume_ec; p += m_processor->consume( reinterpret_cast(m_buf)+p, bytes_transferred-p, - ec + consume_ec ); if (m_alog.static_test(log::alevel::devel)) { @@ -886,20 +941,22 @@ void connection::handle_read_frame(const lib::error_code& ec, s << "bytes left after consume: " << bytes_transferred-p; m_alog.write(log::alevel::devel,s.str()); } - if (ec) { - m_elog.write(log::elevel::rerror,"consume error: "+ec.message()); + if (consume_ec) { + log_err(log::elevel::rerror, "consume", consume_ec); if (config::drop_on_protocol_error) { - this->terminate(ec); + this->terminate(consume_ec); return; } else { lib::error_code close_ec; - this->close(processor::error::to_ws(ec),ec.message(),close_ec); + this->close( + processor::error::to_ws(consume_ec), + consume_ec.message(), + close_ec + ); if (close_ec) { - m_elog.write(log::elevel::fatal, - "Failed to send a close frame after protocol error: " - +close_ec.message()); + log_err(log::elevel::fatal, "Protocol error close frame ", close_ec); this->terminate(close_ec); return; } @@ -910,20 +967,18 @@ void connection::handle_read_frame(const lib::error_code& ec, if (m_processor->ready()) { if (m_alog.static_test(log::alevel::devel)) { std::stringstream s; - s << "Complete frame received. Dispatching"; + s << "Complete message received. Dispatching"; m_alog.write(log::alevel::devel,s.str()); } message_ptr msg = m_processor->get_message(); if (!msg) { - m_alog.write(log::alevel::devel, - "null message from m_processor"); + m_alog.write(log::alevel::devel, "null message from m_processor"); } else if (!is_control(msg->get_opcode())) { // data message, dispatch to user if (m_state != session::state::open) { - m_elog.write(log::elevel::warn, - "got non-close data frame in state closing"); + m_elog.write(log::elevel::warn, "got non-close frame while closing"); } else if (m_message_handler) { m_message_handler(m_connection_hdl, msg); } @@ -933,6 +988,16 @@ void connection::handle_read_frame(const lib::error_code& ec, } } + read_frame(); +} + +/// Issue a new transport read unless reading is paused. +template +void connection::read_frame() { + if (!m_read_flag) { + return; + } + transport_con_type::async_read_at_least( // std::min wont work with undefined static const values. // TODO: is there a more elegant way to do this? @@ -944,12 +1009,6 @@ void connection::handle_read_frame(const lib::error_code& ec, 1, m_buf, config::connection_read_buffer_size, - /*lib::bind( - &type::handle_read_frame, - type::get_shared(), - lib::placeholders::_1, - lib::placeholders::_2 - )*/ m_handle_read_frame ); } @@ -966,8 +1025,7 @@ bool connection::initialize_processor() { int version = processor::get_websocket_version(m_request); if (version < 0) { - m_alog.write(log::alevel::devel, - "BAD REQUEST: can't determine version"); + m_alog.write(log::alevel::devel, "BAD REQUEST: can't determine version"); m_response.set_status(http::status_code::bad_request); return false; } @@ -981,8 +1039,7 @@ bool connection::initialize_processor() { // We don't have a processor for this version. Return bad request // with Sec-WebSocket-Version header filled with values we do accept - m_alog.write(log::alevel::devel, - "BAD REQUEST: no processor for version"); + m_alog.write(log::alevel::devel, "BAD REQUEST: no processor for version"); m_response.set_status(http::status_code::bad_request); std::stringstream ss; @@ -1013,8 +1070,7 @@ bool connection::process_handshake_request() { ); if (!m_uri->get_valid()) { - m_alog.write(log::alevel::devel, - std::string("Bad request: failed to parse uri")); + m_alog.write(log::alevel::devel, "Bad request: failed to parse uri"); m_response.set_status(http::status_code::bad_request); return false; } @@ -1033,8 +1089,7 @@ bool connection::process_handshake_request() { // Validate: make sure all required elements are present. if (ec){ // Not a valid handshake request - m_alog.write(log::alevel::devel, - "BAD REQUEST (724) "+ec.message()); + m_alog.write(log::alevel::devel, "Bad request " + ec.message()); m_response.set_status(http::status_code::bad_request); return false; } @@ -1047,8 +1102,7 @@ bool connection::process_handshake_request() { if (neg_results.first) { // There was a fatal error in extension parsing that should result in // a failed connection attempt. - m_alog.write(log::alevel::devel, - "BAD REQUEST: (737) " + neg_results.first.message()); + m_alog.write(log::alevel::devel, "Bad request: " + neg_results.first.message()); m_response.set_status(http::status_code::bad_request); return false; } else { @@ -1066,8 +1120,7 @@ bool connection::process_handshake_request() { if (!m_uri->get_valid()) { - m_alog.write(log::alevel::devel, - std::string("Bad request: failed to parse uri")); + m_alog.write(log::alevel::devel, "Bad request: failed to parse uri"); m_response.set_status(http::status_code::bad_request); return false; } @@ -1091,14 +1144,14 @@ bool connection::process_handshake_request() { if (ec) { std::stringstream s; s << "Processing error: " << ec << "(" << ec.message() << ")"; - m_alog.write(log::alevel::devel,s.str()); + m_alog.write(log::alevel::devel, s.str()); m_response.set_status(http::status_code::internal_server_error); return false; } } else { // User application has rejected the handshake - m_alog.write(log::alevel::devel,"USER REJECT"); + m_alog.write(log::alevel::devel, "USER REJECT"); // Use Bad Request if the user handler did not provide a more // specific http response error code. @@ -1161,9 +1214,7 @@ void connection::send_http_response() { } template -void connection::handle_send_http_response( - const lib::error_code& ec) -{ +void connection::handle_send_http_response(lib::error_code const & ec) { m_alog.write(log::alevel::devel,"handle_send_http_response"); this->atomic_state_check( @@ -1172,8 +1223,7 @@ void connection::handle_send_http_response( ); if (ec) { - m_elog.write(log::elevel::rerror, - "error in handle_send_http_response: "+ec.message()); + log_err(log::elevel::rerror,"handle_send_http_response",ec); this->terminate(ec); return; } @@ -1230,13 +1280,11 @@ void connection::send_http_request() { m_requested_subprotocols); if (ec) { - m_elog.write(log::elevel::fatal, - "Internal library error: processor error: "+ec.message()); + log_err(log::elevel::fatal,"Internal library error: Processor",ec); return; } } else { - m_elog.write(log::elevel::fatal, - "Internal library error: missing processor"); + m_elog.write(log::elevel::fatal,"Internal library error: missing processor"); return; } @@ -1252,8 +1300,7 @@ void connection::send_http_request() { m_handshake_buffer = m_request.raw(); if (m_alog.static_test(log::alevel::devel)) { - m_alog.write(log::alevel::devel, - "Raw Handshake request:\n"+m_handshake_buffer); + m_alog.write(log::alevel::devel,"Raw Handshake request:\n"+m_handshake_buffer); } if (m_open_handshake_timeout_dur > 0) { @@ -1279,7 +1326,7 @@ void connection::send_http_request() { } template -void connection::handle_send_http_request(const lib::error_code& ec) { +void connection::handle_send_http_request(lib::error_code const & ec) { m_alog.write(log::alevel::devel,"handle_send_http_request"); this->atomic_state_check( @@ -1288,8 +1335,7 @@ void connection::handle_send_http_request(const lib::error_code& ec) { ); if (ec) { - m_elog.write(log::elevel::rerror, - "error in handle_send_http_request: "+ec.message()); + log_err(log::elevel::rerror,"handle_send_http_request",ec); this->terminate(ec); return; } @@ -1314,7 +1360,7 @@ void connection::handle_send_http_request(const lib::error_code& ec) { } template -void connection::handle_read_http_response(const lib::error_code& ec, +void connection::handle_read_http_response(lib::error_code const & ec, size_t bytes_transferred) { m_alog.write(log::alevel::devel,"handle_read_http_response"); @@ -1325,8 +1371,7 @@ void connection::handle_read_http_response(const lib::error_code& ec, ); if (ec) { - m_elog.write(log::elevel::rerror, - "error in handle_read_http_response: "+ec.message()); + log_err(log::elevel::rerror,"handle_send_http_response",ec); this->terminate(ec); return; } @@ -1349,16 +1394,13 @@ void connection::handle_read_http_response(const lib::error_code& ec, m_handshake_timer.reset(); } - lib::error_code ec = m_processor->validate_server_handshake_response( + lib::error_code validate_ec = m_processor->validate_server_handshake_response( m_request, m_response ); - if (ec) { - m_elog.write(log::elevel::rerror, - std::string("Server handshake response was invalid: ")+ - ec.message() - ); - this->terminate(ec); + if (validate_ec) { + log_err(log::elevel::rerror,"Server handshake response",validate_ec); + this->terminate(validate_ec); return; } @@ -1404,14 +1446,13 @@ void connection::handle_open_handshake_timeout( lib::error_code const & ec) { if (ec == transport::error::operation_aborted) { - m_alog.write(log::alevel::devel, - "asio open handshake timer cancelled"); + m_alog.write(log::alevel::devel,"open handshake timer cancelled"); } else if (ec) { m_alog.write(log::alevel::devel, - "asio open handle_open_handshake_timeout error: "+ec.message()); + "open handle_open_handshake_timeout error: "+ec.message()); // TODO: ignore or fail here? } else { - m_alog.write(log::alevel::devel, "asio open handshake timer expired"); + m_alog.write(log::alevel::devel,"open handshake timer expired"); terminate(make_error_code(error::open_handshake_timeout)); } } @@ -1421,8 +1462,7 @@ void connection::handle_close_handshake_timeout( lib::error_code const & ec) { if (ec == transport::error::operation_aborted) { - m_alog.write(log::alevel::devel, - "asio close handshake timer cancelled"); + m_alog.write(log::alevel::devel,"asio close handshake timer cancelled"); } else if (ec) { m_alog.write(log::alevel::devel, "asio open handle_close_handshake_timeout error: "+ec.message()); @@ -1486,7 +1526,7 @@ void connection::handle_terminate(terminate_status tstat, if (ec) { // there was an error actually shutting down the connection - m_elog.write(log::elevel::rerror,ec.message()); + log_err(log::elevel::devel,"handle_terminate",ec); } // clean shutdown @@ -1510,10 +1550,9 @@ void connection::handle_terminate(terminate_status tstat, if (m_termination_handler) { try { m_termination_handler(type::get_shared()); - } catch (const std::exception& e) { + } catch (std::exception const & e) { m_elog.write(log::elevel::warn, - std::string("termination_handler call failed. Reason was: ") - +e.what()); + std::string("termination_handler call failed. Reason was: ")+e.what()); } } } @@ -1533,52 +1572,80 @@ void connection::write_frame() { return; } - // Get the next message in the queue. This will return an empty - // message if the queue was empty. - m_current_msg = write_pop(); - - if (!m_current_msg) { + // pull off all the messages that are ready to write. + // stop if we get a message marked terminal + message_ptr next_message = write_pop(); + while (next_message) { + m_current_msgs.push_back(next_message); + if (!next_message->get_terminal()) { + next_message = write_pop(); + } else { + next_message = message_ptr(); + } + } + + if (m_current_msgs.empty()) { + // there was nothing to send return; + } else { + // At this point we own the next messages to be sent and are + // responsible for holding the write flag until they are + // successfully sent or there is some error + m_write_flag = true; } - - // At this point we own the next message to be sent and are - // responsible for holding the write flag until it is successfully - // sent or there is some error - m_write_flag = true; } - std::string const & header = m_current_msg->get_header(); - std::string const & payload = m_current_msg->get_payload(); - - m_send_buffer.push_back(transport::buffer(header.c_str(),header.size())); - m_send_buffer.push_back(transport::buffer(payload.c_str(),payload.size())); + typename std::vector::iterator it; + for (it = m_current_msgs.begin(); it != m_current_msgs.end(); ++it) { + std::string const & header = (*it)->get_header(); + std::string const & payload = (*it)->get_payload(); + m_send_buffer.push_back(transport::buffer(header.c_str(),header.size())); + m_send_buffer.push_back(transport::buffer(payload.c_str(),payload.size())); + } + // Print detailed send stats if those log levels are enabled if (m_alog.static_test(log::alevel::frame_header)) { if (m_alog.dynamic_test(log::alevel::frame_header)) { - std::stringstream s; - s << "Dispatching write with " << header.size() - << " header bytes and " << payload.size() - << " payload bytes" << std::endl; - m_alog.write(log::alevel::frame_header,s.str()); - m_alog.write(log::alevel::frame_header,"Header: "+utility::to_hex(header)); - } - } - if (m_alog.static_test(log::alevel::frame_payload)) { - if (m_alog.dynamic_test(log::alevel::frame_payload)) { - m_alog.write(log::alevel::frame_payload,"Payload: "+utility::to_hex(payload)); - } - } + std::stringstream general,header,payload; + + general << "Dispatching write containing " << m_current_msgs.size() + <<" message(s) containing "; + header << "Header Bytes: \n"; + payload << "Payload Bytes: \n"; + + size_t hbytes = 0; + size_t pbytes = 0; + + for (size_t i = 0; i < m_current_msgs.size(); i++) { + hbytes += m_current_msgs[i]->get_header().size(); + pbytes += m_current_msgs[i]->get_payload().size(); + + header << "[" << i << "] (" + << m_current_msgs[i]->get_header().size() << ") " + << utility::to_hex(m_current_msgs[i]->get_header()) << "\n"; + + if (m_alog.static_test(log::alevel::frame_payload)) { + if (m_alog.dynamic_test(log::alevel::frame_payload)) { + payload << "[" << i << "] (" + << m_current_msgs[i]->get_payload().size() << ") " + << utility::to_hex(m_current_msgs[i]->get_payload()) + << "\n"; + } + } + } + + general << hbytes << " header bytes and " << pbytes << " payload bytes"; + + m_alog.write(log::alevel::frame_header,general.str()); + m_alog.write(log::alevel::frame_header,header.str()); + m_alog.write(log::alevel::frame_payload,payload.str()); + } + } transport_con_type::async_write( m_send_buffer, - /*lib::bind( - &type::handle_write_frame, - type::get_shared(), - m_current_msg->get_terminal(), - lib::placeholders::_1 - )*/ m_write_frame_handler ); } @@ -1590,18 +1657,19 @@ void connection::handle_write_frame(lib::error_code const & ec) m_alog.write(log::alevel::devel,"connection handle_write_frame"); } - bool terminate = m_current_msg->get_terminal(); + bool terminal = m_current_msgs.back()->get_terminal(); m_send_buffer.clear(); - m_current_msg.reset(); + m_current_msgs.clear(); + // TODO: recycle instead of deleting if (ec) { - m_elog.write(log::elevel::fatal,"error in handle_write_frame: "+ec.message()); + log_err(log::elevel::fatal,"handle_write_frame",ec); this->terminate(ec); return; } - if (terminate) { + if (terminal) { this->terminate(lib::error_code()); return; } @@ -1625,30 +1693,27 @@ void connection::handle_write_frame(lib::error_code const & ec) } template -void connection::atomic_state_change(istate_type req, - istate_type dest, std::string msg) +void connection::atomic_state_change(istate_type req, istate_type dest, + std::string msg) { scoped_lock_type lock(m_connection_state_lock); if (m_internal_state != req) { - throw error::make_error_code(error::invalid_state); - //throw exception(msg,error::INVALID_STATE); + throw exception(msg,error::make_error_code(error::invalid_state)); } m_internal_state = dest; } template -void connection::atomic_state_change( - istate_type internal_req, istate_type internal_dest, - session::state::value external_req, session::state::value external_dest, - std::string msg) +void connection::atomic_state_change(istate_type internal_req, + istate_type internal_dest, session::state::value external_req, + session::state::value external_dest, std::string msg) { scoped_lock_type lock(m_connection_state_lock); if (m_internal_state != internal_req || m_state != external_req) { - throw error::make_error_code(error::invalid_state); - //throw exception(msg,error::INVALID_STATE); + throw exception(msg,error::make_error_code(error::invalid_state)); } m_internal_state = internal_dest; @@ -1656,14 +1721,12 @@ void connection::atomic_state_change( } template -void connection::atomic_state_check(istate_type req, - std::string msg) +void connection::atomic_state_check(istate_type req, std::string msg) { scoped_lock_type lock(m_connection_state_lock); if (m_internal_state != req) { - throw error::make_error_code(error::invalid_state); - //throw exception(msg,error::INVALID_STATE); + throw exception(msg,error::make_error_code(error::invalid_state)); } } @@ -1674,8 +1737,7 @@ const std::vector& connection::get_supported_versions() const } template -void connection::process_control_frame(typename - config::message_type::ptr msg) +void connection::process_control_frame(typename config::message_type::ptr msg) { m_alog.write(log::alevel::devel,"process_control_frame"); @@ -1696,17 +1758,16 @@ void connection::process_control_frame(typename } if (op == frame::opcode::PING) { - bool pong = true; + bool should_reply = true; if (m_ping_handler) { - pong = m_ping_handler(m_connection_hdl, msg->get_payload()); + should_reply = m_ping_handler(m_connection_hdl, msg->get_payload()); } - if (pong) { + if (should_reply) { this->pong(msg->get_payload(),ec); if (ec) { - m_elog.write(log::elevel::devel, - "Failed to send response pong: "+ec.message()); + log_err(log::elevel::devel,"Failed to send response pong",ec); } } } else if (op == frame::opcode::PONG) { @@ -1722,7 +1783,7 @@ void connection::process_control_frame(typename m_remote_close_code = close::extract_code(msg->get_payload(),ec); if (ec) { - std::stringstream s; + s.str(""); if (config::drop_on_protocol_error) { s << "Received invalid close code " << m_remote_close_code << " dropping connection per config."; @@ -1735,8 +1796,7 @@ void connection::process_control_frame(typename ec = send_close_ack(close::status::protocol_error, "Invalid close code"); if (ec) { - m_elog.write(log::elevel::devel, - "send_close_ack error: "+ec.message()); + log_err(log::elevel::devel,"send_close_ack",ec); } } return; @@ -1754,27 +1814,25 @@ void connection::process_control_frame(typename ec = send_close_ack(close::status::protocol_error, "Invalid close reason"); if (ec) { - m_elog.write(log::elevel::devel, - "send_close_ack error: "+ec.message()); + log_err(log::elevel::devel,"send_close_ack",ec); } } return; } if (m_state == session::state::open) { - std::stringstream s; + s.str(""); s << "Received close frame with code " << m_remote_close_code << " and reason " << m_remote_close_reason; m_alog.write(log::alevel::devel,s.str()); ec = send_close_ack(); if (ec) { - m_elog.write(log::elevel::devel, - "send_close_ack error: "+ec.message()); + log_err(log::elevel::devel,"send_close_ack",ec); } } else if (m_state == session::state::closing && !m_was_clean) { // ack of our close - m_alog.write(log::alevel::devel,"Got acknowledgement of close"); + m_alog.write(log::alevel::devel, "Got acknowledgement of close"); m_was_clean = true; @@ -1790,11 +1848,11 @@ void connection::process_control_frame(typename } } else { // spurious, ignore - m_elog.write(log::elevel::devel,"Got close frame in wrong state"); + m_elog.write(log::elevel::devel, "Got close frame in wrong state"); } } else { // got an invalid control opcode - m_elog.write(log::elevel::devel,"Got control frame with invalid opcode"); + m_elog.write(log::elevel::devel, "Got control frame with invalid opcode"); // initiate protocol error shutdown } } @@ -1906,49 +1964,49 @@ template typename connection::processor_ptr connection::get_processor(int version) const { // TODO: allow disabling certain versions + + processor_ptr p; + switch (version) { case 0: - return processor_ptr( - new processor::hybi00( - transport_con_type::is_secure(), - m_is_server, - m_msg_manager - ) + p = lib::make_shared >( + transport_con_type::is_secure(), + m_is_server, + m_msg_manager ); break; case 7: - return processor_ptr( - new processor::hybi07( - transport_con_type::is_secure(), - m_is_server, - m_msg_manager, - m_rng - ) + p = lib::make_shared >( + transport_con_type::is_secure(), + m_is_server, + m_msg_manager, + lib::ref(m_rng) ); break; case 8: - return processor_ptr( - new processor::hybi08( - transport_con_type::is_secure(), - m_is_server, - m_msg_manager, - m_rng - ) + p = lib::make_shared >( + transport_con_type::is_secure(), + m_is_server, + m_msg_manager, + lib::ref(m_rng) ); break; case 13: - return processor_ptr( - new processor::hybi13( - transport_con_type::is_secure(), - m_is_server, - m_msg_manager, - m_rng - ) + p = lib::make_shared >( + transport_con_type::is_secure(), + m_is_server, + m_msg_manager, + lib::ref(m_rng) ); break; default: - return processor_ptr(); + return p; } + + // Settings not configured by the constructor + p->set_max_message_size(m_max_message_size); + + return p; } template @@ -1961,10 +2019,12 @@ void connection::write_push(typename config::message_type::ptr msg) m_send_buffer_size += msg->get_payload().size(); m_send_queue.push(msg); - std::stringstream s; - s << "write_push: message count: " << m_send_queue.size() - << " buffer size: " << m_send_buffer_size; - m_alog.write(log::alevel::devel,s.str()); + if (m_alog.static_test(log::alevel::devel)) { + std::stringstream s; + s << "write_push: message count: " << m_send_queue.size() + << " buffer size: " << m_send_buffer_size; + m_alog.write(log::alevel::devel,s.str()); + } } template @@ -1981,10 +2041,12 @@ typename config::message_type::ptr connection::write_pop() m_send_buffer_size -= msg->get_payload().size(); m_send_queue.pop(); - std::stringstream s; - s << "write_pop: message count: " << m_send_queue.size() - << " buffer size: " << m_send_buffer_size; - m_alog.write(log::alevel::devel,s.str()); + if (m_alog.static_test(log::alevel::devel)) { + std::stringstream s; + s << "write_pop: message count: " << m_send_queue.size() + << " buffer size: " << m_send_buffer_size; + m_alog.write(log::alevel::devel,s.str()); + } return msg; } diff --git a/src/third_party/websocketpp/websocketpp/impl/endpoint_impl.hpp b/src/third_party/websocketpp/websocketpp/impl/endpoint_impl.hpp index 0dd14c5d..ca2a47e9 100644 --- a/src/third_party/websocketpp/websocketpp/impl/endpoint_impl.hpp +++ b/src/third_party/websocketpp/websocketpp/impl/endpoint_impl.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -42,8 +42,8 @@ endpoint::create_connection() { //scoped_lock_type guard(m_mutex); // Create a connection on the heap and manage it using a shared pointer - connection_ptr con(new connection_type(m_is_server,m_user_agent,m_alog, - m_elog, m_rng)); + connection_ptr con = lib::make_shared(m_is_server, + m_user_agent, lib::ref(m_alog), lib::ref(m_elog), lib::ref(m_rng)); connection_weak_ptr w(con); @@ -64,16 +64,19 @@ endpoint::create_connection() { con->set_http_handler(m_http_handler); con->set_validate_handler(m_validate_handler); con->set_message_handler(m_message_handler); - - if (m_open_handshake_timeout_dur == config::timeout_open_handshake) { + + if (m_open_handshake_timeout_dur != config::timeout_open_handshake) { con->set_open_handshake_timeout(m_open_handshake_timeout_dur); } - if (m_close_handshake_timeout_dur == config::timeout_close_handshake) { + if (m_close_handshake_timeout_dur != config::timeout_close_handshake) { con->set_close_handshake_timeout(m_close_handshake_timeout_dur); } - if (m_pong_timeout_dur == config::timeout_pong) { + if (m_pong_timeout_dur != config::timeout_pong) { con->set_pong_timeout(m_pong_timeout_dur); } + if (m_max_message_size != config::max_message_size) { + con->set_max_message_size(m_max_message_size); + } lib::error_code ec; @@ -87,8 +90,7 @@ endpoint::create_connection() { } template -void endpoint::interrupt(connection_hdl hdl, - lib::error_code & ec) +void endpoint::interrupt(connection_hdl hdl, lib::error_code & ec) { connection_ptr con = get_con_from_hdl(hdl,ec); if (ec) {return;} @@ -102,12 +104,46 @@ template void endpoint::interrupt(connection_hdl hdl) { lib::error_code ec; interrupt(hdl,ec); - if (ec) { throw ec; } + if (ec) { throw exception(ec); } } template -void endpoint::send(connection_hdl hdl, std::string const & - payload, frame::opcode::value op, lib::error_code & ec) +void endpoint::pause_reading(connection_hdl hdl, lib::error_code & ec) +{ + connection_ptr con = get_con_from_hdl(hdl,ec); + if (ec) {return;} + + ec = con->pause_reading(); +} + +template +void endpoint::pause_reading(connection_hdl hdl) { + lib::error_code ec; + pause_reading(hdl,ec); + if (ec) { throw exception(ec); } +} + +template +void endpoint::resume_reading(connection_hdl hdl, lib::error_code & ec) +{ + connection_ptr con = get_con_from_hdl(hdl,ec); + if (ec) {return;} + + ec = con->resume_reading(); +} + +template +void endpoint::resume_reading(connection_hdl hdl) { + lib::error_code ec; + resume_reading(hdl,ec); + if (ec) { throw exception(ec); } +} + + + +template +void endpoint::send(connection_hdl hdl, std::string const & payload, + frame::opcode::value op, lib::error_code & ec) { connection_ptr con = get_con_from_hdl(hdl,ec); if (ec) {return;} @@ -116,12 +152,12 @@ void endpoint::send(connection_hdl hdl, std::string const & } template -void endpoint::send(connection_hdl hdl, std::string const & - payload, frame::opcode::value op) +void endpoint::send(connection_hdl hdl, std::string const & payload, + frame::opcode::value op) { lib::error_code ec; send(hdl,payload,op,ec); - if (ec) { throw ec; } + if (ec) { throw exception(ec); } } template @@ -139,7 +175,7 @@ void endpoint::send(connection_hdl hdl, void const * payload, { lib::error_code ec; send(hdl,payload,len,op,ec); - if (ec) { throw ec; } + if (ec) { throw exception(ec); } } template @@ -155,7 +191,7 @@ template void endpoint::send(connection_hdl hdl, message_ptr msg) { lib::error_code ec; send(hdl,msg,ec); - if (ec) { throw ec; } + if (ec) { throw exception(ec); } } template @@ -174,7 +210,7 @@ void endpoint::close(connection_hdl hdl, close::status::value { lib::error_code ec; close(hdl,code,reason,ec); - if (ec) { throw ec; } + if (ec) { throw exception(ec); } } template @@ -187,17 +223,16 @@ void endpoint::ping(connection_hdl hdl, std::string const & } template -void endpoint::ping(connection_hdl hdl, std::string const & - payload) +void endpoint::ping(connection_hdl hdl, std::string const & payload) { lib::error_code ec; ping(hdl,payload,ec); - if (ec) { throw ec; } + if (ec) { throw exception(ec); } } template -void endpoint::pong(connection_hdl hdl, std::string const & - payload, lib::error_code & ec) +void endpoint::pong(connection_hdl hdl, std::string const & payload, + lib::error_code & ec) { connection_ptr con = get_con_from_hdl(hdl,ec); if (ec) {return;} @@ -205,12 +240,11 @@ void endpoint::pong(connection_hdl hdl, std::string const & } template -void endpoint::pong(connection_hdl hdl, std::string const & - payload) +void endpoint::pong(connection_hdl hdl, std::string const & payload) { lib::error_code ec; pong(hdl,payload,ec); - if (ec) { throw ec; } + if (ec) { throw exception(ec); } } } // namespace websocketpp diff --git a/src/third_party/websocketpp/websocketpp/impl/utilities_impl.hpp b/src/third_party/websocketpp/websocketpp/impl/utilities_impl.hpp index 368b8681..3682a501 100644 --- a/src/third_party/websocketpp/websocketpp/impl/utilities_impl.hpp +++ b/src/third_party/websocketpp/websocketpp/impl/utilities_impl.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/third_party/websocketpp/websocketpp/logger/basic.hpp b/src/third_party/websocketpp/websocketpp/logger/basic.hpp index 678c7246..1005774c 100644 --- a/src/third_party/websocketpp/websocketpp/logger/basic.hpp +++ b/src/third_party/websocketpp/websocketpp/logger/basic.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -46,6 +46,7 @@ #include #include +#include #include namespace websocketpp { @@ -55,12 +56,24 @@ namespace log { template class basic { public: - basic(std::ostream * out = &std::cout) + basic(channel_type_hint::value h = + channel_type_hint::access) + : m_static_channels(0xffffffff) + , m_dynamic_channels(0) + , m_out(h == channel_type_hint::error ? &std::cerr : &std::cout) {} + + basic(std::ostream * out) : m_static_channels(0xffffffff) , m_dynamic_channels(0) , m_out(out) {} - basic(level c, std::ostream * out = &std::cout) + basic(level c, channel_type_hint::value h = + channel_type_hint::access) + : m_static_channels(c) + , m_dynamic_channels(0) + , m_out(h == channel_type_hint::error ? &std::cerr : &std::cout) {} + + basic(level c, std::ostream * out) : m_static_channels(c) , m_dynamic_channels(0) , m_out(out) {} @@ -120,13 +133,13 @@ private: // TODO: find a workaround for this or make this format user settable static std::ostream & timestamp(std::ostream & os) { std::time_t t = std::time(NULL); - std::tm* lt = std::localtime(&t); - #ifdef _WEBSOCKETPP_CPP11_CHRONO_ - return os << std::put_time(lt,"%Y-%m-%d %H:%M:%S"); + std::tm lt = lib::localtime(t); + #ifdef _WEBSOCKETPP_PUTTIME_ + return os << std::put_time(<,"%Y-%m-%d %H:%M:%S"); #else // Falls back to strftime, which requires a temporary copy of the string. char buffer[20]; - std::strftime(buffer,sizeof(buffer),"%Y-%m-%d %H:%M:%S",lt); - return os << buffer; + size_t result = std::strftime(buffer,sizeof(buffer),"%Y-%m-%d %H:%M:%S",<); + return os << (result == 0 ? "Unknown" : buffer); #endif } diff --git a/src/third_party/websocketpp/websocketpp/logger/levels.hpp b/src/third_party/websocketpp/websocketpp/logger/levels.hpp index 2c0e92c9..a774aadf 100644 --- a/src/third_party/websocketpp/websocketpp/logger/levels.hpp +++ b/src/third_party/websocketpp/websocketpp/logger/levels.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -36,6 +36,25 @@ namespace log { /// Type of a channel package typedef uint32_t level; +/// Package of values for hinting at the nature of a given logger. +/** + * Used by the library to signal to the logging class a hint that it can use to + * set itself up. For example, the `access` hint indicates that it is an access + * log that might be suitable for being printed to an access log file or to cout + * whereas `error` might be suitable for an error log file or cerr. + */ +struct channel_type_hint { + /// Type of a channel type hint value + typedef uint32_t value; + + /// No information + static value const none = 0; + /// Access log + static value const access = 1; + /// Error log + static value const error = 2; +}; + /// Package of log levels for logging errors struct elevel { /// Special aggregate value representing "no levels" diff --git a/src/third_party/websocketpp/websocketpp/logger/stub.hpp b/src/third_party/websocketpp/websocketpp/logger/stub.hpp index 4608d35b..d9ba6ff9 100644 --- a/src/third_party/websocketpp/websocketpp/logger/stub.hpp +++ b/src/third_party/websocketpp/websocketpp/logger/stub.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -28,7 +28,7 @@ #ifndef WEBSOCKETPP_LOGGER_STUB_HPP #define WEBSOCKETPP_LOGGER_STUB_HPP -#include +#include #include #include @@ -39,20 +39,75 @@ namespace log { /// Stub logger that ignores all input class stub { public: - explicit stub(std::ostream * out) {} - stub(level c, std::ostream * out) {} + /// Construct the logger + /** + * @param hint A channel type specific hint for how to construct the logger + */ + explicit stub(channel_type_hint::value) {} + + /// Construct the logger + /** + * @param default_channels A set of channels to statically enable + * @param hint A channel type specific hint for how to construct the logger + */ + stub(level, channel_type_hint::value) {} _WEBSOCKETPP_CONSTEXPR_TOKEN_ stub() {} - void set_channels(level channels) {} - void clear_channels(level channels) {} + /// Dynamically enable the given list of channels + /** + * All operations on the stub logger are no-ops and all arguments are + * ignored + * + * @param channels The package of channels to enable + */ + void set_channels(level) {} + + /// Dynamically disable the given list of channels + /** + * All operations on the stub logger are no-ops and all arguments are + * ignored + * + * @param channels The package of channels to disable + */ + void clear_channels(level) {} - void write(level channel, std::string const & msg) {} - void write(level channel, char const * msg) {} + /// Write a string message to the given channel + /** + * Writing on the stub logger is a no-op and all arguments are ignored + * + * @param channel The package of channels to write to + * @param msg The message to write + */ + void write(level, std::string const &) {} + + /// Write a cstring message to the given channel + /** + * Writing on the stub logger is a no-op and all arguments are ignored + * + * @param channel The package of channels to write to + * @param msg The message to write + */ + void write(level, char const *) {} - _WEBSOCKETPP_CONSTEXPR_TOKEN_ bool static_test(level channel) const { + /// Test whether a channel is statically enabled + /** + * The stub logger has no channels so all arguments are ignored and + * `static_test` always returns false. + * + * @param channel The package of channels to test + */ + _WEBSOCKETPP_CONSTEXPR_TOKEN_ bool static_test(level) const { return false; } - bool dynamic_test(level channel) { + + /// Test whether a channel is dynamically enabled + /** + * The stub logger has no channels so all arguments are ignored and + * `dynamic_test` always returns false. + * + * @param channel The package of channels to test + */ + bool dynamic_test(level) { return false; } }; diff --git a/src/third_party/websocketpp/websocketpp/message_buffer/alloc.hpp b/src/third_party/websocketpp/websocketpp/message_buffer/alloc.hpp index 5ac0ed43..75d89766 100644 --- a/src/third_party/websocketpp/websocketpp/message_buffer/alloc.hpp +++ b/src/third_party/websocketpp/websocketpp/message_buffer/alloc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -53,7 +53,7 @@ public: * @return A shared pointer to an empty new message */ message_ptr get_message() { - return message_ptr(new message(type::shared_from_this())); + return message_ptr(lib::make_shared(type::shared_from_this())); } /// Get a message buffer with specified size and opcode @@ -64,7 +64,7 @@ public: * @return A shared pointer to a new message with specified size. */ message_ptr get_message(frame::opcode::value op,size_t size) { - return message_ptr(new message(type::shared_from_this(),op,size)); + return message_ptr(lib::make_shared(type::shared_from_this(),op,size)); } /// Recycle a message @@ -77,7 +77,7 @@ public: * * @return true if the message was successfully recycled, false otherwse. */ - bool recycle(message * msg) { + bool recycle(message *) { return false; } }; @@ -94,7 +94,7 @@ public: * @return A pointer to the requested connection message manager. */ con_msg_man_ptr get_manager() const { - return con_msg_man_ptr(new con_msg_manager()); + return con_msg_man_ptr(lib::make_shared()); } }; diff --git a/src/third_party/websocketpp/websocketpp/message_buffer/message.hpp b/src/third_party/websocketpp/websocketpp/message_buffer/message.hpp index e7839c8a..fd70d6bd 100644 --- a/src/third_party/websocketpp/websocketpp/message_buffer/message.hpp +++ b/src/third_party/websocketpp/websocketpp/message_buffer/message.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/third_party/websocketpp/websocketpp/message_buffer/pool.hpp b/src/third_party/websocketpp/websocketpp/message_buffer/pool.hpp index 46e24013..7b82fd21 100644 --- a/src/third_party/websocketpp/websocketpp/message_buffer/pool.hpp +++ b/src/third_party/websocketpp/websocketpp/message_buffer/pool.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -171,7 +171,7 @@ public: * @return A shared pointer to a new message with specified size. */ message_ptr get_message(size_t size) const { - return message_ptr(new message(size)); + return lib::make_shared(size); } /// Recycle a message @@ -201,7 +201,7 @@ public: * @return A pointer to the requested connection message manager. */ con_msg_man_ptr get_manager() const { - return con_msg_man_ptr(new con_msg_manager()); + return lib::make_shared(); } }; diff --git a/src/third_party/websocketpp/websocketpp/processors/base.hpp b/src/third_party/websocketpp/websocketpp/processors/base.hpp index e455e842..66cfc6aa 100644 --- a/src/third_party/websocketpp/websocketpp/processors/base.hpp +++ b/src/third_party/websocketpp/websocketpp/processors/base.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/third_party/websocketpp/websocketpp/processors/hybi00.hpp b/src/third_party/websocketpp/websocketpp/processors/hybi00.hpp index 27d0f936..704f8266 100644 --- a/src/third_party/websocketpp/websocketpp/processors/hybi00.hpp +++ b/src/third_party/websocketpp/websocketpp/processors/hybi00.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -34,6 +34,7 @@ #include #include #include +#include #include @@ -57,8 +58,8 @@ public: typedef typename config::con_msg_manager_type::ptr msg_manager_ptr; - explicit hybi00(bool secure, bool server, msg_manager_ptr manager) - : processor(secure, server) + explicit hybi00(bool secure, bool p_is_server, msg_manager_ptr manager) + : processor(secure, p_is_server) , msg_hdr(0x00) , msg_ftr(0xff) , m_state(HEADER) @@ -109,7 +110,7 @@ public: // of warning or exception. const std::string& key3 = req.get_header("Sec-WebSocket-Key3"); std::copy(key3.c_str(), - key3.c_str()+std::min(static_cast(8), key3.size()), + key3.c_str()+(std::min)(static_cast(8), key3.size()), &key_final[8]); res.append_header( @@ -140,15 +141,32 @@ public: return lib::error_code(); } - // outgoing client connection processing is not supported for this version - lib::error_code client_handshake_request(request_type& req, uri_ptr uri, - std::vector const & subprotocols) const + /// Fill in a set of request headers for a client connection request + /** + * The Hybi 00 processor only implements incoming connections so this will + * always return an error. + * + * @param [out] req Set of headers to fill in + * @param [in] uri The uri being connected to + * @param [in] subprotocols The list of subprotocols to request + */ + lib::error_code client_handshake_request(request_type &, uri_ptr, + std::vector const &) const { return error::make_error_code(error::no_protocol_support); } - lib::error_code validate_server_handshake_response(request_type const & req, - response_type & res) const + /// Validate the server's response to an outgoing handshake request + /** + * The Hybi 00 processor only implements incoming connections so this will + * always return an error. + * + * @param req The original request sent + * @param res The reponse to generate + * @return An error code, 0 on success, non-zero for other errors + */ + lib::error_code validate_server_handshake_response(request_type const &, + response_type &) const { return error::make_error_code(error::no_protocol_support); } @@ -163,9 +181,16 @@ public: return r.get_header("Origin"); } - // hybi00 doesn't support subprotocols so there never will be any requested - lib::error_code extract_subprotocols(request_type const & req, - std::vector & subprotocol_list) + /// Extracts requested subprotocols from a handshake request + /** + * hybi00 doesn't support subprotocols so there never will be any requested + * + * @param [in] req The request to extract from + * @param [out] subprotocol_list A reference to a vector of strings to store + * the results in. + */ + lib::error_code extract_subprotocols(request_type const &, + std::vector &) { return lib::error_code(); } @@ -184,12 +209,12 @@ public: if (last_colon == std::string::npos || (last_sbrace != std::string::npos && last_sbrace > last_colon)) { - return uri_ptr(new uri(base::m_secure, h, request.get_uri())); + return lib::make_shared(base::m_secure, h, request.get_uri()); } else { - return uri_ptr(new uri(base::m_secure, + return lib::make_shared(base::m_secure, h.substr(0,last_colon), h.substr(last_colon+1), - request.get_uri())); + request.get_uri()); } // TODO: check if get_uri is a full uri @@ -318,18 +343,44 @@ public: return lib::error_code(); } - lib::error_code prepare_ping(std::string const & in, message_ptr out) const + /// Prepare a ping frame + /** + * Hybi 00 doesn't support pings so this will always return an error + * + * @param in The string to use for the ping payload + * @param out The message buffer to prepare the ping in. + * @return Status code, zero on success, non-zero on failure + */ + lib::error_code prepare_ping(std::string const &, message_ptr) const { return lib::error_code(error::no_protocol_support); } - lib::error_code prepare_pong(const std::string & in, message_ptr out) const + /// Prepare a pong frame + /** + * Hybi 00 doesn't support pongs so this will always return an error + * + * @param in The string to use for the pong payload + * @param out The message buffer to prepare the pong in. + * @return Status code, zero on success, non-zero on failure + */ + lib::error_code prepare_pong(const std::string &, message_ptr) const { return lib::error_code(error::no_protocol_support); } - lib::error_code prepare_close(close::status::value code, - std::string const & reason, message_ptr out) const + /// Prepare a close frame + /** + * Hybi 00 doesn't support the close code or reason so these parameters are + * ignored. + * + * @param code The close code to send + * @param reason The reason string to send + * @param out The message buffer to prepare the fame in + * @return Status code, zero on success, non-zero on failure + */ + lib::error_code prepare_close(close::status::value, std::string const &, + message_ptr out) const { if (!out) { return lib::error_code(error::invalid_arguments); diff --git a/src/third_party/websocketpp/websocketpp/processors/hybi07.hpp b/src/third_party/websocketpp/websocketpp/processors/hybi07.hpp index 8b2df0ee..59b6f559 100644 --- a/src/third_party/websocketpp/websocketpp/processors/hybi07.hpp +++ b/src/third_party/websocketpp/websocketpp/processors/hybi07.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -45,13 +45,20 @@ public: typedef typename config::con_msg_manager_type::ptr msg_manager_ptr; typedef typename config::rng_type rng_type; - explicit hybi07(bool secure, bool server, msg_manager_ptr manager, - rng_type& rng) - : hybi08(secure, server, manager, rng) {} + explicit hybi07(bool secure, bool p_is_server, msg_manager_ptr manager, rng_type& rng) + : hybi08(secure, p_is_server, manager, rng) {} - // outgoing client connection processing is not supported for this version - lib::error_code client_handshake_request(request_type & req, uri_ptr uri, - std::vector const & subprotocols) const + /// Fill in a set of request headers for a client connection request + /** + * The Hybi 07 processor only implements incoming connections so this will + * always return an error. + * + * @param [out] req Set of headers to fill in + * @param [in] uri The uri being connected to + * @param [in] subprotocols The list of subprotocols to request + */ + lib::error_code client_handshake_request(request_type &, uri_ptr, + std::vector const &) const { return error::make_error_code(error::no_protocol_support); } diff --git a/src/third_party/websocketpp/websocketpp/processors/hybi08.hpp b/src/third_party/websocketpp/websocketpp/processors/hybi08.hpp index 54f21036..7e9337d8 100644 --- a/src/third_party/websocketpp/websocketpp/processors/hybi08.hpp +++ b/src/third_party/websocketpp/websocketpp/processors/hybi08.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -46,13 +46,20 @@ public: typedef typename config::con_msg_manager_type::ptr msg_manager_ptr; typedef typename config::rng_type rng_type; - explicit hybi08(bool secure, bool server, msg_manager_ptr manager, - rng_type& rng) - : hybi13(secure, server, manager, rng) {} + explicit hybi08(bool secure, bool p_is_server, msg_manager_ptr manager, rng_type& rng) + : hybi13(secure, p_is_server, manager, rng) {} - // outgoing client connection processing is not supported for this version - lib::error_code client_handshake_request(request_type& req, uri_ptr uri, - std::vector const & subprotocols) const + /// Fill in a set of request headers for a client connection request + /** + * The Hybi 08 processor only implements incoming connections so this will + * always return an error. + * + * @param [out] req Set of headers to fill in + * @param [in] uri The uri being connected to + * @param [in] subprotocols The list of subprotocols to request + */ + lib::error_code client_handshake_request(request_type &, uri_ptr, + std::vector const &) const { return error::make_error_code(error::no_protocol_support); } diff --git a/src/third_party/websocketpp/websocketpp/processors/hybi13.hpp b/src/third_party/websocketpp/websocketpp/processors/hybi13.hpp index b6b984fe..cb98286c 100644 --- a/src/third_party/websocketpp/websocketpp/processors/hybi13.hpp +++ b/src/third_party/websocketpp/websocketpp/processors/hybi13.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -67,9 +68,8 @@ public: typedef std::pair err_str_pair; - explicit hybi13(bool secure, bool server, msg_manager_ptr manager, - rng_type& rng) - : processor(secure,server) + explicit hybi13(bool secure, bool p_is_server, msg_manager_ptr manager, rng_type& rng) + : processor(secure, p_is_server) , m_msg_manager(manager) , m_rng(rng) { @@ -121,8 +121,8 @@ public: // Figure out if this is an error that should halt all // extension negotiations or simply cause negotiation of // this specific extension to fail. - std::cout << "permessage-compress negotiation failed: " - << neg_ret.first.message() << std::endl; + //std::cout << "permessage-compress negotiation failed: " + // << neg_ret.first.message() << std::endl; } else { // Note: this list will need commas if WebSocket++ ever // supports more than one extension @@ -182,7 +182,13 @@ public: return lib::error_code(); } - lib::error_code client_handshake_request(request_type& req, uri_ptr + /// Fill in a set of request headers for a client connection request + /** + * @param [out] req Set of headers to fill in + * @param [in] uri The uri being connected to + * @param [in] subprotocols The list of subprotocols to request + */ + lib::error_code client_handshake_request(request_type & req, uri_ptr uri, std::vector const & subprotocols) const { req.set_method("GET"); @@ -219,6 +225,12 @@ public: return lib::error_code(); } + /// Validate the server's response to an outgoing handshake request + /** + * @param req The original request sent + * @param res The reponse to generate + * @return An error code, 0 on success, non-zero for other errors + */ lib::error_code validate_server_handshake_response(request_type const & req, response_type& res) const { @@ -369,11 +381,25 @@ public: m_current_msg = &m_control_msg; } else { if (!m_data_msg.msg_ptr) { + if (m_bytes_needed > base::m_max_message_size) { + ec = make_error_code(error::message_too_big); + break; + } + m_data_msg = msg_metadata( m_msg_manager->get_message(op,m_bytes_needed), frame::get_masking_key(m_basic_header,m_extended_header) ); } else { + // Fetch the underlying payload buffer from the data message we + // are writing into. + std::string & out = m_data_msg.msg_ptr->get_raw_payload(); + + if (out.size() + m_bytes_needed > base::m_max_message_size) { + ec = make_error_code(error::message_too_big); + break; + } + // Each frame starts a new masking key. All other state // remains between frames. m_data_msg.prepared_key = prepare_masking_key( @@ -382,14 +408,15 @@ public: m_extended_header ) ); - // TODO: reserve space in the existing message for the new bytes + + out.reserve(out.size() + m_bytes_needed); } m_current_msg = &m_data_msg; } } else if (m_state == EXTENSION) { m_state = APPLICATION; } else if (m_state == APPLICATION) { - size_t bytes_to_process = std::min(m_bytes_needed,len-p); + size_t bytes_to_process = (std::min)(m_bytes_needed,len-p); if (bytes_to_process > 0) { p += this->process_payload_bytes(buf+p,bytes_to_process,ec); @@ -655,7 +682,7 @@ protected: /// Reads bytes from buf into m_extended_header size_t copy_extended_header_bytes(uint8_t const * buf, size_t len) { - size_t bytes_to_read = std::min(m_bytes_needed,len); + size_t bytes_to_read = (std::min)(m_bytes_needed,len); std::copy(buf,buf+bytes_to_read,m_extended_header.bytes+m_cursor); m_cursor += bytes_to_read; diff --git a/src/third_party/websocketpp/websocketpp/processors/processor.hpp b/src/third_party/websocketpp/websocketpp/processors/processor.hpp index 6333b5b5..dc174a49 100644 --- a/src/third_party/websocketpp/websocketpp/processors/processor.hpp +++ b/src/third_party/websocketpp/websocketpp/processors/processor.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -140,12 +140,12 @@ uri_ptr get_uri_from_host(request_type & request, std::string scheme) { if (last_colon == std::string::npos || (last_sbrace != std::string::npos && last_sbrace > last_colon)) { - return uri_ptr(new uri(scheme, h, request.get_uri())); + return lib::make_shared(scheme, h, request.get_uri()); } else { - return uri_ptr(new uri(scheme, + return lib::make_shared(scheme, h.substr(0,last_colon), h.substr(last_colon+1), - request.get_uri())); + request.get_uri()); } } @@ -159,15 +159,45 @@ public: typedef typename config::message_type::ptr message_ptr; typedef std::pair err_str_pair; - explicit processor(bool secure, bool server) + explicit processor(bool secure, bool p_is_server) : m_secure(secure) - , m_server(server) {} + , m_server(p_is_server) + , m_max_message_size(config::max_message_size) + {} virtual ~processor() {} /// Get the protocol version of this processor virtual int get_version() const = 0; + /// Get maximum message size + /** + * Get maximum message size. Maximum message size determines the point at which the + * processor will fail a connection with the message_too_big protocol error. + * + * The default is retrieved from the max_message_size value from the template config + * + * @since 0.3.0 + */ + size_t get_max_message_size() const { + return m_max_message_size; + } + + /// Set maximum message size + /** + * Set maximum message size. Maximum message size determines the point at which the + * processor will fail a connection with the message_too_big protocol error. + * + * The default is retrieved from the max_message_size value from the template config + * + * @since 0.3.0 + * + * @param new_value The value to set as the maximum message size. + */ + void set_max_message_size(size_t new_value) { + m_max_message_size = new_value; + } + /// Returns whether or not the permessage_compress extension is implemented /** * Compile time flag that indicates whether this processor has implemented @@ -182,8 +212,10 @@ public: * Reads the Sec-WebSocket-Extensions header and determines if any of the * requested extensions are supported by this processor. If they are their * settings data is initialized. + * + * @param request The request headers to look at. */ - virtual err_str_pair negotiate_extensions(request_type const & request) { + virtual err_str_pair negotiate_extensions(request_type const &) { return err_str_pair(); } @@ -196,8 +228,7 @@ public: * @return A status code, 0 on success, non-zero for specific sorts of * failure */ - virtual lib::error_code validate_handshake(request_type const & request) - const = 0; + virtual lib::error_code validate_handshake(request_type const & request) const = 0; /// Calculate the appropriate response for this websocket request /** @@ -224,9 +255,7 @@ public: /// Validate the server's response to an outgoing handshake request /** * @param req The original request sent - * * @param res The reponse to generate - * * @return An error code, 0 on success, non-zero for other errors */ virtual lib::error_code validate_server_handshake_response(request_type @@ -236,18 +265,16 @@ public: virtual std::string get_raw(response_type const & request) const = 0; /// Return the value of the header containing the CORS origin. - virtual std::string const & get_origin(request_type const & request) - const = 0; + virtual std::string const & get_origin(request_type const & request) const = 0; /// Extracts requested subprotocols from a handshake request /** * Extracts a list of all subprotocols that the client has requested in the * given opening handshake request. * - * @param req The request to extract from - * - * @param subprotocol_list A reference to a vector of strings to store the - * results in. + * @param [in] req The request to extract from + * @param [out] subprotocol_list A reference to a vector of strings to store + * the results in. */ virtual lib::error_code extract_subprotocols(const request_type & req, std::vector & subprotocol_list) = 0; @@ -261,11 +288,8 @@ public: * interpreted by a protocol processor into discrete frames. * * @param buf Buffer from which bytes should be read. - * * @param len Length of buffer - * * @param ec Reference to an error code to return any errors in - * * @return Number of bytes processed */ virtual size_t consume(uint8_t *buf, size_t len, lib::error_code & ec) = 0; @@ -310,8 +334,7 @@ public: * Performs validation, masking, compression, etc. will return an error if * there was an error, otherwise msg will be ready to be written */ - virtual lib::error_code prepare_data_frame(message_ptr in, message_ptr out) - = 0; + virtual lib::error_code prepare_data_frame(message_ptr in, message_ptr out) = 0; /// Prepare a ping frame /** @@ -319,13 +342,11 @@ public: * other than length. Payload need not be UTF-8. * * @param in The string to use for the ping payload - * * @param out The message buffer to prepare the ping in. - * * @return Status code, zero on success, non-zero on failure */ - virtual lib::error_code prepare_ping(std::string const & in, - message_ptr out) const = 0; + virtual lib::error_code prepare_ping(std::string const & in, message_ptr out) const + = 0; /// Prepare a pong frame /** @@ -333,13 +354,11 @@ public: * other than length. Payload need not be UTF-8. * * @param in The string to use for the pong payload - * * @param out The message buffer to prepare the pong in. - * * @return Status code, zero on success, non-zero on failure */ - virtual lib::error_code prepare_pong(std::string const & in, - message_ptr out) const = 0; + virtual lib::error_code prepare_pong(std::string const & in, message_ptr out) const + = 0; /// Prepare a close frame /** @@ -349,11 +368,8 @@ public: * indicate no code. If no code is supplied a reason may not be specified. * * @param code The close code to send - * * @param reason The reason string to send - * * @param out The message buffer to prepare the fame in - * * @return Status code, zero on success, non-zero on failure */ virtual lib::error_code prepare_close(close::status::value code, @@ -361,6 +377,7 @@ public: protected: bool const m_secure; bool const m_server; + size_t m_max_message_size; }; } // namespace processor diff --git a/src/third_party/websocketpp/websocketpp/random/none.hpp b/src/third_party/websocketpp/websocketpp/random/none.hpp index 60fe7728..2163e6f4 100644 --- a/src/third_party/websocketpp/websocketpp/random/none.hpp +++ b/src/third_party/websocketpp/websocketpp/random/none.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -29,6 +29,7 @@ #define WEBSOCKETPP_RANDOM_NONE_HPP namespace websocketpp { +/// Random number generation policies namespace random { /// Stub RNG policy that always returns 0 namespace none { diff --git a/src/third_party/websocketpp/websocketpp/random/random_device.hpp b/src/third_party/websocketpp/websocketpp/random/random_device.hpp index 7645399b..91e7dd16 100644 --- a/src/third_party/websocketpp/websocketpp/random/random_device.hpp +++ b/src/third_party/websocketpp/websocketpp/random/random_device.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/third_party/websocketpp/websocketpp/roles/client_endpoint.hpp b/src/third_party/websocketpp/websocketpp/roles/client_endpoint.hpp index 1072a0f3..22c7da10 100644 --- a/src/third_party/websocketpp/websocketpp/roles/client_endpoint.hpp +++ b/src/third_party/websocketpp/websocketpp/roles/client_endpoint.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -112,7 +112,7 @@ public: * @return A connection_ptr to the new connection */ connection_ptr get_connection(std::string const & u, lib::error_code & ec) { - uri_ptr location(new uri(u)); + uri_ptr location = lib::make_shared(u); if (!location->get_valid()) { ec = error::make_error_code(error::invalid_uri); diff --git a/src/third_party/websocketpp/websocketpp/roles/server_endpoint.hpp b/src/third_party/websocketpp/websocketpp/roles/server_endpoint.hpp index 77f1c291..e92cbf0a 100644 --- a/src/third_party/websocketpp/websocketpp/roles/server_endpoint.hpp +++ b/src/third_party/websocketpp/websocketpp/roles/server_endpoint.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -64,52 +64,101 @@ public: /// Type of the endpoint component of this server typedef endpoint endpoint_type; - - // TODO: clean up these types - explicit server() : endpoint_type(true) { - endpoint_type::m_alog.write(log::alevel::devel, - "server constructor"); + endpoint_type::m_alog.write(log::alevel::devel, "server constructor"); } - // return an initialized connection_ptr. Call start() on this object to - // begin the processing loop. + /// Create and initialize a new connection + /** + * The connection will be initialized and ready to begin. Call its start() + * method to begin the processing loop. + * + * Note: The connection must either be started or terminated using + * connection::terminate in order to avoid memory leaks. + * + * @return A pointer to the new connection. + */ connection_ptr get_connection() { - connection_ptr con = endpoint_type::create_connection(); - - return con; + return endpoint_type::create_connection(); } - // Starts the server's async connection acceptance loop. - void start_accept() { + /// Starts the server's async connection acceptance loop (exception free) + /** + * Initiates the server connection acceptance loop. Must be called after + * listen. This method will have no effect until the underlying io_service + * starts running. It may be called after the io_service is already running. + * + * Refer to documentation for the transport policy you are using for + * instructions on how to stop this acceptance loop. + * + * @param [out] ec A status code indicating an error, if any. + */ + void start_accept(lib::error_code & ec) { + if (!transport_type::is_listening()) { + ec = error::make_error_code(error::async_accept_not_listening); + return; + } + + ec = lib::error_code(); connection_ptr con = get_connection(); - + transport_type::async_accept( lib::static_pointer_cast(con), - lib::bind( - &type::handle_accept, - this, - con, - lib::placeholders::_1 - ) + lib::bind(&type::handle_accept,this,con,lib::placeholders::_1), + ec ); + + if (ec && con) { + // If the connection was constructed but the accept failed, + // terminate the connection to prevent memory leaks + con->terminate(lib::error_code()); + } } - void handle_accept(connection_ptr con, const lib::error_code& ec) { + /// Starts the server's async connection acceptance loop + /** + * Initiates the server connection acceptance loop. Must be called after + * listen. This method will have no effect until the underlying io_service + * starts running. It may be called after the io_service is already running. + * + * Refer to documentation for the transport policy you are using for + * instructions on how to stop this acceptance loop. + */ + void start_accept() { + lib::error_code ec; + start_accept(ec); + if (ec) { + throw exception(ec); + } + } + + /// Handler callback for start_accept + void handle_accept(connection_ptr con, lib::error_code const & ec) { if (ec) { con->terminate(ec); - endpoint_type::m_elog.write(log::elevel::rerror, - "handle_accept error: "+ec.message()); + if (ec == error::operation_canceled) { + endpoint_type::m_elog.write(log::elevel::info, + "handle_accept error: "+ec.message()); + } else { + endpoint_type::m_elog.write(log::elevel::rerror, + "handle_accept error: "+ec.message()); + } } else { con->start(); } - // TODO: are there cases where we should terminate this loop? - start_accept(); + lib::error_code start_ec; + start_accept(start_ec); + if (start_ec == error::async_accept_not_listening) { + endpoint_type::m_elog.write(log::elevel::info, + "Stopping acceptance of new connections because the underlying transport is no longer listening."); + } else if (start_ec) { + endpoint_type::m_elog.write(log::elevel::rerror, + "Restarting async_accept loop failed: "+ec.message()); + } } -private: }; } // namespace websocketpp diff --git a/src/third_party/websocketpp/websocketpp/server.hpp b/src/third_party/websocketpp/websocketpp/server.hpp index 50d33d10..342fa8c5 100644 --- a/src/third_party/websocketpp/websocketpp/server.hpp +++ b/src/third_party/websocketpp/websocketpp/server.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/third_party/websocketpp/websocketpp/sha1/sha1.hpp b/src/third_party/websocketpp/websocketpp/sha1/sha1.hpp old mode 100644 new mode 100755 index fd4f0760..43a84338 --- a/src/third_party/websocketpp/websocketpp/sha1/sha1.hpp +++ b/src/third_party/websocketpp/websocketpp/sha1/sha1.hpp @@ -1,184 +1,189 @@ -/* -***** -sha1.hpp is a repackaging of the sha1.cpp and sha1.h files from the shallsha1 -library (http://code.google.com/p/smallsha1/) into a single header suitable for -use as a header only library. This conversion was done by Peter Thorson -(webmaster@zaphoyd.com) in 2013. All modifications to the code are redistributed -under the same license as the original, which is listed below. -***** - - Copyright (c) 2011, Micael Hildenborg - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of Micael Hildenborg nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef SHA1_DEFINED -#define SHA1_DEFINED - -namespace websocketpp { -namespace sha1 { - - namespace // local - { - // Rotate an integer value to left. - inline const unsigned int rol(const unsigned int value, - const unsigned int steps) - { - return ((value << steps) | (value >> (32 - steps))); - } - - // Sets the first 16 integers in the buffert to zero. - // Used for clearing the W buffert. - inline void clearWBuffert(unsigned int* buffert) - { - for (int pos = 16; --pos >= 0;) - { - buffert[pos] = 0; - } - } - - inline void innerHash(unsigned int* result, unsigned int* w) - { - unsigned int a = result[0]; - unsigned int b = result[1]; - unsigned int c = result[2]; - unsigned int d = result[3]; - unsigned int e = result[4]; - - int round = 0; - - #define sha1macro(func,val) \ - { \ - const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \ - e = d; \ - d = c; \ - c = rol(b, 30); \ - b = a; \ - a = t; \ - } - - while (round < 16) - { - sha1macro((b & c) | (~b & d), 0x5a827999) - ++round; - } - while (round < 20) - { - w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); - sha1macro((b & c) | (~b & d), 0x5a827999) - ++round; - } - while (round < 40) - { - w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); - sha1macro(b ^ c ^ d, 0x6ed9eba1) - ++round; - } - while (round < 60) - { - w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); - sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc) - ++round; - } - while (round < 80) - { - w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); - sha1macro(b ^ c ^ d, 0xca62c1d6) - ++round; - } - - #undef sha1macro - - result[0] += a; - result[1] += b; - result[2] += c; - result[3] += d; - result[4] += e; - } - } // namespace - - /** - @param src points to any kind of data to be hashed. - @param bytelength the number of bytes to hash from the src pointer. - @param hash should point to a buffer of at least 20 bytes of size for storing the sha1 result in. - */ - inline void calc(const void* src, const int bytelength, unsigned char* hash) { - // Init the result array. - unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 }; - - // Cast the void src pointer to be the byte array we can work with. - const unsigned char* sarray = (const unsigned char*) src; - - // The reusable round buffer - unsigned int w[80]; - - // Loop through all complete 64byte blocks. - const int endOfFullBlocks = bytelength - 64; - int endCurrentBlock; - int currentBlock = 0; - - while (currentBlock <= endOfFullBlocks) - { - endCurrentBlock = currentBlock + 64; - - // Init the round buffer with the 64 byte block data. - for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4) - { - // This line will swap endian on big endian and keep endian on little endian. - w[roundPos++] = (unsigned int) sarray[currentBlock + 3] - | (((unsigned int) sarray[currentBlock + 2]) << 8) - | (((unsigned int) sarray[currentBlock + 1]) << 16) - | (((unsigned int) sarray[currentBlock]) << 24); - } - innerHash(result, w); - } - - // Handle the last and not full 64 byte block if existing. - endCurrentBlock = bytelength - currentBlock; - clearWBuffert(w); - int lastBlockBytes = 0; - for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes) - { - w[lastBlockBytes >> 2] |= (unsigned int) sarray[lastBlockBytes + currentBlock] << ((3 - (lastBlockBytes & 3)) << 3); - } - w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3); - if (endCurrentBlock >= 56) - { - innerHash(result, w); - clearWBuffert(w); - } - w[15] = bytelength << 3; - innerHash(result, w); - - // Store hash in result pointer, and make sure we get in in the correct order on both endian models. - for (int hashByte = 20; --hashByte >= 0;) - { - hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff; - } - } - -} // namespace sha1 -} // namespace websocketpp - -#endif // SHA1_DEFINED +/* +***** +sha1.hpp is a repackaging of the sha1.cpp and sha1.h files from the smallsha1 +library (http://code.google.com/p/smallsha1/) into a single header suitable for +use as a header only library. This conversion was done by Peter Thorson +(webmaster@zaphoyd.com) in 2013. All modifications to the code are redistributed +under the same license as the original, which is listed below. +***** + + Copyright (c) 2011, Micael Hildenborg + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Micael Hildenborg nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SHA1_DEFINED +#define SHA1_DEFINED + +namespace websocketpp { +namespace sha1 { + +namespace { // local + +// Rotate an integer value to left. +inline unsigned int rol(unsigned int value, unsigned int steps) { + return ((value << steps) | (value >> (32 - steps))); +} + +// Sets the first 16 integers in the buffert to zero. +// Used for clearing the W buffert. +inline void clearWBuffert(unsigned int * buffert) +{ + for (int pos = 16; --pos >= 0;) + { + buffert[pos] = 0; + } +} + +inline void innerHash(unsigned int * result, unsigned int * w) +{ + unsigned int a = result[0]; + unsigned int b = result[1]; + unsigned int c = result[2]; + unsigned int d = result[3]; + unsigned int e = result[4]; + + int round = 0; + + #define sha1macro(func,val) \ + { \ + const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \ + e = d; \ + d = c; \ + c = rol(b, 30); \ + b = a; \ + a = t; \ + } + + while (round < 16) + { + sha1macro((b & c) | (~b & d), 0x5a827999) + ++round; + } + while (round < 20) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro((b & c) | (~b & d), 0x5a827999) + ++round; + } + while (round < 40) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro(b ^ c ^ d, 0x6ed9eba1) + ++round; + } + while (round < 60) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc) + ++round; + } + while (round < 80) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro(b ^ c ^ d, 0xca62c1d6) + ++round; + } + + #undef sha1macro + + result[0] += a; + result[1] += b; + result[2] += c; + result[3] += d; + result[4] += e; +} + +} // namespace + +/// Calculate a SHA1 hash +/** + * @param src points to any kind of data to be hashed. + * @param bytelength the number of bytes to hash from the src pointer. + * @param hash should point to a buffer of at least 20 bytes of size for storing + * the sha1 result in. + */ +inline void calc(void const * src, size_t bytelength, unsigned char * hash) { + // Init the result array. + unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, + 0x10325476, 0xc3d2e1f0 }; + + // Cast the void src pointer to be the byte array we can work with. + unsigned char const * sarray = (unsigned char const *) src; + + // The reusable round buffer + unsigned int w[80]; + + // Loop through all complete 64byte blocks. + + size_t endCurrentBlock; + size_t currentBlock = 0; + + if (bytelength >= 64) { + size_t const endOfFullBlocks = bytelength - 64; + + while (currentBlock <= endOfFullBlocks) { + endCurrentBlock = currentBlock + 64; + + // Init the round buffer with the 64 byte block data. + for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4) + { + // This line will swap endian on big endian and keep endian on + // little endian. + w[roundPos++] = (unsigned int) sarray[currentBlock + 3] + | (((unsigned int) sarray[currentBlock + 2]) << 8) + | (((unsigned int) sarray[currentBlock + 1]) << 16) + | (((unsigned int) sarray[currentBlock]) << 24); + } + innerHash(result, w); + } + } + + // Handle the last and not full 64 byte block if existing. + endCurrentBlock = bytelength - currentBlock; + clearWBuffert(w); + size_t lastBlockBytes = 0; + for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes) { + w[lastBlockBytes >> 2] |= (unsigned int) sarray[lastBlockBytes + currentBlock] << ((3 - (lastBlockBytes & 3)) << 3); + } + + w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3); + if (endCurrentBlock >= 56) { + innerHash(result, w); + clearWBuffert(w); + } + w[15] = bytelength << 3; + innerHash(result, w); + + // Store hash in result pointer, and make sure we get in in the correct + // order on both endian models. + for (int hashByte = 20; --hashByte >= 0;) { + hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff; + } +} + +} // namespace sha1 +} // namespace websocketpp + +#endif // SHA1_DEFINED diff --git a/src/third_party/websocketpp/websocketpp/transport/asio/base.hpp b/src/third_party/websocketpp/websocketpp/transport/asio/base.hpp index 28ac933c..8ede3aaa 100644 --- a/src/third_party/websocketpp/websocketpp/transport/asio/base.hpp +++ b/src/third_party/websocketpp/websocketpp/transport/asio/base.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/third_party/websocketpp/websocketpp/transport/asio/connection.hpp b/src/third_party/websocketpp/websocketpp/transport/asio/connection.hpp index f0aefa57..f4341019 100644 --- a/src/third_party/websocketpp/websocketpp/transport/asio/connection.hpp +++ b/src/third_party/websocketpp/websocketpp/transport/asio/connection.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -28,6 +28,7 @@ #ifndef WEBSOCKETPP_TRANSPORT_ASIO_CON_HPP #define WEBSOCKETPP_TRANSPORT_ASIO_CON_HPP +#include #include #include #include @@ -115,7 +116,7 @@ public: * established but before any additional wrappers (proxy connects, TLS * handshakes, etc) have been performed. * - * @since 0.4.0-alpha1 + * @since 0.3.0 * * @param h The handler to call on tcp pre init. */ @@ -144,7 +145,7 @@ public: * etc have been performed. This is fired before any bytes are read or any * WebSocket specific handshake logic has been performed. * - * @since 0.4.0-alpha1 + * @since 0.3.0 * * @param h The handler to call on tcp post init. */ @@ -164,19 +165,19 @@ public: * * @param ec A status value */ - void set_proxy(const std::string & uri, lib::error_code & ec) { + void set_proxy(std::string const & uri, lib::error_code & ec) { // TODO: return errors for illegal URIs here? // TODO: should https urls be illegal for the moment? m_proxy = uri; - m_proxy_data.reset(new proxy_data()); + m_proxy_data = lib::make_shared(); ec = lib::error_code(); } /// Set the proxy to connect through (exception) - void set_proxy(const std::string & uri) { + void set_proxy(std::string const & uri) { lib::error_code ec; set_proxy(uri,ec); - if (ec) { throw ec; } + if (ec) { throw exception(ec); } } /// Set the basic auth credentials to use (exception free) @@ -192,8 +193,8 @@ public: * * @param ec A status value */ - void set_proxy_basic_auth(const std::string & username, const - std::string & password, lib::error_code & ec) + void set_proxy_basic_auth(std::string const & username, std::string const & + password, lib::error_code & ec) { if (!m_proxy_data) { ec = make_error_code(websocketpp::error::invalid_state); @@ -207,12 +208,12 @@ public: } /// Set the basic auth credentials to use (exception) - void set_proxy_basic_auth(const std::string & username, const - std::string & password) + void set_proxy_basic_auth(std::string const & username, std::string const & + password) { lib::error_code ec; set_proxy_basic_auth(username,password,ec); - if (ec) { throw ec; } + if (ec) { throw exception(ec); } } /// Set the proxy timeout duration (exception free) @@ -239,7 +240,7 @@ public: void set_proxy_timeout(long duration) { lib::error_code ec; set_proxy_timeout(duration,ec); - if (ec) { throw ec; } + if (ec) { throw exception(ec); } } const std::string & get_proxy() const { @@ -289,11 +290,9 @@ public: * needed. */ timer_ptr set_timer(long duration, timer_handler callback) { - timer_ptr new_timer( - new boost::asio::deadline_timer( - *m_io_service, - boost::posix_time::milliseconds(duration) - ) + timer_ptr new_timer = lib::make_shared( + lib::ref(*m_io_service), + boost::posix_time::milliseconds(duration) ); if (config::enable_multithreading) { @@ -322,11 +321,11 @@ public: * * TODO: candidate for protected status * - * @param t Pointer to the timer in question + * @param post_timer Pointer to the timer in question * @param callback The function to call back * @param ec The status code */ - void handle_timer(timer_ptr t, timer_handler callback, + void handle_timer(timer_ptr, timer_handler callback, boost::system::error_code const & ec) { if (ec) { @@ -407,7 +406,7 @@ protected: /// Finish constructing the transport /** * init_asio is called once immediately after construction to initialize - * boost::asio components to the io_service + * boost::asio components to the io_service. * * @param io_service A pointer to the io_service to register with this * connection @@ -415,35 +414,38 @@ protected: * @return Status code for the success or failure of the initialization */ lib::error_code init_asio (io_service_ptr io_service) { - // do we need to store or use the io_service at this level? m_io_service = io_service; if (config::enable_multithreading) { - m_strand.reset(new boost::asio::strand(*io_service)); + m_strand = lib::make_shared( + lib::ref(*io_service)); m_async_read_handler = m_strand->wrap(lib::bind( - &type::handle_async_read, get_shared(), - lib::placeholders::_1, lib::placeholders::_2 - )); + &type::handle_async_read, get_shared(),lib::placeholders::_1, + lib::placeholders::_2)); m_async_write_handler = m_strand->wrap(lib::bind( - &type::handle_async_write, get_shared(), - lib::placeholders::_1, lib::placeholders::_2 - )); + &type::handle_async_write, get_shared(),lib::placeholders::_1, + lib::placeholders::_2)); } else { - // TODO: goal: not have this line here - //m_strand.reset(new boost::asio::strand(*io_service)); - - m_async_read_handler = lib::bind( - &type::handle_async_read, get_shared(), - lib::placeholders::_1, lib::placeholders::_2 - ); + m_async_read_handler = lib::bind(&type::handle_async_read, + get_shared(), lib::placeholders::_1, lib::placeholders::_2); m_async_write_handler = lib::bind(&type::handle_async_write, get_shared(), lib::placeholders::_1, lib::placeholders::_2); } - return socket_con_type::init_asio(io_service, m_strand, m_is_server); + lib::error_code ec = socket_con_type::init_asio(io_service, m_strand, + m_is_server); + + if (ec) { + // reset the handlers to break the circular reference: + // this->handler->this + lib::clear_function(m_async_read_handler); + lib::clear_function(m_async_write_handler); + } + + return ec; } void handle_pre_init(lib::error_code const & ec) { @@ -474,16 +476,19 @@ protected: } timer_ptr post_timer; - post_timer = set_timer( - config::timeout_socket_post_init, - lib::bind( - &type::handle_post_init_timeout, - get_shared(), - post_timer, - m_init_handler, - lib::placeholders::_1 - ) - ); + + if (config::timeout_socket_post_init > 0) { + post_timer = set_timer( + config::timeout_socket_post_init, + lib::bind( + &type::handle_post_init_timeout, + get_shared(), + post_timer, + m_init_handler, + lib::placeholders::_1 + ) + ); + } socket_con_type::post_init( lib::bind( @@ -496,8 +501,17 @@ protected: ); } - void handle_post_init_timeout(timer_ptr post_timer, init_handler callback, - const lib::error_code& ec) + /// Post init timeout callback + /** + * The timer pointer is included to ensure the timer isn't destroyed until + * after it has expired. + * + * @param post_timer Pointer to the timer in question + * @param callback The function to call back + * @param ec The status code + */ + void handle_post_init_timeout(timer_ptr, init_handler callback, + lib::error_code const & ec) { lib::error_code ret_ec; @@ -523,23 +537,34 @@ protected: callback(ret_ec); } - void handle_post_init(timer_ptr post_timer, init_handler callback, const - lib::error_code& ec) + /// Post init timeout callback + /** + * The timer pointer is included to ensure the timer isn't destroyed until + * after it has expired. + * + * @param post_timer Pointer to the timer in question + * @param callback The function to call back + * @param ec The status code + */ + void handle_post_init(timer_ptr post_timer, init_handler callback, + lib::error_code const & ec) { if (ec == transport::error::operation_aborted || - post_timer->expires_from_now().is_negative()) + (post_timer && post_timer->expires_from_now().is_negative())) { m_alog.write(log::alevel::devel,"post_init cancelled"); return; } - post_timer->cancel(); + if (post_timer) { + post_timer->cancel(); + } if (m_alog.static_test(log::alevel::devel)) { m_alog.write(log::alevel::devel,"asio connection handle_post_init"); } - if (m_tcp_post_init_handler) { + if (m_tcp_post_init_handler) { m_tcp_post_init_handler(m_connection_hdl); } @@ -685,8 +710,14 @@ protected: } } + /// Proxy read callback + /** + * @param init_handler The function to call back + * @param ec The status code + * @param bytes_transferred The number of bytes read + */ void handle_proxy_read(init_handler callback, - boost::system::error_code const & ec, size_t bytes_transferred) + boost::system::error_code const & ec, size_t) { if (m_alog.static_test(log::alevel::devel)) { m_alog.write(log::alevel::devel, @@ -779,7 +810,7 @@ protected: if (!m_async_read_handler) { m_alog.write(log::alevel::devel, "async_read_at_least called after async_shutdown"); - handler(make_error_code(transport::error::action_after_shutdown), 0); + handler(make_error_code(transport::error::action_after_shutdown),0); return; } @@ -795,36 +826,54 @@ protected: m_read_handler = handler; + if (!m_read_handler) { + m_alog.write(log::alevel::devel, + "asio con async_read_at_least called with bad handler"); + } + boost::asio::async_read( socket_con_type::get_socket(), boost::asio::buffer(buf,len), boost::asio::transfer_at_least(num_bytes), make_custom_alloc_handler( - m_read_handler_allocator, - m_async_read_handler + m_read_handler_allocator, + m_async_read_handler ) ); } - void handle_async_read(const boost::system::error_code& ec, + void handle_async_read(boost::system::error_code const & ec, size_t bytes_transferred) { - if (!ec) { - m_read_handler(lib::error_code(), bytes_transferred); - return; - } + m_alog.write(log::alevel::devel, "asio con handle_async_read"); // translate boost error codes into more lib::error_codes + lib::error_code tec; if (ec == boost::asio::error::eof) { - m_read_handler(make_error_code(transport::error::eof), - bytes_transferred); - } else if (ec.value() == 335544539) { - m_read_handler(make_error_code(transport::error::tls_short_read), - bytes_transferred); + tec = make_error_code(transport::error::eof); + } else if (ec) { + // We don't know much more about the error at this point. As our + // socket/security policy if it knows more: + tec = socket_con_type::translate_ec(ec); + + if (tec == transport::error::tls_error || + tec == transport::error::pass_through) + { + // These are aggregate/catch all errors. Log some human readable + // information to the info channel to give library users some + // more details about why the upstream method may have failed. + log_err(log::elevel::info,"asio async_read_at_least",ec); + } + } + if (m_read_handler) { + m_read_handler(tec,bytes_transferred); + // TODO: why does this line break things? + //m_read_handler = _WEBSOCKETPP_NULL_FUNCTION_; } else { - log_err(log::elevel::info,"asio async_read_at_least",ec); - m_read_handler(make_error_code(transport::error::pass_through), - bytes_transferred); + // This can happen in cases where the connection is terminated while + // the transport is waiting on a read. + m_alog.write(log::alevel::devel, + "handle_async_read called with null read handler"); } } @@ -836,7 +885,7 @@ protected: return; } - m_bufs.push_back(boost::asio::buffer(buf,len)); + m_bufs.push_back(boost::asio::buffer(buf,len)); m_write_handler = handler; @@ -844,8 +893,8 @@ protected: socket_con_type::get_socket(), m_bufs, make_custom_alloc_handler( - m_write_handler_allocator, - m_async_write_handler + m_write_handler_allocator, + m_async_write_handler ) ); } @@ -869,21 +918,33 @@ protected: socket_con_type::get_socket(), m_bufs, make_custom_alloc_handler( - m_write_handler_allocator, - m_async_write_handler + m_write_handler_allocator, + m_async_write_handler ) ); } - void handle_async_write(boost::system::error_code const & ec, - size_t bytes_transferred) - { + /// Async write callback + /** + * @param ec The status code + * @param bytes_transferred The number of bytes read + */ + void handle_async_write(boost::system::error_code const & ec, size_t) { m_bufs.clear(); + lib::error_code tec; if (ec) { log_err(log::elevel::info,"asio async_write",ec); - m_write_handler(make_error_code(transport::error::pass_through)); + tec = make_error_code(transport::error::pass_through); + } + if (m_write_handler) { + m_write_handler(tec); + // TODO: why does this line break things? + //m_write_handler = _WEBSOCKETPP_NULL_FUNCTION_; } else { - m_write_handler(lib::error_code()); + // This can happen in cases where the connection is terminated while + // the transport is waiting on a read. + m_alog.write(log::alevel::devel, + "handle_async_write called with null write handler"); } } @@ -931,12 +992,15 @@ protected: m_alog.write(log::alevel::devel,"asio connection async_shutdown"); } - // Reset cached handlers now that we won't be reading or writing anymore - // These cached handlers store shared pointers to this connection and will leak - // the connection if not destroyed. - m_async_read_handler = 0; - m_async_write_handler = 0; - m_init_handler = 0; + // Reset cached handlers now that we won't be reading or writing anymore + // These cached handlers store shared pointers to this connection and + // will leak the connection if not destroyed. + lib::clear_function(m_async_read_handler); + lib::clear_function(m_async_write_handler); + lib::clear_function(m_init_handler); + + lib::clear_function(m_read_handler); + lib::clear_function(m_write_handler); timer_ptr shutdown_timer; shutdown_timer = set_timer( @@ -961,8 +1025,14 @@ protected: ); } - void handle_async_shutdown_timeout(timer_ptr shutdown_timer, init_handler - callback, const lib::error_code& ec) + /// Async shutdown timeout handler + /** + * @param shutdown_timer A pointer to the timer to keep it in scope + * @param callback The function to call back + * @param ec The status code + */ + void handle_async_shutdown_timeout(timer_ptr, init_handler callback, + lib::error_code const & ec) { lib::error_code ret_ec; @@ -973,7 +1043,7 @@ protected: return; } - log_err(log::elevel::devel,"asio handle_async_socket_shutdown",ec); + log_err(log::elevel::devel,"asio handle_async_shutdown_timeout",ec); ret_ec = ec; } else { ret_ec = make_error_code(transport::error::timeout); @@ -986,7 +1056,7 @@ protected: } void handle_async_shutdown(timer_ptr shutdown_timer, shutdown_handler - callback, const boost::system::error_code & ec) + callback, boost::system::error_code const & ec) { if (ec == boost::asio::error::operation_aborted || shutdown_timer->expires_from_now().is_negative()) @@ -997,25 +1067,37 @@ protected: shutdown_timer->cancel(); + lib::error_code tec; if (ec) { - log_err(log::elevel::info,"asio async_shutdown",ec); if (ec == boost::asio::error::not_connected) { // The socket was already closed when we tried to close it. This // happens periodically (usually if a read or write fails // earlier and if it is a real error will be caught at another // level of the stack. - callback(lib::error_code()); } else { - callback(make_error_code(transport::error::pass_through)); + // We don't know anything more about this error, give our + // socket/security policy a crack at it. + tec = socket_con_type::translate_ec(ec); + + if (tec == transport::error::tls_short_read) { + // TLS short read at this point is somewhat expected if both + // sides try and end the connection at the same time or if + // SSLv2 is being used. In general there is nothing that can + // be done here other than a low level development log. + } else { + // all other errors are effectively pass through errors of + // some sort so print some detail on the info channel for + // library users to look up if needed. + log_err(log::elevel::info,"asio async_shutdown",ec); + } } } else { if (m_alog.static_test(log::alevel::devel)) { m_alog.write(log::alevel::devel, "asio con handle_async_shutdown"); } - - callback(lib::error_code()); } + callback(tec); } private: /// Convenience method for logging the code and message for an error_code diff --git a/src/third_party/websocketpp/websocketpp/transport/asio/endpoint.hpp b/src/third_party/websocketpp/websocketpp/transport/asio/endpoint.hpp index 2728c66b..9ce58256 100644 --- a/src/third_party/websocketpp/websocketpp/transport/asio/endpoint.hpp +++ b/src/third_party/websocketpp/websocketpp/transport/asio/endpoint.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -38,8 +38,6 @@ #include #include -#include - namespace websocketpp { namespace transport { namespace asio { @@ -89,8 +87,10 @@ public: // generate and manage our own io_service explicit endpoint() - : m_external_io_service(false) + : m_io_service(NULL) + , m_external_io_service(false) , m_listen_backlog(0) + , m_reuse_addr(false) , m_state(UNINITIALIZED) { //std::cout << "transport::asio::endpoint constructor" << std::endl; @@ -122,7 +122,8 @@ public: : m_io_service(src.m_io_service) , m_external_io_service(src.m_external_io_service) , m_acceptor(src.m_acceptor) - , m_listen_backlog(0) + , m_listen_backlog(boost::asio::socket_base::max_connections) + , m_reuse_addr(src.m_reuse_addr) , m_state(src.m_state) { src.m_io_service = NULL; @@ -136,13 +137,14 @@ public: m_io_service = rhs.m_io_service; m_external_io_service = rhs.m_external_io_service; m_acceptor = rhs.m_acceptor; - m_listen_backlog = rhs.m_listen_backlog + m_listen_backlog = rhs.m_listen_backlog; + m_reuse_addr = rhs.m_reuse_addr; m_state = rhs.m_state; rhs.m_io_service = NULL; rhs.m_external_io_service = false; rhs.m_acceptor = NULL; - rhs.m_listen_backlog = 0; + rhs.m_listen_backlog = boost::asio::socket_base::max_connections; rhs.m_state = UNINITIALIZED; } return *this; @@ -175,7 +177,9 @@ public: m_io_service = ptr; m_external_io_service = true; - m_acceptor.reset(new boost::asio::ip::tcp::acceptor(*m_io_service)); + m_acceptor = lib::make_shared( + lib::ref(*m_io_service)); + m_state = READY; ec = lib::error_code(); } @@ -191,9 +195,7 @@ public: void init_asio(io_service_ptr ptr) { lib::error_code ec; init_asio(ptr,ec); - if (ec) { - throw ec; - } + if (ec) { throw exception(ec); } } /// Initialize asio transport with internal io_service (exception free) @@ -206,7 +208,7 @@ public: * @param ec Set to indicate what error occurred, if any. */ void init_asio(lib::error_code & ec) { - init_asio(new boost::asio::io_service(),ec); + init_asio(new boost::asio::io_service(), ec); m_external_io_service = false; } @@ -228,7 +230,7 @@ public: * established but before any additional wrappers (proxy connects, TLS * handshakes, etc) have been performed. * - * @since 0.4.0-alpha1 + * @since 0.3.0 * * @param h The handler to call on tcp pre init. */ @@ -257,7 +259,7 @@ public: * etc have been performed. This is fired before any bytes are read or any * WebSocket specific handshake logic has been performed. * - * @since 0.4.0-alpha1 + * @since 0.3.0 * * @param h The handler to call on tcp post init. */ @@ -280,13 +282,31 @@ public: * A value of zero will use the operating system default. This is the * default value. * - * @since 0.4.0-alpha1 + * @since 0.3.0 * * @param backlog The maximum length of the queue of pending connections */ void set_listen_backlog(int backlog) { m_listen_backlog = backlog; } + + /// Sets whether to use the SO_REUSEADDR flag when opening listening sockets + /** + * Specifies whether or not to use the SO_REUSEADDR TCP socket option. What + * this flag does depends on your operating system. Please consult operating + * system documentation for more details. + * + * New values affect future calls to listen only. + * + * The default is false. + * + * @since 0.3.0 + * + * @param value Whether or not to use the SO_REUSEADDR option + */ + void set_reuse_addr(bool value) { + m_reuse_addr = value; + } /// Retrieve a reference to the endpoint's io_service /** @@ -323,16 +343,25 @@ public: m_alog->write(log::alevel::devel,"asio::listen"); - m_acceptor->open(ep.protocol()); - m_acceptor->set_option(boost::asio::socket_base::reuse_address(true)); - m_acceptor->bind(ep); - if (m_listen_backlog == 0) { - m_acceptor->listen(); + boost::system::error_code bec; + + m_acceptor->open(ep.protocol(),bec); + if (!bec) { + m_acceptor->set_option(boost::asio::socket_base::reuse_address(m_reuse_addr),bec); + } + if (!bec) { + m_acceptor->bind(ep,bec); + } + if (!bec) { + m_acceptor->listen(m_listen_backlog,bec); + } + if (bec) { + log_err(log::elevel::info,"asio listen",bec); + ec = make_error_code(error::pass_through); } else { - m_acceptor->listen(m_listen_backlog); + m_state = LISTENING; + ec = lib::error_code(); } - m_state = LISTENING; - ec = lib::error_code(); } /// Set up endpoint for listening manually @@ -344,9 +373,7 @@ public: void listen(boost::asio::ip::tcp::endpoint const & ep) { lib::error_code ec; listen(ep,ec); - if (ec) { - throw ec; - } + if (ec) { throw exception(ec); } } /// Set up endpoint for listening with protocol and port (exception free) @@ -476,9 +503,7 @@ public: { lib::error_code ec; listen(host,service,ec); - if (ec) { - throw ec; - } + if (ec) { throw exception(ec); } } /// Stop listening (exception free) @@ -513,9 +538,15 @@ public: void stop_listening() { lib::error_code ec; stop_listening(ec); - if (ec) { - throw ec; - } + if (ec) { throw exception(ec); } + } + + /// Check if the endpoint is listening + /** + * @return Whether or not the endpoint is listening. + */ + bool is_listening() const { + return (m_state == LISTENING); } /// wraps the run method of the internal io_service object @@ -566,10 +597,12 @@ public: * called either before the endpoint has run out of work or before it was * started * - * @since 0.4.0-alpha1 + * @since 0.3.0 */ void start_perpetual() { - m_work.reset(new boost::asio::io_service::work(*m_io_service)); + m_work = lib::make_shared( + lib::ref(*m_io_service) + ); } /// Clears the endpoint's perpetual flag, allowing it to exit when empty @@ -578,7 +611,7 @@ public: * method to exit normally when it runs out of connections. If there are * currently active connections it will not end until they are complete. * - * @since 0.4.0-alpha1 + * @since 0.3.0 */ void stop_perpetual() { m_work.reset(); @@ -597,11 +630,9 @@ public: * needed. */ timer_ptr set_timer(long duration, timer_handler callback) { - timer_ptr new_timer( - new boost::asio::deadline_timer( - *m_io_service, - boost::posix_time::milliseconds(duration) - ) + timer_ptr new_timer = lib::make_shared( + *m_io_service, + boost::posix_time::milliseconds(duration) ); new_timer->async_wait( @@ -617,7 +648,7 @@ public: return new_timer; } - /// Timer callback + /// Timer handler /** * The timer pointer is included to ensure the timer isn't destroyed until * after it has expired. @@ -626,7 +657,7 @@ public: * @param callback The function to call back * @param ec A status code indicating an error, if any. */ - void handle_timer(timer_ptr t, timer_handler callback, + void handle_timer(timer_ptr, timer_handler callback, boost::system::error_code const & ec) { if (ec) { @@ -653,10 +684,8 @@ public: lib::error_code & ec) { if (m_state != LISTENING) { - m_elog->write(log::elevel::library, - "asio::async_accept called from the wrong state"); using websocketpp::error::make_error_code; - ec = make_error_code(websocketpp::error::invalid_state); + ec = make_error_code(websocketpp::error::async_accept_not_listening); return; } @@ -693,9 +722,7 @@ public: void async_accept(transport_con_ptr tcon, accept_handler callback) { lib::error_code ec; async_accept(tcon,callback,ec); - if (ec) { - throw ec; - } + if (ec) { throw exception(ec); } } protected: /// Initialize logging @@ -721,8 +748,12 @@ protected: m_alog->write(log::alevel::devel, "asio::handle_accept"); if (boost_ec) { - log_err(log::elevel::devel,"asio handle_accept",boost_ec); - ret_ec = make_error_code(error::pass_through); + if (boost_ec == boost::system::errc::operation_canceled) { + ret_ec = make_error_code(websocketpp::error::operation_canceled); + } else { + log_err(log::elevel::info,"asio handle_accept",boost_ec); + ret_ec = make_error_code(error::pass_through); + } } callback(ret_ec); @@ -735,7 +766,8 @@ protected: // Create a resolver if (!m_resolver) { - m_resolver.reset(new boost::asio::ip::tcp::resolver(*m_io_service)); + m_resolver = lib::make_shared( + lib::ref(*m_io_service)); } std::string proxy = tcon->get_proxy(); @@ -748,7 +780,7 @@ protected: } else { lib::error_code ec; - uri_ptr pu(new uri(proxy)); + uri_ptr pu = lib::make_shared(proxy); if (!pu->get_valid()) { cb(make_error_code(error::proxy_invalid)); @@ -814,7 +846,16 @@ protected: } } - void handle_resolve_timeout(timer_ptr dns_timer, connect_handler callback, + /// DNS resolution timeout handler + /** + * The timer pointer is included to ensure the timer isn't destroyed until + * after it has expired. + * + * @param dns_timer Pointer to the timer in question + * @param callback The function to call back + * @param ec A status code indicating an error, if any. + */ + void handle_resolve_timeout(timer_ptr, connect_handler callback, lib::error_code const & ec) { lib::error_code ret_ec; @@ -913,7 +954,17 @@ protected: } } - void handle_connect_timeout(transport_con_ptr tcon, timer_ptr con_timer, + /// Asio connect timeout handler + /** + * The timer pointer is included to ensure the timer isn't destroyed until + * after it has expired. + * + * @param tcon Pointer to the transport connection that is being connected + * @param con_timer Pointer to the timer in question + * @param callback The function to call back + * @param ec A status code indicating an error, if any. + */ + void handle_connect_timeout(transport_con_ptr tcon, timer_ptr, connect_handler callback, lib::error_code const & ec) { lib::error_code ret_ec; @@ -962,10 +1013,6 @@ protected: callback(lib::error_code()); } - bool is_listening() const { - return (m_state == LISTENING); - } - /// Initialize a connection /** * init is called by an endpoint once for each newly created connection. @@ -1022,6 +1069,7 @@ private: // Network constants int m_listen_backlog; + bool m_reuse_addr; elog_type* m_elog; alog_type* m_alog; diff --git a/src/third_party/websocketpp/websocketpp/transport/asio/security/base.hpp b/src/third_party/websocketpp/websocketpp/transport/asio/security/base.hpp index 7e003794..0b494170 100644 --- a/src/third_party/websocketpp/websocketpp/transport/asio/security/base.hpp +++ b/src/third_party/websocketpp/websocketpp/transport/asio/security/base.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -36,7 +36,6 @@ #include -#include #include // Interface that sockets/security policies must implement @@ -95,7 +94,10 @@ namespace error { pass_through, /// Required tls_init handler not present - missing_tls_init_handler + missing_tls_init_handler, + + /// TLS Handshake Failed + tls_handshake_failed, }; } // namespace error @@ -119,9 +121,11 @@ public: case error::tls_handshake_timeout: return "TLS handshake timed out"; case error::pass_through: - return "Pass through from underlying library"; + return "Pass through from socket policy"; case error::missing_tls_init_handler: return "Required tls_init handler not present."; + case error::tls_handshake_failed: + return "TLS handshake failed"; default: return "Unknown"; } diff --git a/src/third_party/websocketpp/websocketpp/transport/asio/security/none.hpp b/src/third_party/websocketpp/websocketpp/transport/asio/security/none.hpp index 1c9486fa..17ddbf6f 100644 --- a/src/third_party/websocketpp/websocketpp/transport/asio/security/none.hpp +++ b/src/third_party/websocketpp/websocketpp/transport/asio/security/none.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -33,14 +33,16 @@ #include -#include #include namespace websocketpp { namespace transport { namespace asio { +/// A socket policy for the asio transport that implements a plain, unencrypted +/// socket namespace basic_socket { +/// The signature of the socket init handler for this socket policy typedef lib::function socket_init_handler; @@ -60,8 +62,10 @@ public: typedef boost::asio::io_service* io_service_ptr; /// Type of a pointer to the ASIO io_service strand being used typedef lib::shared_ptr strand_ptr; + /// Type of the ASIO socket being used + typedef boost::asio::ip::tcp::socket socket_type; /// Type of a shared pointer to the socket being used. - typedef lib::shared_ptr socket_ptr; + typedef lib::shared_ptr socket_ptr; explicit connection() : m_state(UNINITIALIZED) { //std::cout << "transport::asio::basic_socket::connection constructor" @@ -154,14 +158,14 @@ protected: * @param strand A shared pointer to the connection's asio strand * @param is_server Whether or not the endpoint is a server or not. */ - lib::error_code init_asio (io_service_ptr service, strand_ptr strand, - bool is_server) + lib::error_code init_asio (io_service_ptr service, strand_ptr, bool) { if (m_state != UNINITIALIZED) { return socket::make_error_code(socket::error::invalid_state); } - m_socket.reset(new boost::asio::ip::tcp::socket(*service)); + m_socket = lib::make_shared( + lib::ref(*service)); m_state = READY; @@ -229,6 +233,23 @@ protected: lib::error_code get_ec() const { return lib::error_code(); } + + /// Translate any security policy specific information about an error code + /** + * Translate_ec takes a boost error code and attempts to convert its value + * to an appropriate websocketpp error code. The plain socket policy does + * not presently provide any additional information so all errors will be + * reported as the generic transport pass_through error. + * + * @since 0.3.0 + * + * @param ec The error code to translate_ec + * @return The translated error code + */ + lib::error_code translate_ec(boost::system::error_code) { + // We don't know any more information about this error so pass through + return make_error_code(transport::error::pass_through); + } private: enum state { UNINITIALIZED = 0, diff --git a/src/third_party/websocketpp/websocketpp/transport/asio/security/tls.hpp b/src/third_party/websocketpp/websocketpp/transport/asio/security/tls.hpp index 2a743112..68f4198e 100644 --- a/src/third_party/websocketpp/websocketpp/transport/asio/security/tls.hpp +++ b/src/third_party/websocketpp/websocketpp/transport/asio/security/tls.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -37,16 +37,19 @@ #include #include -#include #include namespace websocketpp { namespace transport { namespace asio { +/// A socket policy for the asio transport that implements a TLS encrypted +/// socket by wrapping with an asio::ssl::stream namespace tls_socket { +/// The signature of the socket_init_handler for this socket policy typedef lib::function&)> socket_init_handler; +/// The signature of the tls_init_handler for this socket policy typedef lib::function(connection_hdl)> tls_init_handler; @@ -190,7 +193,8 @@ protected: if (!m_context) { return socket::make_error_code(socket::error::invalid_tls_context); } - m_socket.reset(new socket_type(*service,*m_context)); + m_socket = lib::make_shared( + _WEBSOCKETPP_REF(*service),lib::ref(*m_context)); m_io_service = service; m_strand = strand; @@ -260,11 +264,10 @@ protected: m_hdl = hdl; } - void handle_init(init_handler callback, const - boost::system::error_code& ec) + void handle_init(init_handler callback,boost::system::error_code const & ec) { if (ec) { - m_ec = socket::make_error_code(socket::error::pass_through); + m_ec = socket::make_error_code(socket::error::tls_handshake_failed); } else { m_ec = lib::error_code(); } @@ -284,6 +287,37 @@ protected: void async_shutdown(socket_shutdown_handler callback) { m_socket->async_shutdown(callback); } + + /// Translate any security policy specific information about an error code + /** + * Translate_ec takes a boost error code and attempts to convert its value + * to an appropriate websocketpp error code. Any error that is determined to + * be related to TLS but does not have a more specific websocketpp error + * code is returned under the catch all error "tls_error". + * + * Non-TLS related errors are returned as the transport generic pass_through + * error. + * + * @since 0.3.0 + * + * @param ec The error code to translate_ec + * @return The translated error code + */ + lib::error_code translate_ec(boost::system::error_code ec) { + if (ec.category() == boost::asio::error::get_ssl_category()) { + if (ERR_GET_REASON(ec.value()) == SSL_R_SHORT_READ) { + return make_error_code(transport::error::tls_short_read); + } else { + // We know it is a TLS related error, but otherwise don't know + // more. Pass through as TLS generic. + return make_error_code(transport::error::tls_error); + } + } else { + // We don't know any more information about this error so pass + // through + return make_error_code(transport::error::pass_through); + } + } private: socket_type::handshake_type get_handshake_type() { if (m_is_server) { diff --git a/src/third_party/websocketpp/websocketpp/transport/base/connection.hpp b/src/third_party/websocketpp/websocketpp/transport/base/connection.hpp index 70e1ec50..774c60d0 100644 --- a/src/third_party/websocketpp/websocketpp/transport/base/connection.hpp +++ b/src/third_party/websocketpp/websocketpp/transport/base/connection.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -141,6 +141,7 @@ struct buffer { size_t len; }; +/// Generic transport related errors namespace error { enum value { /// Catch-all error for transport policy errors that don't fit in other @@ -170,9 +171,12 @@ enum value { /// Timer expired timeout, - + /// read or write after shutdown - action_after_shutdown + action_after_shutdown, + + /// Other TLS error + tls_error, }; class category : public lib::error_category { @@ -197,12 +201,14 @@ class category : public lib::error_category { return "The operation is not supported by this transport"; case eof: return "End of File"; - case tls_short_read: + case tls_short_read: return "TLS Short Read"; case timeout: return "Timer Expired"; case action_after_shutdown: return "A transport action was requested after shutdown"; + case tls_error: + return "Generic TLS related error"; default: return "Unknown"; } diff --git a/src/third_party/websocketpp/websocketpp/transport/base/endpoint.hpp b/src/third_party/websocketpp/websocketpp/transport/base/endpoint.hpp index 1fefd483..43bbdf46 100644 --- a/src/third_party/websocketpp/websocketpp/transport/base/endpoint.hpp +++ b/src/third_party/websocketpp/websocketpp/transport/base/endpoint.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/third_party/websocketpp/websocketpp/transport/iostream/base.hpp b/src/third_party/websocketpp/websocketpp/transport/iostream/base.hpp index 5bfb5539..a80169fe 100644 --- a/src/third_party/websocketpp/websocketpp/transport/iostream/base.hpp +++ b/src/third_party/websocketpp/websocketpp/transport/iostream/base.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/src/third_party/websocketpp/websocketpp/transport/iostream/connection.hpp b/src/third_party/websocketpp/websocketpp/transport/iostream/connection.hpp index 458e42cd..cbd802ec 100644 --- a/src/third_party/websocketpp/websocketpp/transport/iostream/connection.hpp +++ b/src/third_party/websocketpp/websocketpp/transport/iostream/connection.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -28,8 +28,9 @@ #ifndef WEBSOCKETPP_TRANSPORT_IOSTREAM_CON_HPP #define WEBSOCKETPP_TRANSPORT_IOSTREAM_CON_HPP -#include #include +#include +#include #include #include @@ -127,14 +128,13 @@ public: return in; } - /// Manual input supply + /// Manual input supply (read some) /** * Copies bytes from buf into WebSocket++'s input buffers. Bytes will be * copied from the supplied buffer to fulfill any pending library reads. It * will return the number of bytes successfully processed. If there are no * pending reads read_some will return immediately. Not all of the bytes may - * be able to be read in one call - * + * be able to be read in one call. * * @since 0.3.0-alpha4 * @@ -148,6 +148,37 @@ public: return this->read_some_impl(buf,len); } + + /// Manual input supply (read all) + /** + * Similar to read_some, but continues to read until all bytes in the + * supplied buffer have been read or the connection runs out of read + * requests. + * + * This method still may not read all of the bytes in the input buffer. if + * it doesn't it indicates that the connection was most likely closed or + * is in an error state where it is no longer accepting new input. + * + * @since 0.3.0 + * + * @param buf Char buffer to read into the websocket + * @param len Length of buf + * @return The number of characters from buf actually read. + */ + size_t read_all(char const * buf, size_t len) { + // this serializes calls to external read. + scoped_lock_type lock(m_read_mutex); + + size_t total_read = 0; + size_t temp_read = 0; + + do { + temp_read = this->read_some_impl(buf+total_read,len-total_read); + total_read += temp_read; + } while (temp_read != 0 && total_read < len); + + return total_read; + } /// Manual input supply (DEPRECATED) /** @@ -273,7 +304,7 @@ public: * @return A handle that can be used to cancel the timer if it is no longer * needed. */ - timer_ptr set_timer(long duration, timer_handler handler) { + timer_ptr set_timer(long, timer_handler) { return timer_ptr(); } protected: @@ -479,7 +510,7 @@ private: return 0; } - size_t bytes_to_copy = std::min(len,m_len-m_cursor); + size_t bytes_to_copy = (std::min)(len,m_len-m_cursor); std::copy(buf,buf+bytes_to_copy,m_buf+m_cursor); diff --git a/src/third_party/websocketpp/websocketpp/transport/iostream/endpoint.hpp b/src/third_party/websocketpp/websocketpp/transport/iostream/endpoint.hpp index ff37866d..6a83b3b7 100644 --- a/src/third_party/websocketpp/websocketpp/transport/iostream/endpoint.hpp +++ b/src/third_party/websocketpp/websocketpp/transport/iostream/endpoint.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -140,7 +140,7 @@ protected: * @param u A URI pointer to the URI to connect to. * @param cb The function to call back with the results when complete. */ - void async_connect(transport_con_ptr tcon, uri_ptr u, connect_handler cb) { + void async_connect(transport_con_ptr, uri_ptr, connect_handler cb) { cb(lib::error_code()); } diff --git a/src/third_party/websocketpp/websocketpp/transport/stub/base.hpp b/src/third_party/websocketpp/websocketpp/transport/stub/base.hpp new file mode 100644 index 00000000..864372a4 --- /dev/null +++ b/src/third_party/websocketpp/websocketpp/transport/stub/base.hpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2014, Peter Thorson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the WebSocket++ Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef WEBSOCKETPP_TRANSPORT_STUB_BASE_HPP +#define WEBSOCKETPP_TRANSPORT_STUB_BASE_HPP + +#include +#include + +#include + +namespace websocketpp { +namespace transport { +/// Stub transport policy that has no input or output. +namespace stub { + +/// stub transport errors +namespace error { +enum value { + /// Catch-all error for transport policy errors that don't fit in other + /// categories + general = 1, + + /// not implimented + not_implimented +}; + +/// iostream transport error category +class category : public lib::error_category { + public: + category() {} + + char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ { + return "websocketpp.transport.stub"; + } + + std::string message(int value) const { + switch(value) { + case general: + return "Generic stub transport policy error"; + case not_implimented: + return "feature not implimented"; + default: + return "Unknown"; + } + } +}; + +/// Get a reference to a static copy of the stub transport error category +inline lib::error_category const & get_category() { + static category instance; + return instance; +} + +/// Get an error code with the given value and the stub transport category +inline lib::error_code make_error_code(error::value e) { + return lib::error_code(static_cast(e), get_category()); +} + +} // namespace error +} // namespace stub +} // namespace transport +} // namespace websocketpp +_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_ +template<> struct is_error_code_enum +{ + static bool const value = true; +}; +_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_ + +#endif // WEBSOCKETPP_TRANSPORT_STUB_BASE_HPP diff --git a/src/third_party/websocketpp/websocketpp/transport/stub/connection.hpp b/src/third_party/websocketpp/websocketpp/transport/stub/connection.hpp new file mode 100644 index 00000000..ce3bdccd --- /dev/null +++ b/src/third_party/websocketpp/websocketpp/transport/stub/connection.hpp @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2014, Peter Thorson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the WebSocket++ Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef WEBSOCKETPP_TRANSPORT_STUB_CON_HPP +#define WEBSOCKETPP_TRANSPORT_STUB_CON_HPP + +#include +#include +#include +#include + +#include +#include + +namespace websocketpp { +namespace transport { +namespace stub { + +/// Empty timer class to stub out for timer functionality that stub +/// transport doesn't support +struct timer { + void cancel() {} +}; + +template +class connection : public lib::enable_shared_from_this< connection > { +public: + /// Type of this connection transport component + typedef connection type; + /// Type of a shared pointer to this connection transport component + typedef lib::shared_ptr ptr; + + /// transport concurrency policy + typedef typename config::concurrency_type concurrency_type; + /// Type of this transport's access logging policy + typedef typename config::alog_type alog_type; + /// Type of this transport's error logging policy + typedef typename config::elog_type elog_type; + + // Concurrency policy types + typedef typename concurrency_type::scoped_lock_type scoped_lock_type; + typedef typename concurrency_type::mutex_type mutex_type; + + typedef lib::shared_ptr timer_ptr; + + explicit connection(bool is_server, alog_type & alog, elog_type & elog) + { + m_alog.write(log::alevel::devel,"stub con transport constructor"); + } + + /// Get a shared pointer to this component + ptr get_shared() { + return type::shared_from_this(); + } + + /// Set whether or not this connection is secure + /** + * Todo: docs + * + * @since 0.3.0-alpha4 + * + * @param value Whether or not this connection is secure. + */ + void set_secure(bool value) {} + + /// Tests whether or not the underlying transport is secure + /** + * TODO: docs + * + * @return Whether or not the underlying transport is secure + */ + bool is_secure() const { + return false; + } + + /// Set human readable remote endpoint address + /** + * Sets the remote endpoint address returned by `get_remote_endpoint`. This + * value should be a human readable string that describes the remote + * endpoint. Typically an IP address or hostname, perhaps with a port. But + * may be something else depending on the nature of the underlying + * transport. + * + * If none is set a default is returned. + * + * @since 0.3.0-alpha4 + * + * @param value The remote endpoint address to set. + */ + void set_remote_endpoint(std::string value) {} + + /// Get human readable remote endpoint address + /** + * TODO: docs + * + * This value is used in access and error logs and is available to the end + * application for including in user facing interfaces and messages. + * + * @return A string identifying the address of the remote endpoint + */ + std::string get_remote_endpoint() const { + return "unknown (stub transport)"; + } + + /// Get the connection handle + /** + * @return The handle for this connection. + */ + connection_hdl get_handle() const { + return connection_hdl(); + } + + /// Call back a function after a period of time. + /** + * Timers are not implemented in this transport. The timer pointer will + * always be empty. The handler will never be called. + * + * @param duration Length of time to wait in milliseconds + * @param callback The function to call back when the timer has expired + * @return A handle that can be used to cancel the timer if it is no longer + * needed. + */ + timer_ptr set_timer(long duration, timer_handler handler) { + return timer_ptr(); + } +protected: + /// Initialize the connection transport + /** + * Initialize the connection's transport component. + * + * @param handler The `init_handler` to call when initialization is done + */ + void init(init_handler handler) { + m_alog.write(log::alevel::devel,"stub connection init"); + handler(make_error_code(error::not_implimented)); + } + + /// Initiate an async_read for at least num_bytes bytes into buf + /** + * Initiates an async_read request for at least num_bytes bytes. The input + * will be read into buf. A maximum of len bytes will be input. When the + * operation is complete, handler will be called with the status and number + * of bytes read. + * + * This method may or may not call handler from within the initial call. The + * application should be prepared to accept either. + * + * The application should never call this method a second time before it has + * been called back for the first read. If this is done, the second read + * will be called back immediately with a double_read error. + * + * If num_bytes or len are zero handler will be called back immediately + * indicating success. + * + * @param num_bytes Don't call handler until at least this many bytes have + * been read. + * @param buf The buffer to read bytes into + * @param len The size of buf. At maximum, this many bytes will be read. + * @param handler The callback to invoke when the operation is complete or + * ends in an error + */ + void async_read_at_least(size_t num_bytes, char *buf, size_t len, + read_handler handler) + { + m_alog.write(log::alevel::devel, "stub_con async_read_at_least"); + handler(make_error_code(error::not_implimented)); + } + + /// Asyncronous Transport Write + /** + * Write len bytes in buf to the output stream. Call handler to report + * success or failure. handler may or may not be called during async_write, + * but it must be safe for this to happen. + * + * Will return 0 on success. + * + * @param buf buffer to read bytes from + * @param len number of bytes to write + * @param handler Callback to invoke with operation status. + */ + void async_write(char const * buf, size_t len, write_handler handler) { + m_alog.write(log::alevel::devel,"stub_con async_write"); + handler(make_error_code(error::not_implimented)); + } + + /// Asyncronous Transport Write (scatter-gather) + /** + * Write a sequence of buffers to the output stream. Call handler to report + * success or failure. handler may or may not be called during async_write, + * but it must be safe for this to happen. + * + * Will return 0 on success. + * + * @param bufs vector of buffers to write + * @param handler Callback to invoke with operation status. + */ + void async_write(std::vector const & bufs, write_handler handler) { + m_alog.write(log::alevel::devel,"stub_con async_write buffer list"); + handler(make_error_code(error::not_implimented)); + } + + /// Set Connection Handle + /** + * @param hdl The new handle + */ + void set_handle(connection_hdl hdl) {} + + /// Call given handler back within the transport's event system (if present) + /** + * Invoke a callback within the transport's event system if it has one. If + * it doesn't, the handler will be invoked immediately before this function + * returns. + * + * @param handler The callback to invoke + * + * @return Whether or not the transport was able to register the handler for + * callback. + */ + lib::error_code dispatch(dispatch_handler handler) { + handler(); + return lib::error_code(); + } + + /// Perform cleanup on socket shutdown_handler + /** + * @param h The `shutdown_handler` to call back when complete + */ + void async_shutdown(shutdown_handler handler) { + handler(lib::error_code()); + } +private: + // member variables! +}; + + +} // namespace stub +} // namespace transport +} // namespace websocketpp + +#endif // WEBSOCKETPP_TRANSPORT_STUB_CON_HPP diff --git a/src/third_party/websocketpp/websocketpp/transport/stub/endpoint.hpp b/src/third_party/websocketpp/websocketpp/transport/stub/endpoint.hpp new file mode 100644 index 00000000..7be76d7f --- /dev/null +++ b/src/third_party/websocketpp/websocketpp/transport/stub/endpoint.hpp @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2014, Peter Thorson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the WebSocket++ Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef WEBSOCKETPP_TRANSPORT_STUB_HPP +#define WEBSOCKETPP_TRANSPORT_STUB_HPP + +#include +#include + +#include +#include + +namespace websocketpp { +namespace transport { +namespace stub { + +template +class endpoint { +public: + /// Type of this endpoint transport component + typedef endpoint type; + /// Type of a pointer to this endpoint transport component + typedef lib::shared_ptr ptr; + + /// Type of this endpoint's concurrency policy + typedef typename config::concurrency_type concurrency_type; + /// Type of this endpoint's error logging policy + typedef typename config::elog_type elog_type; + /// Type of this endpoint's access logging policy + typedef typename config::alog_type alog_type; + + /// Type of this endpoint transport component's associated connection + /// transport component. + typedef iostream::connection transport_con_type; + /// Type of a shared pointer to this endpoint transport component's + /// associated connection transport component + typedef typename transport_con_type::ptr transport_con_ptr; + + // generate and manage our own io_service + explicit endpoint() + { + //std::cout << "transport::iostream::endpoint constructor" << std::endl; + } + + /// Set whether or not endpoint can create secure connections + /** + * TODO: docs + * + * Setting this value only indicates whether or not the endpoint is capable + * of producing and managing secure connections. Connections produced by + * this endpoint must also be individually flagged as secure if they are. + * + * @since 0.3.0-alpha4 + * + * @param value Whether or not the endpoint can create secure connections. + */ + void set_secure(bool value) {} + + /// Tests whether or not the underlying transport is secure + /** + * TODO: docs + * + * @return Whether or not the underlying transport is secure + */ + bool is_secure() const { + return false; + } +protected: + /// Initialize logging + /** + * The loggers are located in the main endpoint class. As such, the + * transport doesn't have direct access to them. This method is called + * by the endpoint constructor to allow shared logging from the transport + * component. These are raw pointers to member variables of the endpoint. + * In particular, they cannot be used in the transport constructor as they + * haven't been constructed yet, and cannot be used in the transport + * destructor as they will have been destroyed by then. + * + * @param a A pointer to the access logger to use. + * @param e A pointer to the error logger to use. + */ + void init_logging(alog_type * a, elog_type * e) {} + + /// Initiate a new connection + /** + * @param tcon A pointer to the transport connection component of the + * connection to connect. + * @param u A URI pointer to the URI to connect to. + * @param cb The function to call back with the results when complete. + */ + void async_connect(transport_con_ptr tcon, uri_ptr u, connect_handler cb) { + cb(make_error_code(error::not_implimented)); + } + + /// Initialize a connection + /** + * Init is called by an endpoint once for each newly created connection. + * It's purpose is to give the transport policy the chance to perform any + * transport specific initialization that couldn't be done via the default + * constructor. + * + * @param tcon A pointer to the transport portion of the connection. + * @return A status code indicating the success or failure of the operation + */ + lib::error_code init(transport_con_ptr tcon) { + cb(make_error_code(error::not_implimented)); + } +private: + +}; + +} // namespace stub +} // namespace transport +} // namespace websocketpp + +#endif // WEBSOCKETPP_TRANSPORT_STUB_HPP diff --git a/src/third_party/websocketpp/websocketpp/uri.hpp b/src/third_party/websocketpp/websocketpp/uri.hpp index 5471031a..ff8285ba 100644 --- a/src/third_party/websocketpp/websocketpp/uri.hpp +++ b/src/third_party/websocketpp/websocketpp/uri.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -47,13 +47,13 @@ static uint16_t const uri_default_secure_port = 443; class uri { public: - explicit uri(std::string const & uri) : m_valid(false) { + explicit uri(std::string const & uri_string) : m_valid(false) { std::string::const_iterator it; std::string::const_iterator temp; int state = 0; - it = uri.begin(); + it = uri_string.begin(); if (std::equal(it,it+6,"wss://")) { m_secure = true; @@ -88,14 +88,14 @@ public: //temp = std::find(it,it2,']'); temp = it; - while (temp != uri.end()) { + while (temp != uri_string.end()) { if (*temp == ']') { break; } ++temp; } - if (temp == uri.end()) { + if (temp == uri_string.end()) { return; } else { // validate IPv6 literal parts @@ -103,7 +103,7 @@ public: m_host.append(it,temp); } it = temp+1; - if (it == uri.end()) { + if (it == uri_string.end()) { state = 2; } else if (*it == '/') { state = 2; @@ -119,7 +119,7 @@ public: // IPv4 or hostname // extract until : or / while (state == 0) { - if (it == uri.end()) { + if (it == uri_string.end()) { state = 2; break; } else if (*it == '/') { @@ -137,7 +137,7 @@ public: // parse port std::string port = ""; while (state == 1) { - if (it == uri.end()) { + if (it == uri_string.end()) { // state is not used after this point presently. // this should be re-enabled if it ever is needed in a future // refactoring @@ -159,7 +159,7 @@ public: } m_resource = "/"; - m_resource.append(it,uri.end()); + m_resource.append(it,uri_string.end()); m_valid = true; @@ -290,10 +290,10 @@ public: * @return query portion of the URI. */ std::string get_query() const { - std::size_t found = m_resource.find('?'); - if (found != std::string::npos) { - return m_resource.substr(found + 1); - } else { + std::size_t found = m_resource.find('?'); + if (found != std::string::npos) { + return m_resource.substr(found + 1); + } else { return ""; } } diff --git a/src/third_party/websocketpp/websocketpp/utilities.hpp b/src/third_party/websocketpp/websocketpp/utilities.hpp index 07745661..747f1199 100644 --- a/src/third_party/websocketpp/websocketpp/utilities.hpp +++ b/src/third_party/websocketpp/websocketpp/utilities.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -78,7 +78,7 @@ struct ci_less : std::binary_function { : public std::binary_function { bool operator() (unsigned char const & c1, unsigned char const & c2) const { - return std::tolower (c1) < std::tolower (c2); + return tolower (c1) < tolower (c2); } }; bool operator() (std::string const & s1, std::string const & s2) const { diff --git a/src/third_party/websocketpp/websocketpp/version.hpp b/src/third_party/websocketpp/websocketpp/version.hpp index e6c9cbf7..a9a80297 100644 --- a/src/third_party/websocketpp/websocketpp/version.hpp +++ b/src/third_party/websocketpp/websocketpp/version.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Peter Thorson. All rights reserved. + * Copyright (c) 2014, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -42,7 +42,7 @@ namespace websocketpp { /// Library major version number static int const major_version = 0; /// Library minor version number -static int const minor_version = 3; +static int const minor_version = 4; /// Library patch version number static int const patch_version = 0; /// Library pre-release flag @@ -50,10 +50,10 @@ static int const patch_version = 0; * This is a textual flag indicating the type and number for pre-release * versions (dev, alpha, beta, rc). This will be blank for release versions. */ -static char const prerelease_flag[] = "alpha4"; +static char const prerelease_flag[] = ""; /// Default user agent string -static char const user_agent[] = "WebSocket++/0.3.0-alpha4"; +static char const user_agent[] = "WebSocket++/0.4.0"; } // namespace websocketpp