diff --git a/Release/libs/websocketpp/.travis.yml b/Release/libs/websocketpp/.travis.yml index 027ac560ed..0ee516e9b8 100644 --- a/Release/libs/websocketpp/.travis.yml +++ b/Release/libs/websocketpp/.travis.yml @@ -2,7 +2,7 @@ language: cpp compiler: - gcc before_install: - - sudo apt-get install libboost-regex1.48-dev libboost-system1.48-dev libboost-thread1.48-dev libboost-test1.48-dev libboost-random1.48-dev -y + - sudo apt-get install libboost-chrono1.48-dev libboost-regex1.48-dev libboost-system1.48-dev libboost-thread1.48-dev libboost-test1.48-dev libboost-random1.48-dev -y env: global: - BOOST_INCLUDES=/usr/include diff --git a/Release/libs/websocketpp/CMakeLists.txt b/Release/libs/websocketpp/CMakeLists.txt index 8279156029..0874b4eed8 100644 --- a/Release/libs/websocketpp/CMakeLists.txt +++ b/Release/libs/websocketpp/CMakeLists.txt @@ -9,8 +9,8 @@ project (websocketpp) cmake_minimum_required (VERSION 2.6) set (WEBSOCKETPP_MAJOR_VERSION 0) -set (WEBSOCKETPP_MINOR_VERSION 5) -set (WEBSOCKETPP_PATCH_VERSION 1) +set (WEBSOCKETPP_MINOR_VERSION 6) +set (WEBSOCKETPP_PATCH_VERSION 0) set (WEBSOCKETPP_VERSION ${WEBSOCKETPP_MAJOR_VERSION}.${WEBSOCKETPP_MINOR_VERSION}.${WEBSOCKETPP_PATCH_VERSION}) set(INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for header files") @@ -70,7 +70,7 @@ if (BUILD_TESTS OR BUILD_EXAMPLES) ############ Compiler specific setup set (WEBSOCKETPP_PLATFORM_LIBS "") - set (WEBSOCKETPP_PLATFORM_TSL_LIBS "") + set (WEBSOCKETPP_PLATFORM_TLS_LIBS "") set (WEBSOCKETPP_BOOST_LIBS "") # VC9 and C++11 reasoning @@ -111,7 +111,7 @@ if (BUILD_TESTS OR BUILD_EXAMPLES) # g++ if (CMAKE_COMPILER_IS_GNUCXX) set (WEBSOCKETPP_PLATFORM_LIBS pthread rt) - set (WEBSOCKETPP_PLATFORM_TSL_LIBS ssl crypto) + set (WEBSOCKETPP_PLATFORM_TLS_LIBS ssl crypto) set (WEBSOCKETPP_BOOST_LIBS system thread) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") if (NOT APPLE) @@ -133,7 +133,7 @@ if (BUILD_TESTS OR BUILD_EXAMPLES) else() set (WEBSOCKETPP_PLATFORM_LIBS pthread) endif() - set (WEBSOCKETPP_PLATFORM_TSL_LIBS ssl crypto) + set (WEBSOCKETPP_PLATFORM_TLS_LIBS ssl crypto) set (WEBSOCKETPP_BOOST_LIBS system thread) set (CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-std=c++0x -stdlib=libc++") # todo: is libc++ really needed here? if (NOT APPLE) diff --git a/Release/libs/websocketpp/Doxyfile b/Release/libs/websocketpp/Doxyfile index ff97242672..b9ff53dc05 100644 --- a/Release/libs/websocketpp/Doxyfile +++ b/Release/libs/websocketpp/Doxyfile @@ -32,9 +32,7 @@ PROJECT_NAME = "websocketpp" # This could be handy for archiving the generated documentation or # if some version control system is used. - -PROJECT_NUMBER = "0.5.1" - +PROJECT_NUMBER = "0.6.0" # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer diff --git a/Release/libs/websocketpp/SConstruct b/Release/libs/websocketpp/SConstruct index e01ff04e94..b064417f49 100644 --- a/Release/libs/websocketpp/SConstruct +++ b/Release/libs/websocketpp/SConstruct @@ -125,6 +125,7 @@ elif env['CXX'].startswith('clang++'): # Wpadded # Wsign-conversion + # platform_libs = [] tls_libs = [] @@ -240,8 +241,12 @@ testee_server = SConscript('#/examples/testee_server/SConscript',variant_dir = b # testee_client testee_client = SConscript('#/examples/testee_client/SConscript',variant_dir = builddir + 'testee_client',duplicate = 0) -# utility_client -utility_client = SConscript('#/examples/utility_client/SConscript',variant_dir = builddir + 'utility_client',duplicate = 0) +# scratch_client +scratch_client = SConscript('#/examples/scratch_client/SConscript',variant_dir = builddir + 'scratch_client',duplicate = 0) + +# scratch_server +scratch_server = SConscript('#/examples/scratch_server/SConscript',variant_dir = builddir + 'scratch_server',duplicate = 0) + # debug_client debug_client = SConscript('#/examples/debug_client/SConscript',variant_dir = builddir + 'debug_client',duplicate = 0) diff --git a/Release/libs/websocketpp/changelog.md b/Release/libs/websocketpp/changelog.md index 296f1054ee..986245bf8b 100644 --- a/Release/libs/websocketpp/changelog.md +++ b/Release/libs/websocketpp/changelog.md @@ -1,10 +1,55 @@ HEAD +0.6.0 +- MINOR BREAKING TRANSPORT POLICY CHANGE: Custom transport policies will now be + required to include a new method `void set_uri(uri_ptr u)`. An implementation + is not required. The stub transport policy includes an example stub method + that can be added to any existing custom transport policy to fulfill this + requirement. This does not affect anyone using the bundled transports or + configs. +- MINOR BREAKING SOCKET POLICY CHANGE: Custom asio transport socket policies + will now be required to include a new method `void set_uri(uri_ptr u)`. Like + with the transport layer, an implementation is not required. This does not + affect anyone using the bundled socket policies. +- MINOR BREAKING DEPENDENCY CHANGE: When using Boost versions greater than or + equal to 1.49 in C++03 mode, `libboost-chrono` is needed now instead of + `libboost-date_time`. Users with C++11 compilers or using Boost versions 1.48 + and earlier are not affected. Note: This change affects the bundled unit test + suite. +- Feature: WebSocket++ Asio transport policy can now be used with the standalone + version of Asio (1.8.0+) when a C++11 compiler and standard library are + present. This means that it is possible now to use WebSocket++'s Asio + transport entirely without Boost. Thank you Robert Seiler for proof of concept + code that was used as a guide for this implementation. Fixes #324 +- Feature: Adds a vectored/scatter-gather write handler to the iostream + transport. +- Feature: Adds the ability to defer sending an HTTP response until sometime + after the `http_handler` is run. This allows processing of long running http + handlers to defer their response until it is ready without blocking the + network thread. references #425 +- Improvement: `echo_server_tls` has been update to demonstrate how to configure + it for Mozilla's recommended intermediate and modern TLS security profiles. +- Improvement: `endpoint::set_timer` now uses a steady clock provided by + `boost::chrono` or `std::chrono` where available instead of the non-monotonic + system clock. Thank you breyed for reporting. fixes #241 +- Improvement: Outgoing TLS connections to servers using the SNI extension to + choose a certificate will now work. Thank you moozzyk for reporting. + Fixes #400 +- Improvement: Removes an unnecessary mutex lock in `get_con_from_hdl`. +- Cleanup: Asio transport policy has been refactored to remove many Boost + dependencies. On C++03 compilers the `boost::noncopyable` dependency has been + removed and the `boost::date_time` dependency has been replaced with the newer + `boost::chrono` when possible. On C++11 compilers the `boost::aligned_storage` + and `boost::date_time` dependencies are gone, replaced with equivalent C++11 + standard library features. +- Bug: Fixes a potential dangling pointer and inconsistent error message + handling in `websocketpp::exception`. #432 Thank you Tom Swirly for the fix. + 0.5.1 - 2015-02-27 - Bug: Fixes an issue where some frame data was counted against the max header size limit, resulting in connections that included a lot of frame data immediately after the opening handshake to fail. -- Bug: Fix a type in the name of the set method for `max_http_body_size`. #406 +- Bug: Fix a typo in the name of the set method for `max_http_body_size`. #406 Thank you jplatte for reporting. 0.5.0 - 2015-01-22 diff --git a/Release/libs/websocketpp/cmake/CMakeHelpers.cmake b/Release/libs/websocketpp/cmake/CMakeHelpers.cmake new file mode 100755 index 0000000000..0a23905e89 --- /dev/null +++ b/Release/libs/websocketpp/cmake/CMakeHelpers.cmake @@ -0,0 +1,78 @@ + +# Print build configuration +macro (print_used_build_config) + message ("\n=========== Used Build Configuration =============\n") + message (STATUS "ENABLE_CPP11 = " ${ENABLE_CPP11}) + message (STATUS "BUILD_EXAMPLES = " ${BUILD_EXAMPLES}) + message (STATUS "BUILD_TESTS = " ${BUILD_TESTS}) + message ("") + message (STATUS "WEBSOCKETPP_ROOT = " ${WEBSOCKETPP_ROOT}) + message (STATUS "WEBSOCKETPP_BIN = " ${WEBSOCKETPP_BIN}) + message (STATUS "WEBSOCKETPP_LIB = " ${WEBSOCKETPP_LIB}) + message (STATUS "Install prefix = " ${CMAKE_INSTALL_PREFIX}) + message ("") + message (STATUS "WEBSOCKETPP_BOOST_LIBS = ${WEBSOCKETPP_BOOST_LIBS}") + message (STATUS "WEBSOCKETPP_PLATFORM_LIBS = ${WEBSOCKETPP_PLATFORM_LIBS}") + message (STATUS "WEBSOCKETPP_PLATFORM_TSL_LIBS = ${WEBSOCKETPP_PLATFORM_TSL_LIBS}") + message ("") +endmacro () + +# Adds the given folder_name into the source files of the current project. +# Use this macro when your module contains .cpp and .h files in several subdirectories. +# Your sources variable needs to be WSPP_SOURCE_FILES and headers variable WSPP_HEADER_FILES. +macro(add_source_folder folder_name) + file(GLOB H_FILES_IN_FOLDER_${folder_name} ${folder_name}/*.hpp ${folder_name}/*.h) + file(GLOB CPP_FILES_IN_FOLDER_${folder_name} ${folder_name}/*.cpp ${folder_name}/*.c) + source_group("Header Files\\${folder_name}" FILES ${H_FILES_IN_FOLDER_${folder_name}}) + source_group("Source Files\\${folder_name}" FILES ${CPP_FILES_IN_FOLDER_${folder_name}}) + set(WSPP_HEADER_FILES ${WSPP_HEADER_FILES} ${H_FILES_IN_FOLDER_${folder_name}}) + set(WSPP_SOURCE_FILES ${WSPP_SOURCE_FILES} ${CPP_FILES_IN_FOLDER_${folder_name}}) +endmacro() + +# Initialize target. +macro (init_target NAME) + set (TARGET_NAME ${NAME}) + message ("** " ${TARGET_NAME}) + + # Include our own module path. This makes #include "x.h" + # work in project subfolders to include the main directory headers. + include_directories (${CMAKE_CURRENT_SOURCE_DIR}) +endmacro () + +# Build executable for executables +macro (build_executable TARGET_NAME) + set (TARGET_LIB_TYPE "EXECUTABLE") + message (STATUS "-- Build Type:") + message (STATUS " " ${TARGET_LIB_TYPE}) + + add_executable (${TARGET_NAME} ${ARGN}) + + include_directories (${WEBSOCKETPP_ROOT} ${WEBSOCKETPP_INCLUDE}) + + set_target_properties (${TARGET_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${WEBSOCKETPP_BIN}) + set_target_properties (${TARGET_NAME} PROPERTIES DEBUG_POSTFIX d) +endmacro () + +# Finalize target for all types +macro (final_target) + if ("${TARGET_LIB_TYPE}" STREQUAL "EXECUTABLE") + install (TARGETS ${TARGET_NAME} + RUNTIME DESTINATION "bin" + CONFIGURATIONS ${CMAKE_CONFIGURATION_TYPES}) + endif () + + # install headers, directly from current source dir and look for subfolders with headers + file (GLOB_RECURSE TARGET_INSTALL_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.hpp) + foreach (hppfile ${TARGET_INSTALL_HEADERS}) + get_filename_component (currdir ${hppfile} PATH) + install (FILES ${hppfile} DESTINATION "include/${TARGET_NAME}/${currdir}") + endforeach() +endmacro () + +macro (link_boost) + target_link_libraries (${TARGET_NAME} ${Boost_LIBRARIES}) +endmacro () + +macro (link_openssl) + target_link_libraries (${TARGET_NAME} ${OPENSSL_SSL_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY}) +endmacro () diff --git a/Release/libs/websocketpp/examples/echo_server/echo_server.cpp b/Release/libs/websocketpp/examples/echo_server/echo_server.cpp index 5ec576f949..5ae78ad39b 100644 --- a/Release/libs/websocketpp/examples/echo_server/echo_server.cpp +++ b/Release/libs/websocketpp/examples/echo_server/echo_server.cpp @@ -19,6 +19,13 @@ void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) { << " and message: " << msg->get_payload() << std::endl; + // check for a special command to instruct the server to stop listening so + // it can be cleanly exited. + if (msg->get_payload() == "stop-listening") { + s->stop_listening(); + return; + } + try { s->send(hdl, msg->get_payload(), msg->get_opcode()); } catch (const websocketpp::lib::error_code& e) { diff --git a/Release/libs/websocketpp/examples/echo_server_tls/dh.pem b/Release/libs/websocketpp/examples/echo_server_tls/dh.pem new file mode 100755 index 0000000000..6b1c74d43f --- /dev/null +++ b/Release/libs/websocketpp/examples/echo_server_tls/dh.pem @@ -0,0 +1,8 @@ +-----BEGIN DH PARAMETERS----- +MIIBCAKCAQEAqxMGKZB8YNV8WQnbJWwwwmifc+PfVRtd1FN5v5aQSsf6dpjX3Zlh +N1NmgecsQyg4u2EWe4Umta10QzCgYaxf6QdTCg7iprLzFNw7IvWYbQ6du12NMGDr +hmwA6KQKwbTgPL6mSlSlcK2wTP2FzxDTNffFu10cB/6Fj4kdQjPG0c1Koz/z7OOq +BuDElJLClS8rjp3z1xvrc7gX95dFa2KaKgOAYDkpe8tfHRhHfJeIVS/whH9hzx6r +OBg+E5K9JyvayrUoKgPeptRKCqo8A4YevtMLpRxMup0nMUgAIv6+BGTwPAFpwgl/ +8UIVcvjh1v95PwGDM/Q8yvIBJznBYk/e2wIBAg== +-----END DH PARAMETERS----- diff --git a/Release/libs/websocketpp/examples/echo_server_tls/echo_server_tls.cpp b/Release/libs/websocketpp/examples/echo_server_tls/echo_server_tls.cpp index 8408ebccca..a260c9e4ea 100644 --- a/Release/libs/websocketpp/examples/echo_server_tls/echo_server_tls.cpp +++ b/Release/libs/websocketpp/examples/echo_server_tls/echo_server_tls.cpp @@ -27,24 +27,66 @@ void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) { } } +void on_http(server* s, websocketpp::connection_hdl hdl) { + server::connection_ptr con = s->get_con_from_hdl(hdl); + + con->set_body("Hello World!"); + con->set_status(websocketpp::http::status_code::ok); +} + std::string get_password() { return "test"; } -context_ptr on_tls_init(websocketpp::connection_hdl hdl) { +// See https://wiki.mozilla.org/Security/Server_Side_TLS for more details about +// the TLS modes. The code below demonstrates how to implement both the modern +enum tls_mode { + MOZILLA_INTERMEDIATE = 1, + MOZILLA_MODERN = 2 +}; + +context_ptr on_tls_init(tls_mode mode, websocketpp::connection_hdl hdl) { std::cout << "on_tls_init called with hdl: " << hdl.lock().get() << std::endl; - context_ptr ctx = websocketpp::lib::make_shared(boost::asio::ssl::context::tlsv1); + std::cout << "using TLS mode: " << (mode == MOZILLA_MODERN ? "Mozilla Modern" : "Mozilla Intermediate") << std::endl; + context_ptr ctx = websocketpp::lib::make_shared(boost::asio::ssl::context::sslv23); try { - ctx->set_options(boost::asio::ssl::context::default_workarounds | - boost::asio::ssl::context::no_sslv2 | - boost::asio::ssl::context::no_sslv3 | - boost::asio::ssl::context::single_dh_use); + if (mode == MOZILLA_MODERN) { + // Modern disables TLSv1 + ctx->set_options(boost::asio::ssl::context::default_workarounds | + boost::asio::ssl::context::no_sslv2 | + boost::asio::ssl::context::no_sslv3 | + boost::asio::ssl::context::no_tlsv1 | + boost::asio::ssl::context::single_dh_use); + } else { + ctx->set_options(boost::asio::ssl::context::default_workarounds | + boost::asio::ssl::context::no_sslv2 | + boost::asio::ssl::context::no_sslv3 | + boost::asio::ssl::context::single_dh_use); + } ctx->set_password_callback(bind(&get_password)); ctx->use_certificate_chain_file("server.pem"); ctx->use_private_key_file("server.pem", boost::asio::ssl::context::pem); + + // Example method of generating this file: + // `openssl dhparam -out dh.pem 2048` + // Mozilla Intermediate suggests 1024 as the minimum size to use + // Mozilla Modern suggests 2048 as the minimum size to use. + ctx->use_tmp_dh_file("dh.pem"); + + std::string ciphers; + + if (mode == MOZILLA_MODERN) { + ciphers = "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK"; + } else { + ciphers = "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA"; + } + + if (SSL_CTX_set_cipher_list(ctx->native_handle() , ciphers.c_str()) != 1) { + std::cout << "Error setting cipher list" << std::endl; + } } catch (std::exception& e) { - std::cout << e.what() << std::endl; + std::cout << "Exception: " << e.what() << std::endl; } return ctx; } @@ -58,8 +100,8 @@ int main() { // Register our message handler echo_server.set_message_handler(bind(&on_message,&echo_server,::_1,::_2)); - echo_server.set_tls_init_handler(bind(&on_tls_init,::_1)); - + echo_server.set_http_handler(bind(&on_http,&echo_server,::_1)); + echo_server.set_tls_init_handler(bind(&on_tls_init,MOZILLA_INTERMEDIATE,::_1)); // Listen on port 9002 echo_server.listen(9002); diff --git a/Release/libs/websocketpp/examples/echo_server_tls/server.pem b/Release/libs/websocketpp/examples/echo_server_tls/server.pem index 9f679a49b6..5196dcfe55 100644 --- a/Release/libs/websocketpp/examples/echo_server_tls/server.pem +++ b/Release/libs/websocketpp/examples/echo_server_tls/server.pem @@ -1,58 +1,55 @@ -----BEGIN RSA PRIVATE KEY----- -Proc-Type: 4,ENCRYPTED -DEK-Info: DES-EDE3-CBC,A0ED66EF872A48A9 - -gXuvKojXzApVhhPVNdRliiajbC4PtwQG5c8TA7JADLgwOR7o9t6KtXEr37bDRpvB -9aO9P+SJaK5OOp3XKPGthOdqv+tvCRTlmzmC8GjPLBX389DWT2xoGu7JkGwDtdSm -rnF49Rlp5bfjpACk5xKNiKeDo1CWfeEJzw9Kto0g+5eMaEdors64oPzjXs3geA2g -TxCJSHv9qSX6++pCLKKCUTbyzidAxV/Zb0AAubt5V40QKqX4HhSwwstFnTaX3tlb -3QOdY+y04VIkM6d7qN5W8M7NzRkMpZ1qBpQcUMpkhQcRzWP2wub5AAff9D2GntRd -4Dz1vn3u41U3Okdr0CNj+iH7byCzuokoAhk6ZQEN6WB+GTpGgfBXdtUZrfpb0MKm -UNYP5AF2AmUqJRXhViTDVtu/V2tHF3LGuNT+W2Dz+spFZEq0byEO0N858eR0dikc -6jOASvNQbSwD0+mkgBC1gXKKU3ngj2gpJUwljeACdWFd8N2egrZfyI05CmX7vPNC -NXbs7k2buWNdjP4/D8IM+HDVidWzQa/kG/qokXKqllem9Egg37lUucwnP3cX2/Hw -U2mfaBWzeZtqc+GqRp08rYIql+Reai3sUYlQMnNk01prVY47UQb+dxuqjaxGV5Xx -Xkx0s2mfQnNRjL4S7Hjhqelufi6GpkCQ2EGsPpA+6K1ztZ0ame9Q2BE1SXeM/6vU -rxT5nRrCxueyXAyQSGcqMX9//gSeK8WWBqG/c1IAMVDa0NWrJeOJhSziE+ta3B0m -bHAPBY6vh0iB3lLdRlbUOPbC6R1TpxMOs+6Vbs2+OTifFpvOVymEoZq/nroyg68P -vn5uCKogwWA7o8EArf/UTlIwWJmH9bgILdZKld4wMel2HQg16RDzm+mEXAJi52a/ -FC+fgfphdxltmUJ+rqOyR4AHULjaTWUQqTIB6sdlzgmES1nXAiE71zX//KFqomar -O60SPPk3C1bs0x5DsvmGJa8SIfDhyd+D7NPyqwEKqrZsaotYGklNkfqxa6pa8mrc -ejxquW1PK4FvBk26+osu5a90Jih0PcQM7DUMMr2WHdTiMSXWAiK2ToYF8Itt25Qv -Cd0CsSYw9CJkXNr1u1+mObheaY9QYOmztnSJLy4ZO2JsMhqNwuAueIcwmhXOREq7 -kzlnGMgJcuSeAS/OBNj8Zgx0c7QQ0kzc+YmnOCsqoMtPsu/CsXJ4iJiM3Tki/2jT -bywrTiQwE6R3a/87GREOREX+WLicZBWX3k9/4tBL5XSe1p5wPpuIRQUDvAGNfNHP -JN7kujDF4SehilF1qtvCygAwvxHFDj+EwhXKNDKJzoZZIM15rAk3k92n2j6nz1qH -a3xOU05yydOlO6F6w51I1QoDddmkzCRNB0TeO3D6rekHsCK1aDWmC+qRcm2ZFtVz -sY6fdZN2NEmMQokIh9Opi1f8CSYSizPESMzdu2SF0xVO9n/IGIkn1ksK04O2BZo0 -X3LBPHLfCRsQNY1eF17bj07fYU2oPZKs/XzJiwxkqK6LFvpeAVaYrtg9fqRO/UVe -QhUIj3BL550ocEpa15xLehLrmwzYiW5zwGjSHQ4EgZluGLCwyKGTh4QswEJRA9Rt +MIIEowIBAAKCAQEA77v5VbFaq+geVd/RCLXoKTWj/LgXGjiOXBpJZca3o5edi7N1 +Ej41/13jfZ4OxgFIRFAALd+fU4NsObXzskth3rJLmJjUtGajRIPqF2IUVjFMmybQ +9dUDSqPzd/bG+ul0DP7DNuiBcLC8XNC3/kchPUzVq9gNDk56jXn87kMoIkVXBWQS +Rwk0yCtELSfwxxRCrGKgQDfXnRdwmkPe42DmKtdGksXJlUhP1UVTAXaSw1Nz64LV +9bJje/eoDsSe4OxifVVToE6ZxIW+r1jVgrcupeYXQrSHIztl2U/rx2JkGMN0eS+P +qrsJmkmRBN1cpgmvSV7WoM3hj6Eq71z4Dfv6EwIDAQABAoIBAEXAL19bZsI1mv3p +TOx34MB8tuXEuhQK+ICbtVdDZhLW/iOzZxCTwSo3qwTVg/7gSKJ3lFXEhprJ1idE +ZU8u157vyUbw0JJceoxoxSdghgI9/cf2lz2vaHHDGgeBaYt/eSB+z1WeeGrNQUDQ +CXiWQXmQbWq+Ra4v70BSieDY8UhmzCTRhvfZV80vaY/4SnHxJ9C8Nu8/An7U3pwq +ccfTaWMp3Q5ztmEnExF6/b1SUsnI8rzFovw/4C50AU09N/Z6zZVFsXgJAT2Kd1Tx +HfP1vUkWZ/TJ6kcmVIV9U3uMcedBD8Rb/3M0Qdp+eymQ+1oYQ3K3/a2RlUQIeXzf +hRbE4wECgYEA/WyULrwBsvSMPqK0K9pZpv921Yl6d4bGnpxKze7ltc9o5/LsU35q +8u29Es7cPyhyUDOsPW8v2CNjw54t+eFGsu59bBvXZNz5gB7hTUEyLntB24cO5PmN +kVExcMDFC6NgPaauBtUhODievKJ2C8P7sRJDAVKE9KkavDddU7nSEjMCgYEA8ivG +AqwNXYsiIFjAo4uj3kuBFt8LU/q4m6GXI+9qyxfiJjuF1dROx5qaQGiE85VaBFUu +gpbnjZH7s+BBgoaQhrB4i6mztljdN1KKuAlnjhB+Fywg8m8N9lAi3wIaxnIEqDkU +vFiIFPTBCk0U7IZ/OyCrKPQTE9ApWHfBwA/vWKECgYBQixrJg61SkBCms5Vpvprx +zY2aLniC1o33yRqpOr09PG9OENH1c19QWCjYenBbjmJOhS2/1L+zBQRnHrXkDion +Ik8wdeTORMDzbF0U7ZyiU0BKIjGkqn/I6LI68LlvinxC+9+hgkltkek5cLTt5lrv +Gyu6ltx02e4KVdpOiuduKwKBgQC3U0PWigCkK8ttyUIrjG5Evcu/UKH2tPpDdpQ/ +8+JYVIAyiSTLtqjcmcDjuTvMWeeHGCTZXvtzRGvSw5VUBiIqlDTtJU6SX7s3QhkZ +MKVf+kQ5roJShJeBOzDquWEjkPTNlEiKPErn8lCgR7HrS/XNAPIRUpOOkCp8ekwF +5Qo/gQKBgAue3TeCeIzxh4PxSAk39Uaj+AaLvlYg8C+ucEodCNQZnJ7jOO0hHkfT +NvZBes0VukCGlBLOGRQtC3kgtyrerscnDiZOhdnJrhPIdNPC0k/p/uAfh7+C5Sxm +rCEL0S7kORdEjlIGd5j6ZEN/HZe8FyOYSjbFAoJSlAId9WMSxycQ -----END RSA PRIVATE KEY----- -----BEGIN CERTIFICATE----- -MIIE0DCCA7igAwIBAgIJAM5MuKJezXq0MA0GCSqGSIb3DQEBBQUAMIGgMQswCQYD -VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xGDAW -BgNVBAoTD1phcGhveWQgU3R1ZGlvczEUMBIGA1UECxMLV2ViU29ja2V0KysxFjAU -BgNVBAMTDVBldGVyIFRob3Jzb24xJDAiBgkqhkiG9w0BCQEWFXdlYm1hc3RlckB6 -YXBob3lkLmNvbTAeFw0xMTExMTUyMTIwMDZaFw0xMjExMTQyMTIwMDZaMIGgMQsw -CQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28x -GDAWBgNVBAoTD1phcGhveWQgU3R1ZGlvczEUMBIGA1UECxMLV2ViU29ja2V0Kysx -FjAUBgNVBAMTDVBldGVyIFRob3Jzb24xJDAiBgkqhkiG9w0BCQEWFXdlYm1hc3Rl -ckB6YXBob3lkLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANR0 -tdwAnIB8I9qRZ7QbzEWY95RpM7GIn0u/9oH90PzdHiE0rXSkKT+yw3XUzH0iw5t0 -5dEwSC+srSP5Vm4cA6kXc94agVVaPW89tGcdP4fHptCruSrzQsDXELCPl5UUvMpA -YUcGisdXYPN/EeOoqb9wKWxoW5mREsyyeWWS89fYN5qU/d0QpbSvEWghqLbL/ZS2 -hOlXT9LufOeA+vHiV1/T/h5xC7ecIH02YDQw1EnqxbPmkLPcWThztLS9FiufNDRM -Rhcoaj2b9VDHvDwdbeA0T5v5qNdG34LaapYOelxzQMOtM0f9Dgqehodyxl2qm9mR -lq432dlOEzDnVCPNHwECAwEAAaOCAQkwggEFMB0GA1UdDgQWBBTTPKfNMnKOykhv -+vKS7vql5JsMyzCB1QYDVR0jBIHNMIHKgBTTPKfNMnKOykhv+vKS7vql5JsMy6GB -pqSBozCBoDELMAkGA1UEBhMCVVMxETAPBgNVBAgTCElsbGlub2lzMRAwDgYDVQQH -EwdDaGljYWdvMRgwFgYDVQQKEw9aYXBob3lkIFN0dWRpb3MxFDASBgNVBAsTC1dl -YlNvY2tldCsrMRYwFAYDVQQDEw1QZXRlciBUaG9yc29uMSQwIgYJKoZIhvcNAQkB -FhV3ZWJtYXN0ZXJAemFwaG95ZC5jb22CCQDOTLiiXs16tDAMBgNVHRMEBTADAQH/ -MA0GCSqGSIb3DQEBBQUAA4IBAQB+SH0s/hrv5VYqgX6SNLzxdSLvCVsUkCdTpxwY -wOJ84XmYcXDMhKDtZqLtOtN6pfEwVusFlC9mkieuunztCnWNmsSG83RuljJPjFSi -1d4Id4bKEQkQ4cfnjoHKivRrViWLnxuNnLzC6tpyGH/35kKWhhr6T58AXerFgVw3 -mHvLPTr1DuhdAZA0ZuvuseVAFFAjI3RetSySwHJE3ak8KswDVfLi6E3XxMVsIWTS -/iFsC2WwoZQlljya2V/kRYIhu+uCdqJ01wunn2BvmURPSgr4GTBF0FQ9JGpNbXxM -TAU7oQJgyFc5sCcuEgPTO0dWVQTvdZVgay4tkmduKDRkmJBF +MIIEpzCCA4+gAwIBAgIJAMlCHvwnJ+F/MA0GCSqGSIb3DQEBCwUAMIGTMQswCQYD +VQQGEwJVUzELMAkGA1UECBMCSUwxEDAOBgNVBAcTB0NoaWNhZ28xGTAXBgNVBAoT +EFdlYlNvY2tldCsrIERlbW8xIjAgBgNVBAMTGXV0aWxpdGllcy53ZWJzb2NrZXRw +cC5vcmcxJjAkBgkqhkiG9w0BCQEWF3dlYnNvY2tldHBwQHphcGhveWQuY29tMB4X +DTE1MDQyNTE1NTk1M1oXDTE4MDMyODE1NTk1M1owgZMxCzAJBgNVBAYTAlVTMQsw +CQYDVQQIEwJJTDEQMA4GA1UEBxMHQ2hpY2FnbzEZMBcGA1UEChMQV2ViU29ja2V0 +KysgRGVtbzEiMCAGA1UEAxMZdXRpbGl0aWVzLndlYnNvY2tldHBwLm9yZzEmMCQG +CSqGSIb3DQEJARYXd2Vic29ja2V0cHBAemFwaG95ZC5jb20wggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQDvu/lVsVqr6B5V39EItegpNaP8uBcaOI5cGkll +xrejl52Ls3USPjX/XeN9ng7GAUhEUAAt359Tg2w5tfOyS2HeskuYmNS0ZqNEg+oX +YhRWMUybJtD11QNKo/N39sb66XQM/sM26IFwsLxc0Lf+RyE9TNWr2A0OTnqNefzu +QygiRVcFZBJHCTTIK0QtJ/DHFEKsYqBAN9edF3CaQ97jYOYq10aSxcmVSE/VRVMB +dpLDU3PrgtX1smN796gOxJ7g7GJ9VVOgTpnEhb6vWNWCty6l5hdCtIcjO2XZT+vH +YmQYw3R5L4+quwmaSZEE3VymCa9JXtagzeGPoSrvXPgN+/oTAgMBAAGjgfswgfgw +HQYDVR0OBBYEFAWNBET93ZzSukXGkuGb93CfmUkDMIHIBgNVHSMEgcAwgb2AFAWN +BET93ZzSukXGkuGb93CfmUkDoYGZpIGWMIGTMQswCQYDVQQGEwJVUzELMAkGA1UE +CBMCSUwxEDAOBgNVBAcTB0NoaWNhZ28xGTAXBgNVBAoTEFdlYlNvY2tldCsrIERl +bW8xIjAgBgNVBAMTGXV0aWxpdGllcy53ZWJzb2NrZXRwcC5vcmcxJjAkBgkqhkiG +9w0BCQEWF3dlYnNvY2tldHBwQHphcGhveWQuY29tggkAyUIe/Ccn4X8wDAYDVR0T +BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEA2DRQSDmo2Q5t8MEjp6jddRIFts5t +BDBWPSwJ0qvmheFt53MuLds2hhvMn42WGrKtVJiLiDyOWuUZ41REJZb1uaissUuY +r9pLuP5QLdibx7+/30iDEY0OGTgtSTfgwNx8bIApBSHoZEN3/HaikqplBng2+6u/ +kTe6UnRrBJ+8JOGl+duhCXNPeSyLa2NcrxE9XpWC/k1kC9MTUF+2NuqCtK3zO8ci +p0mqARWDSrEBYISh3dAOgDFrcX6zj+0MK+iswu3ijEdItGAjxjlQ2t4XT1T/CDbc +ysHg04TJw7v682+v124GrnrAPYUK34OK8kFVJ60SNYRUi7euOCdTM4Lwkw== -----END CERTIFICATE----- + diff --git a/Release/libs/websocketpp/examples/print_server/print_server.cpp b/Release/libs/websocketpp/examples/print_server/print_server.cpp index 78fb0e8f92..5f6f444df8 100644 --- a/Release/libs/websocketpp/examples/print_server/print_server.cpp +++ b/Release/libs/websocketpp/examples/print_server/print_server.cpp @@ -13,6 +13,8 @@ int main() { server print_server; print_server.set_message_handler(&on_message); + print_server.set_access_channels(websocketpp::log::alevel::all); + print_server.set_error_channels(websocketpp::log::elevel::all); print_server.init_asio(); print_server.listen(9002); diff --git a/Release/libs/websocketpp/examples/scratch_client/SConscript b/Release/libs/websocketpp/examples/scratch_client/SConscript new file mode 100755 index 0000000000..6e7b2ef07f --- /dev/null +++ b/Release/libs/websocketpp/examples/scratch_client/SConscript @@ -0,0 +1,24 @@ +## Scratch client example +## + +Import('env') +Import('env_cpp11') +Import('boostlibs') +Import('platform_libs') +Import('polyfill_libs') +Import('tls_libs') + +env = env.Clone () +env_cpp11 = env_cpp11.Clone () + +prgs = [] + +# if a C++11 environment is available build using that, otherwise use boost +if env_cpp11.has_key('WSPP_CPP11_ENABLED'): + ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + [tls_libs] + prgs += env_cpp11.Program('scratch_client', ["scratch_client.cpp"], LIBS = ALL_LIBS) +else: + ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs] + prgs += env.Program('utility_client', ["utility_client.cpp"], LIBS = ALL_LIBS) + +Return('prgs') diff --git a/Release/libs/websocketpp/examples/scratch_client/scratch_client.cpp b/Release/libs/websocketpp/examples/scratch_client/scratch_client.cpp new file mode 100755 index 0000000000..9b5a25c0d0 --- /dev/null +++ b/Release/libs/websocketpp/examples/scratch_client/scratch_client.cpp @@ -0,0 +1,270 @@ +/* + * 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. + */ + +// **NOTE:** This file is a snapshot of the WebSocket++ utility client tutorial. +// Additional related material can be found in the tutorials/utility_client +// directory of the WebSocket++ repository. + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +typedef websocketpp::client client; + +class connection_metadata { +public: + typedef websocketpp::lib::shared_ptr ptr; + + connection_metadata(int id, websocketpp::connection_hdl hdl, std::string uri) + : m_id(id) + , m_hdl(hdl) + , m_status("Connecting") + , m_uri(uri) + , m_server("N/A") + {} + + void on_open(client * c, websocketpp::connection_hdl hdl) { + m_status = "Open"; + + client::connection_ptr con = c->get_con_from_hdl(hdl); + m_server = con->get_response_header("Server"); + } + + void on_fail(client * c, websocketpp::connection_hdl hdl) { + m_status = "Failed"; + + client::connection_ptr con = c->get_con_from_hdl(hdl); + m_server = con->get_response_header("Server"); + m_error_reason = con->get_ec().message(); + } + + void on_close(client * c, websocketpp::connection_hdl hdl) { + m_status = "Closed"; + client::connection_ptr con = c->get_con_from_hdl(hdl); + std::stringstream s; + s << "close code: " << con->get_remote_close_code() << " (" + << websocketpp::close::status::get_string(con->get_remote_close_code()) + << "), close reason: " << con->get_remote_close_reason(); + m_error_reason = s.str(); + } + + websocketpp::connection_hdl get_hdl() const { + return m_hdl; + } + + int get_id() const { + return m_id; + } + + std::string get_status() const { + return m_status; + } + + friend std::ostream & operator<< (std::ostream & out, connection_metadata const & data); +private: + int m_id; + websocketpp::connection_hdl m_hdl; + std::string m_status; + std::string m_uri; + std::string m_server; + std::string m_error_reason; +}; + +std::ostream & operator<< (std::ostream & out, connection_metadata const & data) { + out << "> URI: " << data.m_uri << "\n" + << "> Status: " << data.m_status << "\n" + << "> Remote Server: " << (data.m_server.empty() ? "None Specified" : data.m_server) << "\n" + << "> Error/close reason: " << (data.m_error_reason.empty() ? "N/A" : data.m_error_reason); + + return out; +} + +class websocket_endpoint { +public: + websocket_endpoint () : m_next_id(0) { + m_endpoint.clear_access_channels(websocketpp::log::alevel::all); + m_endpoint.clear_error_channels(websocketpp::log::elevel::all); + + m_endpoint.init_asio(); + m_endpoint.start_perpetual(); + + m_thread.reset(new websocketpp::lib::thread(&client::run, &m_endpoint)); + } + + ~websocket_endpoint() { + m_endpoint.stop_perpetual(); + + for (con_list::const_iterator it = m_connection_list.begin(); it != m_connection_list.end(); ++it) { + if (it->second->get_status() != "Open") { + // Only close open connections + continue; + } + + std::cout << "> Closing connection " << it->second->get_id() << std::endl; + + websocketpp::lib::error_code ec; + m_endpoint.close(it->second->get_hdl(), websocketpp::close::status::going_away, "", ec); + if (ec) { + std::cout << "> Error closing connection " << it->second->get_id() << ": " + << ec.message() << std::endl; + } + } + + m_thread->join(); + } + + int connect(std::string const & uri) { + websocketpp::lib::error_code ec; + + client::connection_ptr con = m_endpoint.get_connection(uri, ec); + + if (ec) { + std::cout << "> Connect initialization error: " << ec.message() << std::endl; + return -1; + } + + int new_id = m_next_id++; + connection_metadata::ptr metadata_ptr(new connection_metadata(new_id, con->get_handle(), uri)); + m_connection_list[new_id] = metadata_ptr; + + con->set_open_handler(websocketpp::lib::bind( + &connection_metadata::on_open, + metadata_ptr, + &m_endpoint, + websocketpp::lib::placeholders::_1 + )); + con->set_fail_handler(websocketpp::lib::bind( + &connection_metadata::on_fail, + metadata_ptr, + &m_endpoint, + websocketpp::lib::placeholders::_1 + )); + con->set_close_handler(websocketpp::lib::bind( + &connection_metadata::on_close, + metadata_ptr, + &m_endpoint, + websocketpp::lib::placeholders::_1 + )); + + m_endpoint.connect(con); + + return new_id; + } + + void close(int id, websocketpp::close::status::value code, std::string reason) { + websocketpp::lib::error_code ec; + + con_list::iterator metadata_it = m_connection_list.find(id); + if (metadata_it == m_connection_list.end()) { + std::cout << "> No connection found with id " << id << std::endl; + return; + } + + m_endpoint.close(metadata_it->second->get_hdl(), code, reason, ec); + if (ec) { + std::cout << "> Error initiating close: " << ec.message() << std::endl; + } + } + + connection_metadata::ptr get_metadata(int id) const { + con_list::const_iterator metadata_it = m_connection_list.find(id); + if (metadata_it == m_connection_list.end()) { + return connection_metadata::ptr(); + } else { + return metadata_it->second; + } + } +private: + typedef std::map con_list; + + client m_endpoint; + websocketpp::lib::shared_ptr m_thread; + + con_list m_connection_list; + int m_next_id; +}; + +int main() { + bool done = false; + std::string input; + websocket_endpoint endpoint; + + while (!done) { + std::cout << "Enter Command: "; + std::getline(std::cin, input); + + if (input == "quit") { + done = true; + } else if (input == "help") { + std::cout + << "\nCommand List:\n" + << "connect \n" + << "close [] []\n" + << "show \n" + << "help: Display this help text\n" + << "quit: Exit the program\n" + << std::endl; + } else if (input.substr(0,7) == "connect") { + int id = endpoint.connect(input.substr(8)); + if (id != -1) { + std::cout << "> Created connection with id " << id << std::endl; + } + } else if (input.substr(0,5) == "close") { + std::stringstream ss(input); + + std::string cmd; + int id; + int close_code = websocketpp::close::status::normal; + std::string reason = ""; + + ss >> cmd >> id >> close_code; + std::getline(ss,reason); + + endpoint.close(id, close_code, reason); + } else if (input.substr(0,4) == "show") { + int id = atoi(input.substr(5).c_str()); + + connection_metadata::ptr metadata = endpoint.get_metadata(id); + if (metadata) { + std::cout << *metadata << std::endl; + } else { + std::cout << "> Unknown connection id " << id << std::endl; + } + } else { + std::cout << "> Unrecognized Command" << std::endl; + } + } + + return 0; +} diff --git a/Release/libs/websocketpp/examples/scratch_server/SConscript b/Release/libs/websocketpp/examples/scratch_server/SConscript new file mode 100755 index 0000000000..bf90f7433e --- /dev/null +++ b/Release/libs/websocketpp/examples/scratch_server/SConscript @@ -0,0 +1,24 @@ +## Scratch server example +## + +Import('env') +Import('env_cpp11') +Import('boostlibs') +Import('platform_libs') +Import('polyfill_libs') +Import('tls_libs') + +env = env.Clone () +env_cpp11 = env_cpp11.Clone () + +prgs = [] + +# if a C++11 environment is available build using that, otherwise use boost +if env_cpp11.has_key('WSPP_CPP11_ENABLED'): + ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + [tls_libs] + ['z'] + prgs += env_cpp11.Program('scratch_server', ["scratch_server.cpp"], LIBS = ALL_LIBS) +else: + ALL_LIBS = boostlibs(['system','regex','random'],env) + [platform_libs] + [polyfill_libs] + [tls_libs] + ['z'] + prgs += env.Program('scratch_server', ["scratch_server.cpp"], LIBS = ALL_LIBS) + +Return('prgs') diff --git a/Release/libs/websocketpp/examples/scratch_server/scratch_server.cpp b/Release/libs/websocketpp/examples/scratch_server/scratch_server.cpp new file mode 100755 index 0000000000..e37a58929b --- /dev/null +++ b/Release/libs/websocketpp/examples/scratch_server/scratch_server.cpp @@ -0,0 +1,106 @@ +/** + * This example is presently used as a scratch space. It may or may not be broken + * at any given time. + */ + +#include + +#include +#include + +#include + +struct deflate_config : public websocketpp::config::debug_core { + typedef deflate_config type; + typedef debug_core base; + + typedef base::concurrency_type concurrency_type; + + typedef base::request_type request_type; + typedef base::response_type response_type; + + typedef base::message_type message_type; + typedef base::con_msg_manager_type con_msg_manager_type; + typedef base::endpoint_msg_manager_type endpoint_msg_manager_type; + + typedef base::alog_type alog_type; + typedef base::elog_type elog_type; + + typedef base::rng_type rng_type; + + struct transport_config : public base::transport_config { + typedef type::concurrency_type concurrency_type; + typedef type::alog_type alog_type; + typedef type::elog_type elog_type; + typedef type::request_type request_type; + typedef type::response_type response_type; + typedef websocketpp::transport::asio::basic_socket::endpoint + socket_type; + }; + + typedef websocketpp::transport::asio::endpoint + transport_type; + + /// permessage_compress extension + struct permessage_deflate_config {}; + + typedef websocketpp::extensions::permessage_deflate::enabled + permessage_deflate_type; +}; + +typedef websocketpp::server server; + +typedef server::message_ptr message_ptr; + +// Define a callback to handle incoming messages +void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) { + /*std::cout << "on_message called with hdl: " << hdl.lock().get() + << " and message (" << msg->get_payload().size() << "): " << msg->get_payload() + << std::endl; + */ + try { + s->send(hdl, msg->get_payload(), msg->get_opcode()); + } catch (const websocketpp::lib::error_code& e) { + std::cout << "Echo failed because: " << e + << "(" << e.message() << ")" << std::endl; + } +} + +int main(int argc, char * argv[]) { + // Create a server endpoint + server echo_server; + + try { + // Set logging settings + if (argc > 1 && std::string(argv[1]) == "-d") { + echo_server.set_access_channels(websocketpp::log::alevel::all); + echo_server.set_error_channels(websocketpp::log::elevel::all); + } else { + echo_server.set_access_channels(websocketpp::log::alevel::none); + echo_server.set_error_channels(websocketpp::log::elevel::none); + } + + // Initialize ASIO + echo_server.init_asio(); + + // Register our message handler + using websocketpp::lib::placeholders::_1; + using websocketpp::lib::placeholders::_2; + echo_server.set_message_handler(bind(&on_message,&echo_server,_1,_2)); + + // Listen on port 9002 + echo_server.listen(9002); + + // Start the server accept loop + echo_server.start_accept(); + + // Start the ASIO io_service run loop + echo_server.run(); + } catch (const std::exception & e) { + std::cout << e.what() << std::endl; + } catch (websocketpp::lib::error_code e) { + std::cout << e.message() << std::endl; + } catch (...) { + std::cout << "other exception" << std::endl; + } +} diff --git a/Release/libs/websocketpp/examples/telemetry_client/telemetry_client.cpp b/Release/libs/websocketpp/examples/telemetry_client/telemetry_client.cpp index 658fb3d468..6a57da15d4 100644 --- a/Release/libs/websocketpp/examples/telemetry_client/telemetry_client.cpp +++ b/Release/libs/websocketpp/examples/telemetry_client/telemetry_client.cpp @@ -30,9 +30,9 @@ class telemetry_client { // Bind the handlers we are using using websocketpp::lib::placeholders::_1; using websocketpp::lib::bind; - m_client.set_open_handler(bind(&telemetry_client::on_open,this,::_1)); - m_client.set_close_handler(bind(&telemetry_client::on_close,this,::_1)); - m_client.set_fail_handler(bind(&telemetry_client::on_fail,this,::_1)); + m_client.set_open_handler(bind(&telemetry_client::on_open,this,_1)); + m_client.set_close_handler(bind(&telemetry_client::on_close,this,_1)); + m_client.set_fail_handler(bind(&telemetry_client::on_fail,this,_1)); } // This method will block until the connection is complete diff --git a/Release/libs/websocketpp/examples/telemetry_server/telemetry_server.cpp b/Release/libs/websocketpp/examples/telemetry_server/telemetry_server.cpp index 80a791343b..7c45ae590a 100644 --- a/Release/libs/websocketpp/examples/telemetry_server/telemetry_server.cpp +++ b/Release/libs/websocketpp/examples/telemetry_server/telemetry_server.cpp @@ -46,9 +46,9 @@ class telemetry_server { // Bind the handlers we are using using websocketpp::lib::placeholders::_1; using websocketpp::lib::bind; - m_endpoint.set_open_handler(bind(&telemetry_server::on_open,this,::_1)); - m_endpoint.set_close_handler(bind(&telemetry_server::on_close,this,::_1)); - m_endpoint.set_http_handler(bind(&telemetry_server::on_http,this,::_1)); + m_endpoint.set_open_handler(bind(&telemetry_server::on_open,this,_1)); + m_endpoint.set_close_handler(bind(&telemetry_server::on_close,this,_1)); + m_endpoint.set_http_handler(bind(&telemetry_server::on_http,this,_1)); } void run(std::string docroot, uint16_t port) { diff --git a/Release/libs/websocketpp/examples/testee_client/SConscript b/Release/libs/websocketpp/examples/testee_client/SConscript index 9547f3fc43..64f0ef1f35 100644 --- a/Release/libs/websocketpp/examples/testee_client/SConscript +++ b/Release/libs/websocketpp/examples/testee_client/SConscript @@ -14,10 +14,10 @@ prgs = [] # if a C++11 environment is available build using that, otherwise use boost if env_cpp11.has_key('WSPP_CPP11_ENABLED'): - ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + ['z'] prgs += env_cpp11.Program('testee_client', ["testee_client.cpp"], LIBS = ALL_LIBS) else: - ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs] + ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs] + ['z'] prgs += env.Program('testee_client', ["testee_client.cpp"], LIBS = ALL_LIBS) Return('prgs') diff --git a/Release/libs/websocketpp/examples/testee_client/testee_client.cpp b/Release/libs/websocketpp/examples/testee_client/testee_client.cpp index d191df5796..b66e63353f 100644 --- a/Release/libs/websocketpp/examples/testee_client/testee_client.cpp +++ b/Release/libs/websocketpp/examples/testee_client/testee_client.cpp @@ -1,10 +1,75 @@ -#include +/* + * Copyright (c) 2015, 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. + * + */ +#include #include +#include #include -typedef websocketpp::client client; +struct deflate_config : public websocketpp::config::asio_client { + typedef deflate_config type; + typedef asio_client base; + + typedef base::concurrency_type concurrency_type; + + typedef base::request_type request_type; + typedef base::response_type response_type; + + typedef base::message_type message_type; + typedef base::con_msg_manager_type con_msg_manager_type; + typedef base::endpoint_msg_manager_type endpoint_msg_manager_type; + + typedef base::alog_type alog_type; + typedef base::elog_type elog_type; + + typedef base::rng_type rng_type; + + struct transport_config : public base::transport_config { + typedef type::concurrency_type concurrency_type; + typedef type::alog_type alog_type; + typedef type::elog_type elog_type; + typedef type::request_type request_type; + typedef type::response_type response_type; + typedef websocketpp::transport::asio::basic_socket::endpoint + socket_type; + }; + + typedef websocketpp::transport::asio::endpoint + transport_type; + + /// permessage_compress extension + struct permessage_deflate_config {}; + + typedef websocketpp::extensions::permessage_deflate::enabled + permessage_deflate_type; +}; + +typedef websocketpp::client client; using websocketpp::lib::placeholders::_1; using websocketpp::lib::placeholders::_2; diff --git a/Release/libs/websocketpp/examples/testee_server/SConscript b/Release/libs/websocketpp/examples/testee_server/SConscript index 526886f68a..3c75f4ff27 100644 --- a/Release/libs/websocketpp/examples/testee_server/SConscript +++ b/Release/libs/websocketpp/examples/testee_server/SConscript @@ -14,10 +14,10 @@ prgs = [] # if a C++11 environment is available build using that, otherwise use boost if env_cpp11.has_key('WSPP_CPP11_ENABLED'): - ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + ['z'] prgs += env_cpp11.Program('testee_server', ["testee_server.cpp"], LIBS = ALL_LIBS) else: - ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs] + ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs] + ['z'] prgs += env.Program('testee_server', ["testee_server.cpp"], LIBS = ALL_LIBS) Return('prgs') diff --git a/Release/libs/websocketpp/examples/testee_server/testee_server.cpp b/Release/libs/websocketpp/examples/testee_server/testee_server.cpp index d44368c886..9ac9a7d4ca 100644 --- a/Release/libs/websocketpp/examples/testee_server/testee_server.cpp +++ b/Release/libs/websocketpp/examples/testee_server/testee_server.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Peter Thorson. All rights reserved. + * Copyright (c) 2015, 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: @@ -27,6 +27,7 @@ #include #include +#include #include struct testee_config : public websocketpp::config::asio { @@ -64,6 +65,12 @@ struct testee_config : public websocketpp::config::asio { websocketpp::log::elevel::none; static const websocketpp::log::level alog_level = websocketpp::log::alevel::none; + + /// permessage_compress extension + struct permessage_deflate_config {}; + + typedef websocketpp::extensions::permessage_deflate::enabled + permessage_deflate_type; }; typedef websocketpp::server server; diff --git a/Release/libs/websocketpp/examples/utility_client/CMakeLists.txt b/Release/libs/websocketpp/examples/utility_client/CMakeLists.txt index 865a4c783d..6e6cd8c9d5 100644 --- a/Release/libs/websocketpp/examples/utility_client/CMakeLists.txt +++ b/Release/libs/websocketpp/examples/utility_client/CMakeLists.txt @@ -1,11 +1,23 @@ +## Utility client example +## -file (GLOB SOURCE_FILES *.cpp) -file (GLOB HEADER_FILES *.hpp) +Import('env') +Import('env_cpp11') +Import('boostlibs') +Import('platform_libs') +Import('polyfill_libs') -init_target (utility_client) +env = env.Clone () +env_cpp11 = env_cpp11.Clone () -build_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES}) +prgs = [] -link_boost () -final_target () +# if a C++11 environment is available build using that, otherwise use boost +if env_cpp11.has_key('WSPP_CPP11_ENABLED'): + ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + prgs += env_cpp11.Program('utility_client', ["utility_client.cpp"], LIBS = ALL_LIBS) +else: + ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs] + prgs += env.Program('utility_client', ["utility_client.cpp"], LIBS = ALL_LIBS) +Return('prgs') \ No newline at end of file diff --git a/Release/libs/websocketpp/examples/utility_client/SConscript b/Release/libs/websocketpp/examples/utility_client/SConscript index 88def4b084..865a4c783d 100644 --- a/Release/libs/websocketpp/examples/utility_client/SConscript +++ b/Release/libs/websocketpp/examples/utility_client/SConscript @@ -1,23 +1,11 @@ -## Utility client example -## -Import('env') -Import('env_cpp11') -Import('boostlibs') -Import('platform_libs') -Import('polyfill_libs') +file (GLOB SOURCE_FILES *.cpp) +file (GLOB HEADER_FILES *.hpp) -env = env.Clone () -env_cpp11 = env_cpp11.Clone () +init_target (utility_client) -prgs = [] +build_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES}) -# if a C++11 environment is available build using that, otherwise use boost -if env_cpp11.has_key('WSPP_CPP11_ENABLED'): - ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] - prgs += env_cpp11.Program('utility_client', ["utility_client.cpp"], LIBS = ALL_LIBS) -else: - ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs] - prgs += env.Program('utility_client', ["utility_client.cpp"], LIBS = ALL_LIBS) +link_boost () +final_target () -Return('prgs') diff --git a/Release/libs/websocketpp/examples/utility_client/utility_client.cpp b/Release/libs/websocketpp/examples/utility_client/utility_client.cpp index ee13f16a5b..e9108dc015 100644 --- a/Release/libs/websocketpp/examples/utility_client/utility_client.cpp +++ b/Release/libs/websocketpp/examples/utility_client/utility_client.cpp @@ -322,4 +322,4 @@ int main() { } return 0; -} +} \ No newline at end of file diff --git a/Release/libs/websocketpp/readme.md b/Release/libs/websocketpp/readme.md index a9551373d9..18716d4fa8 100644 --- a/Release/libs/websocketpp/readme.md +++ b/Release/libs/websocketpp/readme.md @@ -1,10 +1,12 @@ -WebSocket++ (0.5.1) +WebSocket++ (0.6.0) ========================== WebSocket++ is a header only C++ library that implements RFC6455 The WebSocket Protocol. It allows integrating WebSocket client and server functionality into C++ programs. It uses interchangeable network transport modules including one -based on C++ iostreams and one based on Boost Asio. +based on raw char buffers, one based on C++ iostreams, and one based on Asio +(either via Boost or standalone). End users can write additional transport +policies to support other networking or event libraries as needed. Major Features ============== @@ -13,7 +15,7 @@ Major Features * Message/event based interface * Supports secure WebSockets (TLS), IPv6, and explicit proxies. * Flexible dependency management (C++11 Standard Library or Boost) -* Interchangeable network transport modules (iostream and Boost Asio) +* Interchangeable network transport modules (raw, iostream, Asio, or custom) * Portable/cross platform (Posix/Windows, 32/64bit, Intel/ARM/PPC) * Thread-safe @@ -31,6 +33,8 @@ http://www.zaphoyd.com/websocketpp/manual/ **GitHub Repository** https://github.com/zaphoyd/websocketpp/ +GitHub pull requests should be submitted to the `develop` branch. + **Announcements Mailing List** http://groups.google.com/group/websocketpp-announcements/ diff --git a/Release/libs/websocketpp/test/connection/connection.cpp b/Release/libs/websocketpp/test/connection/connection.cpp index 0c67bd1935..5491ab1d06 100644 --- a/Release/libs/websocketpp/test/connection/connection.cpp +++ b/Release/libs/websocketpp/test/connection/connection.cpp @@ -167,6 +167,15 @@ void http_func(server* s, websocketpp::connection_hdl hdl) { con->set_status(websocketpp::http::status_code::ok); } +void defer_http_func(server* s, bool * deferred, websocketpp::connection_hdl hdl) { + *deferred = true; + + server::connection_ptr con = s->get_con_from_hdl(hdl); + + websocketpp::lib::error_code ec = con->defer_http_response(); + BOOST_CHECK_EQUAL(ec, websocketpp::lib::error_code()); +} + void check_on_fail(server* s, websocketpp::lib::error_code ec, bool & called, websocketpp::connection_hdl hdl) { @@ -223,6 +232,44 @@ BOOST_AUTO_TEST_CASE( http_request ) { BOOST_CHECK_EQUAL(run_server_test(s,input), output); } +BOOST_AUTO_TEST_CASE( deferred_http_request ) { + std::string input = "GET /foo/bar HTTP/1.1\r\nHost: www.example.com\r\nOrigin: http://www.example.com\r\n\r\n"; + std::string output = "HTTP/1.1 200 OK\r\nContent-Length: 8\r\nServer: "; + output+=websocketpp::user_agent; + output+="\r\n\r\n/foo/bar"; + + server s; + server::connection_ptr con; + bool deferred = false; + s.set_http_handler(bind(&defer_http_func,&s, &deferred,::_1)); + + s.clear_access_channels(websocketpp::log::alevel::all); + s.clear_error_channels(websocketpp::log::elevel::all); + + std::stringstream ostream; + s.register_ostream(&ostream); + + con = s.get_connection(); + con->start(); + + BOOST_CHECK(!deferred); + BOOST_CHECK_EQUAL(ostream.str(), ""); + con->read_some(input.data(),input.size()); + BOOST_CHECK(deferred); + BOOST_CHECK_EQUAL(ostream.str(), ""); + + con->set_body(con->get_resource()); + con->set_status(websocketpp::http::status_code::ok); + + websocketpp::lib::error_code ec; + s.send_http_response(con->get_handle(),ec); + BOOST_CHECK_EQUAL(ec, websocketpp::lib::error_code()); + BOOST_CHECK_EQUAL(ostream.str(), output); + con->send_http_response(ec); + BOOST_CHECK_EQUAL(ec, make_error_code(websocketpp::error::invalid_state)); + +} + BOOST_AUTO_TEST_CASE( request_no_server_header ) { std::string input = "GET / HTTP/1.1\r\nHost: www.example.com\r\nConnection: upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nOrigin: http://www.example.com\r\n\r\n"; std::string output = "HTTP/1.1 101 Switching Protocols\r\nConnection: upgrade\r\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\nUpgrade: websocket\r\n\r\n"; diff --git a/Release/libs/websocketpp/test/endpoint/endpoint.cpp b/Release/libs/websocketpp/test/endpoint/endpoint.cpp index 08b0560b50..34764d1bd7 100644 --- a/Release/libs/websocketpp/test/endpoint/endpoint.cpp +++ b/Release/libs/websocketpp/test/endpoint/endpoint.cpp @@ -57,6 +57,35 @@ BOOST_AUTO_TEST_CASE( initialize_server_asio_external ) { s.init_asio(&ios); } +#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_ +BOOST_AUTO_TEST_CASE( move_construct_server_core ) { + websocketpp::server s1; + + websocketpp::server s2(std::move(s1)); +} + +/* +// temporary disable because library doesn't pass +BOOST_AUTO_TEST_CASE( emplace ) { + std::stringstream out1; + std::stringstream out2; + + std::vector> v; + + v.emplace_back(); + v.emplace_back(); + + v[0].get_alog().set_ostream(&out1); + v[0].get_alog().set_ostream(&out2); + + v[0].get_alog().write(websocketpp::log::alevel::app,"devel0"); + v[1].get_alog().write(websocketpp::log::alevel::app,"devel1"); + BOOST_CHECK( out1.str().size() > 0 ); + BOOST_CHECK( out2.str().size() > 0 ); +}*/ + +#endif // _WEBSOCKETPP_MOVE_SEMANTICS_ + struct endpoint_extension { endpoint_extension() : extension_value(5) {} diff --git a/Release/libs/websocketpp/test/extension/permessage_deflate.cpp b/Release/libs/websocketpp/test/extension/permessage_deflate.cpp index 60e3c24d57..06ace5e2c5 100644 --- a/Release/libs/websocketpp/test/extension/permessage_deflate.cpp +++ b/Release/libs/websocketpp/test/extension/permessage_deflate.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Peter Thorson. All rights reserved. + * Copyright (c) 2013, 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: @@ -100,10 +100,10 @@ BOOST_AUTO_TEST_CASE( negotiation_invalid_attr ) { BOOST_CHECK_EQUAL( v.esp.second, ""); } -// Negotiate s2c_no_context_takeover -BOOST_AUTO_TEST_CASE( negotiate_s2c_no_context_takeover_invalid ) { +// Negotiate server_no_context_takeover +BOOST_AUTO_TEST_CASE( negotiate_server_no_context_takeover_invalid ) { ext_vars v; - v.attr["s2c_no_context_takeover"] = "foo"; + v.attr["server_no_context_takeover"] = "foo"; v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( !v.exts.is_enabled() ); @@ -111,30 +111,30 @@ BOOST_AUTO_TEST_CASE( negotiate_s2c_no_context_takeover_invalid ) { BOOST_CHECK_EQUAL( v.esp.second, ""); } -BOOST_AUTO_TEST_CASE( negotiate_s2c_no_context_takeover ) { +BOOST_AUTO_TEST_CASE( negotiate_server_no_context_takeover ) { ext_vars v; - v.attr["s2c_no_context_takeover"] = ""; + v.attr["server_no_context_takeover"] = ""; v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( v.exts.is_enabled() ); BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() ); - BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_no_context_takeover"); + BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_no_context_takeover"); } -BOOST_AUTO_TEST_CASE( negotiate_s2c_no_context_takeover_server_initiated ) { +BOOST_AUTO_TEST_CASE( negotiate_server_no_context_takeover_server_initiated ) { ext_vars v; - v.exts.enable_s2c_no_context_takeover(); + v.exts.enable_server_no_context_takeover(); v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( v.exts.is_enabled() ); BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() ); - BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_no_context_takeover"); + BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_no_context_takeover"); } -// Negotiate c2s_no_context_takeover -BOOST_AUTO_TEST_CASE( negotiate_c2s_no_context_takeover_invalid ) { +// Negotiate client_no_context_takeover +BOOST_AUTO_TEST_CASE( negotiate_client_no_context_takeover_invalid ) { ext_vars v; - v.attr["c2s_no_context_takeover"] = "foo"; + v.attr["client_no_context_takeover"] = "foo"; v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( !v.exts.is_enabled() ); @@ -142,29 +142,29 @@ BOOST_AUTO_TEST_CASE( negotiate_c2s_no_context_takeover_invalid ) { BOOST_CHECK_EQUAL( v.esp.second, ""); } -BOOST_AUTO_TEST_CASE( negotiate_c2s_no_context_takeover ) { +BOOST_AUTO_TEST_CASE( negotiate_client_no_context_takeover ) { ext_vars v; - v.attr["c2s_no_context_takeover"] = ""; + v.attr["client_no_context_takeover"] = ""; v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( v.exts.is_enabled() ); BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() ); - BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; c2s_no_context_takeover"); + BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_no_context_takeover"); } -BOOST_AUTO_TEST_CASE( negotiate_c2s_no_context_takeover_server_initiated ) { +BOOST_AUTO_TEST_CASE( negotiate_client_no_context_takeover_server_initiated ) { ext_vars v; - v.exts.enable_c2s_no_context_takeover(); + v.exts.enable_client_no_context_takeover(); v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( v.exts.is_enabled() ); BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() ); - BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; c2s_no_context_takeover"); + BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_no_context_takeover"); } -// Negotiate s2c_max_window_bits -BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_invalid ) { +// Negotiate server_max_window_bits +BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_invalid ) { ext_vars v; std::vector values; @@ -175,7 +175,7 @@ BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_invalid ) { std::vector::const_iterator it; for (it = values.begin(); it != values.end(); ++it) { - v.attr["s2c_max_window_bits"] = *it; + v.attr["server_max_window_bits"] = *it; v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( !v.exts.is_enabled() ); @@ -184,16 +184,16 @@ BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_invalid ) { } } -BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_valid ) { +BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_valid ) { ext_vars v; - v.attr["s2c_max_window_bits"] = "8"; + v.attr["server_max_window_bits"] = "8"; v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( v.exts.is_enabled() ); BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() ); - BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_max_window_bits=8"); + BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_max_window_bits=8"); - v.attr["s2c_max_window_bits"] = "15"; + v.attr["server_max_window_bits"] = "15"; v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( v.exts.is_enabled() ); @@ -201,21 +201,21 @@ BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_valid ) { BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate"); } -BOOST_AUTO_TEST_CASE( invalid_set_s2c_max_window_bits ) { +BOOST_AUTO_TEST_CASE( invalid_set_server_max_window_bits ) { ext_vars v; - v.ec = v.exts.set_s2c_max_window_bits(7,pmd_mode::decline); + v.ec = v.exts.set_server_max_window_bits(7,pmd_mode::decline); BOOST_CHECK_EQUAL(v.ec,pmde::make_error_code(pmde::invalid_max_window_bits)); - v.ec = v.exts.set_s2c_max_window_bits(16,pmd_mode::decline); + v.ec = v.exts.set_server_max_window_bits(16,pmd_mode::decline); BOOST_CHECK_EQUAL(v.ec,pmde::make_error_code(pmde::invalid_max_window_bits)); } -BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_decline ) { +BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_decline ) { ext_vars v; - v.attr["s2c_max_window_bits"] = "8"; + v.attr["server_max_window_bits"] = "8"; - v.ec = v.exts.set_s2c_max_window_bits(15,pmd_mode::decline); + v.ec = v.exts.set_server_max_window_bits(15,pmd_mode::decline); v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( v.exts.is_enabled() ); BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() ); @@ -223,44 +223,44 @@ BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_decline ) { BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate"); } -BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_accept ) { +BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_accept ) { ext_vars v; - v.attr["s2c_max_window_bits"] = "8"; + v.attr["server_max_window_bits"] = "8"; - v.ec = v.exts.set_s2c_max_window_bits(15,pmd_mode::accept); + v.ec = v.exts.set_server_max_window_bits(15,pmd_mode::accept); v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( v.exts.is_enabled() ); BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() ); BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() ); - BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_max_window_bits=8"); + BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_max_window_bits=8"); } -BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_largest ) { +BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_largest ) { ext_vars v; - v.attr["s2c_max_window_bits"] = "8"; + v.attr["server_max_window_bits"] = "8"; - v.ec = v.exts.set_s2c_max_window_bits(15,pmd_mode::largest); + v.ec = v.exts.set_server_max_window_bits(15,pmd_mode::largest); v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( v.exts.is_enabled() ); BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() ); BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() ); - BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_max_window_bits=8"); + BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_max_window_bits=8"); } -BOOST_AUTO_TEST_CASE( negotiate_s2c_max_window_bits_smallest ) { +BOOST_AUTO_TEST_CASE( negotiate_server_max_window_bits_smallest ) { ext_vars v; - v.attr["s2c_max_window_bits"] = "8"; + v.attr["server_max_window_bits"] = "8"; - v.ec = v.exts.set_s2c_max_window_bits(15,pmd_mode::smallest); + v.ec = v.exts.set_server_max_window_bits(15,pmd_mode::smallest); v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( v.exts.is_enabled() ); BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() ); BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() ); - BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_max_window_bits=8"); + BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_max_window_bits=8"); } -// Negotiate s2c_max_window_bits -BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_invalid ) { +// Negotiate server_max_window_bits +BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_invalid ) { ext_vars v; std::vector values; @@ -270,7 +270,7 @@ BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_invalid ) { std::vector::const_iterator it; for (it = values.begin(); it != values.end(); ++it) { - v.attr["c2s_max_window_bits"] = *it; + v.attr["client_max_window_bits"] = *it; v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( !v.exts.is_enabled() ); @@ -279,43 +279,43 @@ BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_invalid ) { } } -BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_valid ) { +BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_valid ) { ext_vars v; - v.attr["c2s_max_window_bits"] = ""; + v.attr["client_max_window_bits"] = ""; v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( v.exts.is_enabled() ); BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() ); BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate"); - v.attr["c2s_max_window_bits"] = "8"; + v.attr["client_max_window_bits"] = "8"; v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( v.exts.is_enabled() ); BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() ); - BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; c2s_max_window_bits=8"); + BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_max_window_bits=8"); - v.attr["c2s_max_window_bits"] = "15"; + v.attr["client_max_window_bits"] = "15"; v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( v.exts.is_enabled() ); BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() ); BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate"); } -BOOST_AUTO_TEST_CASE( invalid_set_c2s_max_window_bits ) { +BOOST_AUTO_TEST_CASE( invalid_set_client_max_window_bits ) { ext_vars v; - v.ec = v.exts.set_c2s_max_window_bits(7,pmd_mode::decline); + v.ec = v.exts.set_client_max_window_bits(7,pmd_mode::decline); BOOST_CHECK_EQUAL(v.ec,pmde::make_error_code(pmde::invalid_max_window_bits)); - v.ec = v.exts.set_c2s_max_window_bits(16,pmd_mode::decline); + v.ec = v.exts.set_client_max_window_bits(16,pmd_mode::decline); BOOST_CHECK_EQUAL(v.ec,pmde::make_error_code(pmde::invalid_max_window_bits)); } -BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_decline ) { +BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_decline ) { ext_vars v; - v.attr["c2s_max_window_bits"] = "8"; + v.attr["client_max_window_bits"] = "8"; - v.ec = v.exts.set_c2s_max_window_bits(8,pmd_mode::decline); + v.ec = v.exts.set_client_max_window_bits(8,pmd_mode::decline); v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( v.exts.is_enabled() ); BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() ); @@ -323,40 +323,40 @@ BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_decline ) { BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate"); } -BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_accept ) { +BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_accept ) { ext_vars v; - v.attr["c2s_max_window_bits"] = "8"; + v.attr["client_max_window_bits"] = "8"; - v.ec = v.exts.set_c2s_max_window_bits(15,pmd_mode::accept); + v.ec = v.exts.set_client_max_window_bits(15,pmd_mode::accept); v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( v.exts.is_enabled() ); BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() ); BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() ); - BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; c2s_max_window_bits=8"); + BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_max_window_bits=8"); } -BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_largest ) { +BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_largest ) { ext_vars v; - v.attr["c2s_max_window_bits"] = "8"; + v.attr["client_max_window_bits"] = "8"; - v.ec = v.exts.set_c2s_max_window_bits(15,pmd_mode::largest); + v.ec = v.exts.set_client_max_window_bits(15,pmd_mode::largest); v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( v.exts.is_enabled() ); BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() ); BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() ); - BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; c2s_max_window_bits=8"); + BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_max_window_bits=8"); } -BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_smallest ) { +BOOST_AUTO_TEST_CASE( negotiate_client_max_window_bits_smallest ) { ext_vars v; - v.attr["c2s_max_window_bits"] = "8"; + v.attr["client_max_window_bits"] = "8"; - v.ec = v.exts.set_c2s_max_window_bits(15,pmd_mode::smallest); + v.ec = v.exts.set_client_max_window_bits(15,pmd_mode::smallest); v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( v.exts.is_enabled() ); BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() ); BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() ); - BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; c2s_max_window_bits=8"); + BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_max_window_bits=8"); } @@ -364,180 +364,286 @@ BOOST_AUTO_TEST_CASE( negotiate_c2s_max_window_bits_smallest ) { BOOST_AUTO_TEST_CASE( negotiate_two_client_initiated1 ) { ext_vars v; - v.attr["s2c_no_context_takeover"] = ""; - v.attr["c2s_no_context_takeover"] = ""; + v.attr["server_no_context_takeover"] = ""; + v.attr["client_no_context_takeover"] = ""; v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( v.exts.is_enabled() ); BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() ); - BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_no_context_takeover; c2s_no_context_takeover"); + BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_no_context_takeover; client_no_context_takeover"); } BOOST_AUTO_TEST_CASE( negotiate_two_client_initiated2 ) { ext_vars v; - v.attr["s2c_no_context_takeover"] = ""; - v.attr["s2c_max_window_bits"] = "10"; + v.attr["server_no_context_takeover"] = ""; + v.attr["server_max_window_bits"] = "10"; v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( v.exts.is_enabled() ); BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() ); - BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_no_context_takeover; s2c_max_window_bits=10"); + BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_no_context_takeover; server_max_window_bits=10"); } BOOST_AUTO_TEST_CASE( negotiate_two_client_initiated3 ) { ext_vars v; - v.attr["s2c_no_context_takeover"] = ""; - v.attr["c2s_max_window_bits"] = "10"; + v.attr["server_no_context_takeover"] = ""; + v.attr["client_max_window_bits"] = "10"; v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( v.exts.is_enabled() ); BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() ); - BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_no_context_takeover; c2s_max_window_bits=10"); + BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_no_context_takeover; client_max_window_bits=10"); } BOOST_AUTO_TEST_CASE( negotiate_two_client_initiated4 ) { ext_vars v; - v.attr["c2s_no_context_takeover"] = ""; - v.attr["s2c_max_window_bits"] = "10"; + v.attr["client_no_context_takeover"] = ""; + v.attr["server_max_window_bits"] = "10"; v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( v.exts.is_enabled() ); BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() ); - BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; c2s_no_context_takeover; s2c_max_window_bits=10"); + BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_no_context_takeover; server_max_window_bits=10"); } BOOST_AUTO_TEST_CASE( negotiate_two_client_initiated5 ) { ext_vars v; - v.attr["c2s_no_context_takeover"] = ""; - v.attr["c2s_max_window_bits"] = "10"; + v.attr["client_no_context_takeover"] = ""; + v.attr["client_max_window_bits"] = "10"; v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( v.exts.is_enabled() ); BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() ); - BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; c2s_no_context_takeover; c2s_max_window_bits=10"); + BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_no_context_takeover; client_max_window_bits=10"); } BOOST_AUTO_TEST_CASE( negotiate_two_client_initiated6 ) { ext_vars v; - v.attr["s2c_max_window_bits"] = "10"; - v.attr["c2s_max_window_bits"] = "10"; + v.attr["server_max_window_bits"] = "10"; + v.attr["client_max_window_bits"] = "10"; v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( v.exts.is_enabled() ); BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() ); - BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_max_window_bits=10; c2s_max_window_bits=10"); + BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_max_window_bits=10; client_max_window_bits=10"); } BOOST_AUTO_TEST_CASE( negotiate_three_client_initiated1 ) { ext_vars v; - v.attr["s2c_no_context_takeover"] = ""; - v.attr["c2s_no_context_takeover"] = ""; - v.attr["s2c_max_window_bits"] = "10"; + v.attr["server_no_context_takeover"] = ""; + v.attr["client_no_context_takeover"] = ""; + v.attr["server_max_window_bits"] = "10"; v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( v.exts.is_enabled() ); BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() ); - BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_no_context_takeover; c2s_no_context_takeover; s2c_max_window_bits=10"); + BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_no_context_takeover; client_no_context_takeover; server_max_window_bits=10"); } BOOST_AUTO_TEST_CASE( negotiate_three_client_initiated2 ) { ext_vars v; - v.attr["s2c_no_context_takeover"] = ""; - v.attr["c2s_no_context_takeover"] = ""; - v.attr["c2s_max_window_bits"] = "10"; + v.attr["server_no_context_takeover"] = ""; + v.attr["client_no_context_takeover"] = ""; + v.attr["client_max_window_bits"] = "10"; v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( v.exts.is_enabled() ); BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() ); - BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_no_context_takeover; c2s_no_context_takeover; c2s_max_window_bits=10"); + BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_no_context_takeover; client_no_context_takeover; client_max_window_bits=10"); } BOOST_AUTO_TEST_CASE( negotiate_three_client_initiated3 ) { ext_vars v; - v.attr["s2c_no_context_takeover"] = ""; - v.attr["s2c_max_window_bits"] = "10"; - v.attr["c2s_max_window_bits"] = "10"; + v.attr["server_no_context_takeover"] = ""; + v.attr["server_max_window_bits"] = "10"; + v.attr["client_max_window_bits"] = "10"; v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( v.exts.is_enabled() ); BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() ); - BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_no_context_takeover; s2c_max_window_bits=10; c2s_max_window_bits=10"); + BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_no_context_takeover; server_max_window_bits=10; client_max_window_bits=10"); } BOOST_AUTO_TEST_CASE( negotiate_three_client_initiated4 ) { ext_vars v; - v.attr["c2s_no_context_takeover"] = ""; - v.attr["s2c_max_window_bits"] = "10"; - v.attr["c2s_max_window_bits"] = "10"; + v.attr["client_no_context_takeover"] = ""; + v.attr["server_max_window_bits"] = "10"; + v.attr["client_max_window_bits"] = "10"; v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( v.exts.is_enabled() ); BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() ); - BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; c2s_no_context_takeover; s2c_max_window_bits=10; c2s_max_window_bits=10"); + BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; client_no_context_takeover; server_max_window_bits=10; client_max_window_bits=10"); } BOOST_AUTO_TEST_CASE( negotiate_four_client_initiated ) { ext_vars v; - v.attr["s2c_no_context_takeover"] = ""; - v.attr["c2s_no_context_takeover"] = ""; - v.attr["s2c_max_window_bits"] = "10"; - v.attr["c2s_max_window_bits"] = "10"; + v.attr["server_no_context_takeover"] = ""; + v.attr["client_no_context_takeover"] = ""; + v.attr["server_max_window_bits"] = "10"; + v.attr["client_max_window_bits"] = "10"; v.esp = v.exts.negotiate(v.attr); BOOST_CHECK( v.exts.is_enabled() ); BOOST_CHECK_EQUAL( v.esp.first, websocketpp::lib::error_code() ); - BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; s2c_no_context_takeover; c2s_no_context_takeover; s2c_max_window_bits=10; c2s_max_window_bits=10"); + BOOST_CHECK_EQUAL( v.esp.second, "permessage-deflate; server_no_context_takeover; client_no_context_takeover; server_max_window_bits=10; client_max_window_bits=10"); } // Compression -/* BOOST_AUTO_TEST_CASE( compress_data ) { ext_vars v; - std::string in = "Hello"; - std::string out; - std::string in2; - std::string out2; + std::string compress_in = "Hello"; + std::string compress_out; + std::string decompress_out; - v.exts.init(); + v.exts.init(true); - v.ec = v.exts.compress(in,out); + v.ec = v.exts.compress(compress_in,compress_out); + BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() ); - std::cout << "in : " << websocketpp::utility::to_hex(in) << std::endl; + v.ec = v.exts.decompress(reinterpret_cast(compress_out.data()),compress_out.size(),decompress_out); BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() ); - std::cout << "out: " << websocketpp::utility::to_hex(out) << std::endl; + BOOST_CHECK_EQUAL( compress_in, decompress_out ); +} + +BOOST_AUTO_TEST_CASE( compress_data_multiple ) { + ext_vars v; + + v.exts.init(true); + + for (int i = 0; i < 2; i++) { + std::string compress_in = "Hello"; + std::string compress_out; + std::string decompress_out; + + v.ec = v.exts.compress(compress_in,compress_out); + BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() ); + + v.ec = v.exts.decompress(reinterpret_cast(compress_out.data()),compress_out.size(),decompress_out); + BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() ); + BOOST_CHECK_EQUAL( compress_in, decompress_out ); + } +} + +BOOST_AUTO_TEST_CASE( compress_data_large ) { + ext_vars v; - in2 = out; + std::string compress_in(600,'*'); + std::string compress_out; + std::string decompress_out; - v.ec = v.exts.decompress(reinterpret_cast(in2.data()),in2.size(),out2); + websocketpp::http::attribute_list alist; + alist["server_max_window_bits"] = "8"; + v.exts.set_server_max_window_bits(8,websocketpp::extensions::permessage_deflate::mode::smallest); + + v.exts.negotiate(alist); + v.exts.init(true); + + v.ec = v.exts.compress(compress_in,compress_out); + BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() ); + + v.ec = v.exts.decompress(reinterpret_cast(compress_out.data()),compress_out.size(),decompress_out); BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() ); - std::cout << "out: " << websocketpp::utility::to_hex(out2) << std::endl; - BOOST_CHECK_EQUAL( out, out2 ); + BOOST_CHECK_EQUAL( compress_in, decompress_out ); } +BOOST_AUTO_TEST_CASE( compress_data_no_context_takeover ) { + ext_vars v; + + std::string compress_in = "Hello"; + std::string compress_out1; + std::string compress_out2; + std::string decompress_out; + + websocketpp::http::attribute_list alist; + + alist["server_no_context_takeover"] = ""; + v.exts.enable_server_no_context_takeover(); + + v.exts.negotiate(alist); + v.exts.init(true); + + v.ec = v.exts.compress(compress_in,compress_out1); + BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() ); + + v.ec = v.exts.decompress( + reinterpret_cast(compress_out1.data()), + compress_out1.size(), + decompress_out + ); + BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() ); + BOOST_CHECK_EQUAL( compress_in, decompress_out ); + + decompress_out = ""; + + v.ec = v.exts.compress(compress_in,compress_out2); + BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() ); + + v.ec = v.exts.decompress( + reinterpret_cast(compress_out2.data()), + compress_out2.size(), + decompress_out + ); + BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() ); + BOOST_CHECK_EQUAL( compress_in, decompress_out ); + + BOOST_CHECK_EQUAL( compress_out1, compress_out2 ); +} + +BOOST_AUTO_TEST_CASE( compress_empty ) { + ext_vars v; + + std::string compress_in = ""; + std::string compress_out; + std::string decompress_out; + + v.exts.init(true); + + v.ec = v.exts.compress(compress_in,compress_out); + BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() ); + + v.ec = v.exts.decompress(reinterpret_cast(compress_out.data()),compress_out.size(),decompress_out); + + compress_out = ""; + decompress_out = ""; + + v.ec = v.exts.compress(compress_in,compress_out); + BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() ); + + v.ec = v.exts.decompress(reinterpret_cast(compress_out.data()),compress_out.size(),decompress_out); + BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() ); + BOOST_CHECK_EQUAL( compress_in, decompress_out ); +} + +/// @todo: more compression tests +/** + * - compress at different compression levels + */ + +// Decompression BOOST_AUTO_TEST_CASE( decompress_data ) { ext_vars v; - uint8_t in[12] = {0xf2, 0x48, 0xcd, 0xc9, 0xc9, 0x07, 0x00, 0x00, 0x00, 0xff, 0xff}; - std::string out; + uint8_t in[11] = {0xf2, 0x48, 0xcd, 0xc9, 0xc9, 0x07, 0x00, 0x00, 0x00, 0xff, 0xff}; + std::string out = ""; + std::string reference = "Hello"; - v.exts.init(); + v.exts.init(true); - v.ec = v.exts.decompress(in,12,out); + v.ec = v.exts.decompress(in,11,out); BOOST_CHECK_EQUAL( v.ec, websocketpp::lib::error_code() ); - std::cout << "out: " << websocketpp::utility::to_hex(out) << std::endl; - BOOST_CHECK( false ); + BOOST_CHECK_EQUAL( out, reference ); } -*/ diff --git a/Release/libs/websocketpp/test/http/a.out b/Release/libs/websocketpp/test/http/a.out new file mode 100755 index 0000000000..b2a20f1c70 Binary files /dev/null and b/Release/libs/websocketpp/test/http/a.out differ diff --git a/Release/libs/websocketpp/test/http/perf.out b/Release/libs/websocketpp/test/http/perf.out new file mode 100755 index 0000000000..587237cf55 Binary files /dev/null and b/Release/libs/websocketpp/test/http/perf.out differ diff --git a/Release/libs/websocketpp/test/http/test.out b/Release/libs/websocketpp/test/http/test.out new file mode 100755 index 0000000000..4d685e6234 Binary files /dev/null and b/Release/libs/websocketpp/test/http/test.out differ diff --git a/Release/libs/websocketpp/test/logger/basic.cpp b/Release/libs/websocketpp/test/logger/basic.cpp index de51e5ad20..a73053575b 100644 --- a/Release/libs/websocketpp/test/logger/basic.cpp +++ b/Release/libs/websocketpp/test/logger/basic.cpp @@ -34,6 +34,8 @@ #include #include +typedef websocketpp::log::basic basic_access_log_type; + BOOST_AUTO_TEST_CASE( is_token_char ) { typedef websocketpp::log::basic error_log; @@ -79,3 +81,65 @@ BOOST_AUTO_TEST_CASE( basic_concurrency ) { //std::cout << "|" << out.str() << "|" << std::endl; BOOST_CHECK( out.str().size() > 0 ); } + + +BOOST_AUTO_TEST_CASE( copy_constructor ) { + std::stringstream out; + + basic_access_log_type logger1(0xffffffff,&out); + basic_access_log_type logger2(logger1); + + logger2.set_channels(0xffffffff); + logger2.write(websocketpp::log::alevel::devel,"devel"); + BOOST_CHECK( out.str().size() > 0 ); +} + +#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_ +BOOST_AUTO_TEST_CASE( move_constructor ) { + std::stringstream out; + + basic_access_log_type logger1(0xffffffff,&out); + basic_access_log_type logger2(std::move(logger1)); + + logger2.set_channels(0xffffffff); + logger2.write(websocketpp::log::alevel::devel,"devel"); + BOOST_CHECK( out.str().size() > 0 ); +} + +// Emplace requires move assignment, which logger doesn't support right now +// due to const members. This is pretty irritating and will probably result in +// the const members being removed. For now though this test will fail to +// compile +/*BOOST_AUTO_TEST_CASE( emplace ) { + std::stringstream out1; + std::stringstream out2; + + std::vector v; + + v.emplace_back(websocketpp::log::level(0xffffffff),&out1); + v.emplace_back(websocketpp::log::level(0xffffffff),&out2); + + v[0].set_channels(0xffffffff); + v[1].set_channels(0xffffffff); + v[0].write(websocketpp::log::alevel::devel,"devel"); + v[1].write(websocketpp::log::alevel::devel,"devel"); + BOOST_CHECK( out1.str().size() > 0 ); + BOOST_CHECK( out2.str().size() > 0 ); +}*/ +#endif // #ifdef _WEBSOCKETPP_MOVE_SEMANTICS_ + +// As long as there are const member variables these can't exist +// These remain commented as they are useful for testing the deleted operators +/*BOOST_AUTO_TEST_CASE( copy_assign ) { + basic_access_log_type logger1; + basic_access_log_type logger2; + + logger2 = logger1; +} + +BOOST_AUTO_TEST_CASE( move_assign ) { + basic_access_log_type logger1; + basic_access_log_type logger2; + + logger2 = std::move(logger1); +}*/ diff --git a/Release/libs/websocketpp/test/processors/hybi13.cpp b/Release/libs/websocketpp/test/processors/hybi13.cpp index d16ba1797b..9b2618ac07 100644 --- a/Release/libs/websocketpp/test/processors/hybi13.cpp +++ b/Release/libs/websocketpp/test/processors/hybi13.cpp @@ -682,7 +682,7 @@ BOOST_AUTO_TEST_CASE( extension_negotiation_permessage_deflate ) { processor_setup_ext env(true); env.req.replace_header("Sec-WebSocket-Extensions", - "permessage-deflate; c2s_max_window_bits"); + "permessage-deflate; client_max_window_bits"); std::pair neg_results; neg_results = env.p.negotiate_extensions(env.req); diff --git a/Release/libs/websocketpp/test/transport/SConscript b/Release/libs/websocketpp/test/transport/SConscript index 74ec781ef9..71b31b6c5a 100644 --- a/Release/libs/websocketpp/test/transport/SConscript +++ b/Release/libs/websocketpp/test/transport/SConscript @@ -11,7 +11,7 @@ Import('tls_libs') env = env.Clone () env_cpp11 = env_cpp11.Clone () -BOOST_LIBS = boostlibs(['unit_test_framework','system','thread','random'],env) + [platform_libs] + [tls_libs] +BOOST_LIBS = boostlibs(['unit_test_framework','system','thread','random','chrono'],env) + [platform_libs] + [tls_libs] objs = env.Object('boost_integration.o', ["integration.cpp"], LIBS = BOOST_LIBS) prgs = env.Program('test_boost_integration', ["boost_integration.o"], LIBS = BOOST_LIBS) diff --git a/Release/libs/websocketpp/test/transport/asio/SConscript b/Release/libs/websocketpp/test/transport/asio/SConscript index 6cae57c07b..ea0526b3ac 100644 --- a/Release/libs/websocketpp/test/transport/asio/SConscript +++ b/Release/libs/websocketpp/test/transport/asio/SConscript @@ -11,7 +11,7 @@ Import('tls_libs') env = env.Clone () env_cpp11 = env_cpp11.Clone () -BOOST_LIBS = boostlibs(['unit_test_framework','system','thread'],env) + [platform_libs] + [tls_libs] +BOOST_LIBS = boostlibs(['unit_test_framework','system','thread','chrono'],env) + [platform_libs] + [tls_libs] objs = env.Object('base_boost.o', ["base.cpp"], LIBS = BOOST_LIBS) objs += env.Object('timers_boost.o', ["timers.cpp"], LIBS = BOOST_LIBS) diff --git a/Release/libs/websocketpp/test/transport/integration.cpp b/Release/libs/websocketpp/test/transport/integration.cpp index 1d2e7e795c..f886fbf263 100644 --- a/Release/libs/websocketpp/test/transport/integration.cpp +++ b/Release/libs/websocketpp/test/transport/integration.cpp @@ -607,3 +607,11 @@ BOOST_AUTO_TEST_CASE( pause_reading ) { BOOST_AUTO_TEST_CASE( server_connection_cleanup ) { server_tls s; } + +#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_ +BOOST_AUTO_TEST_CASE( move_construct_transport ) { + server s1; + + server s2(std::move(s1)); +} +#endif // _WEBSOCKETPP_MOVE_SEMANTICS_ diff --git a/Release/libs/websocketpp/test/transport/iostream/connection.cpp b/Release/libs/websocketpp/test/transport/iostream/connection.cpp index 49465d6bae..2a45013523 100644 --- a/Release/libs/websocketpp/test/transport/iostream/connection.cpp +++ b/Release/libs/websocketpp/test/transport/iostream/connection.cpp @@ -117,7 +117,7 @@ struct stub_con : public iostream_con { indef_read_size = num_bytes; indef_read_buf = buf; indef_read_len = len; - + indef_read(); } @@ -138,7 +138,7 @@ struct stub_con : public iostream_con { void handle_indef(websocketpp::lib::error_code const & e, size_t amt_read) { ec = e; indef_read_total += amt_read; - + indef_read(); } @@ -203,6 +203,15 @@ websocketpp::lib::error_code write_handler(std::string & o, websocketpp::connect return websocketpp::lib::error_code(); } +websocketpp::lib::error_code vector_write_handler(std::string & o, websocketpp::connection_hdl, std::vector const & bufs) { + std::vector::const_iterator it; + for (it = bufs.begin(); it != bufs.end(); it++) { + o += std::string((*it).buf, (*it).len); + } + + return websocketpp::lib::error_code(); +} + websocketpp::lib::error_code write_handler_error(websocketpp::connection_hdl, char const *, size_t) { return make_error_code(websocketpp::transport::error::general); } @@ -249,7 +258,7 @@ BOOST_AUTO_TEST_CASE( async_write_vector_0_write_handler ) { std::string output; stub_con::ptr con(new stub_con(true,alogger,elogger)); - + con->set_write_handler(websocketpp::lib::bind( &write_handler, websocketpp::lib::ref(output), @@ -354,6 +363,31 @@ BOOST_AUTO_TEST_CASE( async_write_vector_2_write_handler ) { BOOST_CHECK_EQUAL( output, "foobar" ); } +BOOST_AUTO_TEST_CASE( async_write_vector_2_vector_write_handler ) { + std::string output; + + stub_con::ptr con(new stub_con(true,alogger,elogger)); + con->set_vector_write_handler(websocketpp::lib::bind( + &vector_write_handler, + websocketpp::lib::ref(output), + websocketpp::lib::placeholders::_1, + websocketpp::lib::placeholders::_2 + )); + + std::vector bufs; + + std::string foo = "foo"; + std::string bar = "bar"; + + bufs.push_back(websocketpp::transport::buffer(foo.data(),foo.size())); + bufs.push_back(websocketpp::transport::buffer(bar.data(),bar.size())); + + con->write(bufs); + + BOOST_CHECK( !con->ec ); + BOOST_CHECK_EQUAL( output, "foobar" ); +} + BOOST_AUTO_TEST_CASE( async_read_at_least_too_much ) { stub_con::ptr con(new stub_con(true,alogger,elogger)); @@ -483,7 +517,7 @@ BOOST_AUTO_TEST_CASE( async_read_at_least_read_some_indef ) { BOOST_CHECK( !con->ec ); BOOST_CHECK_EQUAL( std::string(buf,10), "aaaaaxxxxx" ); BOOST_CHECK_EQUAL( con->indef_read_total, 5 ); - + // A subsequent read should read 5 more because the indef read refreshes // itself. The new read will start again at the beginning of the buffer. BOOST_CHECK_EQUAL(con->read_some(input+5,5), 5); @@ -539,7 +573,7 @@ websocketpp::lib::error_code sd_handler(websocketpp::connection_hdl) { BOOST_AUTO_TEST_CASE( shutdown_handler ) { stub_con::ptr con(new stub_con(true,alogger,elogger)); - + con->set_shutdown_handler(&sd_handler); BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) ); con->shutdown(); diff --git a/Release/libs/websocketpp/tutorials/utility_client/utility_client.md b/Release/libs/websocketpp/tutorials/utility_client/utility_client.md index 5490f571bb..85cc928178 100644 --- a/Release/libs/websocketpp/tutorials/utility_client/utility_client.md +++ b/Release/libs/websocketpp/tutorials/utility_client/utility_client.md @@ -235,7 +235,7 @@ The `websocket_endpoint` object has gained some new data members and methods. It A new WebSocket connection is initiated via a three step process. First, a connection request is created by `endpoint::get_connection(uri)`. Next, the connection request is configured. Lastly, the connection request is submitted back to the endpoint via `endpoint::connect()` which adds it to the queue of new connections to make. > ###### Terminology `connection_ptr` -> WebSocket++ keeps track of connection related resources using a reference counted shared pointer. The type of this pointer is `endpoint::connection_ptr`. A `connection_ptr` allows direct access to information about the connection and allows changing connection settings. Because of this direct access and their internal resource management role within the library it is not safe to for end applications to use `connection_ptr` except in the specific circumstances detailed below. +> WebSocket++ keeps track of connection related resources using a reference counted shared pointer. The type of this pointer is `endpoint::connection_ptr`. A `connection_ptr` allows direct access to information about the connection and allows changing connection settings. Because of this direct access and their internal resource management role within the library it is not safe for end applications to use `connection_ptr` except in the specific circumstances detailed below. > > **When is it safe to use `connection_ptr`?** > - After `endpoint::get_connection(...)` and before `endpoint::connect()`: `get_connection` returns a `connection_ptr`. It is safe to use this pointer to configure your new connection. Once you submit the connection to `connect` you may no longer use the `connection_ptr` and should discard it immediately for optimal memory management. @@ -813,6 +813,13 @@ Enter Command: show 0 _Using TLS / Secure WebSockets_ +- Change the includes +- link to the new library dependencies +- Switch the config +- add the `tls_init_handler` +- configure the SSL context for desired security level +- mixing secure and non-secure connections in one application. + Chapter 2: Intermediate Features -------------------------------- diff --git a/Release/libs/websocketpp/websocketpp/common/asio.hpp b/Release/libs/websocketpp/websocketpp/common/asio.hpp new file mode 100755 index 0000000000..ca48359399 --- /dev/null +++ b/Release/libs/websocketpp/websocketpp/common/asio.hpp @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2015, 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_ASIO_HPP +#define WEBSOCKETPP_COMMON_ASIO_HPP + +// This file goes to some length to preserve compatibility with versions of +// boost older than 1.49 (where the first modern steady_timer timer based on +// boost/std chrono was introduced. +// +// For the versions older than 1.49, the deadline_timer is used instead. this +// brings in dependencies on boost date_time and it has a different interface +// that is normalized by the `lib::asio::is_neg` and `lib::asio::milliseconds` +// wrappers provided by this file. +// +// The primary reason for this continued support is that boost 1.48 is the +// default and not easily changeable version of boost supplied by the package +// manager of popular Linux distributions like Ubuntu 12.04 LTS. Once the need +// for this has passed this should be cleaned up and simplified. + +#ifdef ASIO_STANDALONE + #include + + #if (ASIO_VERSION/100000) == 1 && ((ASIO_VERSION/100)%1000) < 8 + static_assert(false, "The minimum version of standalone Asio is 1.8.0"); + #endif + + #include + #include + #include +#else + #include + + // See note above about boost <1.49 compatibility. If we are running on + // boost > 1.48 pull in the steady timer and chrono library + #if (BOOST_VERSION/100000) == 1 && ((BOOST_VERSION/100)%1000) > 48 + #include + #include + #endif + + #include + #include +#endif + +namespace websocketpp { +namespace lib { + +#ifdef ASIO_STANDALONE + namespace asio { + using namespace ::asio; + // Here we assume that we will be using std::error_code with standalone + // Asio. This is probably a good assumption, but it is possible in rare + // cases that local Asio versions would be used. + using std::errc; + + // See note above about boost <1.49 compatibility. Because we require + // a standalone Asio version of 1.8+ we are guaranteed to have + // steady_timer available. By convention we require the chrono library + // (either boost or std) for use with standalone Asio. + template + bool is_neg(T duration) { + return duration.count() < 0; + } + inline lib::chrono::milliseconds milliseconds(long duration) { + return lib::chrono::milliseconds(duration); + } + } // namespace asio + +#else + namespace asio { + using namespace boost::asio; + + // See note above about boost <1.49 compatibility + #if (BOOST_VERSION/100000) == 1 && ((BOOST_VERSION/100)%1000) > 48 + // Using boost::asio >=1.49 so we use chrono and steady_timer + template + bool is_neg(T duration) { + return duration.count() < 0; + } + inline lib::chrono::milliseconds milliseconds(long duration) { + return lib::chrono::milliseconds(duration); + } + #else + // Using boost::asio <1.49 we pretend a deadline timer is a steady + // timer and wrap the negative detection and duration conversion + // appropriately. + typedef boost::asio::deadline_timer steady_timer; + + template + bool is_neg(T duration) { + return duration.is_negative(); + } + inline boost::posix_time::time_duration milliseconds(long duration) { + return boost::posix_time::milliseconds(duration); + } + #endif + + using boost::system::error_code; + namespace errc = boost::system::errc; + } // namespace asio +#endif + + +} // namespace lib +} // namespace websocketpp + +#endif // WEBSOCKETPP_COMMON_ASIO_HPP diff --git a/Release/libs/websocketpp/websocketpp/common/asio_ssl.hpp b/Release/libs/websocketpp/websocketpp/common/asio_ssl.hpp new file mode 100755 index 0000000000..cc74297ea7 --- /dev/null +++ b/Release/libs/websocketpp/websocketpp/common/asio_ssl.hpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, 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_ASIO_SSL_HPP +#define WEBSOCKETPP_COMMON_ASIO_SSL_HPP + +#ifdef ASIO_STANDALONE + #include +#else + #include +#endif + +#endif // WEBSOCKETPP_COMMON_ASIO_SSL_HPP diff --git a/Release/libs/websocketpp/websocketpp/common/chrono.hpp b/Release/libs/websocketpp/websocketpp/common/chrono.hpp index c536a3652c..d50dd1209a 100644 --- a/Release/libs/websocketpp/websocketpp/common/chrono.hpp +++ b/Release/libs/websocketpp/websocketpp/common/chrono.hpp @@ -28,7 +28,12 @@ #ifndef WEBSOCKETPP_COMMON_CHRONO_HPP #define WEBSOCKETPP_COMMON_CHRONO_HPP -#if defined _WEBSOCKETPP_CPP11_STL_ && !defined _WEBSOCKETPP_NO_CPP11_CHRONO_ +#include + +// If we've determined that we're in full C++11 mode and the user hasn't +// explicitly disabled the use of C++11 functional header, then prefer it to +// boost. +#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_CHRONO_ #ifndef _WEBSOCKETPP_CPP11_CHRONO_ #define _WEBSOCKETPP_CPP11_CHRONO_ #endif @@ -44,9 +49,9 @@ namespace websocketpp { namespace lib { #ifdef _WEBSOCKETPP_CPP11_CHRONO_ - using std::chrono::system_clock; + namespace chrono = std::chrono; #else - using boost::chrono::system_clock; + namespace chrono = boost::chrono; #endif } // namespace lib diff --git a/Release/libs/websocketpp/websocketpp/common/cpp11.hpp b/Release/libs/websocketpp/websocketpp/common/cpp11.hpp index 6c79d644d7..a150de363b 100644 --- a/Release/libs/websocketpp/websocketpp/common/cpp11.hpp +++ b/Release/libs/websocketpp/websocketpp/common/cpp11.hpp @@ -80,6 +80,12 @@ #ifndef _WEBSOCKETPP_NULLPTR_TOKEN_ #define _WEBSOCKETPP_NULLPTR_TOKEN_ nullptr #endif + #ifndef _WEBSOCKETPP_MOVE_SEMANTICS_ + #define _WEBSOCKETPP_MOVE_SEMANTICS_ + #endif + #ifndef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ + #define _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ + #endif #ifndef __GNUC__ // GCC as of version 4.9 (latest) does not support std::put_time yet. diff --git a/Release/libs/websocketpp/websocketpp/common/network.hpp b/Release/libs/websocketpp/websocketpp/common/network.hpp index 3f98396656..26a4cb9ea8 100644 --- a/Release/libs/websocketpp/websocketpp/common/network.hpp +++ b/Release/libs/websocketpp/websocketpp/common/network.hpp @@ -36,6 +36,8 @@ #include #endif +#include + namespace websocketpp { namespace lib { namespace net { diff --git a/Release/libs/websocketpp/websocketpp/common/system_error.hpp b/Release/libs/websocketpp/websocketpp/common/system_error.hpp index 4abe1732f1..e5aea25495 100644 --- a/Release/libs/websocketpp/websocketpp/common/system_error.hpp +++ b/Release/libs/websocketpp/websocketpp/common/system_error.hpp @@ -61,6 +61,7 @@ namespace websocketpp { namespace lib { #ifdef _WEBSOCKETPP_CPP11_SYSTEM_ERROR_ + using std::errc; using std::error_code; using std::error_category; using std::error_condition; @@ -68,6 +69,7 @@ namespace lib { #define _WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_ namespace std { #define _WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_ } #else + namespace errc = boost::system::errc; using boost::system::error_code; using boost::system::error_category; using boost::system::error_condition; diff --git a/Release/libs/websocketpp/websocketpp/error_container.hpp b/Release/libs/websocketpp/websocketpp/common/type_traits.hpp old mode 100644 new mode 100755 similarity index 64% rename from Release/libs/websocketpp/websocketpp/error_container.hpp rename to Release/libs/websocketpp/websocketpp/common/type_traits.hpp index b7c75ac964..72cc2e1e40 --- a/Release/libs/websocketpp/websocketpp/error_container.hpp +++ b/Release/libs/websocketpp/websocketpp/common/type_traits.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Peter Thorson. All rights reserved. + * Copyright (c) 2015, 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,47 +25,39 @@ * */ -#ifndef WEBSOCKETPP_ERROR_MESSAGE_HPP -#define WEBSOCKETPP_ERROR_MESSAGE_HPP +#ifndef WEBSOCKETPP_COMMON_TYPE_TRAITS_HPP +#define WEBSOCKETPP_COMMON_TYPE_TRAITS_HPP -namespace websocketpp { +#include + +// If we've determined that we're in full C++11 mode and the user hasn't +// explicitly disabled the use of C++11 functional header, then prefer it to +// boost. +#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_TYPE_TRAITS_ + #ifndef _WEBSOCKETPP_CPP11_TYPE_TRAITS_ + #define _WEBSOCKETPP_CPP11_TYPE_TRAITS_ + #endif +#endif -/** - * The transport::security::* classes are a set of security/socket related - * policies and support code for the ASIO transport types. - */ -class error_msg { -public: - const std::string& get_msg() const { - return m_error_msg; - } - void set_msg(const std::string& msg) { - m_error_msg = msg; - } +#ifdef _WEBSOCKETPP_CPP11_TYPE_TRAITS_ + #include +#else + #include +#endif - 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 append_msg(const T& thing) { - std::stringsteam val; - val << thing; - this->append_msg(val.str()); - } -private: - // error resources - std::string m_error_msg; -}; +namespace websocketpp { +namespace lib { + +#ifdef _WEBSOCKETPP_CPP11_TYPE_TRAITS_ + using std::aligned_storage; +#else + using boost::aligned_storage; +#endif +} // namespace lib } // namespace websocketpp -#endif // WEBSOCKETPP_ERROR_MESSAGE_HPP +#endif // WEBSOCKETPP_COMMON_TYPE_TRAITS_HPP diff --git a/Release/libs/websocketpp/websocketpp/connection.hpp b/Release/libs/websocketpp/websocketpp/connection.hpp index 954683279d..203de6f66e 100644 --- a/Release/libs/websocketpp/websocketpp/connection.hpp +++ b/Release/libs/websocketpp/websocketpp/connection.hpp @@ -214,6 +214,20 @@ namespace internal_state { PROCESS_CONNECTION = 7 }; } // namespace internal_state + + +namespace http_state { + // states to keep track of the progress of http connections + + enum value { + init = 0, + deferred = 1, + headers_written = 2, + body_written = 3, + closed = 4 + }; +} // namespace http_state + } // namespace session /// Represents an individual WebSocket connection @@ -312,6 +326,7 @@ class connection , m_local_close_code(close::status::abnormal_close) , m_remote_close_code(close::status::abnormal_close) , m_is_http(false) + , m_http_state(session::http_state::init) , m_was_clean(false) { m_alog.write(log::alevel::devel,"connection constructor"); @@ -1060,6 +1075,52 @@ class connection request_type const & get_request() const { return m_request; } + + /// Defer HTTP Response until later (Exception free) + /** + * Used in the http handler to defer the HTTP response for this connection + * until later. Handshake timers will be canceled and the connection will be + * left open until `send_http_response` or an equivalent is called. + * + * Warning: deferred connections won't time out and as a result can tie up + * resources. + * + * @since 0.6.0 + * + * @return A status code, zero on success, non-zero otherwise + */ + lib::error_code defer_http_response(); + + /// Send deferred HTTP Response (exception free) + /** + * Sends an http response to an HTTP connection that was deferred. This will + * send a complete response including all headers, status line, and body + * text. The connection will be closed afterwards. + * + * @since 0.6.0 + * + * @param ec A status code, zero on success, non-zero otherwise + */ + void send_http_response(lib::error_code & ec); + + /// Send deferred HTTP Response + void send_http_response(); + + // TODO HTTPNBIO: write_headers + // function that processes headers + status so far and writes it to the wire + // beginning the HTTP response body state. This method will ignore anything + // in the response body. + + // TODO HTTPNBIO: write_body_message + // queues the specified message_buffer for async writing + + // TODO HTTPNBIO: finish connection + // + + // TODO HTTPNBIO: write_response + // Writes the whole response, headers + body and closes the connection + + ///////////////////////////////////////////////////////////// // Pass-through access to the other connection information // @@ -1202,7 +1263,8 @@ class connection void handle_read_http_response(lib::error_code const & ec, size_t bytes_transferred); - void handle_send_http_response(lib::error_code const & ec); + + void handle_write_http_response(lib::error_code const & ec); void handle_send_http_request(lib::error_code const & ec); void handle_open_handshake_timeout(lib::error_code const & ec); @@ -1254,13 +1316,13 @@ class connection lib::error_code process_handshake_request(); private: /// Completes m_response, serializes it, and sends it out on the wire. - void send_http_response(lib::error_code const & ec); + void write_http_response(lib::error_code const & ec); /// Sends an opening WebSocket connect request void send_http_request(); - /// Alternate path for send_http_response in error conditions - void send_http_response_error(lib::error_code const & ec); + /// Alternate path for write_http_response in error conditions + void write_http_response_error(lib::error_code const & ec); /// Process control message /** @@ -1510,6 +1572,10 @@ class connection /// A flag that gets set once it is determined that the connection is an /// HTTP connection and not a WebSocket one. bool m_is_http; + + /// A flag that gets set when the completion of an http connection is + /// deferred until later. + session::http_state::value m_http_state; bool m_was_clean; diff --git a/Release/libs/websocketpp/websocketpp/endpoint.hpp b/Release/libs/websocketpp/websocketpp/endpoint.hpp index 15db1ccb34..908a6f96f9 100644 --- a/Release/libs/websocketpp/websocketpp/endpoint.hpp +++ b/Release/libs/websocketpp/websocketpp/endpoint.hpp @@ -104,6 +104,56 @@ class endpoint : public config::transport_type, public config::endpoint_base { transport_type::init_logging(&m_alog, &m_elog); } + + /// Destructor + ~endpoint() {} + + #ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ + // no copy constructor because endpoints are not copyable + endpoint(endpoint &) = delete; + + // no copy assignment operator because endpoints are not copyable + endpoint & operator=(endpoint const &) = delete; + #endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ + + #ifdef _WEBSOCKETPP_MOVE_SEMANTICS_ + /// Move constructor + endpoint(endpoint && o) + : config::transport_type(std::move(o)) + , config::endpoint_base(std::move(o)) + , m_alog(std::move(o.m_alog)) + , m_elog(std::move(o.m_elog)) + , m_user_agent(std::move(o.m_user_agent)) + , m_open_handler(std::move(o.m_open_handler)) + + , m_close_handler(std::move(o.m_close_handler)) + , m_fail_handler(std::move(o.m_fail_handler)) + , m_ping_handler(std::move(o.m_ping_handler)) + , m_pong_handler(std::move(o.m_pong_handler)) + , m_pong_timeout_handler(std::move(o.m_pong_timeout_handler)) + , m_interrupt_handler(std::move(o.m_interrupt_handler)) + , m_http_handler(std::move(o.m_http_handler)) + , m_validate_handler(std::move(o.m_validate_handler)) + , m_message_handler(std::move(o.m_message_handler)) + + , m_open_handshake_timeout_dur(o.m_open_handshake_timeout_dur) + , m_close_handshake_timeout_dur(o.m_close_handshake_timeout_dur) + , m_pong_timeout_dur(o.m_pong_timeout_dur) + , m_max_message_size(o.m_max_message_size) + , m_max_http_body_size(o.m_max_http_body_size) + + , m_rng(std::move(o.m_rng)) + , m_is_server(o.m_is_server) + {} + + #ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ + // no move assignment operator because of const member variables + endpoint & operator=(endpoint &&) = delete; + #endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ + + #endif // _WEBSOCKETPP_MOVE_SEMANTICS_ + + /// Returns the user agent string that this endpoint will use /** * Returns the user agent string that this endpoint will use when creating @@ -466,6 +516,35 @@ class endpoint : public config::transport_type, public config::endpoint_base { /// Resume reading of new data void resume_reading(connection_hdl hdl); + /// Send deferred HTTP Response + /** + * Sends an http response to an HTTP connection that was deferred. This will + * send a complete response including all headers, status line, and body + * text. The connection will be closed afterwards. + * + * Exception free variant + * + * @since 0.6.0 + * + * @param hdl The connection to send the response on + * @param ec A status code, zero on success, non-zero otherwise + */ + void send_http_response(connection_hdl hdl, lib::error_code & ec); + + /// Send deferred HTTP Response (exception free) + /** + * Sends an http response to an HTTP connection that was deferred. This will + * send a complete response including all headers, status line, and body + * text. The connection will be closed afterwards. + * + * Exception variant + * + * @since 0.6.0 + * + * @param hdl The connection to send the response on + */ + void send_http_response(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 @@ -559,7 +638,6 @@ class endpoint : public config::transport_type, public config::endpoint_base { * @return the connection_ptr. May be NULL if the handle was invalid. */ connection_ptr get_con_from_hdl(connection_hdl hdl, lib::error_code & ec) { - scoped_lock_type lock(m_mutex); connection_ptr con = lib::static_pointer_cast( hdl.lock()); if (!con) { diff --git a/Release/libs/websocketpp/websocketpp/error.hpp b/Release/libs/websocketpp/websocketpp/error.hpp index 81fff8733d..562fb6ed71 100644 --- a/Release/libs/websocketpp/websocketpp/error.hpp +++ b/Release/libs/websocketpp/websocketpp/error.hpp @@ -140,7 +140,10 @@ enum value { unsupported_version, /// HTTP parse error - http_parse_error + http_parse_error, + + /// Extension negotiation failed + extension_neg_failed }; // enum value @@ -216,6 +219,8 @@ class category : public lib::error_category { return "Unsupported version"; case error::http_parse_error: return "HTTP parse error"; + case error::extension_neg_failed: + return "Extension negotiation failed"; default: return "Unknown"; } @@ -250,7 +255,7 @@ class exception : public std::exception { {} explicit exception(lib::error_code ec) - : m_code(ec) + : m_msg(ec.message()), m_code(ec) {} ~exception() throw() {} @@ -263,7 +268,7 @@ class exception : public std::exception { return m_code; } - std::string m_msg; + const std::string m_msg; lib::error_code m_code; }; diff --git a/Release/libs/websocketpp/websocketpp/extensions/permessage_deflate/disabled.hpp b/Release/libs/websocketpp/websocketpp/extensions/permessage_deflate/disabled.hpp index c76bf93649..49c0e1dcf7 100644 --- a/Release/libs/websocketpp/websocketpp/extensions/permessage_deflate/disabled.hpp +++ b/Release/libs/websocketpp/websocketpp/extensions/permessage_deflate/disabled.hpp @@ -55,7 +55,7 @@ class disabled { public: /// Negotiate extension /** - * The disabled extension always fails the negotiation with a disabled + * The disabled extension always fails the negotiation with a disabled * error. * * @param offer Attribute from client's offer @@ -65,6 +65,17 @@ class disabled { return make_pair(make_error_code(error::disabled),std::string()); } + /// Initialize state + /** + * For the disabled extension state initialization is a no-op. + * + * @param is_server True to initialize as a server, false for a client. + * @return A code representing the error that occurred, if any + */ + lib::error_code init(bool) { + return lib::error_code(); + } + /// Returns true if the extension is capable of providing /// permessage_deflate functionality bool is_implemented() const { @@ -77,6 +88,17 @@ class disabled { return false; } + /// Generate extension offer + /** + * Creates an offer string to include in the Sec-WebSocket-Extensions + * header of outgoing client requests. + * + * @return A WebSocket extension offer string for this extension + */ + std::string generate_offer() const { + return ""; + } + /// Compress bytes /** * @param [in] in String to compress diff --git a/Release/libs/websocketpp/websocketpp/extensions/permessage_deflate/enabled.hpp b/Release/libs/websocketpp/websocketpp/extensions/permessage_deflate/enabled.hpp index 73b9b30728..1581f14cb4 100644 --- a/Release/libs/websocketpp/websocketpp/extensions/permessage_deflate/enabled.hpp +++ b/Release/libs/websocketpp/websocketpp/extensions/permessage_deflate/enabled.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Peter Thorson. All rights reserved. + * Copyright (c) 2015, 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: @@ -50,9 +50,13 @@ namespace extensions { /** * ### permessage-deflate interface * - * **is_implemented**\n - * `bool is_implemented()`\n - * Returns whether or not the object implements the extension or not + * **init**\n + * `lib::error_code init(bool is_server)`\n + * Performs initialization + * + * **is_implimented**\n + * `bool is_implimented()`\n + * Returns whether or not the object impliments the extension or not * * **is_enabled**\n * `bool is_enabled()`\n @@ -136,7 +140,7 @@ class category : public lib::error_category { case zlib_error: return "A zlib function returned an error"; case uninitialized: - return "Object must be initialized before use"; + return "Deflate extension must be initialized before use"; default: return "Unknown permessage-compress error"; } @@ -144,13 +148,13 @@ class category : public lib::error_category { }; /// Get a reference to a static copy of the permessage-deflate error category -lib::error_category const & get_category() { +inline lib::error_category const & get_category() { static category instance; return instance; } /// Create an error code in the permessage-deflate category -lib::error_code make_error_code(error::value e) { +inline lib::error_code make_error_code(error::value e) { return lib::error_code(static_cast(e), get_category()); } @@ -170,19 +174,19 @@ namespace websocketpp { namespace extensions { namespace permessage_deflate { -/// Default value for s2c_max_window_bits as defined by RFC6455 -static uint8_t const default_s2c_max_window_bits = 15; -/// Minimum value for s2c_max_window_bits as defined by RFC6455 -static uint8_t const min_s2c_max_window_bits = 8; -/// Maximum value for s2c_max_window_bits as defined by RFC6455 -static uint8_t const max_s2c_max_window_bits = 15; +/// Default value for server_max_window_bits as defined by draft 17 +static uint8_t const default_server_max_window_bits = 15; +/// Minimum value for server_max_window_bits as defined by draft 17 +static uint8_t const min_server_max_window_bits = 8; +/// Maximum value for server_max_window_bits as defined by draft 17 +static uint8_t const max_server_max_window_bits = 15; -/// Default value for c2s_max_window_bits as defined by RFC6455 -static uint8_t const default_c2s_max_window_bits = 15; -/// Minimum value for c2s_max_window_bits as defined by RFC6455 -static uint8_t const min_c2s_max_window_bits = 8; -/// Maximum value for c2s_max_window_bits as defined by RFC6455 -static uint8_t const max_c2s_max_window_bits = 15; +/// Default value for client_max_window_bits as defined by draft 17 +static uint8_t const default_client_max_window_bits = 15; +/// Minimum value for client_max_window_bits as defined by draft 17 +static uint8_t const min_client_max_window_bits = 8; +/// Maximum value for client_max_window_bits as defined by draft 17 +static uint8_t const max_client_max_window_bits = 15; namespace mode { enum value { @@ -202,12 +206,12 @@ class enabled { public: enabled() : m_enabled(false) - , m_s2c_no_context_takeover(false) - , m_c2s_no_context_takeover(false) - , m_s2c_max_window_bits(15) - , m_c2s_max_window_bits(15) - , m_s2c_max_window_bits_mode(mode::accept) - , m_c2s_max_window_bits_mode(mode::accept) + , m_server_no_context_takeover(false) + , m_client_no_context_takeover(false) + , m_server_max_window_bits(15) + , m_client_max_window_bits(15) + , m_server_max_window_bits_mode(mode::accept) + , m_client_max_window_bits_mode(mode::accept) , m_initialized(false) , m_compress_buffer_size(16384) { @@ -244,20 +248,25 @@ class enabled { /// Initialize zlib state /** + * Note: this should be called *after* the negotiation methods. It will use + * information from the negotiation to determine how to initialize the zlib + * data structures. * * @todo memory level, strategy, etc are hardcoded - * @todo server detection is hardcoded + * + * @param is_server True to initialize as a server, false for a client. + * @return A code representing the error that occurred, if any */ - lib::error_code init() { + lib::error_code init(bool is_server) { uint8_t deflate_bits; uint8_t inflate_bits; - if (true /*is_server*/) { - deflate_bits = m_s2c_max_window_bits; - inflate_bits = m_c2s_max_window_bits; + if (is_server) { + deflate_bits = m_server_max_window_bits; + inflate_bits = m_client_max_window_bits; } else { - deflate_bits = m_c2s_max_window_bits; - inflate_bits = m_s2c_max_window_bits; + deflate_bits = m_client_max_window_bits; + inflate_bits = m_server_max_window_bits; } int ret = deflateInit2( @@ -265,8 +274,8 @@ class enabled { Z_DEFAULT_COMPRESSION, Z_DEFLATED, -1*deflate_bits, - 8, // memory level 1-9 - /*Z_DEFAULT_STRATEGY*/Z_FIXED + 4, // memory level 1-9 + Z_DEFAULT_STRATEGY ); if (ret != Z_OK) { @@ -283,6 +292,13 @@ class enabled { } m_compress_buffer.reset(new unsigned char[m_compress_buffer_size]); + if ((m_server_no_context_takeover && is_server) || + (m_client_no_context_takeover && !is_server)) + { + m_flush = Z_FULL_FLUSH; + } else { + m_flush = Z_SYNC_FLUSH; + } m_initialized = true; return lib::error_code(); } @@ -329,8 +345,8 @@ class enabled { * the option will be in use so they can optimize resource usage if they * are able. */ - void enable_s2c_no_context_takeover() { - m_s2c_no_context_takeover = true; + void enable_server_no_context_takeover() { + m_server_no_context_takeover = true; } /// Reset client's outgoing LZ77 sliding window for each new message @@ -348,8 +364,8 @@ class enabled { * This option is supported by all compliant clients and servers. Enabling * it via either endpoint should be sufficient to ensure it is used. */ - void enable_c2s_no_context_takeover() { - m_c2s_no_context_takeover = true; + void enable_client_no_context_takeover() { + m_client_no_context_takeover = true; } /// Limit server LZ77 sliding window size @@ -374,12 +390,12 @@ class enabled { * @param mode The mode to use for negotiating this parameter * @return A status code */ - lib::error_code set_s2c_max_window_bits(uint8_t bits, mode::value mode) { - if (bits < min_s2c_max_window_bits || bits > max_s2c_max_window_bits) { + lib::error_code set_server_max_window_bits(uint8_t bits, mode::value mode) { + if (bits < min_server_max_window_bits || bits > max_server_max_window_bits) { return error::make_error_code(error::invalid_max_window_bits); } - m_s2c_max_window_bits = bits; - m_s2c_max_window_bits_mode = mode; + m_server_max_window_bits = bits; + m_server_max_window_bits_mode = mode; return lib::error_code(); } @@ -405,12 +421,12 @@ class enabled { * @param mode The mode to use for negotiating this parameter * @return A status code */ - lib::error_code set_c2s_max_window_bits(uint8_t bits, mode::value mode) { - if (bits < min_c2s_max_window_bits || bits > max_c2s_max_window_bits) { + lib::error_code set_client_max_window_bits(uint8_t bits, mode::value mode) { + if (bits < min_client_max_window_bits || bits > max_client_max_window_bits) { return error::make_error_code(error::invalid_max_window_bits); } - m_c2s_max_window_bits = bits; - m_c2s_max_window_bits_mode = mode; + m_client_max_window_bits = bits; + m_client_max_window_bits_mode = mode; return lib::error_code(); } @@ -423,7 +439,8 @@ class enabled { * @return A WebSocket extension offer string for this extension */ std::string generate_offer() const { - return ""; + // TODO: this should be dynamically generated based on user settings + return "permessage-deflate; client_no_context_takeover; client_max_window_bits"; } /// Validate extension response @@ -435,7 +452,7 @@ class enabled { * @return Validation error or 0 on success */ lib::error_code validate_offer(http::attribute_list const &) { - return make_error_code(error::general); + return lib::error_code(); } /// Negotiate extension @@ -452,14 +469,14 @@ class enabled { http::attribute_list::const_iterator it; for (it = offer.begin(); it != offer.end(); ++it) { - if (it->first == "s2c_no_context_takeover") { - negotiate_s2c_no_context_takeover(it->second,ret.first); - } else if (it->first == "c2s_no_context_takeover") { - negotiate_c2s_no_context_takeover(it->second,ret.first); - } else if (it->first == "s2c_max_window_bits") { - negotiate_s2c_max_window_bits(it->second,ret.first); - } else if (it->first == "c2s_max_window_bits") { - negotiate_c2s_max_window_bits(it->second,ret.first); + if (it->first == "server_no_context_takeover") { + negotiate_server_no_context_takeover(it->second,ret.first); + } else if (it->first == "client_no_context_takeover") { + negotiate_client_no_context_takeover(it->second,ret.first); + } else if (it->first == "server_max_window_bits") { + negotiate_server_max_window_bits(it->second,ret.first); + } else if (it->first == "client_max_window_bits") { + negotiate_client_max_window_bits(it->second,ret.first); } else { ret.first = make_error_code(error::invalid_attributes); } @@ -479,6 +496,9 @@ class enabled { /// Compress bytes /** + * @todo: avail_in/out is 32 bit, need to fix for cases of >32 bit frames + * on 64 bit machines. + * * @param [in] in String to compress * @param [out] out String to append compressed bytes to * @return Error or status code @@ -490,7 +510,13 @@ class enabled { size_t output; - m_dstate.avail_out = m_compress_buffer_size; + if (in.empty()) { + uint8_t buf[6] = {0x02, 0x00, 0x00, 0x00, 0xff, 0xff}; + out.append((char *)(buf),6); + return lib::error_code(); + } + + m_dstate.avail_in = in.size(); m_dstate.next_in = (unsigned char *)(const_cast(in.data())); do { @@ -498,7 +524,7 @@ class enabled { m_dstate.avail_out = m_compress_buffer_size; m_dstate.next_out = m_compress_buffer.get(); - deflate(&m_dstate, Z_SYNC_FLUSH); + deflate(&m_dstate, m_flush); output = m_compress_buffer_size - m_dstate.avail_out; @@ -553,35 +579,35 @@ class enabled { std::string generate_response() { std::string ret = "permessage-deflate"; - if (m_s2c_no_context_takeover) { - ret += "; s2c_no_context_takeover"; + if (m_server_no_context_takeover) { + ret += "; server_no_context_takeover"; } - if (m_c2s_no_context_takeover) { - ret += "; c2s_no_context_takeover"; + if (m_client_no_context_takeover) { + ret += "; client_no_context_takeover"; } - if (m_s2c_max_window_bits < default_s2c_max_window_bits) { + if (m_server_max_window_bits < default_server_max_window_bits) { std::stringstream s; - s << int(m_s2c_max_window_bits); - ret += "; s2c_max_window_bits="+s.str(); + s << int(m_server_max_window_bits); + ret += "; server_max_window_bits="+s.str(); } - if (m_c2s_max_window_bits < default_c2s_max_window_bits) { + if (m_client_max_window_bits < default_client_max_window_bits) { std::stringstream s; - s << int(m_c2s_max_window_bits); - ret += "; c2s_max_window_bits="+s.str(); + s << int(m_client_max_window_bits); + ret += "; client_max_window_bits="+s.str(); } return ret; } - /// Negotiate s2c_no_context_takeover attribute + /// Negotiate server_no_context_takeover attribute /** * @param [in] value The value of the attribute from the offer * @param [out] ec A reference to the error code to return errors via */ - void negotiate_s2c_no_context_takeover(std::string const & value, + void negotiate_server_no_context_takeover(std::string const & value, lib::error_code & ec) { if (!value.empty()) { @@ -589,15 +615,15 @@ class enabled { return; } - m_s2c_no_context_takeover = true; + m_server_no_context_takeover = true; } - /// Negotiate c2s_no_context_takeover attribute + /// Negotiate client_no_context_takeover attribute /** * @param [in] value The value of the attribute from the offer * @param [out] ec A reference to the error code to return errors via */ - void negotiate_c2s_no_context_takeover(std::string const & value, + void negotiate_client_no_context_takeover(std::string const & value, lib::error_code & ec) { if (!value.empty()) { @@ -605,13 +631,13 @@ class enabled { return; } - m_c2s_no_context_takeover = true; + m_client_no_context_takeover = true; } - /// Negotiate s2c_max_window_bits attribute + /// Negotiate server_max_window_bits attribute /** - * When this method starts, m_s2c_max_window_bits will contain the server's - * preferred value and m_s2c_max_window_bits_mode will contain the mode the + * When this method starts, m_server_max_window_bits will contain the server's + * preferred value and m_server_max_window_bits_mode will contain the mode the * server wants to use to for negotiation. `value` contains the value the * client requested that we use. * @@ -624,39 +650,39 @@ class enabled { * @param [in] value The value of the attribute from the offer * @param [out] ec A reference to the error code to return errors via */ - void negotiate_s2c_max_window_bits(std::string const & value, + void negotiate_server_max_window_bits(std::string const & value, lib::error_code & ec) { uint8_t bits = uint8_t(atoi(value.c_str())); - if (bits < min_s2c_max_window_bits || bits > max_s2c_max_window_bits) { + if (bits < min_server_max_window_bits || bits > max_server_max_window_bits) { ec = make_error_code(error::invalid_attribute_value); - m_s2c_max_window_bits = default_s2c_max_window_bits; + m_server_max_window_bits = default_server_max_window_bits; return; } - switch (m_s2c_max_window_bits_mode) { + switch (m_server_max_window_bits_mode) { case mode::decline: - m_s2c_max_window_bits = default_s2c_max_window_bits; + m_server_max_window_bits = default_server_max_window_bits; break; case mode::accept: - m_s2c_max_window_bits = bits; + m_server_max_window_bits = bits; break; case mode::largest: - m_s2c_max_window_bits = (std::min)(bits,m_s2c_max_window_bits); + m_server_max_window_bits = std::min(bits,m_server_max_window_bits); break; case mode::smallest: - m_s2c_max_window_bits = min_s2c_max_window_bits; + m_server_max_window_bits = min_server_max_window_bits; break; default: ec = make_error_code(error::invalid_mode); - m_s2c_max_window_bits = default_s2c_max_window_bits; + m_server_max_window_bits = default_server_max_window_bits; } } - /// Negotiate c2s_max_window_bits attribute + /// Negotiate client_max_window_bits attribute /** - * When this method starts, m_c2s_max_window_bits and m_c2s_max_window_mode + * When this method starts, m_client_max_window_bits and m_c2s_max_window_mode * will contain the server's preferred values for window size and * negotiation mode. * @@ -669,49 +695,50 @@ class enabled { * @param [in] value The value of the attribute from the offer * @param [out] ec A reference to the error code to return errors via */ - void negotiate_c2s_max_window_bits(std::string const & value, + void negotiate_client_max_window_bits(std::string const & value, lib::error_code & ec) { uint8_t bits = uint8_t(atoi(value.c_str())); if (value.empty()) { - bits = default_c2s_max_window_bits; - } else if (bits < min_c2s_max_window_bits || - bits > max_c2s_max_window_bits) + bits = default_client_max_window_bits; + } else if (bits < min_client_max_window_bits || + bits > max_client_max_window_bits) { ec = make_error_code(error::invalid_attribute_value); - m_c2s_max_window_bits = default_c2s_max_window_bits; + m_client_max_window_bits = default_client_max_window_bits; return; } - switch (m_c2s_max_window_bits_mode) { + switch (m_client_max_window_bits_mode) { case mode::decline: - m_c2s_max_window_bits = default_c2s_max_window_bits; + m_client_max_window_bits = default_client_max_window_bits; break; case mode::accept: - m_c2s_max_window_bits = bits; + m_client_max_window_bits = bits; break; case mode::largest: - m_c2s_max_window_bits = std::min(bits,m_c2s_max_window_bits); + m_client_max_window_bits = std::min(bits,m_client_max_window_bits); break; case mode::smallest: - m_c2s_max_window_bits = min_c2s_max_window_bits; + m_client_max_window_bits = min_client_max_window_bits; break; default: ec = make_error_code(error::invalid_mode); - m_c2s_max_window_bits = default_c2s_max_window_bits; + m_client_max_window_bits = default_client_max_window_bits; } } bool m_enabled; - bool m_s2c_no_context_takeover; - bool m_c2s_no_context_takeover; - uint8_t m_s2c_max_window_bits; - uint8_t m_c2s_max_window_bits; - mode::value m_s2c_max_window_bits_mode; - mode::value m_c2s_max_window_bits_mode; + bool m_server_no_context_takeover; + bool m_client_no_context_takeover; + uint8_t m_server_max_window_bits; + uint8_t m_client_max_window_bits; + mode::value m_server_max_window_bits_mode; + mode::value m_client_max_window_bits_mode; bool m_initialized; + int m_flush; size_t m_compress_buffer_size; lib::unique_ptr_uchar_array m_compress_buffer; z_stream m_dstate; diff --git a/Release/libs/websocketpp/websocketpp/frame.hpp b/Release/libs/websocketpp/websocketpp/frame.hpp index 7179089bae..8a173375a2 100644 --- a/Release/libs/websocketpp/websocketpp/frame.hpp +++ b/Release/libs/websocketpp/websocketpp/frame.hpp @@ -30,7 +30,6 @@ #include #include -#include #include #include @@ -55,19 +54,19 @@ static unsigned int const MAX_EXTENDED_HEADER_LENGTH = 12; /// Two byte conversion union union uint16_converter { uint16_t i; - std::array c; + uint8_t c[2]; }; /// Four byte conversion union union uint32_converter { uint32_t i; - std::array c; + uint8_t c[4]; }; /// Eight byte conversion union union uint64_converter { uint64_t i; - std::array c; + uint8_t c[8]; }; /// Constants and utility functions related to WebSocket opcodes @@ -235,17 +234,17 @@ struct basic_header { /// The variable size component of a WebSocket frame header struct extended_header { extended_header() { - std::fill_n(this->bytes.begin(), MAX_EXTENDED_HEADER_LENGTH, 0x00); + std::fill_n(this->bytes,MAX_EXTENDED_HEADER_LENGTH,0x00); } extended_header(uint64_t payload_size) { - std::fill_n(this->bytes.begin(), MAX_EXTENDED_HEADER_LENGTH, 0x00); + std::fill_n(this->bytes,MAX_EXTENDED_HEADER_LENGTH,0x00); copy_payload(payload_size); } extended_header(uint64_t payload_size, uint32_t masking_key) { - std::fill_n(this->bytes.begin(), MAX_EXTENDED_HEADER_LENGTH, 0x00); + std::fill_n(this->bytes,MAX_EXTENDED_HEADER_LENGTH,0x00); // Copy payload size int offset = copy_payload(payload_size); @@ -253,10 +252,10 @@ struct extended_header { // Copy Masking Key uint32_converter temp32; temp32.i = masking_key; - std::copy(temp32.c.begin(), temp32.c.end(), bytes.begin() + offset); + std::copy(temp32.c,temp32.c+4,bytes+offset); } - std::array bytes; + uint8_t bytes[MAX_EXTENDED_HEADER_LENGTH]; private: int copy_payload(uint64_t payload_size) { int payload_offset = 0; @@ -269,7 +268,7 @@ struct extended_header { uint64_converter temp64; temp64.i = lib::net::_htonll(payload_size); - std::copy(temp64.c.begin() + payload_offset, temp64.c.begin() + 8, bytes.begin()); + std::copy(temp64.c+payload_offset,temp64.c+8,bytes); return 8-payload_offset; } @@ -495,7 +494,7 @@ inline std::string prepare_header(const basic_header &h, const ret.push_back(char(h.b0)); ret.push_back(char(h.b1)); ret.append( - reinterpret_cast(&*e.bytes.begin()), + reinterpret_cast(e.bytes), get_header_len(h)-BASIC_HEADER_LENGTH ); @@ -523,8 +522,7 @@ inline masking_key_type get_masking_key(const basic_header &h, const temp32.i = 0; } else { unsigned int offset = get_masking_key_offset(h); - auto ptr = e.bytes.begin() + offset; - std::copy(ptr, ptr + 4, temp32.c.begin()); + std::copy(e.bytes+offset,e.bytes+offset+4,temp32.c); } return temp32; @@ -541,7 +539,7 @@ inline masking_key_type get_masking_key(const basic_header &h, const */ inline uint16_t get_extended_size(const extended_header &e) { uint16_converter temp16; - std::copy(e.bytes.begin() , e.bytes.begin() + 2, temp16.c.begin()); + std::copy(e.bytes,e.bytes+2,temp16.c); return ntohs(temp16.i); } @@ -556,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.begin(), e.bytes.begin() + 8, temp64.c.begin()); + std::copy(e.bytes,e.bytes+8,temp64.c); return lib::net::_ntohll(temp64.i); } diff --git a/Release/libs/websocketpp/websocketpp/impl/connection_impl.hpp b/Release/libs/websocketpp/websocketpp/impl/connection_impl.hpp index 55832d01a1..b191756d70 100644 --- a/Release/libs/websocketpp/websocketpp/impl/connection_impl.hpp +++ b/Release/libs/websocketpp/websocketpp/impl/connection_impl.hpp @@ -85,6 +85,7 @@ lib::error_code connection::send(std::string const & payload, { message_ptr msg = m_msg_manager->get_message(op,payload.size()); msg->append_payload(payload); + msg->set_compressed(true); return send(msg); } @@ -635,7 +636,66 @@ void connection::remove_header(std::string const & key) } } +/// Defer HTTP Response until later +/** + * Used in the http handler to defer the HTTP response for this connection + * until later. Handshake timers will be canceled and the connection will be + * left open until `send_http_response` or an equivalent is called. + * + * Warning: deferred connections won't time out and as a result can tie up + * resources. + * + * @return A status code, zero on success, non-zero otherwise + */ +template +lib::error_code connection::defer_http_response() { + // Cancel handshake timer, otherwise the connection will time out and we'll + // close the connection before the app has a chance to send a response. + if (m_handshake_timer) { + m_handshake_timer->cancel(); + m_handshake_timer.reset(); + } + + // Do something to signal deferral + m_http_state = session::http_state::deferred; + + return lib::error_code(); +} +/// Send deferred HTTP Response (exception free) +/** + * Sends an http response to an HTTP connection that was deferred. This will + * send a complete response including all headers, status line, and body + * text. The connection will be closed afterwards. + * + * @since 0.6.0 + * + * @param ec A status code, zero on success, non-zero otherwise + */ +template +void connection::send_http_response(lib::error_code & ec) { + { + scoped_lock_type lock(m_connection_state_lock); + if (m_http_state != session::http_state::deferred) { + ec = error::make_error_code(error::invalid_state); + return; + } + + m_http_state = session::http_state::body_written; + } + + this->write_http_response(lib::error_code()); + ec = lib::error_code(); +} + +template +void connection::send_http_response() { + lib::error_code ec; + this->send_http_response(ec); + if (ec) { + throw exception(ec); + } +} @@ -728,7 +788,7 @@ void connection::read_handshake(size_t num_bytes) { ); } -// All exit paths for this function need to call send_http_response() or submit +// All exit paths for this function need to call write_http_response() or submit // a new read request with this function as the handler. template void connection::handle_read_handshake(lib::error_code const & ec, @@ -784,7 +844,7 @@ void connection::handle_read_handshake(lib::error_code const & ec, // All HTTP exceptions will result in this request failing and an error // response being returned. No more bytes will be read in this con. m_response.set_status(e.m_error_code,e.m_error_msg); - this->send_http_response_error(error::make_error_code(error::http_parse_error)); + this->write_http_response_error(error::make_error_code(error::http_parse_error)); return; } @@ -806,7 +866,7 @@ void connection::handle_read_handshake(lib::error_code const & ec, if (m_request.ready()) { lib::error_code processor_ec = this->initialize_processor(); if (processor_ec) { - this->send_http_response_error(processor_ec); + this->write_http_response_error(processor_ec); return; } @@ -823,7 +883,7 @@ void connection::handle_read_handshake(lib::error_code const & ec, // TODO: need more bytes m_alog.write(log::alevel::devel,"short key3 read"); m_response.set_status(http::status_code::internal_server_error); - this->send_http_response_error(processor::error::make_error_code(processor::error::short_key3)); + this->write_http_response_error(processor::error::make_error_code(processor::error::short_key3)); return; } } @@ -847,7 +907,9 @@ void connection::handle_read_handshake(lib::error_code const & ec, // We have the complete request. Process it. lib::error_code handshake_ec = this->process_handshake_request(); - this->send_http_response(handshake_ec); + if (!m_is_http || m_http_state != session::http_state::deferred) { + this->write_http_response(handshake_ec); + } } else { // read at least 1 more byte transport_con_type::async_read_at_least( @@ -864,26 +926,26 @@ void connection::handle_read_handshake(lib::error_code const & ec, } } -// send_http_response requires the request to be fully read and the connection +// write_http_response requires the request to be fully read and the connection // to be in the PROCESS_HTTP_REQUEST state. In some cases we can detect errors // before the request is fully read (specifically at a point where we aren't // sure if the hybi00 key3 bytes need to be read). This method sets the correct -// state and calls send_http_response +// state and calls write_http_response template -void connection::send_http_response_error(lib::error_code const & ec) { +void connection::write_http_response_error(lib::error_code const & ec) { if (m_internal_state != istate::READ_HTTP_REQUEST) { m_alog.write(log::alevel::devel, - "send_http_response_error called in invalid state"); + "write_http_response_error called in invalid state"); this->terminate(error::make_error_code(error::invalid_state)); return; } m_internal_state = istate::PROCESS_HTTP_REQUEST; - this->send_http_response(ec); + this->write_http_response(ec); } -// All exit paths for this function need to call send_http_response() or submit +// All exit paths for this function need to call write_http_response() or submit // a new read request with this function as the handler. template void connection::handle_read_frame(lib::error_code const & ec, @@ -965,6 +1027,12 @@ void connection::handle_read_frame(lib::error_code const & ec, lib::error_code consume_ec; + if (m_alog.static_test(log::alevel::devel)) { + std::stringstream s; + s << "Processing Bytes: " << utility::to_hex(reinterpret_cast(m_buf)+p,bytes_transferred-p); + m_alog.write(log::alevel::devel,s.str()); + } + p += m_processor->consume( reinterpret_cast(m_buf)+p, bytes_transferred-p, @@ -1113,6 +1181,7 @@ lib::error_code connection::process_handshake_request() { if (m_http_handler) { m_is_http = true; m_http_handler(m_connection_hdl); + if (m_state == session::state::closed) { return error::make_error_code(error::http_connection_ended); } @@ -1207,8 +1276,8 @@ lib::error_code connection::process_handshake_request() { } template -void connection::send_http_response(lib::error_code const & ec) { - m_alog.write(log::alevel::devel,"connection send_http_response"); +void connection::write_http_response(lib::error_code const & ec) { + m_alog.write(log::alevel::devel,"connection write_http_response"); if (ec == error::make_error_code(error::http_connection_ended)) { m_alog.write(log::alevel::http,"An HTTP handler took over the connection."); @@ -1254,7 +1323,7 @@ void connection::send_http_response(lib::error_code const & ec) { m_handshake_buffer.data(), m_handshake_buffer.size(), lib::bind( - &type::handle_send_http_response, + &type::handle_write_http_response, type::get_shared(), lib::placeholders::_1 ) @@ -1262,8 +1331,8 @@ void connection::send_http_response(lib::error_code const & ec) { } template -void connection::handle_send_http_response(lib::error_code const & ec) { - m_alog.write(log::alevel::devel,"handle_send_http_response"); +void connection::handle_write_http_response(lib::error_code const & ec) { + m_alog.write(log::alevel::devel,"handle_write_http_response"); lib::error_code ecm = ec; @@ -1279,7 +1348,7 @@ void connection::handle_send_http_response(lib::error_code const & ec) { // usually by the handshake timer. This is basically expected // (though hopefully rare) and there is nothing we can do so ignore. m_alog.write(log::alevel::devel, - "handle_send_http_response invoked after connection was closed"); + "handle_write_http_response invoked after connection was closed"); return; } else { ecm = error::make_error_code(error::invalid_state); @@ -1294,7 +1363,7 @@ void connection::handle_send_http_response(lib::error_code const & ec) { return; } - log_err(log::elevel::rerror,"handle_send_http_response",ecm); + log_err(log::elevel::rerror,"handle_write_http_response",ecm); this->terminate(ecm); return; } @@ -1525,6 +1594,25 @@ void connection::handle_read_http_response(lib::error_code const & ec, return; } + // Read extension parameters and set up values necessary for the end + // user to complete extension negotiation. + std::pair neg_results; + neg_results = m_processor->negotiate_extensions(m_response); + + if (neg_results.first) { + // There was a fatal error in extension negotiation. For the moment + // kill all connections that fail extension negotiation. + + // TODO: deal with cases where the response is well formed but + // doesn't match the options requested by the client. Its possible + // that the best behavior in this cases is to log and continue with + // an unextended connection. + m_alog.write(log::alevel::devel, "Extension negotiation failed: " + + neg_results.first.message()); + this->terminate(make_error_code(error::extension_neg_failed)); + // TODO: close connection with reason 1010 (and list extensions) + } + // response is valid, connection can now be assumed to be open m_internal_state = istate::PROCESS_CONNECTION; m_state = session::state::open; @@ -1608,7 +1696,10 @@ void connection::terminate(lib::error_code const & ec) { m_local_close_reason = ec.message(); } - // TODO: does this need a mutex? + // TODO: does any of this need a mutex? + if (m_is_http) { + m_http_state = session::http_state::closed; + } if (m_state == session::state::connecting) { m_state = session::state::closed; tstat = failed; diff --git a/Release/libs/websocketpp/websocketpp/impl/endpoint_impl.hpp b/Release/libs/websocketpp/websocketpp/impl/endpoint_impl.hpp index 5895199a01..e09cda95ec 100644 --- a/Release/libs/websocketpp/websocketpp/impl/endpoint_impl.hpp +++ b/Release/libs/websocketpp/websocketpp/impl/endpoint_impl.hpp @@ -142,7 +142,21 @@ void endpoint::resume_reading(connection_hdl hdl) { if (ec) { throw exception(ec); } } +template +void endpoint::send_http_response(connection_hdl hdl, + lib::error_code & ec) +{ + connection_ptr con = get_con_from_hdl(hdl,ec); + if (ec) {return;} + con->send_http_response(ec); +} +template +void endpoint::send_http_response(connection_hdl hdl) { + lib::error_code ec; + send_http_response(hdl,ec); + if (ec) { throw exception(ec); } +} template void endpoint::send(connection_hdl hdl, std::string const & payload, diff --git a/Release/libs/websocketpp/websocketpp/logger/basic.hpp b/Release/libs/websocketpp/websocketpp/logger/basic.hpp index 95099a8343..84514130e7 100644 --- a/Release/libs/websocketpp/websocketpp/logger/basic.hpp +++ b/Release/libs/websocketpp/websocketpp/logger/basic.hpp @@ -80,6 +80,36 @@ class basic { , m_dynamic_channels(0) , m_out(out) {} + /// Destructor + ~basic() {} + + /// Copy constructor + basic(basic const & other) + : m_static_channels(other.m_static_channels) + , m_dynamic_channels(other.m_dynamic_channels) + , m_out(other.m_out) + {} + +#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ + // no copy assignment operator because of const member variables + basic & operator=(basic const &) = delete; +#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ + +#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_ + /// Move constructor + basic(basic && other) + : m_static_channels(other.m_static_channels) + , m_dynamic_channels(other.m_dynamic_channels) + , m_out(other.m_out) + {} + +#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ + // no move assignment operator because of const member variables + basic & operator=(basic &&) = delete; +#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ + +#endif // _WEBSOCKETPP_MOVE_SEMANTICS_ + void set_ostream(std::ostream * out = &std::cout) { m_out = out; } diff --git a/Release/libs/websocketpp/websocketpp/message_buffer/message.hpp b/Release/libs/websocketpp/websocketpp/message_buffer/message.hpp index b127ee254b..da36e20012 100644 --- a/Release/libs/websocketpp/websocketpp/message_buffer/message.hpp +++ b/Release/libs/websocketpp/websocketpp/message_buffer/message.hpp @@ -146,10 +146,10 @@ class message { /// Set or clear the compression flag /** - * The compression flag is used to indicate whether or not the message is - * or should be compressed. Compression is not guaranteed. Both endpoints - * must support a compression extension and the connection must have had - * that extension negotiated in its handshake. + * Setting the compression flag indicates that the data in this message + * would benefit from compression. If both endpoints negotiate a compression + * extension WebSocket++ will attempt to compress messages with this flag. + * Setting this flag does not guarantee that the message will be compressed. * * @param value The value to set the compressed flag to */ diff --git a/Release/libs/websocketpp/websocketpp/processors/hybi00.hpp b/Release/libs/websocketpp/websocketpp/processors/hybi00.hpp index d693a47442..991813922b 100644 --- a/Release/libs/websocketpp/websocketpp/processors/hybi00.hpp +++ b/Release/libs/websocketpp/websocketpp/processors/hybi00.hpp @@ -98,7 +98,7 @@ class hybi00 : public processor { lib::error_code process_handshake(request_type const & req, std::string const & subprotocol, response_type & res) const { - std::array key_final; + char key_final[16]; // copy key1 into final key decode_client_key(req.get_header("Sec-WebSocket-Key1"), &key_final[0]); @@ -112,13 +112,13 @@ class hybi00 : public processor { // TODO: decide if it is best to silently fail here or produce some sort // of warning or exception. std::string const & key3 = req.get_header("Sec-WebSocket-Key3"); - std::copy(key3.begin(), - key3.begin() + std::min(size_t(8), key3.size()), - key_final.begin() + 8); + std::copy(key3.c_str(), + key3.c_str()+(std::min)(static_cast(8), key3.size()), + &key_final[8]); res.append_header( "Sec-WebSocket-Key3", - md5::md5_hash_string(std::string(key_final.begin(), key_final.end())) + md5::md5_hash_string(std::string(key_final,16)) ); res.append_header("Upgrade","WebSocket"); @@ -415,11 +415,9 @@ class hybi00 : public processor { num = static_cast(strtoul(digits.c_str(), NULL, 10)); if (spaces > 0 && num > 0) { num = htonl(num/spaces); -#ifdef _MS_WINDOWS - memcpy_s(result, 4, reinterpret_cast(&num), 4); -#else - memcpy(result, reinterpret_cast(&num), 4); -#endif + std::copy(reinterpret_cast(&num), + reinterpret_cast(&num)+4, + result); } else { std::fill(result,result+4,0); } diff --git a/Release/libs/websocketpp/websocketpp/processors/hybi13.hpp b/Release/libs/websocketpp/websocketpp/processors/hybi13.hpp index 66e2e75f1a..b46593f651 100644 --- a/Release/libs/websocketpp/websocketpp/processors/hybi13.hpp +++ b/Release/libs/websocketpp/websocketpp/processors/hybi13.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Peter Thorson. All rights reserved. + * Copyright (c) 2015, 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: @@ -85,7 +85,21 @@ class hybi13 : public processor { return m_permessage_deflate.is_implemented(); } - err_str_pair negotiate_extensions(request_type const & req) { + err_str_pair negotiate_extensions(request_type const & request) { + return negotiate_extensions_helper(request); + } + + err_str_pair negotiate_extensions(response_type const & response) { + return negotiate_extensions_helper(response); + } + + /// Extension negotiation helper function + /** + * This exists mostly because the code for requests and responses is + * identical and I can't have virtual template methods. + */ + template + err_str_pair negotiate_extensions_helper(header_type const & header) { err_str_pair ret; // Respect blanket disabling of all extensions and don't even parse @@ -97,7 +111,7 @@ class hybi13 : public processor { http::parameter_list p; - bool error = req.get_header_as_plist("Sec-WebSocket-Extensions",p); + bool error = header.get_header_as_plist("Sec-WebSocket-Extensions",p); if (error) { ret.first = make_error_code(error::extension_parse_error); @@ -116,6 +130,14 @@ class hybi13 : public processor { for (it = p.begin(); it != p.end(); ++it) { // look through each extension, if the key is permessage-deflate if (it->first == "permessage-deflate") { + // if we have already successfully negotiated this extension + // then skip any other requests to negotiate the same one + // with different parameters + if (m_permessage_deflate.is_enabled()) { + continue; + } + + neg_ret = m_permessage_deflate.negotiate(it->second); if (neg_ret.first) { @@ -128,6 +150,7 @@ class hybi13 : public processor { // Note: this list will need commas if WebSocket++ ever // supports more than one extension ret.second += neg_ret.second; + m_permessage_deflate.init(base::m_server); continue; } } @@ -214,14 +237,21 @@ class hybi13 : public processor { // Generate handshake key frame::uint32_converter conv; - std::array raw_key; + unsigned char raw_key[16]; for (int i = 0; i < 4; i++) { conv.i = m_rng(); - std::copy(conv.c.begin(), conv.c.begin() + 4, raw_key.begin() + i * 4); + std::copy(conv.c,conv.c+4,&raw_key[i*4]); } - req.replace_header("Sec-WebSocket-Key",base64_encode(&raw_key[0], 16)); + req.replace_header("Sec-WebSocket-Key",base64_encode(raw_key, 16)); + + if (m_permessage_deflate.is_implemented()) { + std::string offer = m_permessage_deflate.generate_offer(); + if (!offer.empty()) { + req.replace_header("Sec-WebSocket-Extensions",offer); + } + } return lib::error_code(); } @@ -264,6 +294,8 @@ class hybi13 : public processor { return error::make_error_code(error::missing_required_header); } + // check extensions + return lib::error_code(); } @@ -391,6 +423,10 @@ class hybi13 : public processor { m_msg_manager->get_message(op,m_bytes_needed), frame::get_masking_key(m_basic_header,m_extended_header) ); + + if (m_permessage_deflate.is_enabled()) { + m_data_msg.msg_ptr->set_compressed(frame::get_rsv1(m_basic_header)); + } } else { // Fetch the underlying payload buffer from the data message we // are writing into. @@ -432,15 +468,10 @@ class hybi13 : public processor { // If this was the last frame in the message set the ready flag. // Otherwise, reset processor state to read additional frames. if (frame::get_fin(m_basic_header)) { - // ensure that text messages end on a valid UTF8 code point - if (frame::get_opcode(m_basic_header) == frame::opcode::TEXT) { - if (!m_current_msg->validator.complete()) { - ec = make_error_code(error::invalid_utf8); - break; - } + ec = finalize_message(); + if (ec) { + break; } - - m_state = READY; } else { this->reset_headers(); } @@ -454,6 +485,44 @@ class hybi13 : public processor { return p; } + /// Perform any finalization actions on an incoming message + /** + * Called after the full message is received. Provides the opportunity for + * extensions to complete any data post processing as well as final UTF8 + * validation checks for text messages. + * + * @return A code indicating errors, if any + */ + lib::error_code finalize_message() { + std::string & out = m_current_msg->msg_ptr->get_raw_payload(); + + // if the frame is compressed, append the compression + // trailer and flush the compression buffer. + if (m_permessage_deflate.is_enabled() + && m_current_msg->msg_ptr->get_compressed()) + { + uint8_t trailer[4] = {0x00, 0x00, 0xff, 0xff}; + + // Decompress current buffer into the message buffer + lib::error_code ec; + ec = m_permessage_deflate.decompress(trailer,4,out); + if (ec) { + return ec; + } + } + + // ensure that text messages end on a valid UTF8 code point + if (frame::get_opcode(m_basic_header) == frame::opcode::TEXT) { + if (!m_current_msg->validator.complete()) { + return make_error_code(error::invalid_utf8); + } + } + + m_state = READY; + + return lib::error_code(); + } + void reset_headers() { m_state = HEADER_BASIC; m_bytes_needed = frame::BASIC_HEADER_LENGTH; @@ -461,9 +530,9 @@ class hybi13 : public processor { m_basic_header.b0 = 0x00; m_basic_header.b1 = 0x00; - std::fill( - m_extended_header.bytes.begin(), - m_extended_header.bytes.end(), + std::fill_n( + m_extended_header.bytes, + frame::MAX_EXTENDED_HEADER_LENGTH, 0x00 ); } @@ -551,18 +620,11 @@ class hybi13 : public processor { && in->get_compressed(); bool fin = in->get_fin(); - // generate header - frame::basic_header h(op,i.size(),fin,masked,compressed); - if (masked) { // Generate masking key. key.i = m_rng(); - - frame::extended_header e(i.size(),key.i); - out->set_header(frame::prepare_header(h,e)); } else { - frame::extended_header e(i.size()); - out->set_header(frame::prepare_header(h,e)); + key.i = 0; } // prepare payload @@ -570,6 +632,14 @@ class hybi13 : public processor { // compress and store in o after header. m_permessage_deflate.compress(i,o); + if (o.size() < 4) { + return make_error_code(error::general); + } + + // Strip trailing 4 0x00 0x00 0xff 0xff bytes before writing to the + // wire + o.resize(o.size()-4); + // mask in place if necessary if (masked) { this->masked_copy(o,o,key); @@ -588,6 +658,17 @@ class hybi13 : public processor { } } + // generate header + frame::basic_header h(op,o.size(),fin,masked,compressed); + + if (masked) { + frame::extended_header e(o.size(),key.i); + out->set_header(frame::prepare_header(h,e)); + } else { + frame::extended_header e(o.size()); + out->set_header(frame::prepare_header(h,e)); + } + out->set_prepared(true); out->set_opcode(op); @@ -686,7 +767,7 @@ class hybi13 : public processor { size_t copy_extended_header_bytes(uint8_t const * buf, size_t len) { size_t bytes_to_read = (std::min)(m_bytes_needed,len); - std::copy(buf, buf + bytes_to_read, m_extended_header.bytes.begin() + m_cursor); + std::copy(buf,buf+bytes_to_read,m_extended_header.bytes+m_cursor); m_cursor += bytes_to_read; m_bytes_needed -= bytes_to_read; @@ -730,13 +811,13 @@ class hybi13 : public processor { // decompress message if needed. if (m_permessage_deflate.is_enabled() - && frame::get_rsv1(m_basic_header)) + && m_current_msg->msg_ptr->get_compressed()) { // Decompress current buffer into the message buffer - m_permessage_deflate.decompress(buf,len,out); - - // get the length of the newly uncompressed output - offset = out.size() - offset; + ec = m_permessage_deflate.decompress(buf,len,out); + if (ec) { + return 0; + } } else { // No compression, straight copy out.append(reinterpret_cast(buf),len); @@ -937,7 +1018,8 @@ class hybi13 : public processor { out->set_header(frame::prepare_header(h,e)); std::copy(payload.begin(),payload.end(),o.begin()); } - + + out->set_opcode(op); out->set_prepared(true); return lib::error_code(); diff --git a/Release/libs/websocketpp/websocketpp/processors/processor.hpp b/Release/libs/websocketpp/websocketpp/processors/processor.hpp index 99b64cae8a..ff3cbb2e78 100644 --- a/Release/libs/websocketpp/websocketpp/processors/processor.hpp +++ b/Release/libs/websocketpp/websocketpp/processors/processor.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Peter Thorson. All rights reserved. + * Copyright (c) 2015, 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: @@ -217,13 +217,28 @@ class processor { /** * 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. + * settings data is initialized and an extension string to send to the + * is returned. * - * @param request The request headers to look at. + * @param request The request or response headers to look at. */ virtual err_str_pair negotiate_extensions(request_type const &) { return err_str_pair(); } + + /// Initializes extensions based on the Sec-WebSocket-Extensions header + /** + * Reads the Sec-WebSocket-Extensions header and determines if any of the + * requested extensions were accepted by the server. If they are their + * settings data is initialized. If they are not a list of required + * extensions (if any) is returned. This list may be sent back to the server + * as a part of the 1010/Extension required close code. + * + * @param response The request or response headers to look at. + */ + virtual err_str_pair negotiate_extensions(response_type const &) { + return err_str_pair(); + } /// validate a WebSocket handshake request for this version /** diff --git a/Release/libs/websocketpp/websocketpp/roles/client_endpoint.hpp b/Release/libs/websocketpp/websocketpp/roles/client_endpoint.hpp index d5a9f00384..b793873ac2 100644 --- a/Release/libs/websocketpp/websocketpp/roles/client_endpoint.hpp +++ b/Release/libs/websocketpp/websocketpp/roles/client_endpoint.hpp @@ -29,6 +29,7 @@ #define WEBSOCKETPP_CLIENT_ENDPOINT_HPP #include +#include #include diff --git a/Release/libs/websocketpp/websocketpp/roles/server_endpoint.hpp b/Release/libs/websocketpp/websocketpp/roles/server_endpoint.hpp index 45a4bef9e0..dadcf72f77 100644 --- a/Release/libs/websocketpp/websocketpp/roles/server_endpoint.hpp +++ b/Release/libs/websocketpp/websocketpp/roles/server_endpoint.hpp @@ -69,6 +69,28 @@ class server : public endpoint,config> { endpoint_type::m_alog.write(log::alevel::devel, "server constructor"); } + /// Destructor + ~server() {} + +#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ + // no copy constructor because endpoints are not copyable + server(server &) = delete; + + // no copy assignment operator because endpoints are not copyable + server & operator=(server const &) = delete; +#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ + +#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_ + /// Move constructor + server(server && o) : endpoint,config>(std::move(o)) {} + +#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ + // no move assignment operator because of const member variables + server & operator=(server &&) = delete; +#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ + +#endif // _WEBSOCKETPP_MOVE_SEMANTICS_ + /// Create and initialize a new connection /** * The connection will be initialized and ready to begin. Call its start() diff --git a/Release/libs/websocketpp/websocketpp/transport/asio/base.hpp b/Release/libs/websocketpp/websocketpp/transport/asio/base.hpp index 8ede3aaabd..6ee881ab85 100644 --- a/Release/libs/websocketpp/websocketpp/transport/asio/base.hpp +++ b/Release/libs/websocketpp/websocketpp/transport/asio/base.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Peter Thorson. All rights reserved. + * Copyright (c) 2015, 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,123 +28,107 @@ #ifndef WEBSOCKETPP_TRANSPORT_ASIO_BASE_HPP #define WEBSOCKETPP_TRANSPORT_ASIO_BASE_HPP +#include #include #include #include - -#include - -#include -#include -#include +#include #include namespace websocketpp { namespace transport { -/// Transport policy that uses boost::asio +/// Transport policy that uses asio /** - * This policy uses a single boost::asio io_service to provide transport + * This policy uses a single asio io_service to provide transport * services to a WebSocket++ endpoint. */ namespace asio { -// - // Class to manage the memory to be used for handler-based custom allocation. // It contains a single block of memory which may be returned for allocation // requests. If the memory is in use when an allocation request is made, the // allocator delegates allocation to the global heap. -class handler_allocator - : private boost::noncopyable -{ +class handler_allocator { public: - handler_allocator() - : in_use_(false) - { - } - - void* allocate(std::size_t size) - { - if (!in_use_ && size < storage_.size) - { - in_use_ = true; - return storage_.address(); - } - else - { - return ::operator new(size); + static const size_t size = 1024; + + handler_allocator() : m_in_use(false) {} + +#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ + handler_allocator(handler_allocator const & cpy) = delete; + handler_allocator & operator =(handler_allocator const &) = delete; +#endif + + void * allocate(std::size_t memsize) { + if (!m_in_use && memsize < size) { + m_in_use = true; + return static_cast(&m_storage); + } else { + return ::operator new(memsize); + } } - } - void deallocate(void* pointer) - { - if (pointer == storage_.address()) - { - in_use_ = false; - } - else - { - ::operator delete(pointer); + void deallocate(void * pointer) { + if (pointer == &m_storage) { + m_in_use = false; + } else { + ::operator delete(pointer); + } } - } private: - // Storage space used for handler-based custom memory allocation. - boost::aligned_storage<1024> storage_; + // Storage space used for handler-based custom memory allocation. + lib::aligned_storage::type m_storage; - // Whether the handler-based custom allocation storage has been used. - bool in_use_; + // Whether the handler-based custom allocation storage has been used. + bool m_in_use; }; // Wrapper class template for handler objects to allow handler memory // allocation to be customised. Calls to operator() are forwarded to the // encapsulated handler. template -class custom_alloc_handler -{ +class custom_alloc_handler { public: - custom_alloc_handler(handler_allocator& a, Handler h) - : allocator_(a), - handler_(h) - { - } - - template - void operator()(Arg1 arg1) - { - handler_(arg1); - } - - template - void operator()(Arg1 arg1, Arg2 arg2) - { - handler_(arg1, arg2); - } - - friend void* asio_handler_allocate(std::size_t size, - custom_alloc_handler* this_handler) - { - return this_handler->allocator_.allocate(size); - } - - friend void asio_handler_deallocate(void* pointer, std::size_t /*size*/, - custom_alloc_handler* this_handler) - { - this_handler->allocator_.deallocate(pointer); - } + custom_alloc_handler(handler_allocator& a, Handler h) + : allocator_(a), + handler_(h) + {} + + template + void operator()(Arg1 arg1) { + handler_(arg1); + } + + template + void operator()(Arg1 arg1, Arg2 arg2) { + handler_(arg1, arg2); + } + + friend void* asio_handler_allocate(std::size_t size, + custom_alloc_handler * this_handler) + { + return this_handler->allocator_.allocate(size); + } + + friend void asio_handler_deallocate(void* pointer, std::size_t /*size*/, + custom_alloc_handler * this_handler) + { + this_handler->allocator_.deallocate(pointer); + } private: - handler_allocator& allocator_; - Handler handler_; + handler_allocator & allocator_; + Handler handler_; }; // Helper function to wrap a handler object to add custom allocation. template inline custom_alloc_handler make_custom_alloc_handler( - handler_allocator& a, Handler h) + handler_allocator & a, Handler h) { - return custom_alloc_handler(a, h); + return custom_alloc_handler(a, h); } @@ -158,13 +142,13 @@ inline custom_alloc_handler make_custom_alloc_handler( template class endpoint; -typedef lib::function +typedef lib::function socket_shutdown_handler; -typedef lib::function async_read_handler; -typedef lib::function async_write_handler; typedef lib::function pre_init_handler; diff --git a/Release/libs/websocketpp/websocketpp/transport/asio/connection.hpp b/Release/libs/websocketpp/websocketpp/transport/asio/connection.hpp index 0be40f6b45..635a0f3a15 100644 --- a/Release/libs/websocketpp/websocketpp/transport/asio/connection.hpp +++ b/Release/libs/websocketpp/websocketpp/transport/asio/connection.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Peter Thorson. All rights reserved. + * Copyright (c) 2015, 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,15 +37,15 @@ #include #include +#include +#include +#include #include #include #include #include -#include -#include - #include #include #include @@ -57,10 +57,10 @@ namespace asio { typedef lib::function tcp_init_handler; -/// Boost Asio based connection transport component +/// Asio based connection transport component /** * transport::asio::connection implements a connection transport component using - * Boost ASIO that works with the transport::asio::endpoint endpoint transport + * Asio that works with the transport::asio::endpoint endpoint transport * component. */ template @@ -85,12 +85,12 @@ class connection : public config::socket_type::socket_con_type { typedef typename config::response_type response_type; typedef typename response_type::ptr response_ptr; - /// Type of a pointer to the ASIO io_service being used - 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 a pointer to the ASIO timer class - typedef lib::shared_ptr timer_ptr; + /// Type of a pointer to the Asio io_service being used + typedef lib::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 a pointer to the Asio timer class + typedef lib::shared_ptr timer_ptr; // connection is friends with its associated endpoint to allow the endpoint // to call private/protected utility methods that we don't want to expose @@ -98,7 +98,7 @@ class connection : public config::socket_type::socket_con_type { friend class endpoint; // generate and manage our own io_service - explicit connection(bool is_server, alog_type& alog, elog_type& elog) + explicit connection(bool is_server, alog_type & alog, elog_type & elog) : m_is_server(is_server) , m_alog(alog) , m_elog(elog) @@ -115,6 +115,22 @@ class connection : public config::socket_type::socket_con_type { return socket_con_type::is_secure(); } + /// Set uri hook + /** + * Called by the endpoint as a connection is being established to provide + * the uri being connected to to the transport layer. + * + * This transport policy doesn't use the uri except to forward it to the + * socket layer. + * + * @since 0.6.0 + * + * @param u The uri to set + */ + void set_uri(uri_ptr u) { + socket_con_type::set_uri(u); + } + /// Sets the tcp pre init handler /** * The tcp pre init handler is called after the raw tcp connection has been @@ -295,9 +311,9 @@ class connection : public config::socket_type::socket_con_type { * needed. */ timer_ptr set_timer(long duration, timer_handler callback) { - timer_ptr new_timer = lib::make_shared( + timer_ptr new_timer = lib::make_shared( lib::ref(*m_io_service), - boost::posix_time::milliseconds(duration) + lib::asio::milliseconds(duration) ); if (config::enable_multithreading) { @@ -331,10 +347,10 @@ class connection : public config::socket_type::socket_con_type { * @param ec The status code */ void handle_timer(timer_ptr, timer_handler callback, - boost::system::error_code const & ec) + lib::asio::error_code const & ec) { if (ec) { - if (ec == boost::asio::error::operation_aborted) { + if (ec == lib::asio::error::operation_aborted) { callback(make_error_code(transport::error::operation_aborted)); } else { log_err(log::elevel::info,"asio handle_timer",ec); @@ -344,7 +360,7 @@ class connection : public config::socket_type::socket_con_type { callback(lib::error_code()); } } -protected: + /// Get a pointer to this connection's strand strand_ptr get_strand() { return m_strand; @@ -353,7 +369,7 @@ class connection : public config::socket_type::socket_con_type { /// Initialize transport for reading /** * init_asio is called once immediately after construction to initialize - * boost::asio components to the io_service + * Asio components to the io_service * * The transport initialization sequence consists of the following steps: * - Pre-init: the underlying socket is initialized to the point where @@ -367,6 +383,7 @@ class connection : public config::socket_type::socket_con_type { * read or write the WebSocket handshakes. At this point the original * callback function is called. */ +protected: void init(init_handler callback) { if (m_alog.static_test(log::alevel::devel)) { m_alog.write(log::alevel::devel,"asio connection init"); @@ -411,7 +428,7 @@ class connection : public config::socket_type::socket_con_type { /// Finish constructing the transport /** * init_asio is called once immediately after construction to initialize - * boost::asio components to the io_service. + * Asio components to the io_service. * * @param io_service A pointer to the io_service to register with this * connection @@ -422,7 +439,7 @@ class connection : public config::socket_type::socket_con_type { m_io_service = io_service; if (config::enable_multithreading) { - m_strand = lib::make_shared( + m_strand = lib::make_shared( lib::ref(*io_service)); m_async_read_handler = m_strand->wrap(lib::bind( @@ -555,7 +572,7 @@ class connection : public config::socket_type::socket_con_type { lib::error_code const & ec) { if (ec == transport::error::operation_aborted || - (post_timer && post_timer->expires_from_now().is_negative())) + (post_timer && lib::asio::is_neg(post_timer->expires_from_now()))) { m_alog.write(log::alevel::devel,"post_init cancelled"); return; @@ -590,8 +607,8 @@ class connection : public config::socket_type::socket_con_type { m_proxy_data->write_buf = m_proxy_data->req.raw(); - m_bufs.push_back(boost::asio::buffer(m_proxy_data->write_buf.data(), - m_proxy_data->write_buf.size())); + m_bufs.push_back(lib::asio::buffer(m_proxy_data->write_buf.data(), + m_proxy_data->write_buf.size())); m_alog.write(log::alevel::devel,m_proxy_data->write_buf); @@ -608,7 +625,7 @@ class connection : public config::socket_type::socket_con_type { // Send proxy request if (config::enable_multithreading) { - boost::asio::async_write( + lib::asio::async_write( socket_con_type::get_next_layer(), m_bufs, m_strand->wrap(lib::bind( @@ -618,7 +635,7 @@ class connection : public config::socket_type::socket_con_type { )) ); } else { - boost::asio::async_write( + lib::asio::async_write( socket_con_type::get_next_layer(), m_bufs, lib::bind( @@ -648,7 +665,7 @@ class connection : public config::socket_type::socket_con_type { } void handle_proxy_write(init_handler callback, - boost::system::error_code const & ec) + lib::asio::error_code const & ec) { if (m_alog.static_test(log::alevel::devel)) { m_alog.write(log::alevel::devel, @@ -660,8 +677,8 @@ class connection : public config::socket_type::socket_con_type { // Timer expired or the operation was aborted for some reason. // Whatever aborted it will be issuing the callback so we are safe to // return - if (ec == boost::asio::error::operation_aborted || - m_proxy_data->timer->expires_from_now().is_negative()) + if (ec == lib::asio::error::operation_aborted || + lib::asio::is_neg(m_proxy_data->timer->expires_from_now())) { m_elog.write(log::elevel::devel,"write operation aborted"); return; @@ -691,7 +708,7 @@ class connection : public config::socket_type::socket_con_type { } if (config::enable_multithreading) { - boost::asio::async_read_until( + lib::asio::async_read_until( socket_con_type::get_next_layer(), m_proxy_data->read_buf, "\r\n\r\n", @@ -702,7 +719,7 @@ class connection : public config::socket_type::socket_con_type { )) ); } else { - boost::asio::async_read_until( + lib::asio::async_read_until( socket_con_type::get_next_layer(), m_proxy_data->read_buf, "\r\n\r\n", @@ -722,7 +739,7 @@ class connection : public config::socket_type::socket_con_type { * @param bytes_transferred The number of bytes read */ void handle_proxy_read(init_handler callback, - boost::system::error_code const & ec, size_t) + lib::asio::error_code const & ec, size_t) { if (m_alog.static_test(log::alevel::devel)) { m_alog.write(log::alevel::devel, @@ -732,8 +749,8 @@ class connection : public config::socket_type::socket_con_type { // Timer expired or the operation was aborted for some reason. // Whatever aborted it will be issuing the callback so we are safe to // return - if (ec == boost::asio::error::operation_aborted || - m_proxy_data->timer->expires_from_now().is_negative()) + if (ec == lib::asio::error::operation_aborted || + lib::asio::is_neg(m_proxy_data->timer->expires_from_now())) { m_elog.write(log::elevel::devel,"read operation aborted"); return; @@ -836,10 +853,10 @@ class connection : public config::socket_type::socket_con_type { "asio con async_read_at_least called with bad handler"); } - boost::asio::async_read( + lib::asio::async_read( socket_con_type::get_socket(), - boost::asio::buffer(buf,len), - boost::asio::transfer_at_least(num_bytes), + lib::asio::buffer(buf,len), + lib::asio::transfer_at_least(num_bytes), make_custom_alloc_handler( m_read_handler_allocator, m_async_read_handler @@ -847,14 +864,14 @@ class connection : public config::socket_type::socket_con_type { ); } - void handle_async_read(boost::system::error_code const & ec, + void handle_async_read(lib::asio::error_code const & ec, size_t bytes_transferred) { m_alog.write(log::alevel::devel, "asio con handle_async_read"); - // translate boost error codes into more lib::error_codes + // translate asio error codes into more lib::error_codes lib::error_code tec; - if (ec == boost::asio::error::eof) { + if (ec == lib::asio::error::eof) { tec = make_error_code(transport::error::eof); } else if (ec) { // We don't know much more about the error at this point. As our @@ -890,11 +907,11 @@ class connection : public config::socket_type::socket_con_type { return; } - m_bufs.push_back(boost::asio::buffer(buf,len)); + m_bufs.push_back(lib::asio::buffer(buf,len)); m_write_handler = handler; - boost::asio::async_write( + lib::asio::async_write( socket_con_type::get_socket(), m_bufs, make_custom_alloc_handler( @@ -914,12 +931,12 @@ class connection : public config::socket_type::socket_con_type { std::vector::const_iterator it; for (it = bufs.begin(); it != bufs.end(); ++it) { - m_bufs.push_back(boost::asio::buffer((*it).buf,(*it).len)); + m_bufs.push_back(lib::asio::buffer((*it).buf,(*it).len)); } m_write_handler = handler; - boost::asio::async_write( + lib::asio::async_write( socket_con_type::get_socket(), m_bufs, make_custom_alloc_handler( @@ -934,7 +951,7 @@ class connection : public config::socket_type::socket_con_type { * @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) { + void handle_async_write(lib::asio::error_code const & ec, size_t) { m_bufs.clear(); lib::error_code tec; if (ec) { @@ -1061,10 +1078,10 @@ class connection : public config::socket_type::socket_con_type { } void handle_async_shutdown(timer_ptr shutdown_timer, shutdown_handler - callback, boost::system::error_code const & ec) + callback, lib::asio::error_code const & ec) { - if (ec == boost::asio::error::operation_aborted || - shutdown_timer->expires_from_now().is_negative()) + if (ec == lib::asio::error::operation_aborted || + lib::asio::is_neg(shutdown_timer->expires_from_now())) { m_alog.write(log::alevel::devel,"async_shutdown cancelled"); return; @@ -1074,7 +1091,7 @@ class connection : public config::socket_type::socket_con_type { lib::error_code tec; if (ec) { - if (ec == boost::asio::error::not_connected) { + if (ec == lib::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 @@ -1124,7 +1141,7 @@ class connection : public config::socket_type::socket_con_type { request_type req; response_type res; std::string write_buf; - boost::asio::streambuf read_buf; + lib::asio::streambuf read_buf; long timeout_proxy; timer_ptr timer; }; @@ -1137,7 +1154,7 @@ class connection : public config::socket_type::socket_con_type { strand_ptr m_strand; connection_hdl m_connection_hdl; - std::vector m_bufs; + std::vector m_bufs; // Handlers tcp_init_handler m_tcp_pre_init_handler; diff --git a/Release/libs/websocketpp/websocketpp/transport/asio/endpoint.hpp b/Release/libs/websocketpp/websocketpp/transport/asio/endpoint.hpp index ef3b07db46..4e278d41c1 100644 --- a/Release/libs/websocketpp/websocketpp/transport/asio/endpoint.hpp +++ b/Release/libs/websocketpp/websocketpp/transport/asio/endpoint.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Peter Thorson. All rights reserved. + * Copyright (c) 2015, 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,10 +37,6 @@ #include -#include -#include -#include - #include #include @@ -48,10 +44,10 @@ namespace websocketpp { namespace transport { namespace asio { -/// Boost Asio based endpoint transport component +/// Asio based endpoint transport component /** * transport::asio::endpoint implements an endpoint transport component using - * Boost ASIO. + * Asio. */ template class endpoint : public config::socket_type { @@ -81,15 +77,15 @@ class endpoint : public config::socket_type { typedef typename transport_con_type::ptr transport_con_ptr; /// Type of a pointer to the ASIO io_service being used - typedef boost::asio::io_service* io_service_ptr; + typedef lib::asio::io_service * io_service_ptr; /// Type of a shared pointer to the acceptor being used - typedef lib::shared_ptr acceptor_ptr; + typedef lib::shared_ptr acceptor_ptr; /// Type of a shared pointer to the resolver being used - typedef lib::shared_ptr resolver_ptr; + typedef lib::shared_ptr resolver_ptr; /// Type of timer handle - typedef lib::shared_ptr timer_ptr; + typedef lib::shared_ptr timer_ptr; /// Type of a shared pointer to an io_service work object - typedef lib::shared_ptr work_ptr; + typedef lib::shared_ptr work_ptr; // generate and manage our own io_service explicit endpoint() @@ -113,23 +109,28 @@ class endpoint : public config::socket_type { /// transport::asio objects are moveable but not copyable or assignable. /// The following code sets this situation up based on whether or not we /// have C++11 support or not -#ifdef _WEBSOCKETPP_DELETED_FUNCTIONS_ - endpoint(const endpoint& src) = delete; +#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ + endpoint(const endpoint & src) = delete; endpoint& operator= (const endpoint & rhs) = delete; #else private: - endpoint(const endpoint& src); - endpoint& operator= (const endpoint & rhs); + endpoint(const endpoint & src); + endpoint & operator= (const endpoint & rhs); public: -#endif - -#ifdef _WEBSOCKETPP_RVALUE_REFERENCES_ - endpoint (endpoint&& src) - : m_io_service(src.m_io_service) +#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_ + +#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_ + endpoint (endpoint && src) + : config::socket_type(std::move(src)) + , m_tcp_pre_init_handler(src.m_tcp_pre_init_handler) + , m_tcp_post_init_handler(src.m_tcp_post_init_handler) + , m_io_service(src.m_io_service) , m_external_io_service(src.m_external_io_service) , m_acceptor(src.m_acceptor) - , m_listen_backlog(boost::asio::socket_base::max_connections) + , m_listen_backlog(lib::asio::socket_base::max_connections) , m_reuse_addr(src.m_reuse_addr) + , m_elog(src.m_elog) + , m_alog(src.m_alog) , m_state(src.m_state) { src.m_io_service = NULL; @@ -138,7 +139,7 @@ class endpoint : public config::socket_type { src.m_state = UNINITIALIZED; } - endpoint& operator= (const endpoint && rhs) { + /*endpoint & operator= (const endpoint && rhs) { if (this != &rhs) { m_io_service = rhs.m_io_service; m_external_io_service = rhs.m_external_io_service; @@ -150,12 +151,15 @@ class endpoint : public config::socket_type { rhs.m_io_service = NULL; rhs.m_external_io_service = false; rhs.m_acceptor = NULL; - rhs.m_listen_backlog = boost::asio::socket_base::max_connections; + rhs.m_listen_backlog = lib::asio::socket_base::max_connections; rhs.m_state = UNINITIALIZED; + + // TODO: this needs to be updated } return *this; - } -#endif + }*/ +#endif // _WEBSOCKETPP_MOVE_SEMANTICS_ + /// Return whether or not the endpoint produces secure connections. bool is_secure() const { return socket_type::is_secure(); @@ -183,7 +187,7 @@ class endpoint : public config::socket_type { m_io_service = ptr; m_external_io_service = true; - m_acceptor = lib::make_shared( + m_acceptor = lib::make_shared( lib::ref(*m_io_service)); m_state = READY; @@ -214,7 +218,7 @@ class endpoint : public config::socket_type { * @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 lib::asio::io_service(), ec); m_external_io_service = false; } @@ -226,7 +230,7 @@ class endpoint : public config::socket_type { * @see init_asio(io_service_ptr ptr) */ void init_asio() { - init_asio(new boost::asio::io_service()); + init_asio(new lib::asio::io_service()); m_external_io_service = false; } @@ -325,7 +329,7 @@ class endpoint : public config::socket_type { * * @return A reference to the endpoint's io_service */ - boost::asio::io_service & get_io_service() { + lib::asio::io_service & get_io_service() { return *m_io_service; } @@ -337,7 +341,7 @@ class endpoint : public config::socket_type { * @param ep An endpoint to read settings from * @param ec Set to indicate what error occurred, if any. */ - void listen(boost::asio::ip::tcp::endpoint const & ep, lib::error_code & ec) + void listen(lib::asio::ip::tcp::endpoint const & ep, lib::error_code & ec) { if (m_state != READY) { m_elog->write(log::elevel::library, @@ -349,11 +353,11 @@ class endpoint : public config::socket_type { m_alog->write(log::alevel::devel,"asio::listen"); - boost::system::error_code bec; + lib::asio::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); + m_acceptor->set_option(lib::asio::socket_base::reuse_address(m_reuse_addr),bec); } if (!bec) { m_acceptor->bind(ep,bec); @@ -379,7 +383,7 @@ class endpoint : public config::socket_type { * * @param ep An endpoint to read settings from */ - void listen(boost::asio::ip::tcp::endpoint const & ep) { + void listen(lib::asio::ip::tcp::endpoint const & ep) { lib::error_code ec; listen(ep,ec); if (ec) { throw exception(ec); } @@ -392,8 +396,8 @@ class endpoint : public config::socket_type { * listening. * * Common options include: - * - IPv6 with mapped IPv4 for dual stack hosts boost::asio::ip::tcp::v6() - * - IPv4 only: boost::asio::ip::tcp::v4() + * - IPv6 with mapped IPv4 for dual stack hosts lib::asio::ip::tcp::v6() + * - IPv4 only: lib::asio::ip::tcp::v4() * * @param internet_protocol The internet protocol to use. * @param port The port to listen on. @@ -403,7 +407,7 @@ class endpoint : public config::socket_type { void listen(InternetProtocol const & internet_protocol, uint16_t port, lib::error_code & ec) { - boost::asio::ip::tcp::endpoint ep(internet_protocol, port); + lib::asio::ip::tcp::endpoint ep(internet_protocol, port); listen(ep,ec); } @@ -414,8 +418,8 @@ class endpoint : public config::socket_type { * listening. * * Common options include: - * - IPv6 with mapped IPv4 for dual stack hosts boost::asio::ip::tcp::v6() - * - IPv4 only: boost::asio::ip::tcp::v4() + * - IPv6 with mapped IPv4 for dual stack hosts lib::asio::ip::tcp::v6() + * - IPv4 only: lib::asio::ip::tcp::v4() * * @param internet_protocol The internet protocol to use. * @param port The port to listen on. @@ -423,7 +427,7 @@ class endpoint : public config::socket_type { template void listen(InternetProtocol const & internet_protocol, uint16_t port) { - boost::asio::ip::tcp::endpoint ep(internet_protocol, port); + lib::asio::ip::tcp::endpoint ep(internet_protocol, port); listen(ep); } @@ -440,7 +444,7 @@ class endpoint : public config::socket_type { * @param ec Set to indicate what error occurred, if any. */ void listen(uint16_t port, lib::error_code & ec) { - listen(boost::asio::ip::tcp::v6(), port, ec); + listen(lib::asio::ip::tcp::v6(), port, ec); } /// Set up endpoint for listening on a port @@ -456,13 +460,13 @@ class endpoint : public config::socket_type { * @param ec Set to indicate what error occurred, if any. */ void listen(uint16_t port) { - listen(boost::asio::ip::tcp::v6(), port); + listen(lib::asio::ip::tcp::v6(), port); } /// Set up endpoint for listening on a host and service (exception free) /** * Bind the internal acceptor using the given host and service. More details - * about what host and service can be are available in the boost asio + * about what host and service can be are available in the Asio * documentation for ip::basic_resolver_query::basic_resolver_query's * constructors. * @@ -478,7 +482,7 @@ class endpoint : public config::socket_type { void listen(std::string const & host, std::string const & service, lib::error_code & ec) { - using boost::asio::ip::tcp; + using lib::asio::ip::tcp; tcp::resolver r(*m_io_service); tcp::resolver::query query(host, service); tcp::resolver::iterator endpoint_iterator = r.resolve(query); @@ -495,7 +499,7 @@ class endpoint : public config::socket_type { /// Set up endpoint for listening on a host and service /** * Bind the internal acceptor using the given host and service. More details - * about what host and service can be are available in the boost asio + * about what host and service can be are available in the Asio * documentation for ip::basic_resolver_query::basic_resolver_query's * constructors. * @@ -609,7 +613,7 @@ class endpoint : public config::socket_type { * @since 0.3.0 */ void start_perpetual() { - m_work = lib::make_shared( + m_work = lib::make_shared( lib::ref(*m_io_service) ); } @@ -639,9 +643,9 @@ class endpoint : public config::socket_type { * needed. */ timer_ptr set_timer(long duration, timer_handler callback) { - timer_ptr new_timer = lib::make_shared( + timer_ptr new_timer = lib::make_shared( *m_io_service, - boost::posix_time::milliseconds(duration) + lib::asio::milliseconds(duration) ); new_timer->async_wait( @@ -667,10 +671,10 @@ class endpoint : public config::socket_type { * @param ec A status code indicating an error, if any. */ void handle_timer(timer_ptr, timer_handler callback, - boost::system::error_code const & ec) + lib::asio::error_code const & ec) { if (ec) { - if (ec == boost::asio::error::operation_aborted) { + if (ec == lib::asio::error::operation_aborted) { callback(make_error_code(transport::error::operation_aborted)); } else { m_elog->write(log::elevel::info, @@ -749,18 +753,18 @@ class endpoint : public config::socket_type { m_elog = e; } - void handle_accept(accept_handler callback, boost::system::error_code const - & boost_ec) + void handle_accept(accept_handler callback, lib::asio::error_code const & + asio_ec) { lib::error_code ret_ec; m_alog->write(log::alevel::devel, "asio::handle_accept"); - if (boost_ec) { - if (boost_ec == boost::system::errc::operation_canceled) { + if (asio_ec) { + if (asio_ec == lib::asio::errc::operation_canceled) { ret_ec = make_error_code(websocketpp::error::operation_canceled); } else { - log_err(log::elevel::info,"asio handle_accept",boost_ec); + log_err(log::elevel::info,"asio handle_accept",asio_ec); ret_ec = make_error_code(error::pass_through); } } @@ -771,14 +775,16 @@ class endpoint : public config::socket_type { /// Initiate a new connection // TODO: there have to be some more failure conditions here void async_connect(transport_con_ptr tcon, uri_ptr u, connect_handler cb) { - using namespace boost::asio::ip; + using namespace lib::asio::ip; // Create a resolver if (!m_resolver) { - m_resolver = lib::make_shared( + m_resolver = lib::make_shared( lib::ref(*m_io_service)); } + tcon->set_uri(u); + std::string proxy = tcon->get_proxy(); std::string host; std::string port; @@ -888,11 +894,11 @@ class endpoint : public config::socket_type { } void handle_resolve(transport_con_ptr tcon, timer_ptr dns_timer, - connect_handler callback, boost::system::error_code const & ec, - boost::asio::ip::tcp::resolver::iterator iterator) + connect_handler callback, lib::asio::error_code const & ec, + lib::asio::ip::tcp::resolver::iterator iterator) { - if (ec == boost::asio::error::operation_aborted || - dns_timer->expires_from_now().is_negative()) + if (ec == lib::asio::error::operation_aborted || + lib::asio::is_neg(dns_timer->expires_from_now())) { m_alog->write(log::alevel::devel,"async_resolve cancelled"); return; @@ -910,7 +916,7 @@ class endpoint : public config::socket_type { std::stringstream s; s << "Async DNS resolve successful. Results: "; - boost::asio::ip::tcp::resolver::iterator it, end; + lib::asio::ip::tcp::resolver::iterator it, end; for (it = iterator; it != end; ++it) { s << (*it).endpoint() << " "; } @@ -935,7 +941,7 @@ class endpoint : public config::socket_type { ); if (config::enable_multithreading) { - boost::asio::async_connect( + lib::asio::async_connect( tcon->get_raw_socket(), iterator, tcon->get_strand()->wrap(lib::bind( @@ -948,7 +954,7 @@ class endpoint : public config::socket_type { )) ); } else { - boost::asio::async_connect( + lib::asio::async_connect( tcon->get_raw_socket(), iterator, lib::bind( @@ -997,10 +1003,10 @@ class endpoint : public config::socket_type { } void handle_connect(transport_con_ptr tcon, timer_ptr con_timer, - connect_handler callback, boost::system::error_code const & ec) + connect_handler callback, lib::asio::error_code const & ec) { - if (ec == boost::asio::error::operation_aborted || - con_timer->expires_from_now().is_negative()) + if (ec == lib::asio::error::operation_aborted || + lib::asio::is_neg(con_timer->expires_from_now())) { m_alog->write(log::alevel::devel,"async_connect cancelled"); return; diff --git a/Release/libs/websocketpp/websocketpp/transport/asio/security/base.hpp b/Release/libs/websocketpp/websocketpp/transport/asio/security/base.hpp index 543a3533c0..dff14508bd 100644 --- a/Release/libs/websocketpp/websocketpp/transport/asio/security/base.hpp +++ b/Release/libs/websocketpp/websocketpp/transport/asio/security/base.hpp @@ -34,8 +34,6 @@ #include #include -#include - #include // Interface that sockets/security policies must implement @@ -56,6 +54,7 @@ // Connection // TODO +// set_hostname(std::string hostname) // pre_init(init_handler); // post_init(init_handler); @@ -97,7 +96,10 @@ namespace error { missing_tls_init_handler, /// TLS Handshake Failed - tls_handshake_failed + tls_handshake_failed, + + /// Failed to set TLS SNI hostname + tls_failed_sni_hostname }; } // namespace error @@ -126,6 +128,8 @@ class socket_category : public lib::error_category { return "Required tls_init handler not present."; case error::tls_handshake_failed: return "TLS handshake failed"; + case error::tls_failed_sni_hostname: + return "Failed to set TLS SNI hostname"; default: return "Unknown"; } diff --git a/Release/libs/websocketpp/websocketpp/transport/asio/security/none.hpp b/Release/libs/websocketpp/websocketpp/transport/asio/security/none.hpp index 14b6f8b5f7..138ea403a0 100644 --- a/Release/libs/websocketpp/websocketpp/transport/asio/security/none.hpp +++ b/Release/libs/websocketpp/websocketpp/transport/asio/security/none.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Peter Thorson. All rights reserved. + * Copyright (c) 2015, 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,12 +28,13 @@ #ifndef WEBSOCKETPP_TRANSPORT_SECURITY_NONE_HPP #define WEBSOCKETPP_TRANSPORT_SECURITY_NONE_HPP +#include + #include +#include #include -#include - #include #include @@ -45,13 +46,13 @@ namespace asio { namespace basic_socket { /// The signature of the socket init handler for this socket policy -typedef lib::function +typedef lib::function socket_init_handler; -/// Basic Boost ASIO connection socket component +/// Basic Asio connection socket component /** * transport::asio::basic_socket::connection implements a connection socket - * component using Boost ASIO ip::tcp::socket. + * component using Asio ip::tcp::socket. */ class connection : public lib::enable_shared_from_this { public: @@ -60,12 +61,12 @@ class connection : public lib::enable_shared_from_this { /// Type of a shared pointer to this connection socket component typedef lib::shared_ptr ptr; - /// Type of a pointer to the ASIO io_service being used - 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 a pointer to the Asio io_service being used + typedef lib::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; + typedef lib::asio::ip::tcp::socket socket_type; /// Type of a shared pointer to the socket being used. typedef lib::shared_ptr socket_ptr; @@ -91,7 +92,7 @@ class connection : public lib::enable_shared_from_this { /** * The socket initialization handler is called after the socket object is * created but before it is used. This gives the application a chance to - * set any ASIO socket options it needs. + * set any Asio socket options it needs. * * @param h The new socket_init_handler */ @@ -103,7 +104,7 @@ class connection : public lib::enable_shared_from_this { /** * This is used internally. It can also be used to set socket options, etc */ - boost::asio::ip::tcp::socket& get_socket() { + lib::asio::ip::tcp::socket & get_socket() { return *m_socket; } @@ -111,7 +112,7 @@ class connection : public lib::enable_shared_from_this { /** * This is used internally. */ - boost::asio::ip::tcp::socket& get_next_layer() { + lib::asio::ip::tcp::socket & get_next_layer() { return *m_socket; } @@ -119,7 +120,7 @@ class connection : public lib::enable_shared_from_this { /** * This is used internally. It can also be used to set socket options, etc */ - boost::asio::ip::tcp::socket& get_raw_socket() { + lib::asio::ip::tcp::socket & get_raw_socket() { return *m_socket; } @@ -133,16 +134,16 @@ class connection : public lib::enable_shared_from_this { * * @return A string identifying the address of the remote endpoint */ - std::string get_remote_endpoint(lib::error_code &ec) const { + std::string get_remote_endpoint(lib::error_code & ec) const { std::stringstream s; - boost::system::error_code bec; - boost::asio::ip::tcp::endpoint ep = m_socket->remote_endpoint(bec); + lib::asio::error_code aec; + lib::asio::ip::tcp::endpoint ep = m_socket->remote_endpoint(aec); - if (bec) { + if (aec) { ec = error::make_error_code(error::pass_through); - s << "Error getting remote endpoint: " << bec - << " (" << bec.message() << ")"; + s << "Error getting remote endpoint: " << aec + << " (" << aec.message() << ")"; return s.str(); } else { ec = lib::error_code(); @@ -154,7 +155,7 @@ class connection : public lib::enable_shared_from_this { /// Perform one time initializations /** * init_asio is called once immediately after construction to initialize - * boost::asio components to the io_service + * Asio components to the io_service * * @param service A pointer to the endpoint's io_service * @param strand A shared pointer to the connection's asio strand @@ -166,7 +167,7 @@ class connection : public lib::enable_shared_from_this { return socket::make_error_code(socket::error::invalid_state); } - m_socket = lib::make_shared( + m_socket = lib::make_shared( lib::ref(*service)); m_state = READY; @@ -174,6 +175,19 @@ class connection : public lib::enable_shared_from_this { return lib::error_code(); } + /// Set uri hook + /** + * Called by the transport as a connection is being established to provide + * the uri being connected to to the security/socket layer. + * + * This socket policy doesn't use the uri so it is ignored. + * + * @since 0.6.0 + * + * @param u The uri to set + */ + void set_uri(uri_ptr) {} + /// Pre-initialize security policy /** * Called by the transport after a new connection is created to initialize @@ -227,8 +241,8 @@ class connection : public lib::enable_shared_from_this { } void async_shutdown(socket_shutdown_handler h) { - boost::system::error_code ec; - m_socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both,ec); + lib::asio::error_code ec; + m_socket->shutdown(lib::asio::ip::tcp::socket::shutdown_both, ec); h(ec); } @@ -248,7 +262,7 @@ class connection : public lib::enable_shared_from_this { * @param ec The error code to translate_ec * @return The translated error code */ - lib::error_code translate_ec(boost::system::error_code) { + lib::error_code translate_ec(lib::asio::error_code) { // We don't know any more information about this error so pass through return make_error_code(transport::error::pass_through); } diff --git a/Release/libs/websocketpp/websocketpp/transport/asio/security/tls.hpp b/Release/libs/websocketpp/websocketpp/transport/asio/security/tls.hpp index 8434a5c3d9..9ce9408f85 100644 --- a/Release/libs/websocketpp/websocketpp/transport/asio/security/tls.hpp +++ b/Release/libs/websocketpp/websocketpp/transport/asio/security/tls.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Peter Thorson. All rights reserved. + * Copyright (c) 2015, 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: @@ -30,14 +30,14 @@ #include +#include + +#include +#include #include #include #include -#include -#include -#include - #include #include @@ -49,16 +49,16 @@ namespace asio { namespace tls_socket { /// The signature of the socket_init_handler for this socket policy -typedef lib::function&)> socket_init_handler; +typedef lib::function&)> socket_init_handler; /// The signature of the tls_init_handler for this socket policy -typedef lib::function(connection_hdl)> +typedef lib::function(connection_hdl)> tls_init_handler; /// TLS enabled Boost ASIO connection socket component /** * transport::asio::tls_socket::connection implements a secure connection socket - * component that uses Boost ASIO's ssl::stream to wrap an ip::tcp::socket. + * component that uses Asio's ssl::stream to wrap an ip::tcp::socket. */ class connection : public lib::enable_shared_from_this { public: @@ -68,17 +68,15 @@ class connection : public lib::enable_shared_from_this { typedef lib::shared_ptr ptr; /// Type of the ASIO socket being used - typedef boost::asio::ssl::stream socket_type; + typedef lib::asio::ssl::stream socket_type; /// Type of a shared pointer to the ASIO socket being used typedef lib::shared_ptr socket_ptr; /// Type of a pointer to the ASIO io_service being used - typedef boost::asio::io_service* io_service_ptr; + typedef lib::asio::io_service * io_service_ptr; /// Type of a pointer to the ASIO io_service strand being used - typedef lib::shared_ptr strand_ptr; + typedef lib::shared_ptr strand_ptr; /// Type of a shared pointer to the ASIO TLS context being used - typedef lib::shared_ptr context_ptr; - - typedef boost::system::error_code boost_error; + typedef lib::shared_ptr context_ptr; explicit connection() { //std::cout << "transport::asio::tls_socket::connection constructor" @@ -102,7 +100,7 @@ class connection : public lib::enable_shared_from_this { /** * This is used internally. It can also be used to set socket options, etc */ - socket_type::lowest_layer_type& get_raw_socket() { + socket_type::lowest_layer_type & get_raw_socket() { return m_socket->lowest_layer(); } @@ -110,7 +108,7 @@ class connection : public lib::enable_shared_from_this { /** * This is used internally. */ - socket_type::next_layer_type& get_next_layer() { + socket_type::next_layer_type & get_next_layer() { return m_socket->next_layer(); } @@ -118,7 +116,7 @@ class connection : public lib::enable_shared_from_this { /** * This is used internally. */ - socket_type& get_socket() { + socket_type & get_socket() { return *m_socket; } @@ -157,16 +155,16 @@ class connection : public lib::enable_shared_from_this { * * @return A string identifying the address of the remote endpoint */ - std::string get_remote_endpoint(lib::error_code &ec) const { + std::string get_remote_endpoint(lib::error_code & ec) const { std::stringstream s; - boost::system::error_code bec; - boost::asio::ip::tcp::endpoint ep = m_socket->lowest_layer().remote_endpoint(bec); + lib::asio::error_code aec; + lib::asio::ip::tcp::endpoint ep = m_socket->lowest_layer().remote_endpoint(aec); - if (bec) { + if (aec) { ec = error::make_error_code(error::pass_through); - s << "Error getting remote endpoint: " << bec - << " (" << bec.message() << ")"; + s << "Error getting remote endpoint: " << aec + << " (" << aec.message() << ")"; return s.str(); } else { ec = lib::error_code(); @@ -178,7 +176,7 @@ class connection : public lib::enable_shared_from_this { /// Perform one time initializations /** * init_asio is called once immediately after construction to initialize - * boost::asio components to the io_service + * Asio components to the io_service * * @param service A pointer to the endpoint's io_service * @param strand A pointer to the connection's strand @@ -205,6 +203,22 @@ class connection : public lib::enable_shared_from_this { return lib::error_code(); } + /// Set hostname hook + /** + * Called by the transport as a connection is being established to provide + * the hostname being connected to to the security/socket layer. + * + * This socket policy uses the hostname to set the appropriate TLS SNI + * header. + * + * @since 0.6.0 + * + * @param u The uri to set + */ + void set_uri(uri_ptr u) { + m_uri = u; + } + /// Pre-initialize security policy /** * Called by the transport after a new connection is created to initialize @@ -266,8 +280,7 @@ class connection : public lib::enable_shared_from_this { m_hdl = hdl; } - void handle_init(init_handler callback,boost::system::error_code const & ec) - { + void handle_init(init_handler callback,lib::asio::error_code const & ec) { if (ec) { m_ec = socket::make_error_code(socket::error::tls_handshake_failed); } else { @@ -306,7 +319,7 @@ class connection : public lib::enable_shared_from_this { * @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 (ec.category() == lib::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 { @@ -323,9 +336,9 @@ class connection : public lib::enable_shared_from_this { private: socket_type::handshake_type get_handshake_type() { if (m_is_server) { - return boost::asio::ssl::stream_base::server; + return lib::asio::ssl::stream_base::server; } else { - return boost::asio::ssl::stream_base::client; + return lib::asio::ssl::stream_base::client; } } @@ -333,6 +346,7 @@ class connection : public lib::enable_shared_from_this { strand_ptr m_strand; context_ptr m_context; socket_ptr m_socket; + uri_ptr m_uri; bool m_is_server; lib::error_code m_ec; @@ -342,10 +356,10 @@ class connection : public lib::enable_shared_from_this { tls_init_handler m_tls_init_handler; }; -/// TLS enabled Boost ASIO endpoint socket component +/// TLS enabled Asio endpoint socket component /** * transport::asio::tls_socket::endpoint implements a secure endpoint socket - * component that uses Boost ASIO's ssl::stream to wrap an ip::tcp::socket. + * component that uses Asio's ssl::stream to wrap an ip::tcp::socket. */ class endpoint { public: diff --git a/Release/libs/websocketpp/websocketpp/transport/debug/connection.hpp b/Release/libs/websocketpp/websocketpp/transport/debug/connection.hpp index 7b8c29cbde..36b282a20d 100644 --- a/Release/libs/websocketpp/websocketpp/transport/debug/connection.hpp +++ b/Release/libs/websocketpp/websocketpp/transport/debug/connection.hpp @@ -32,6 +32,7 @@ #include +#include #include #include @@ -103,6 +104,20 @@ class connection : public lib::enable_shared_from_this< connection > { return false; } + /// Set uri hook + /** + * Called by the endpoint as a connection is being established to provide + * the uri being connected to to the transport layer. + * + * Implementation is optional and can be ignored if the transport has no + * need for this information. + * + * @since 0.6.0 + * + * @param u The uri to set + */ + void set_uri(uri_ptr) {} + /// Set human readable remote endpoint address /** * Sets the remote endpoint address returned by `get_remote_endpoint`. This diff --git a/Release/libs/websocketpp/websocketpp/transport/iostream/base.hpp b/Release/libs/websocketpp/websocketpp/transport/iostream/base.hpp index 0103856a97..f878398783 100644 --- a/Release/libs/websocketpp/websocketpp/transport/iostream/base.hpp +++ b/Release/libs/websocketpp/websocketpp/transport/iostream/base.hpp @@ -33,7 +33,10 @@ #include #include +#include + #include +#include namespace websocketpp { namespace transport { @@ -41,10 +44,19 @@ namespace transport { namespace iostream { /// The type and signature of the callback used by iostream transport to write -typedef lib::function +typedef lib::function write_handler; -/// The type and signature of the callback used by iostream transport to signal +/// The type and signature of the callback used by iostream transport to perform +/// vectored writes. +/** + * If a vectored write handler is not set the standard write handler will be + * called multiple times. + */ +typedef lib::function const + & bufs)> vector_write_handler; + +/// The type and signature of the callback used by iostream transport to signal /// a transport shutdown. typedef lib::function shutdown_handler; diff --git a/Release/libs/websocketpp/websocketpp/transport/iostream/connection.hpp b/Release/libs/websocketpp/websocketpp/transport/iostream/connection.hpp index c0d0901180..81c4f41134 100644 --- a/Release/libs/websocketpp/websocketpp/transport/iostream/connection.hpp +++ b/Release/libs/websocketpp/websocketpp/transport/iostream/connection.hpp @@ -32,6 +32,8 @@ #include +#include + #include #include @@ -105,6 +107,19 @@ class connection : public lib::enable_shared_from_this< connection > { m_output_stream = o; } + /// Set uri hook + /** + * Called by the endpoint as a connection is being established to provide + * the uri being connected to to the transport layer. + * + * This transport policy doesn't use the uri so it is ignored. + * + * @since 0.6.0 + * + * @param u The uri to set + */ + void set_uri(uri_ptr) {} + /// Overloaded stream input operator /** * Attempts to read input from the given stream into the transport. Bytes @@ -153,7 +168,7 @@ class connection : public lib::enable_shared_from_this< connection > { 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 @@ -173,7 +188,7 @@ class connection : public lib::enable_shared_from_this< connection > { 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; @@ -312,25 +327,60 @@ class connection : public lib::enable_shared_from_this< connection > { timer_ptr set_timer(long, timer_handler) { return timer_ptr(); } - + /// Sets the write handler /** * The write handler is called when the iostream transport receives data * that needs to be written to the appropriate output location. This handler * can be used in place of registering an ostream for output. * - * The signature of the handler is + * The signature of the handler is * `lib::error_code (connection_hdl, char const *, size_t)` The * code returned will be reported and logged by the core library. * + * See also, set_vector_write_handler, for an optional write handler that + * allows more efficient handling of multiple writes at once. + * + * @see set_vector_write_handler + * * @since 0.5.0 * - * @param h The handler to call on connection shutdown. + * @param h The handler to call when data is to be written. */ void set_write_handler(write_handler h) { m_write_handler = h; } - + + /// Sets the vectored write handler + /** + * The vectored write handler is called when the iostream transport receives + * multiple chunks of data that need to be written to the appropriate output + * location. This handler can be used in conjunction with the write_handler + * in place of registering an ostream for output. + * + * The sequence of buffers represents bytes that should be written + * consecutively and it is suggested to group the buffers into as few next + * layer packets as possible. Vector write is used to allow implementations + * that support it to coalesce writes into a single TCP packet or TLS + * segment for improved efficiency. + * + * This is an optional handler. If it is not defined then multiple calls + * will be made to the standard write handler. + * + * The signature of the handler is + * `lib::error_code (connection_hdl, std::vector + * const & bufs)`. The code returned will be reported and logged by the core + * library. The `websocketpp::transport::buffer` type is a struct with two + * data members. buf (char const *) and len (size_t). + * + * @since 0.6.0 + * + * @param h The handler to call when vectored data is to be written. + */ + void set_vector_write_handler(vector_write_handler h) { + m_vector_write_handler = h; + } + /// Sets the shutdown handler /** * The shutdown handler is called when the iostream transport receives a @@ -434,7 +484,7 @@ class connection : public lib::enable_shared_from_this< connection > { * @param len number of bytes to write * @param handler Callback to invoke with operation status. */ - void async_write(char const * buf, size_t len, transport::write_handler + void async_write(char const * buf, size_t len, transport::write_handler handler) { m_alog.write(log::alevel::devel,"iostream_con async_write"); @@ -444,7 +494,7 @@ class connection : public lib::enable_shared_from_this< connection > { if (m_output_stream) { m_output_stream->write(buf,len); - + if (m_output_stream->bad()) { ec = make_error_code(error::bad_stream); } @@ -492,17 +542,19 @@ class connection : public lib::enable_shared_from_this< connection > { break; } } + } else if (m_vector_write_handler) { + ec = m_vector_write_handler(m_connection_hdl, bufs); } else if (m_write_handler) { std::vector::const_iterator it; for (it = bufs.begin(); it != bufs.end(); it++) { ec = m_write_handler(m_connection_hdl, (*it).buf, (*it).len); if (ec) {break;} } - + } else { ec = make_error_code(error::output_stream_required); } - + handler(ec); } @@ -540,11 +592,11 @@ class connection : public lib::enable_shared_from_this< connection > { */ void async_shutdown(transport::shutdown_handler handler) { lib::error_code ec; - + if (m_shutdown_handler) { ec = m_shutdown_handler(m_connection_hdl); } - + handler(ec); } private: @@ -636,6 +688,7 @@ class connection : public lib::enable_shared_from_this< connection > { std::ostream * m_output_stream; connection_hdl m_connection_hdl; write_handler m_write_handler; + vector_write_handler m_vector_write_handler; shutdown_handler m_shutdown_handler; bool m_reading; diff --git a/Release/libs/websocketpp/websocketpp/transport/stub/connection.hpp b/Release/libs/websocketpp/websocketpp/transport/stub/connection.hpp index 3e501a9635..59bd4a0a43 100644 --- a/Release/libs/websocketpp/websocketpp/transport/stub/connection.hpp +++ b/Release/libs/websocketpp/websocketpp/transport/stub/connection.hpp @@ -103,6 +103,20 @@ class connection : public lib::enable_shared_from_this< connection > { return false; } + /// Set uri hook + /** + * Called by the endpoint as a connection is being established to provide + * the uri being connected to to the transport layer. + * + * Implementation is optional and can be ignored if the transport has no + * need for this information. + * + * @since 0.6.0 + * + * @param u The uri to set + */ + void set_uri(uri_ptr) {} + /// Set human readable remote endpoint address /** * Sets the remote endpoint address returned by `get_remote_endpoint`. This diff --git a/Release/libs/websocketpp/websocketpp/version.hpp b/Release/libs/websocketpp/websocketpp/version.hpp index 24d6be4a2e..56a0a76d69 100644 --- a/Release/libs/websocketpp/websocketpp/version.hpp +++ b/Release/libs/websocketpp/websocketpp/version.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Peter Thorson. All rights reserved. + * Copyright (c) 2015, 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,18 +42,18 @@ namespace websocketpp { /// Library major version number static int const major_version = 0; /// Library minor version number -static int const minor_version = 5; +static int const minor_version = 6; /// Library patch version number -static int const patch_version = 1; +static int const patch_version = 0; /// Library pre-release flag /** * 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[] = ""; +static char const prerelease_flag[] = "permessagedeflate"; /// Default user agent string -static char const user_agent[] = "WebSocket++/0.5.1"; +static char const user_agent[] = "WebSocketpp/0.6.0-permessagedeflate"; } // namespace websocketpp