From ec8b73cad4ed67b842b536394341911c0d09c6ff Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Fri, 24 May 2013 22:14:06 -0700 Subject: [PATCH 01/44] clarifies the purpose of utility client and removes contradictory comments references #242 --- examples/utility_client/utility_client.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/utility_client/utility_client.cpp b/examples/utility_client/utility_client.cpp index 6d22f7b8de..2f6320b034 100644 --- a/examples/utility_client/utility_client.cpp +++ b/examples/utility_client/utility_client.cpp @@ -1,3 +1,8 @@ +/** + * This example is presently used as a scratch space. It may or may not be broken + * at any given time. + */ + #include #include @@ -24,7 +29,6 @@ public: typedef std::chrono::duration dur_type; perftest () { - // We expect there to be a lot of errors, so suppress them m_endpoint.set_access_channels(websocketpp::log::alevel::all); m_endpoint.set_error_channels(websocketpp::log::elevel::all); From 5677b5f400cef0a376b5ca979f9c57d2794b7b9c Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Sun, 26 May 2013 20:02:08 -0500 Subject: [PATCH 02/44] adds dummy timer support + tests to iostream transport --- test/transport/iostream/connection.cpp | 14 ++++++++++- websocketpp/transport/iostream/connection.hpp | 24 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/test/transport/iostream/connection.cpp b/test/transport/iostream/connection.cpp index 6f49349947..362c46df68 100644 --- a/test/transport/iostream/connection.cpp +++ b/test/transport/iostream/connection.cpp @@ -52,6 +52,8 @@ typedef websocketpp::transport::iostream::connection iostream_con; using websocketpp::transport::iostream::error::make_error_code; struct stub_con : public iostream_con { + typedef iostream_con::timer_ptr timer_ptr; + stub_con(bool is_server, config::alog_type &a, config::elog_type & e) : iostream_con(is_server,a,e) // Set the error to a known code that is unused by the library @@ -267,4 +269,14 @@ BOOST_AUTO_TEST_CASE( async_read_at_least2 ) { BOOST_CHECK( channel.tellg() == -1 ); BOOST_CHECK( !con.ec ); BOOST_CHECK( std::string(buf,10) == "abcdefgxxx" ); -} \ No newline at end of file +} + +void timer_callback_stub(const websocketpp::lib::error_code & ec) {} + +BOOST_AUTO_TEST_CASE( set_timer ) { + stub_con con(true,a,e); + + stub_con::timer_ptr tp = con.set_timer(1000,timer_callback_stub); + + BOOST_CHECK( !tp ); +} diff --git a/websocketpp/transport/iostream/connection.hpp b/websocketpp/transport/iostream/connection.hpp index ab2b19b01d..63b250b9f3 100644 --- a/websocketpp/transport/iostream/connection.hpp +++ b/websocketpp/transport/iostream/connection.hpp @@ -42,6 +42,12 @@ namespace websocketpp { namespace transport { namespace iostream { +/// Empty timer class to stub out for timer functionality that iostream +/// transport doesn't support +struct timer { + void cancel() {} +}; + template class connection { public: @@ -61,6 +67,8 @@ public: typedef typename concurrency_type::scoped_lock_type scoped_lock_type; typedef typename concurrency_type::mutex_type mutex_type; + typedef lib::shared_ptr timer_ptr; + explicit connection(bool is_server, alog_type& alog, elog_type& elog) : m_output_stream(NULL) , m_reading(false) @@ -160,6 +168,22 @@ public: connection_hdl get_handle() const { return m_connection_hdl; } + + /// Call back a function after a period of time. + /** + * Timers are not implimented in this transport. The timer pointer will + * always be empty. The handler will never be called. + * + * @param duration Length of time to wait in milliseconds + * + * @param callback The function to call back when the timer has expired + * + * @return A handle that can be used to cancel the timer if it is no longer + * needed. + */ + timer_ptr set_timer(long duration, timer_handler callback) { + return timer_ptr(); + } protected: void init(init_handler callback) { m_alog.write(log::alevel::devel,"iostream connection init"); From 10a8af1ac3f55da9095e6c6f11b5697a7dddfcb3 Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Sun, 26 May 2013 22:04:28 -0500 Subject: [PATCH 03/44] adds pong timer support and new full stack automated integration testing for it --- SConstruct | 2 +- test/transport/SConscript | 24 +++++ test/transport/integration.cpp | 131 +++++++++++++++++++++++++++ websocketpp/connection.hpp | 23 ++++- websocketpp/impl/connection_impl.hpp | 70 ++++++++++++-- 5 files changed, 237 insertions(+), 13 deletions(-) create mode 100644 test/transport/SConscript create mode 100644 test/transport/integration.cpp diff --git a/SConstruct b/SConstruct index b104241a14..b930d4d3ab 100644 --- a/SConstruct +++ b/SConstruct @@ -198,7 +198,7 @@ Export('polyfill_libs') if not env['PLATFORM'].startswith('win'): # Unit tests, add test folders with SConscript files to to_test list. - to_test = ['utility','http','logger','random','processors','message_buffer','extension','transport/iostream','transport/asio','roles','endpoint','connection'] #,'http','processors','connection' + to_test = ['utility','http','logger','random','processors','message_buffer','extension','transport/iostream','transport/asio','roles','endpoint','connection','transport'] #,'http','processors','connection' for t in to_test: new_tests = SConscript('#/test/'+t+'/SConscript',variant_dir = testdir + t, duplicate = 0) diff --git a/test/transport/SConscript b/test/transport/SConscript new file mode 100644 index 0000000000..b31a190059 --- /dev/null +++ b/test/transport/SConscript @@ -0,0 +1,24 @@ +## transport integration tests +## + +Import('env') +Import('env_cpp11') +Import('boostlibs') +Import('platform_libs') +Import('polyfill_libs') +Import('tls_libs') + +env = env.Clone () +env_cpp11 = env_cpp11.Clone () + +BOOST_LIBS = boostlibs(['unit_test_framework','system','thread','regex','random'],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) + +if env_cpp11.has_key('WSPP_CPP11_ENABLED'): + BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework','system'],env_cpp11) + [platform_libs] + [polyfill_libs] + [tls_libs] + objs += env_cpp11.Object('stl_integration.o', ["integration.cpp"], LIBS = BOOST_LIBS_CPP11) + prgs += env_cpp11.Program('test_stl_integration', ["stl_integration.o"], LIBS = BOOST_LIBS_CPP11) + +Return('prgs') diff --git a/test/transport/integration.cpp b/test/transport/integration.cpp new file mode 100644 index 0000000000..369688d191 --- /dev/null +++ b/test/transport/integration.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2011, 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. + * + */ +//#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MODULE transport_integration +#include + +#include + +#include +#include +#include +#include + +typedef websocketpp::server server; +typedef websocketpp::client client; + +using websocketpp::lib::placeholders::_1; +using websocketpp::lib::placeholders::_2; +using websocketpp::lib::bind; + +void run_server(server * s, int port) { + try { + s->clear_access_channels(websocketpp::log::alevel::all); + s->clear_error_channels(websocketpp::log::elevel::all); + + s->init_asio(); + + s->listen(port); + s->start_accept(); + s->run(); + } catch (std::exception & e) { + std::cout << e.what() << std::endl; + } catch (boost::system::error_code & ec) { + std::cout << ec.message() << std::endl; + } +} + +void run_client(client & c, std::string uri) { + c.clear_access_channels(websocketpp::log::alevel::all); + c.clear_error_channels(websocketpp::log::elevel::all); + + c.init_asio(); + + websocketpp::lib::error_code ec; + client::connection_ptr con = c.get_connection(uri,ec); + BOOST_CHECK( !ec ); + c.connect(con); + + c.run(); +} + +bool on_ping(websocketpp::connection_hdl, std::string payload) { + return false; +} + +void cancel_on_open(server * s, websocketpp::connection_hdl hdl) { + s->cancel(); +} + +template +void ping_on_open(T * c, std::string payload, websocketpp::connection_hdl hdl) { + typename T::connection_ptr con = c->get_con_from_hdl(hdl); + con->ping(payload); +} + +void fail_on_pong(websocketpp::connection_hdl hdl, std::string payload) { + BOOST_FAIL( "expected no pong" ); +} + +template +void req_pong_timeout(T * c, std::string expected_payload, + websocketpp::connection_hdl hdl, std::string payload) +{ + typename T::connection_ptr con = c->get_con_from_hdl(hdl); + BOOST_CHECK_EQUAL( payload, expected_payload ); + con->close(websocketpp::close::status::normal,""); +} + +// Wait for the specified time period then fail the test +void run_test_timer(long value) { + /*boost::asio::io_service ios; + boost::asio::deadline_timer t(ios,boost::posix_time::milliseconds(value)); + boost::system::error_code ec; + t.wait(ec);*/ + sleep(value); + BOOST_FAIL( "Test timed out" ); +} + +BOOST_AUTO_TEST_CASE( pong_timeout ) { + server s; + client c; + + s.set_ping_handler(on_ping); + s.set_open_handler(bind(&cancel_on_open,&s,::_1)); + + c.set_pong_handler(bind(&fail_on_pong,::_1,::_2)); + c.set_open_handler(bind(&ping_on_open,&c,"foo",::_1)); + c.set_pong_timeout_handler(bind(&req_pong_timeout,&c,"foo",::_1,::_2)); + + websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005)); + websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,6)); + sthread.detach(); + tthread.detach(); + + run_client(c, "http://localhost:9005"); +} + diff --git a/websocketpp/connection.hpp b/websocketpp/connection.hpp index 55150b2b64..d43408135c 100644 --- a/websocketpp/connection.hpp +++ b/websocketpp/connection.hpp @@ -163,7 +163,10 @@ public: // Message handler (needs to know message type) typedef lib::function message_handler; - + + /// Type of a pointer to a transport timer handle + typedef typename transport_con_type::timer_ptr timer_ptr; + // Misc Convenience Types typedef session::internal_state::value istate_type; @@ -263,11 +266,18 @@ public: * If the transport component being used supports timers, the pong timeout * handler is called whenever a pong control frame is not received with the * configured timeout period after the application sends a ping. - * + * + * The config setting `timeout_pong` controls the length of the timeout + * period. It is specified in milliseconds. + * * This can be used to probe the health of the remote endpoint's WebSocket * implimentation. This does not guarantee that the remote application * itself is still healthy but can be a useful diagnostic. * + * Note: receipt of this callback doesn't mean the pong will never come. + * This functionality will not suppress delivery of the pong in question + * should it arrive after the timeout. + * * @param h The new pong_timeout_handler */ void set_pong_timeout_handler(pong_timeout_handler h) { @@ -428,7 +438,13 @@ public: * @param payload Payload to be used for the ping */ void ping(const std::string& payload); - + + /// exception free variant of ping + void ping(const std::string & payload, lib::error_code & ec); + + /// Utility method that gets called back when the ping timer expires + void handle_pong_timeout(std::string payload, const lib::error_code & ec); + /// Send a pong /** * Initiates a pong with the given payload. @@ -1027,6 +1043,7 @@ private: size_t m_buf_cursor; termination_handler m_termination_handler; con_msg_manager_ptr m_msg_manager; + timer_ptr m_ping_timer; // TODO: this is not memory efficient. this value is not used after the // handshake. diff --git a/websocketpp/impl/connection_impl.hpp b/websocketpp/impl/connection_impl.hpp index 9919afccdb..7d0f7370cd 100644 --- a/websocketpp/impl/connection_impl.hpp +++ b/websocketpp/impl/connection_impl.hpp @@ -139,21 +139,45 @@ lib::error_code connection::send(typename config::message_type::ptr msg) } template -void connection::ping(const std::string& payload) { +void connection::ping(const std::string& payload, lib::error_code& ec) { m_alog.write(log::alevel::devel,"connection ping"); if (m_state != session::state::open) { - throw error::make_error_code(error::invalid_state); + ec = error::make_error_code(error::invalid_state); + return; } message_ptr msg = m_msg_manager->get_message(); if (!msg) { - throw error::make_error_code(error::no_outgoing_buffers); + ec = error::make_error_code(error::no_outgoing_buffers); + return; } - lib::error_code ec = m_processor->prepare_ping(payload,msg); - if (ec) { - throw ec; + ec = m_processor->prepare_ping(payload,msg); + if (ec) {return;} + + // set ping timer if we are listening for one + if (m_pong_timeout_handler) { + // Cancel any existing timers + if (m_ping_timer) { + m_ping_timer->cancel(); + } + + m_ping_timer = transport_con_type::set_timer( + config::timeout_pong, + lib::bind( + &type::handle_pong_timeout, + type::shared_from_this(), + payload, + lib::placeholders::_1 + ) + ); + + if (!m_ping_timer) { + // Our transport doesn't support timers + m_elog.write(log::elevel::warn,"Warning: a pong_timeout_handler is \ + set but the transport in use does not support timeouts."); + } } bool needs_writing = false; @@ -169,6 +193,36 @@ void connection::ping(const std::string& payload) { type::shared_from_this() )); } + + ec = lib::error_code(); +} + +template +void connection::ping(const std::string& payload) { + lib::error_code ec; + ping(payload,ec); + if (ec) { + throw ec; + } +} + +template +void connection::handle_pong_timeout(std::string payload, const lib::error_code & + ec) +{ + if (ec) { + if (ec == transport::error::operation_aborted) { + // ignore, this is expected + return; + } + + m_elog.write(log::elevel::devel,"pong_timeout error: "+ec.message()); + return; + } + + if (m_pong_timeout_handler) { + m_pong_timeout_handler(m_connection_hdl,payload); + } } template @@ -187,9 +241,7 @@ void connection::pong(const std::string& payload, lib::error_code& ec) { } ec = m_processor->prepare_pong(payload,msg); - if (ec) { - return; - } + if (ec) {return;} bool needs_writing = false; { From f0f346dabe410c99363f7942549dc52d56ed4805 Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Wed, 29 May 2013 08:48:08 -0500 Subject: [PATCH 04/44] experimental dual core travis build --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ef470fb941..079695d3f3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ env: global: - BOOST_INCLUDES=/usr/include - BOOST_LIBS=/usr/lib -script: scons && scons test +script: scons -j 2 && scons test branches: only: - experimental From e4c4cf2018218c034c75c6ca26fe20149f6bf9bd Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Wed, 29 May 2013 08:48:22 -0500 Subject: [PATCH 05/44] updates readme and roadmap --- readme.md | 3 +++ roadmap.md | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index f4f54e9e16..ed19b3d3ed 100644 --- a/readme.md +++ b/readme.md @@ -45,6 +45,9 @@ https://github.com/zaphoyd/websocketpp/ **Announcements Mailing List** http://groups.google.com/group/websocketpp-announcements/ +**IRC Channel** +#websocketpp (freenode) + **Discussion / Development / Support Mailing List / Forum** http://groups.google.com/group/websocketpp/ diff --git a/roadmap.md b/roadmap.md index e9ae05e458..3936e5d7df 100644 --- a/roadmap.md +++ b/roadmap.md @@ -41,4 +41,5 @@ Needs work: Non-release blocking feature roadmap - Extension support - permessage_compress extension -- Message buffer pool \ No newline at end of file +- Message buffer pool +- CMake build/install support \ No newline at end of file From d9e3f626e27613373fd1789cbabf5d5cb8cef7f3 Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Wed, 29 May 2013 09:06:46 -0500 Subject: [PATCH 06/44] use custom config so we can play with timer duration values --- test/transport/integration.cpp | 43 ++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/test/transport/integration.cpp b/test/transport/integration.cpp index 369688d191..539c7fbbaa 100644 --- a/test/transport/integration.cpp +++ b/test/transport/integration.cpp @@ -35,8 +35,47 @@ #include #include -typedef websocketpp::server server; -typedef websocketpp::client client; +struct config : public websocketpp::config::asio_client { + typedef config type; + typedef websocketpp::config::asio 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; + + /// Length of time before an opening handshake is aborted + static const long timeout_open_handshake = 500; + /// Length of time before a closing handshake is aborted + static const long timeout_close_handshake = 500; + /// Length of time to wait for a pong after a ping + static const long timeout_pong = 500; +}; + +typedef websocketpp::server server; +typedef websocketpp::client client; using websocketpp::lib::placeholders::_1; using websocketpp::lib::placeholders::_2; From 370bd93182098e73895e5fad4360bd06053782c3 Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Wed, 29 May 2013 09:07:19 -0500 Subject: [PATCH 07/44] remove exception suppression, test framework will catch these --- test/transport/integration.cpp | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/test/transport/integration.cpp b/test/transport/integration.cpp index 539c7fbbaa..2fbd26ad8d 100644 --- a/test/transport/integration.cpp +++ b/test/transport/integration.cpp @@ -82,20 +82,14 @@ using websocketpp::lib::placeholders::_2; using websocketpp::lib::bind; void run_server(server * s, int port) { - try { - s->clear_access_channels(websocketpp::log::alevel::all); - s->clear_error_channels(websocketpp::log::elevel::all); + s->clear_access_channels(websocketpp::log::alevel::all); + s->clear_error_channels(websocketpp::log::elevel::all); - s->init_asio(); + s->init_asio(); - s->listen(port); - s->start_accept(); - s->run(); - } catch (std::exception & e) { - std::cout << e.what() << std::endl; - } catch (boost::system::error_code & ec) { - std::cout << ec.message() << std::endl; - } + s->listen(port); + s->start_accept(); + s->run(); } void run_client(client & c, std::string uri) { From 7ca4f37c2c6dd56fa13d34bec19cb59706d6f1c4 Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Wed, 29 May 2013 09:07:48 -0500 Subject: [PATCH 08/44] stop the server after the last connection ends and let the server thread clean up --- test/transport/integration.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/transport/integration.cpp b/test/transport/integration.cpp index 2fbd26ad8d..d9bae9d54f 100644 --- a/test/transport/integration.cpp +++ b/test/transport/integration.cpp @@ -114,6 +114,10 @@ void cancel_on_open(server * s, websocketpp::connection_hdl hdl) { s->cancel(); } +void stop_on_close(server * s, websocketpp::connection_hdl hdl) { + s->stop(); +} + template void ping_on_open(T * c, std::string payload, websocketpp::connection_hdl hdl) { typename T::connection_ptr con = c->get_con_from_hdl(hdl); @@ -148,7 +152,7 @@ BOOST_AUTO_TEST_CASE( pong_timeout ) { client c; s.set_ping_handler(on_ping); - s.set_open_handler(bind(&cancel_on_open,&s,::_1)); + s.set_close_handler(bind(&stop_on_close,&s,::_1)); c.set_pong_handler(bind(&fail_on_pong,::_1,::_2)); c.set_open_handler(bind(&ping_on_open,&c,"foo",::_1)); @@ -156,9 +160,10 @@ BOOST_AUTO_TEST_CASE( pong_timeout ) { websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005)); websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,6)); - sthread.detach(); tthread.detach(); run_client(c, "http://localhost:9005"); + + sthread.join(); } From 7e6d4212a5ca9f0f23d047e7758eb1b7c82e7b0f Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Wed, 29 May 2013 09:09:03 -0500 Subject: [PATCH 09/44] only load boost libraries that we need to improve test times --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 079695d3f3..16a3cf0a5b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,8 +2,7 @@ language: cpp compiler: - gcc before_install: - - sudo apt-get update -qq -y - - sudo apt-get install libboost1.48-all-dev -y + - sudo apt-get install libboost-regex1.48.0-dev libboost-system1.48-dev libboost-thread1.48-dev libboost-test1.48-dev libboost-random1.48-dev -y env: global: - BOOST_INCLUDES=/usr/include From ad2ff8ca0ac5a57331ccf1a82dbce3f1d484e405 Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Wed, 29 May 2013 09:15:37 -0500 Subject: [PATCH 10/44] fix travis script? --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 16a3cf0a5b..34f4ced673 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ language: cpp compiler: - gcc before_install: + - sudo apt-get update -qq -y - sudo apt-get install libboost-regex1.48.0-dev libboost-system1.48-dev libboost-thread1.48-dev libboost-test1.48-dev libboost-random1.48-dev -y env: global: From 6e0411020c1e24d30a16ab78007b86c4bf97f382 Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Wed, 29 May 2013 09:17:17 -0500 Subject: [PATCH 11/44] fix broken package name --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 34f4ced673..7487eed658 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,8 +2,7 @@ language: cpp compiler: - gcc before_install: - - sudo apt-get update -qq -y - - sudo apt-get install libboost-regex1.48.0-dev libboost-system1.48-dev libboost-thread1.48-dev libboost-test1.48-dev libboost-random1.48-dev -y + - 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 env: global: - BOOST_INCLUDES=/usr/include From 245978fd86ab70aa03c38535f475a9d1c7f241cb Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Wed, 29 May 2013 09:22:27 -0500 Subject: [PATCH 12/44] remove unneeded dependencies --- test/logger/SConscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/logger/SConscript b/test/logger/SConscript index c4db1b2611..795a263ba1 100644 --- a/test/logger/SConscript +++ b/test/logger/SConscript @@ -10,7 +10,7 @@ Import('polyfill_libs') env = env.Clone () env_cpp11 = env_cpp11.Clone () -BOOST_LIBS = boostlibs(['unit_test_framework','regex','chrono','system'],env) + [platform_libs] +BOOST_LIBS = boostlibs(['unit_test_framework','regex','system'],env) + [platform_libs] objs = env.Object('logger_basic_boost.o', ["basic.cpp"], LIBS = BOOST_LIBS) prgs = env.Program('logger_basic_boost', ["logger_basic_boost.o"], LIBS = BOOST_LIBS) From ea36bf1cf73cd45335548396912b92b8e0b3993b Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Thu, 30 May 2013 13:32:33 -0500 Subject: [PATCH 13/44] removes unused files --- websocketpp/roles/client.hpp | 44 ------------------------------------ websocketpp/roles/server.hpp | 44 ------------------------------------ 2 files changed, 88 deletions(-) delete mode 100644 websocketpp/roles/client.hpp delete mode 100644 websocketpp/roles/server.hpp diff --git a/websocketpp/roles/client.hpp b/websocketpp/roles/client.hpp deleted file mode 100644 index b09911aaa4..0000000000 --- a/websocketpp/roles/client.hpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2012, 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_CLIENT_ROLE_HPP -#define WEBSOCKETPP_CLIENT_ROLE_HPP - -#include - -namespace websocketpp { -namespace role { - -class client { -public: - static bool is_server = false; -} - -} // namespace role -} // namespace websocketpp - -#endif //WEBSOCKETPP_CLIENT_ROLE_HPP \ No newline at end of file diff --git a/websocketpp/roles/server.hpp b/websocketpp/roles/server.hpp deleted file mode 100644 index b0e875cd41..0000000000 --- a/websocketpp/roles/server.hpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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: - * * 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_SERVER_ROLE_HPP -#define WEBSOCKETPP_SERVER_ROLE_HPP - -#include - -namespace websocketpp { -namespace role { - -class server { -public: - static bool is_server = true; -} - -} // namespace role -} // namespace websocketpp - -#endif //WEBSOCKETPP_SERVER_ROLE_HPP \ No newline at end of file From fcac7071eba44fc4665f97d781be49d17df9c202 Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Thu, 30 May 2013 13:32:45 -0500 Subject: [PATCH 14/44] adds documentation --- Doxyfile | 8 ++++---- websocketpp/concurrency/basic.hpp | 1 + websocketpp/concurrency/none.hpp | 1 + websocketpp/config/asio.hpp | 1 + websocketpp/config/asio_client.hpp | 1 + websocketpp/config/asio_no_tls.hpp | 1 + websocketpp/config/asio_no_tls_client.hpp | 1 + websocketpp/config/core.hpp | 1 + websocketpp/config/core_client.hpp | 1 + websocketpp/config/debug.hpp | 1 + websocketpp/config/debug_asio.hpp | 1 + websocketpp/config/debug_asio_no_tls.hpp | 1 + websocketpp/connection.hpp | 2 +- websocketpp/endpoint.hpp | 2 +- websocketpp/logger/basic.hpp | 1 + websocketpp/logger/stub.hpp | 2 +- websocketpp/md5/md5.hpp | 1 + websocketpp/processors/hybi13.hpp | 1 + websocketpp/processors/processor.hpp | 7 ++++--- websocketpp/random/none.hpp | 1 + websocketpp/random/random_device.hpp | 1 + websocketpp/sha1/sha1.hpp | 1 + websocketpp/transport/asio/base.hpp | 1 + websocketpp/transport/base/endpoint.hpp | 1 + websocketpp/transport/iostream/base.hpp | 1 + websocketpp/utf8_validator.hpp | 3 ++- 26 files changed, 33 insertions(+), 11 deletions(-) diff --git a/Doxyfile b/Doxyfile index 6640b84f57..2bb390bb68 100644 --- a/Doxyfile +++ b/Doxyfile @@ -668,7 +668,7 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = +INPUT = websocketpp # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is @@ -948,13 +948,13 @@ HTML_EXTRA_FILES = # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # The allowed range is 0 to 359. -HTML_COLORSTYLE_HUE = 220 +HTML_COLORSTYLE_HUE = 236 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of # the colors in the HTML output. For a value of 0 the output will use # grayscales only. A value of 255 will produce the most vivid colors. -HTML_COLORSTYLE_SAT = 100 +HTML_COLORSTYLE_SAT = 0 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to # the luminance component of the colors in the HTML output. Values below @@ -963,7 +963,7 @@ HTML_COLORSTYLE_SAT = 100 # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, # and 100 does not change the gamma. -HTML_COLORSTYLE_GAMMA = 80 +HTML_COLORSTYLE_GAMMA = 148 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting diff --git a/websocketpp/concurrency/basic.hpp b/websocketpp/concurrency/basic.hpp index e9a2aa6ee7..ed2fb7d606 100644 --- a/websocketpp/concurrency/basic.hpp +++ b/websocketpp/concurrency/basic.hpp @@ -33,6 +33,7 @@ namespace websocketpp { namespace concurrency { +/// Concurrency policy that uses std::mutex / boost::mutex class basic { public: typedef lib::mutex mutex_type; diff --git a/websocketpp/concurrency/none.hpp b/websocketpp/concurrency/none.hpp index 1826b17e20..d5d0b14121 100644 --- a/websocketpp/concurrency/none.hpp +++ b/websocketpp/concurrency/none.hpp @@ -58,6 +58,7 @@ public: } // namespace none_impl +/// Stub Concurrency policy to remove locking in single threaded projects class none { public: typedef none_impl::fake_mutex mutex_type; diff --git a/websocketpp/config/asio.hpp b/websocketpp/config/asio.hpp index 7b794364d4..d0fed07c17 100644 --- a/websocketpp/config/asio.hpp +++ b/websocketpp/config/asio.hpp @@ -39,6 +39,7 @@ namespace websocketpp { namespace config { +/// Server config with asio transport and TLS enabled struct asio_tls : public core { typedef asio_tls type; typedef core base; diff --git a/websocketpp/config/asio_client.hpp b/websocketpp/config/asio_client.hpp index 0c03142ecb..b145940609 100644 --- a/websocketpp/config/asio_client.hpp +++ b/websocketpp/config/asio_client.hpp @@ -39,6 +39,7 @@ namespace websocketpp { namespace config { +/// Client config with asio transport and TLS enabled struct asio_tls_client : public core_client { typedef asio_tls_client type; typedef core_client base; diff --git a/websocketpp/config/asio_no_tls.hpp b/websocketpp/config/asio_no_tls.hpp index 6b7bebe3bd..71e2135485 100644 --- a/websocketpp/config/asio_no_tls.hpp +++ b/websocketpp/config/asio_no_tls.hpp @@ -34,6 +34,7 @@ namespace websocketpp { namespace config { +/// Server config with asio transport and TLS disabled struct asio : public core { typedef asio type; typedef core base; diff --git a/websocketpp/config/asio_no_tls_client.hpp b/websocketpp/config/asio_no_tls_client.hpp index 8f866ff43a..ab80bb0ae0 100644 --- a/websocketpp/config/asio_no_tls_client.hpp +++ b/websocketpp/config/asio_no_tls_client.hpp @@ -34,6 +34,7 @@ namespace websocketpp { namespace config { +/// Client config with asio transport and TLS disabled struct asio_client : public core_client { typedef asio_client type; typedef core_client base; diff --git a/websocketpp/config/core.hpp b/websocketpp/config/core.hpp index db90e2e08c..48e24a9a1f 100644 --- a/websocketpp/config/core.hpp +++ b/websocketpp/config/core.hpp @@ -63,6 +63,7 @@ namespace websocketpp { namespace config { +/// Server config with iostream transport struct core { typedef core type; diff --git a/websocketpp/config/core_client.hpp b/websocketpp/config/core_client.hpp index 777981805c..fb68209ce3 100644 --- a/websocketpp/config/core_client.hpp +++ b/websocketpp/config/core_client.hpp @@ -63,6 +63,7 @@ namespace websocketpp { namespace config { +/// Client config with iostream transport struct core_client { typedef core_client type; diff --git a/websocketpp/config/debug.hpp b/websocketpp/config/debug.hpp index 64b6206e5a..5d9d6bbaed 100644 --- a/websocketpp/config/debug.hpp +++ b/websocketpp/config/debug.hpp @@ -64,6 +64,7 @@ namespace websocketpp { namespace config { +/// Client/Server debug config with iostream transport struct debug_core { typedef debug_core type; diff --git a/websocketpp/config/debug_asio.hpp b/websocketpp/config/debug_asio.hpp index 1545f10a7e..becf5480f2 100644 --- a/websocketpp/config/debug_asio.hpp +++ b/websocketpp/config/debug_asio.hpp @@ -39,6 +39,7 @@ namespace websocketpp { namespace config { +/// Client/Server debug config with asio transport and TLS enabled struct debug_asio_tls : public debug_core { typedef debug_asio_tls type; typedef debug_core base; diff --git a/websocketpp/config/debug_asio_no_tls.hpp b/websocketpp/config/debug_asio_no_tls.hpp index 81c7f40d5b..d9aec66c12 100644 --- a/websocketpp/config/debug_asio_no_tls.hpp +++ b/websocketpp/config/debug_asio_no_tls.hpp @@ -34,6 +34,7 @@ namespace websocketpp { namespace config { +/// Client/Server debug config with asio transport and TLS disabled struct debug_asio : public debug_core { typedef debug_asio type; typedef debug_core base; diff --git a/websocketpp/connection.hpp b/websocketpp/connection.hpp index d43408135c..11e401437c 100644 --- a/websocketpp/connection.hpp +++ b/websocketpp/connection.hpp @@ -113,7 +113,7 @@ namespace internal_state { } // namespace internal_state } // namespace session -// impliments the websocket state machine +/// Represents an individual WebSocket connection template class connection : public config::transport_type::transport_con_type diff --git a/websocketpp/endpoint.hpp b/websocketpp/endpoint.hpp index 63b7579c6c..6e08127472 100644 --- a/websocketpp/endpoint.hpp +++ b/websocketpp/endpoint.hpp @@ -38,7 +38,7 @@ namespace websocketpp { static const char user_agent[] = "WebSocket++/0.3.0dev"; -// creates and manages connections +/// Creates and manages connections associated with a WebSocket endpoint template class endpoint : public config::transport_type, public config::endpoint_base { public: diff --git a/websocketpp/logger/basic.hpp b/websocketpp/logger/basic.hpp index 91b0001f2d..144a00dd19 100644 --- a/websocketpp/logger/basic.hpp +++ b/websocketpp/logger/basic.hpp @@ -49,6 +49,7 @@ namespace websocketpp { namespace log { +/// Basic logger that outputs to an ostream template class basic { public: diff --git a/websocketpp/logger/stub.hpp b/websocketpp/logger/stub.hpp index 41cd30b5b6..4a73c67af6 100644 --- a/websocketpp/logger/stub.hpp +++ b/websocketpp/logger/stub.hpp @@ -35,7 +35,7 @@ namespace websocketpp { namespace log { -/// Stub logger that ignores all input! +/// Stub logger that ignores all input class stub { public: stub(std::ostream* out = &std::cout) {} diff --git a/websocketpp/md5/md5.hpp b/websocketpp/md5/md5.hpp index b06a2be82b..740b382eb3 100644 --- a/websocketpp/md5/md5.hpp +++ b/websocketpp/md5/md5.hpp @@ -70,6 +70,7 @@ #include #include +/// Provides MD5 hashing functionality namespace md5 { typedef unsigned char md5_byte_t; /* 8-bit byte */ diff --git a/websocketpp/processors/hybi13.hpp b/websocketpp/processors/hybi13.hpp index b4ee5f53ed..6231d678f6 100644 --- a/websocketpp/processors/hybi13.hpp +++ b/websocketpp/processors/hybi13.hpp @@ -54,6 +54,7 @@ namespace websocketpp { namespace processor { +/// Processor for Hybi version 13 (RFC6455) template class hybi13 : public processor { public: diff --git a/websocketpp/processors/processor.hpp b/websocketpp/processors/processor.hpp index cde2f58c39..60c62e1555 100644 --- a/websocketpp/processors/processor.hpp +++ b/websocketpp/processors/processor.hpp @@ -153,6 +153,7 @@ uri_ptr get_uri_from_host(request_type & request, std::string scheme) { // } // } +/// WebSocket protocol processor base class template class processor { public: @@ -193,9 +194,9 @@ public: /// validate a WebSocket handshake request for this version /** - * @param r The WebSocket handshake request to validate. - * is_websocket_handshake(r) must be true and get_websocket_version(r) - * must equal this->get_version(). + * @param request The WebSocket handshake request to validate. + * is_websocket_handshake(request) must be true and + * get_websocket_version(request) must equal this->get_version(). * * @return A status code, 0 on success, non-zero for specific sorts of * failure diff --git a/websocketpp/random/none.hpp b/websocketpp/random/none.hpp index c2d3e20fdd..bd740021df 100644 --- a/websocketpp/random/none.hpp +++ b/websocketpp/random/none.hpp @@ -30,6 +30,7 @@ namespace websocketpp { namespace random { +/// Stub RNG policy that always returns 0 namespace none { /// Thread safe stub "random" integer generator. diff --git a/websocketpp/random/random_device.hpp b/websocketpp/random/random_device.hpp index 47d06a7a4c..fec2bb65a5 100644 --- a/websocketpp/random/random_device.hpp +++ b/websocketpp/random/random_device.hpp @@ -32,6 +32,7 @@ namespace websocketpp { namespace random { +/// RNG policy based on std::random_device or boost::random_device namespace random_device { /// Thread safe non-deterministic random integer generator. diff --git a/websocketpp/sha1/sha1.hpp b/websocketpp/sha1/sha1.hpp index 83aeecda50..931f9ddd16 100755 --- a/websocketpp/sha1/sha1.hpp +++ b/websocketpp/sha1/sha1.hpp @@ -30,6 +30,7 @@ namespace websocketpp { +/// Provides SHA1 hashing functionality class SHA1 { public: diff --git a/websocketpp/transport/asio/base.hpp b/websocketpp/transport/asio/base.hpp index f313b916e4..fa260b4fc7 100644 --- a/websocketpp/transport/asio/base.hpp +++ b/websocketpp/transport/asio/base.hpp @@ -38,6 +38,7 @@ namespace websocketpp { namespace transport { +/// Transport policy that uses boost::asio namespace asio { typedef lib::function diff --git a/websocketpp/transport/base/endpoint.hpp b/websocketpp/transport/base/endpoint.hpp index a4ccec0ac0..3d203c2f6d 100644 --- a/websocketpp/transport/base/endpoint.hpp +++ b/websocketpp/transport/base/endpoint.hpp @@ -37,6 +37,7 @@ #include namespace websocketpp { +/// Transport policies provide network connectivity and timers namespace transport { // Endpoint callbacks diff --git a/websocketpp/transport/iostream/base.hpp b/websocketpp/transport/iostream/base.hpp index 6818de4121..c86e8255a6 100644 --- a/websocketpp/transport/iostream/base.hpp +++ b/websocketpp/transport/iostream/base.hpp @@ -35,6 +35,7 @@ namespace websocketpp { namespace transport { +/// Transport policy that uses STL iostream for I/O and does not support timers namespace iostream { namespace error { diff --git a/websocketpp/utf8_validator.hpp b/websocketpp/utf8_validator.hpp index 58b3391628..61ea988406 100644 --- a/websocketpp/utf8_validator.hpp +++ b/websocketpp/utf8_validator.hpp @@ -40,7 +40,8 @@ decode(uint32_t* state, uint32_t* codep, uint8_t byte) { *state = utf8d[256 + *state*16 + type]; return *state; } - + +/// Provides streaming UTF8 validation functionality class validator { public: validator() : m_state(UTF8_ACCEPT),m_codepoint(0) {} From e8aa1e0e125b919e750cf40799bc272833e1f07c Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Thu, 30 May 2013 17:50:10 -0500 Subject: [PATCH 15/44] consolodates md5 code --- websocketpp/{md5 => common}/md5.hpp | 54 ++-- websocketpp/md5/md5.c | 381 ---------------------------- websocketpp/md5/md5.h | 93 ------- 3 files changed, 24 insertions(+), 504 deletions(-) rename websocketpp/{md5 => common}/md5.hpp (92%) delete mode 100644 websocketpp/md5/md5.c delete mode 100644 websocketpp/md5/md5.h diff --git a/websocketpp/md5/md5.hpp b/websocketpp/common/md5.hpp similarity index 92% rename from websocketpp/md5/md5.hpp rename to websocketpp/common/md5.hpp index 740b382eb3..352521cb99 100644 --- a/websocketpp/md5/md5.hpp +++ b/websocketpp/common/md5.hpp @@ -1,8 +1,8 @@ /* - md5.hpp is a reformulation of the md5.h and md5.c code (included) to allow it to - function as a component of a header only library. This conversion was done by Peter - Thorson (webmaster@zaphoyd.com) in 2012 for the WebSocket++ project. The changes are - released under the same license as the original (listed below) + md5.hpp is a reformulation of the md5.h and md5.c code to allow it to function + as a component of a header only library. This conversion was done by Peter + Thorson (webmaster@zaphoyd.com) in 2012 for the WebSocket++ project. The + changes are released under the same license as the original (listed below) */ /* Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. @@ -53,8 +53,8 @@ 1999-05-03 lpd Original version. */ -#ifndef md5_INCLUDED -# define md5_INCLUDED +#ifndef WEBSOCKETPP_COMMON_MD5_HPP +#define WEBSOCKETPP_COMMON_MD5_HPP /* * This package supports both compile-time and run-time determination of CPU @@ -70,6 +70,7 @@ #include #include +namespace websocketpp { /// Provides MD5 hashing functionality namespace md5 { @@ -87,7 +88,7 @@ typedef struct md5_state_s { inline void md5_init(md5_state_t *pms); /* Append a string to the message. */ -inline void md5_append(md5_state_t *pms, const md5_byte_t *data, size_t nbytes); +inline void md5_append(md5_state_t *pms, md5_byte_t const * data, size_t nbytes); /* Finish the message and return the digest. */ inline void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); @@ -165,9 +166,7 @@ inline void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); #define ZSW_MD5_T63 0x2ad7d2bb #define ZSW_MD5_T64 /* 0xeb86d391 */ (ZSW_MD5_T_MASK ^ 0x14792c6e) -static void -md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) -{ +static void md5_process(md5_state_t *pms, md5_byte_t const * data /*[64]*/) { md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], d = pms->abcd[3]; @@ -178,7 +177,7 @@ md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) #else /* Define storage for little-endian or both types of CPUs. */ md5_word_t xbuf[16]; - const md5_word_t *X; + md5_word_t const * X; #endif { @@ -188,9 +187,9 @@ md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) * little-endian machine, since we can use a more efficient * algorithm on the latter. */ - static const int w = 1; + static int const w = 1; - if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ + if (*((md5_byte_t const *)&w)) /* dynamic little-endian */ #endif #if ZSW_MD5_BYTE_ORDER <= 0 /* little-endian */ { @@ -198,9 +197,9 @@ md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) * On little-endian machines, we can process properly aligned * data without copying it. */ - if (!((data - (const md5_byte_t *)0) & 3)) { + if (!((data - (md5_byte_t const *)0) & 3)) { /* data are properly aligned */ - X = (const md5_word_t *)data; + X = (md5_word_t const *)data; } else { /* not aligned */ std::memcpy(xbuf, data, 64); @@ -346,9 +345,7 @@ md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) pms->abcd[3] += d; } -void -md5_init(md5_state_t *pms) -{ +void md5_init(md5_state_t *pms) { pms->count[0] = pms->count[1] = 0; pms->abcd[0] = 0x67452301; pms->abcd[1] = /*0xefcdab89*/ ZSW_MD5_T_MASK ^ 0x10325476; @@ -356,10 +353,8 @@ md5_init(md5_state_t *pms) pms->abcd[3] = 0x10325476; } -void -md5_append(md5_state_t *pms, const md5_byte_t *data, size_t nbytes) -{ - const md5_byte_t *p = data; +void md5_append(md5_state_t *pms, md5_byte_t const * data, size_t nbytes) { + md5_byte_t const * p = data; size_t left = nbytes; int offset = (pms->count[0] >> 3) & 63; md5_word_t nbits = (md5_word_t)(nbytes << 3); @@ -394,10 +389,8 @@ md5_append(md5_state_t *pms, const md5_byte_t *data, size_t nbytes) std::memcpy(pms->buf, p, left); } -void -md5_finish(md5_state_t *pms, md5_byte_t digest[16]) -{ - static const md5_byte_t pad[64] = { +void md5_finish(md5_state_t *pms, md5_byte_t digest[16]) { + static md5_byte_t const pad[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -418,13 +411,13 @@ md5_finish(md5_state_t *pms, md5_byte_t digest[16]) } // some convenience c++ functions -inline std::string md5_hash_string(const std::string& s) { +inline std::string md5_hash_string(std::string const & s) { char digest[16]; md5_state_t state; md5_init(&state); - md5_append(&state, (const md5_byte_t *)s.c_str(), s.size()); + md5_append(&state, (md5_byte_t const *)s.c_str(), s.size()); md5_finish(&state, (md5_byte_t *)digest); std::string ret; @@ -436,7 +429,7 @@ inline std::string md5_hash_string(const std::string& s) { const char hexval[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; -inline std::string md5_hash_hex(const std::string& input) { +inline std::string md5_hash_hex(std::string const & input) { std::string hash = md5_hash_string(input); std::string hex; @@ -449,5 +442,6 @@ inline std::string md5_hash_hex(const std::string& input) { } } // md5 +} // websocketpp -#endif // md5_INCLUDED +#endif // WEBSOCKETPP_COMMON_MD5_HPP diff --git a/websocketpp/md5/md5.c b/websocketpp/md5/md5.c deleted file mode 100644 index bc8e872b4c..0000000000 --- a/websocketpp/md5/md5.c +++ /dev/null @@ -1,381 +0,0 @@ -/* - Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - L. Peter Deutsch - ghost@aladdin.com - - */ -/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ -/* - Independent implementation of MD5 (RFC 1321). - - This code implements the MD5 Algorithm defined in RFC 1321, whose - text is available at - http://www.ietf.org/rfc/rfc1321.txt - The code is derived from the text of the RFC, including the test suite - (section A.5) but excluding the rest of Appendix A. It does not include - any code or documentation that is identified in the RFC as being - copyrighted. - - The original and principal author of md5.c is L. Peter Deutsch - . Other authors are noted in the change history - that follows (in reverse chronological order): - - 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order - either statically or dynamically; added missing #include - in library. - 2002-03-11 lpd Corrected argument list for main(), and added int return - type, in test program and T value program. - 2002-02-21 lpd Added missing #include in test program. - 2000-07-03 lpd Patched to eliminate warnings about "constant is - unsigned in ANSI C, signed in traditional"; made test program - self-checking. - 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. - 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). - 1999-05-03 lpd Original version. - */ - -#include "md5.h" -#include - -#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ -#ifdef ARCH_IS_BIG_ENDIAN -# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) -#else -# define BYTE_ORDER 0 -#endif - -#define T_MASK ((md5_word_t)~0) -#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) -#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) -#define T3 0x242070db -#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) -#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) -#define T6 0x4787c62a -#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) -#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) -#define T9 0x698098d8 -#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) -#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) -#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) -#define T13 0x6b901122 -#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) -#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) -#define T16 0x49b40821 -#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) -#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) -#define T19 0x265e5a51 -#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) -#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) -#define T22 0x02441453 -#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) -#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) -#define T25 0x21e1cde6 -#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) -#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) -#define T28 0x455a14ed -#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) -#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) -#define T31 0x676f02d9 -#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) -#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) -#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) -#define T35 0x6d9d6122 -#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) -#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) -#define T38 0x4bdecfa9 -#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) -#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) -#define T41 0x289b7ec6 -#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) -#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) -#define T44 0x04881d05 -#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) -#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) -#define T47 0x1fa27cf8 -#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) -#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) -#define T50 0x432aff97 -#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) -#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) -#define T53 0x655b59c3 -#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) -#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) -#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) -#define T57 0x6fa87e4f -#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) -#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) -#define T60 0x4e0811a1 -#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) -#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) -#define T63 0x2ad7d2bb -#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) - - -static void -md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) -{ - md5_word_t - a = pms->abcd[0], b = pms->abcd[1], - c = pms->abcd[2], d = pms->abcd[3]; - md5_word_t t; -#if BYTE_ORDER > 0 - /* Define storage only for big-endian CPUs. */ - md5_word_t X[16]; -#else - /* Define storage for little-endian or both types of CPUs. */ - md5_word_t xbuf[16]; - const md5_word_t *X; -#endif - - { -#if BYTE_ORDER == 0 - /* - * Determine dynamically whether this is a big-endian or - * little-endian machine, since we can use a more efficient - * algorithm on the latter. - */ - static const int w = 1; - - if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ -#endif -#if BYTE_ORDER <= 0 /* little-endian */ - { - /* - * On little-endian machines, we can process properly aligned - * data without copying it. - */ - if (!((data - (const md5_byte_t *)0) & 3)) { - /* data are properly aligned */ - X = (const md5_word_t *)data; - } else { - /* not aligned */ - memcpy(xbuf, data, 64); - X = xbuf; - } - } -#endif -#if BYTE_ORDER == 0 - else /* dynamic big-endian */ -#endif -#if BYTE_ORDER >= 0 /* big-endian */ - { - /* - * On big-endian machines, we must arrange the bytes in the - * right order. - */ - const md5_byte_t *xp = data; - int i; - -# if BYTE_ORDER == 0 - X = xbuf; /* (dynamic only) */ -# else -# define xbuf X /* (static only) */ -# endif - for (i = 0; i < 16; ++i, xp += 4) - xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); - } -#endif - } - -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) - - /* Round 1. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ -#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + F(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 7, T1); - SET(d, a, b, c, 1, 12, T2); - SET(c, d, a, b, 2, 17, T3); - SET(b, c, d, a, 3, 22, T4); - SET(a, b, c, d, 4, 7, T5); - SET(d, a, b, c, 5, 12, T6); - SET(c, d, a, b, 6, 17, T7); - SET(b, c, d, a, 7, 22, T8); - SET(a, b, c, d, 8, 7, T9); - SET(d, a, b, c, 9, 12, T10); - SET(c, d, a, b, 10, 17, T11); - SET(b, c, d, a, 11, 22, T12); - SET(a, b, c, d, 12, 7, T13); - SET(d, a, b, c, 13, 12, T14); - SET(c, d, a, b, 14, 17, T15); - SET(b, c, d, a, 15, 22, T16); -#undef SET - - /* Round 2. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ -#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + G(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 1, 5, T17); - SET(d, a, b, c, 6, 9, T18); - SET(c, d, a, b, 11, 14, T19); - SET(b, c, d, a, 0, 20, T20); - SET(a, b, c, d, 5, 5, T21); - SET(d, a, b, c, 10, 9, T22); - SET(c, d, a, b, 15, 14, T23); - SET(b, c, d, a, 4, 20, T24); - SET(a, b, c, d, 9, 5, T25); - SET(d, a, b, c, 14, 9, T26); - SET(c, d, a, b, 3, 14, T27); - SET(b, c, d, a, 8, 20, T28); - SET(a, b, c, d, 13, 5, T29); - SET(d, a, b, c, 2, 9, T30); - SET(c, d, a, b, 7, 14, T31); - SET(b, c, d, a, 12, 20, T32); -#undef SET - - /* Round 3. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + H(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 5, 4, T33); - SET(d, a, b, c, 8, 11, T34); - SET(c, d, a, b, 11, 16, T35); - SET(b, c, d, a, 14, 23, T36); - SET(a, b, c, d, 1, 4, T37); - SET(d, a, b, c, 4, 11, T38); - SET(c, d, a, b, 7, 16, T39); - SET(b, c, d, a, 10, 23, T40); - SET(a, b, c, d, 13, 4, T41); - SET(d, a, b, c, 0, 11, T42); - SET(c, d, a, b, 3, 16, T43); - SET(b, c, d, a, 6, 23, T44); - SET(a, b, c, d, 9, 4, T45); - SET(d, a, b, c, 12, 11, T46); - SET(c, d, a, b, 15, 16, T47); - SET(b, c, d, a, 2, 23, T48); -#undef SET - - /* Round 4. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ -#define I(x, y, z) ((y) ^ ((x) | ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + I(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 6, T49); - SET(d, a, b, c, 7, 10, T50); - SET(c, d, a, b, 14, 15, T51); - SET(b, c, d, a, 5, 21, T52); - SET(a, b, c, d, 12, 6, T53); - SET(d, a, b, c, 3, 10, T54); - SET(c, d, a, b, 10, 15, T55); - SET(b, c, d, a, 1, 21, T56); - SET(a, b, c, d, 8, 6, T57); - SET(d, a, b, c, 15, 10, T58); - SET(c, d, a, b, 6, 15, T59); - SET(b, c, d, a, 13, 21, T60); - SET(a, b, c, d, 4, 6, T61); - SET(d, a, b, c, 11, 10, T62); - SET(c, d, a, b, 2, 15, T63); - SET(b, c, d, a, 9, 21, T64); -#undef SET - - /* Then perform the following additions. (That is increment each - of the four registers by the value it had before this block - was started.) */ - pms->abcd[0] += a; - pms->abcd[1] += b; - pms->abcd[2] += c; - pms->abcd[3] += d; -} - -void -md5_init(md5_state_t *pms) -{ - pms->count[0] = pms->count[1] = 0; - pms->abcd[0] = 0x67452301; - pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; - pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; - pms->abcd[3] = 0x10325476; -} - -void -md5_append(md5_state_t *pms, const md5_byte_t *data, size_t nbytes) -{ - const md5_byte_t *p = data; - size_t left = nbytes; - int offset = (pms->count[0] >> 3) & 63; - md5_word_t nbits = (md5_word_t)(nbytes << 3); - - if (nbytes <= 0) - return; - - /* Update the message length. */ - pms->count[1] += nbytes >> 29; - pms->count[0] += nbits; - if (pms->count[0] < nbits) - pms->count[1]++; - - /* Process an initial partial block. */ - if (offset) { - int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); - - memcpy(pms->buf + offset, p, copy); - if (offset + copy < 64) - return; - p += copy; - left -= copy; - md5_process(pms, pms->buf); - } - - /* Process full blocks. */ - for (; left >= 64; p += 64, left -= 64) - md5_process(pms, p); - - /* Process a final partial block. */ - if (left) - memcpy(pms->buf, p, left); -} - -void -md5_finish(md5_state_t *pms, md5_byte_t digest[16]) -{ - static const md5_byte_t pad[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - md5_byte_t data[8]; - int i; - - /* Save the length before padding. */ - for (i = 0; i < 8; ++i) - data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); - /* Pad to 56 bytes mod 64. */ - md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); - /* Append the length. */ - md5_append(pms, data, 8); - for (i = 0; i < 16; ++i) - digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); -} diff --git a/websocketpp/md5/md5.h b/websocketpp/md5/md5.h deleted file mode 100644 index 3f4d426025..0000000000 --- a/websocketpp/md5/md5.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - L. Peter Deutsch - ghost@aladdin.com - - */ -/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */ -/* - Independent implementation of MD5 (RFC 1321). - - This code implements the MD5 Algorithm defined in RFC 1321, whose - text is available at - http://www.ietf.org/rfc/rfc1321.txt - The code is derived from the text of the RFC, including the test suite - (section A.5) but excluding the rest of Appendix A. It does not include - any code or documentation that is identified in the RFC as being - copyrighted. - - The original and principal author of md5.h is L. Peter Deutsch - . Other authors are noted in the change history - that follows (in reverse chronological order): - - 2002-04-13 lpd Removed support for non-ANSI compilers; removed - references to Ghostscript; clarified derivation from RFC 1321; - now handles byte order either statically or dynamically. - 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. - 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); - added conditionalization for C++ compilation from Martin - Purschke . - 1999-05-03 lpd Original version. - */ - -#ifndef md5_INCLUDED -# define md5_INCLUDED - -/* - * This package supports both compile-time and run-time determination of CPU - * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be - * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is - * defined as non-zero, the code will be compiled to run only on big-endian - * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to - * run on either big- or little-endian CPUs, but will run slightly less - * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. - */ - -#include - -typedef unsigned char md5_byte_t; /* 8-bit byte */ -typedef unsigned int md5_word_t; /* 32-bit word */ - -/* Define the state of the MD5 Algorithm. */ -typedef struct md5_state_s { - md5_word_t count[2]; /* message length in bits, lsw first */ - md5_word_t abcd[4]; /* digest buffer */ - md5_byte_t buf[64]; /* accumulate block */ -} md5_state_t; - -#ifdef __cplusplus -extern "C" -{ -#endif - -/* Initialize the algorithm. */ -void md5_init(md5_state_t *pms); - -/* Append a string to the message. */ -void md5_append(md5_state_t *pms, const md5_byte_t *data, size_t nbytes); - -/* Finish the message and return the digest. */ -void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); - -#ifdef __cplusplus -} /* end extern "C" */ -#endif - -#endif /* md5_INCLUDED */ From dcb13d58bef54a59c73aeb913ca7463dfdbdcbf9 Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Thu, 30 May 2013 17:56:57 -0500 Subject: [PATCH 16/44] updates hybi00 to use new md5 header --- websocketpp/processors/hybi00.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/websocketpp/processors/hybi00.hpp b/websocketpp/processors/hybi00.hpp index 1b4a6cc34c..3ded374070 100644 --- a/websocketpp/processors/hybi00.hpp +++ b/websocketpp/processors/hybi00.hpp @@ -42,7 +42,7 @@ #include #include -#include +#include namespace websocketpp { namespace processor { From 38a565888f774b847e700769c3df9ae77c519ec5 Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Thu, 30 May 2013 18:05:34 -0500 Subject: [PATCH 17/44] adds documentation --- websocketpp/close.hpp | 213 +++++++++++++++++++++++----------- websocketpp/logger/levels.hpp | 102 ++++++++++++---- 2 files changed, 224 insertions(+), 91 deletions(-) diff --git a/websocketpp/close.hpp b/websocketpp/close.hpp index 1d7d4b4171..2509c34995 100644 --- a/websocketpp/close.hpp +++ b/websocketpp/close.hpp @@ -29,6 +29,10 @@ #ifndef WEBSOCKETPP_CLOSE_HPP #define WEBSOCKETPP_CLOSE_HPP +/** \file + * A package of types and methods for manipulating WebSocket close codes. + */ + #include #include #include @@ -37,60 +41,137 @@ #include namespace websocketpp { +/// A package of types and methods for manipulating WebSocket close codes. namespace close { +/// A package of types and methods for manipulating WebSocket close status' namespace status { + /// The type of a close code value. typedef uint16_t value; - // A blank value for internal use - static const value blank = 0; + /// A blank value for internal use. + static value const blank = 0; + + /// Normal closure, meaning that the purpose for which the connection was + /// established has been fulfilled. + static value const normal = 1000; + + /// The endpoint was "going away", such as a server going down or a browser + /// navigating away from a page. + static value const going_away = 1001; + + /// A protocol error occurred. + static value const protocol_error = 1002; + + /// The connection was terminated because an endpoint received a type of + /// data it cannot accept. + /** + * (e.g., an endpoint that understands only text data MAY send this if it + * receives a binary message). + */ + static value const unsupported_data = 1003; + + /// A dummy value to indicate that no status code was received. + /** + * This value is illegal on the wire. + */ + static value const no_status = 1005; + + /// A dummy value to indicate that the connection was closed abnormally. + /** + * In such a case there was no close frame to extract a value from. This + * value is illegal on the wire. + */ + static value const abnormal_close = 1006; + + /// An endpoint received message data inconsistent with its type. + /** + * For example: Invalid UTF8 bytes in a text message. + */ + static value const invalid_payload = 1007; + + /// An endpoint received a message that violated its policy. + /** + * This is a generic status code that can be returned when there is no other + * more suitable status code (e.g., 1003 or 1009) or if there is a need to + * hide specific details about the policy. + */ + static value const policy_violation = 1008; + + /// An endpoint received a message too large to process. + static value const message_too_big = 1009; + + /// A client expected the server to accept a required extension request + /** + * The list of extensions that are needed SHOULD appear in the /reason/ part + * of the Close frame. Note that this status code is not used by the server, + * because it can fail the WebSocket handshake instead. + */ + static value const extension_required = 1010; + + /// An endpoint encountered an unexpected condition that prevented it from + /// fulfilling the request. + static value const internal_endpoint_error = 1011; + + /// An endpoint failed to perform a TLS handshake + /** + * Designated for use in applications expecting a status code to indicate + * that the connection was closed due to a failure to perform a TLS + * handshake (e.g., the server certificate can't be verified). This value is + * illegal on the wire. + */ + static value const tls_handshake = 1015; + + /// First value in range reserved for future protocol use + static value const rsv_start = 1016; + /// Last value in range reserved for future protocol use + static value const rsv_end = 2999; - // Codes from RFC6455 - static const value normal = 1000; - static const value going_away = 1001; - static const value protocol_error = 1002; - static const value unsupported_data = 1003; - static const value no_status = 1005; - static const value abnormal_close = 1006; - static const value invalid_payload = 1007; - static const value policy_violation = 1008; - static const value message_too_big = 1009; - static const value extension_required = 1010; - static const value internal_endpoint_error = 1011; - static const value tls_handshake = 1015; // is this official? - - /// Ranges of values that are reserved for future protocol use - static const value rsv_start = 1016; - static const value rsv_end = 2999; - /// Test whether a close code is in a reserved range - inline bool reserved(value s) { - return ((s >= rsv_start && s <= rsv_end) || - s == 1004 || s == 1012 || s == 1013 || s == 1014); + /** + * @param [in] code The code to test + * @return Whether or not code is reserved + */ + inline bool reserved(value code) { + return ((code >= rsv_start && code <= rsv_end) || + code == 1004 || code == 1012 || code == 1013 || code == 1014); } - - // Ranges of values that are always invalid on the wire - static const value invalid_low = 999; - static const value invalid_high = 5000; - - // Test whether a close code is invalid on the wire - inline bool invalid(value s) { - return (s <= invalid_low ||s >= invalid_high || - s == no_status || s == abnormal_close || s == tls_handshake); + + /// First value in range that is always invalid on the wire + static value const invalid_low = 999; + /// Last value in range that is always invalid on the wire + static value const invalid_high = 5000; + + /// Test whether a close code is invalid on the wire + /** + * @param [in] code The code to test + * @return Whether or not code is invalid on the wire + */ + inline bool invalid(value code) { + return (code <= invalid_low || code >= invalid_high || + code == no_status || code == abnormal_close || + code == tls_handshake); } - - /// There is a class of errors for which once they are discovered normal - /// WebSocket functionality can no longer occur. This function determines - /// if a given code is one of these values. This information is used to - /// determine if the system has the capability of waiting for a close - /// acknowledgement or if it should drop the TCP connection immediately - /// after sending its close frame. - inline bool terminal(value s) { - return (s == protocol_error || s == invalid_payload || - policy_violation || message_too_big || - internal_endpoint_error); + + /// Determine if the code represents an unrecoverable error + /** + * There is a class of errors for which once they are discovered normal + * WebSocket functionality can no longer occur. This function determines + * if a given code is one of these values. This information is used to + * determine if the system has the capability of waiting for a close + * acknowledgement or if it should drop the TCP connection immediately + * after sending its close frame. + * + * @param [in] code The value to test. + * @return True if the code represents an unrecoverable error + */ + inline bool terminal(value code) { + return (code == protocol_error || code == invalid_payload || + code == policy_violation || code == message_too_big || + code == internal_endpoint_error); } } // namespace status +/// Type used to convert close statuses between integer and wire representations union code_converter { uint16_t i; char c[2]; @@ -98,22 +179,21 @@ union code_converter { /// Extract a close code value from a close payload /** - * If there is no close value (ie string is empty) status::no_status is + * If there is no close value (ie string is empty) status::no_status is * returned. If a code couldn't be extracted (usually do to a short or * otherwise mangled payload) status::protocol_error is returned and the ec * value is flagged as an error. Note that this case is different than the case * where protocol error is received over the wire. * - * If the value is in an invalid or reserved range ec is set accordingly - * - * @param payload Close frame payload value recieved over the wire. - * - * @param ec A status code, zero on success, non-zero on failure or partial - * success. See notes above. + * If the value is in an invalid or reserved range ec is set accordingly. * + * @param [in] payload Close frame payload value recieved over the wire. + * @param [out] ec Set to indicate what error occurred, if any. * @return The extracted value */ -inline status::value extract_code(const std::string& payload, lib::error_code & ec) { +inline status::value extract_code(std::string const & payload, lib::error_code + & ec) +{ ec = lib::error_code(); if (payload.size() == 0) { @@ -127,44 +207,43 @@ inline status::value extract_code(const std::string& payload, lib::error_code & val.c[0] = payload[0]; val.c[1] = payload[1]; - + status::value code(ntohs(val.i)); - + if (status::invalid(code)) { ec = make_error_code(error::invalid_close_code); } - + if (status::reserved(code)) { ec = make_error_code(error::reserved_close_code); } - + return code; } /// Extract the reason string from a close payload /** - * Extract the reason string from a close payload message. The string should be - * A valid utf8 message. An invalid_utf8 error will be set if the function - * extracts a reason that is not valid utf8. + * The string should be a valid UTF8 message. error::invalid_utf8 will be set if + * the function extracts a reason that is not valid UTF8. * - * @param payload The payload string to extract a reason from. - * - * @param ec A place to store error values, zero on success, non-zero otherwise - * - * @return the reason string. + * @param [in] payload The payload string to extract a reason from. + * @param [out] ec Set to indicate what error occurred, if any. + * @return The reason string. */ -inline std::string extract_reason(const std::string& payload, lib::error_code & ec) { - std::string reason = ""; +inline std::string extract_reason(std::string const & payload, lib::error_code + & ec) +{ + std::string reason = ""; ec = lib::error_code(); if (payload.size() > 2) { reason.append(payload.begin()+2,payload.end()); } - + if (!websocketpp::utf8_validator::validate(reason)) { ec = make_error_code(error::invalid_utf8); } - + return reason; } diff --git a/websocketpp/logger/levels.hpp b/websocketpp/logger/levels.hpp index 02b342a121..5b7f851985 100644 --- a/websocketpp/logger/levels.hpp +++ b/websocketpp/logger/levels.hpp @@ -33,19 +33,43 @@ namespace websocketpp { namespace log { +/// Type of a channel package typedef uint32_t level; +/// Package of log levels for logging errors struct elevel { - static const level none = 0x0; - static const level devel = 0x1; - static const level library = 0x2; - static const level info = 0x4; - static const level warn = 0x8; - static const level rerror = 0x10; - static const level fatal = 0x20; - static const level all = 0xffffffff; + /// Special aggregate value representing "no levels" + static level const none = 0x0; + /// Low level debugging information (warning: very chatty) + static level const devel = 0x1; + /// Information about unusual system states or other minor internal library + /// problems, less chatty than devel. + static level const library = 0x2; + /// Information about minor configuration problems or additional information + /// about other warnings. + static level const info = 0x4; + /// Information about important problems not severe enough to terminate + /// connections. + static level const warn = 0x8; + /// Recoverable error. Recovery may mean cleanly closing the connection with + /// an appropriate error code to the remote endpoint. + static level const rerror = 0x10; + /// Unrecoverable error. This error will trigger immediate unclean + /// termination of the connection or endpoint. + static level const fatal = 0x20; + /// Special aggregate value representing "all levels" + static level const all = 0xffffffff; - static const char* channel_name(level channel) { + /// Get the textual name of a channel given a channel id + /** + * The id must be that of a single channel. Passing an aggregate channel + * package results in undefined behavior. + * + * @param channel The channel id to look up. + * + * @return The name of the specified channel. + */ + static char const * channel_name(level channel) { switch(channel) { case devel: return "devel"; @@ -65,23 +89,53 @@ struct elevel { } }; +/// Package of log levels for logging access events struct alevel { - static const level none = 0x0; - static const level connect = 0x1; - static const level disconnect = 0x2; - static const level control = 0x4; - static const level frame_header = 0x8; - static const level frame_payload = 0x10; - static const level message_header = 0x20; - static const level message_payload = 0x40; - static const level endpoint = 0x80; - static const level debug_handshake = 0x100; - static const level debug_close = 0x200; - static const level devel = 0x400; - static const level app = 0x800; - static const level all = 0xffffffff; + /// Special aggregate value representing "no levels" + static level const none = 0x0; + /// Information about new connections + /** + * One line for each new connection that includes a host of information + * including: the remote address, websocket version, requested resource, + * http code, remote user agent + */ + static level const connect = 0x1; + /// One line for each closed connection. Includes closing codes and reasons. + static level const disconnect = 0x2; + /// One line per control frame + static level const control = 0x4; + /// One line per frame, includes the full frame header + static level const frame_header = 0x8; + /// One line per frame, includes the full message payload (warning: chatty) + static level const frame_payload = 0x10; + /// Reserved + static level const message_header = 0x20; + /// Reserved + static level const message_payload = 0x40; + /// Reserved + static level const endpoint = 0x80; + /// Extra information about opening handshakes + static level const debug_handshake = 0x100; + /// Extra information about closing handshakes + static level const debug_close = 0x200; + /// Development messages (warning: very chatty) + static level const devel = 0x400; + /// Special channel for application specific logs. Not used by the library. + static level const app = 0x800; + /// Special aggregate value representing "all levels" + static level const all = 0xffffffff; - static const char* channel_name(level channel) { + /// Get the textual name of a channel given a channel id + /** + * Get the textual name of a channel given a channel id. The id must be that + * of a single channel. Passing an aggregate channel package results in + * undefined behavior. + * + * @param channel The channelid to look up. + * + * @return The name of the specified channel. + */ + static char const * channel_name(level channel) { switch(channel) { case connect: return "connect"; From 808179551fa2be6cae79364fe9a23546feed472d Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Thu, 30 May 2013 23:29:48 -0500 Subject: [PATCH 18/44] remove dead code --- websocketpp/concurrency/none.hpp | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/websocketpp/concurrency/none.hpp b/websocketpp/concurrency/none.hpp index d5d0b14121..8c240e1d58 100644 --- a/websocketpp/concurrency/none.hpp +++ b/websocketpp/concurrency/none.hpp @@ -28,34 +28,21 @@ #ifndef WEBSOCKETPP_CONCURRENCY_NONE_HPP #define WEBSOCKETPP_CONCURRENCY_NONE_HPP -//#include - namespace websocketpp { namespace concurrency { namespace none_impl { class fake_mutex { public: - fake_mutex() { - //std::cout << "fake_mutex constructor: " << this << std::endl; - } - - ~fake_mutex() { - //std::cout << "fake_mutex destructor: " << this << std::endl; - } + fake_mutex() {} + ~fake_mutex() {} }; class fake_lock_guard { public: - explicit fake_lock_guard(fake_mutex foo) { - //std::cout << "fake_lock_guard constructor: " << this << " mutex: " << &foo << std::endl; - } - - ~fake_lock_guard() { - //std::cout << "fake_lock_guard destructor: " << this << std::endl; - } + explicit fake_lock_guard(fake_mutex foo) {} + ~fake_lock_guard() {} }; - } // namespace none_impl /// Stub Concurrency policy to remove locking in single threaded projects From 2e2a8e4346d503f69b7b3712b28abef01de8b356 Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Thu, 30 May 2013 23:30:04 -0500 Subject: [PATCH 19/44] documentation and reorganization --- websocketpp/frame.hpp | 256 +++++++++++++++++++++++++----------------- 1 file changed, 152 insertions(+), 104 deletions(-) diff --git a/websocketpp/frame.hpp b/websocketpp/frame.hpp index b6ffdef683..afe359515d 100644 --- a/websocketpp/frame.hpp +++ b/websocketpp/frame.hpp @@ -36,32 +36,42 @@ #include namespace websocketpp { +/// Data structures and utility functions for manipulating WebSocket frames /** * namespace frame provides a number of data structures and utility functions * for reading, writing, and manipulating binary encoded WebSocket frames. */ namespace frame { -static const unsigned int BASIC_HEADER_LENGTH = 2; -static const unsigned int MAX_HEADER_LENGTH = 14; -static const unsigned int MAX_EXTENDED_HEADER_LENGTH = 12; +/// Minimum length of a WebSocket frame header. +static unsigned int const BASIC_HEADER_LENGTH = 2; +/// Maximum length of a WebSocket header +static unsigned int const MAX_HEADER_LENGTH = 14; +/// Maximum length of the variable portion of the WebSocket header +static unsigned int const MAX_EXTENDED_HEADER_LENGTH = 12; +/// Two byte conversion union union uint16_converter { uint16_t i; uint8_t c[2]; }; +/// Four byte conversion union union uint32_converter { uint32_t i; uint8_t c[4]; }; +/// Eight byte conversion union union uint64_converter { uint64_t i; uint8_t c[8]; }; -// WebSocket Opcodes are 4 bits. See spec section 5.2 +/// Constants and utility functions related to WebSocket opcodes +/** + * WebSocket Opcodes are 4 bits. See RFC6455 section 5.2. + */ namespace opcode { enum value { continuation = 0x0, @@ -98,50 +108,83 @@ namespace opcode { CONTROL_RSVE = 0xE, CONTROL_RSVF = 0xF }; - + + /// Check if an opcode is reserved + /** + * @param v The opcode to test. + * @return Whether or not the opcode is reserved. + */ inline bool reserved(value v) { - return (v >= RSV3 && v <= RSV7) || - (v >= CONTROL_RSVB && v <= CONTROL_RSVF); + return (v >= rsv3 && v <= rsv7) || + (v >= control_rsvb && v <= control_rsvf); } - + + /// Check if an opcode is invalid + /** + * Invalid opcodes are negative or require greater than 4 bits to store. + * + * @param v The opcode to test. + * @return Whether or not the opcode is invalid. + */ inline bool invalid(value v) { return (v > 0xF || v < 0); } - + + /// Check if an opcode is for a control frame + /** + * @param v The opcode to test. + * @return Whether or not the opcode is a control opcode. + */ inline bool is_control(value v) { return v >= 0x8; } } +/// Constants related to frame and payload limits namespace limits { + /// Minimum length of a WebSocket frame header. + static unsigned int const basic_header_length = 2; + + /// Maximum length of a WebSocket header + static unsigned int const max_header_length = 14; + + /// Maximum length of the variable portion of the WebSocket header + static unsigned int const max_extended_header_length = 12; + /// Maximum size of a basic WebSocket payload - static const uint8_t payload_size_basic = 125; + static uint8_t const payload_size_basic = 125; + /// Maximum size of an extended WebSocket payload (basic payload = 126) - static const uint16_t payload_size_extended = 0xFFFF; // 2^16, 65535 + static uint16_t const payload_size_extended = 0xFFFF; // 2^16, 65535 + /// Maximum size of a jumbo WebSocket payload (basic payload = 127) - static const uint64_t payload_size_jumbo = 0x7FFFFFFFFFFFFFFFLL;//2^63 + static uint64_t const payload_size_jumbo = 0x7FFFFFFFFFFFFFFFLL;//2^63 + /// Maximum size of close frame reason - /// This is payload_size_basic - 2 bytes (as first two bytes are used for - //// the close code - static const uint8_t close_reason_size = 123; + /** + * This is payload_size_basic - 2 bytes (as first two bytes are used for + * the close code + */ + static uint8_t const close_reason_size = 123; } // masks for fields in the basic header -static const uint8_t BHB0_OPCODE = 0x0F; -static const uint8_t BHB0_RSV3 = 0x10; -static const uint8_t BHB0_RSV2 = 0x20; -static const uint8_t BHB0_RSV1 = 0x40; -static const uint8_t BHB0_FIN = 0x80; +static uint8_t const BHB0_OPCODE = 0x0F; +static uint8_t const BHB0_RSV3 = 0x10; +static uint8_t const BHB0_RSV2 = 0x20; +static uint8_t const BHB0_RSV1 = 0x40; +static uint8_t const BHB0_FIN = 0x80; -static const uint8_t BHB1_PAYLOAD = 0x7F; -static const uint8_t BHB1_MASK = 0x80; +static uint8_t const BHB1_PAYLOAD = 0x7F; +static uint8_t const BHB1_MASK = 0x80; -static const uint8_t payload_size_code_16bit = 0x7E; // 126 -static const uint8_t payload_size_code_64bit = 0x7F; // 127 +static uint8_t const payload_size_code_16bit = 0x7E; // 126 +static uint8_t const payload_size_code_64bit = 0x7F; // 127 typedef uint32_converter masking_key_type; +/// The constant size component of a WebSocket frame header struct basic_header { basic_header() : b0(0x00),b1(0x00) {} @@ -187,6 +230,7 @@ struct basic_header { uint8_t b1; }; +/// The variable size component of a WebSocket frame header struct extended_header { extended_header() { std::fill_n(this->bytes,MAX_EXTENDED_HEADER_LENGTH,0x00); @@ -229,64 +273,66 @@ private: } }; -// Forward function declarations -bool get_fin(const basic_header &); -bool get_rsv1(const basic_header &); -bool get_rsv2(const basic_header &); -bool get_rsv3(const basic_header &); -opcode::value get_opcode(const basic_header &); -bool get_masked(const basic_header &); -uint8_t get_basic_size(const basic_header &); -size_t get_header_len(const basic_header &); -unsigned int get_masking_key_offset(const basic_header &); +bool get_fin(basic_header const &h); +void set_fin(basic_header &h, bool value); +bool get_rsv1(basic_header const &h); +void set_rsv1(basic_header &h, bool value); +bool get_rsv2(basic_header const &h); +void set_rsv2(basic_header &h, bool value); +bool get_rsv3(basic_header const &h); +void set_rsv3(basic_header &h, bool value); +opcode::value get_opcode(basic_header const &h); +bool get_masked(basic_header const &h); +void set_masked(basic_header &h, bool value); +uint8_t get_basic_size(basic_header const &); +size_t get_header_len(basic_header const &); +unsigned int get_masking_key_offset(basic_header const &); -std::string write_header(const basic_header &, const extended_header &); +std::string write_header(basic_header const &, extended_header const &); +masking_key_type get_masking_key(basic_header const &, extended_header const &); +uint16_t get_extended_size(extended_header const &); +uint64_t get_jumbo_size(extended_header const &); +uint64_t get_payload_size(basic_header const &, extended_header const &); -masking_key_type get_masking_key(const basic_header &, const extended_header &); -uint16_t get_extended_size(const extended_header &); -uint64_t get_jumbo_size(const extended_header &); -uint64_t get_payload_size(const basic_header &, const extended_header &); - -size_t prepare_masking_key(const masking_key_type& key); +size_t prepare_masking_key(masking_key_type const & key); size_t circshift_prepared_key(size_t prepared_key, size_t offset); // Functions for performing xor based masking and unmasking template -void byte_mask(iter_type b, iter_type e, iter_type o, const masking_key_type& +void byte_mask(iter_type b, iter_type e, iter_type o, masking_key_type const & key, size_t key_offset = 0); template -void byte_mask(iter_type b, iter_type e, const masking_key_type& key, +void byte_mask(iter_type b, iter_type e, masking_key_type const & key, size_t key_offset = 0); -void word_mask_exact(uint8_t* input, uint8_t* output, size_t length, - const masking_key_type& key); -void word_mask_exact(uint8_t* data, size_t length, const masking_key_type& key); -size_t word_mask_circ(uint8_t* input, uint8_t* output, size_t length, +void word_mask_exact(uint8_t * input, uint8_t * output, size_t length, + masking_key_type const & key); +void word_mask_exact(uint8_t * data, size_t length, masking_key_type const & + key); +size_t word_mask_circ(uint8_t * input, uint8_t * output, size_t length, size_t prepared_key); -size_t word_mask_circ(uint8_t* data, size_t length, size_t prepared_key); +size_t word_mask_circ(uint8_t * data, size_t length, size_t prepared_key); - -// Function implimentation - -/// check whether the frame's FIN bit is set +/// Check whether the frame's FIN bit is set. /** + * @param [in] h The basic header to extract from. * @return True if the header's fin bit is set. */ -inline bool get_fin(const basic_header &h) { +inline bool get_fin(basic_header const & h) { return ((h.b0 & BHB0_FIN) == BHB0_FIN); } /// Set the frame's FIN bit /** - * @param h Header to set - * - * @param value Value to set it to + * @param [out] h Header to set. + * @param [in] value Value to set it to. */ -inline void set_fin(basic_header &h, bool value) { +inline void set_fin(basic_header & h, bool value) { h.b0 = (value ? h.b0 | BHB0_FIN : h.b0 & ~BHB0_FIN); } /// check whether the frame's RSV1 bit is set /** + * @param [in] h The basic header to extract from. * @return True if the header's RSV1 bit is set. */ inline bool get_rsv1(const basic_header &h) { @@ -295,9 +341,8 @@ inline bool get_rsv1(const basic_header &h) { /// Set the frame's RSV1 bit /** - * @param h Header to set - * - * @param value Value to set it to + * @param [out] h Header to set. + * @param [in] value Value to set it to. */ inline void set_rsv1(basic_header &h, bool value) { h.b0 = (value ? h.b0 | BHB0_RSV1 : h.b0 & ~BHB0_RSV1); @@ -305,6 +350,7 @@ inline void set_rsv1(basic_header &h, bool value) { /// check whether the frame's RSV2 bit is set /** + * @param [in] h The basic header to extract from. * @return True if the header's RSV2 bit is set. */ inline bool get_rsv2(const basic_header &h) { @@ -313,9 +359,8 @@ inline bool get_rsv2(const basic_header &h) { /// Set the frame's RSV2 bit /** - * @param h Header to set - * - * @param value Value to set it to + * @param [out] h Header to set. + * @param [in] value Value to set it to. */ inline void set_rsv2(basic_header &h, bool value) { h.b0 = (value ? h.b0 | BHB0_RSV2 : h.b0 & ~BHB0_RSV2); @@ -323,6 +368,7 @@ inline void set_rsv2(basic_header &h, bool value) { /// check whether the frame's RSV3 bit is set /** + * @param [in] h The basic header to extract from. * @return True if the header's RSV3 bit is set. */ inline bool get_rsv3(const basic_header &h) { @@ -331,34 +377,37 @@ inline bool get_rsv3(const basic_header &h) { /// Set the frame's RSV3 bit /** - * @param h Header to set - * - * @param value Value to set it to + * @param [out] h Header to set. + * @param [in] value Value to set it to. */ inline void set_rsv3(basic_header &h, bool value) { h.b0 = (value ? h.b0 | BHB0_RSV3 : h.b0 & ~BHB0_RSV3); } /// Extract opcode from basic header +/** + * @param [in] h The basic header to extract from. + * @return The opcode value of the header. + */ inline opcode::value get_opcode(const basic_header &h) { return opcode::value(h.b0 & BHB0_OPCODE); } /// check whether the frame is masked /** + * @param [in] h The basic header to extract from. * @return True if the header mask bit is set. */ -inline bool get_masked(const basic_header &h) { +inline bool get_masked(basic_header const & h) { return ((h.b1 & BHB1_MASK) == BHB1_MASK); } /// Set the frame's MASK bit /** - * @param h Header to set - * - * @param value Value to set it to + * @param [out] h Header to set. + * @param value Value to set it to. */ -inline void set_masked(basic_header &h, bool value) { +inline void set_masked(basic_header & h, bool value) { h.b1 = (value ? h.b1 | BHB1_MASK : h.b1 & ~BHB1_MASK); } @@ -375,21 +424,46 @@ inline void set_masked(basic_header &h, bool value) { * PAYLOAD_SIZE_CODE_64BIT (0x7F) indicates that the actual payload is less * than 63 bit * - * @param h basic header to read value from - * - * @return the exact size encoded in h + * @param [in] h Basic header to read value from. + * @return The exact size encoded in h. */ inline uint8_t get_basic_size(const basic_header &h) { return h.b1 & BHB1_PAYLOAD; } -/// Set the frame's MASK bit +/// Calculates the full length of the header based on the first bytes. /** - * @param h Header to set + * A WebSocket frame header always has at least two bytes. Encoded within the + * first two bytes is all the information necessary to calculate the full + * (variable) header length. get_header_len() calculates the full header + * length for the given two byte basic header. * - * @param size + * @param h Basic frame header to extract size from. + * @return Full length of the extended header. */ -inline lib::error_code set_size(basic_header &h, extended_header &eh, uint64_t +inline size_t get_header_len(basic_header const & h) { + // TODO: check extensions? + + // masking key offset represents the space used for the extended length + // fields + size_t size = BASIC_HEADER_LENGTH + get_masking_key_offset(h); + + // If the header is masked there is a 4 byte masking key + if (get_masked(h)) { + size += 4; + } + + return size; +} + +/// Set the frame's size +/** + * @param [out] h The basic header to set. + * @param [out] eh The extended header to set. + * @param [in] The size to set. + * @return What error occurred, if any. + */ +inline lib::error_code set_size(basic_header & h, extended_header & eh, uint64_t size) { // make sure value isn't too big @@ -411,32 +485,6 @@ inline lib::error_code set_size(basic_header &h, extended_header &eh, uint64_t return lib::error_code(); } -/// Calculates the full length of the header based on the first bytes. -/** - * A WebSocket frame header always has at least two bytes. Encoded within the - * first two bytes is all the information necessary to calculate the full - * (variable) header length. get_header_len() calculates the full header - * length for the given two byte basic header. - * - * @param h Basic frame header to extract size from - * - * @return Full length of the extended header. - */ -inline size_t get_header_len(const basic_header &h) { - // TODO: check extensions? - - // masking key offset represents the space used for the extended length - // fields - size_t size = BASIC_HEADER_LENGTH + get_masking_key_offset(h); - - // If the header is masked there is a 4 byte masking key - if (get_masked(h)) { - size += 4; - } - - return size; -} - /// Calculate the offset location of the masking key within the extended header /** * Calculate the offset location of the masking key within the extended header From 2352f09c68c08bbca2ca8d4b25eef4a157215a33 Mon Sep 17 00:00:00 2001 From: breyed Date: Sat, 8 Jun 2013 10:26:55 -0500 Subject: [PATCH 20/44] Automatically configure platform via Boost.Config --- websocketpp/config/boost_config.hpp | 71 +++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 websocketpp/config/boost_config.hpp diff --git a/websocketpp/config/boost_config.hpp b/websocketpp/config/boost_config.hpp new file mode 100644 index 0000000000..9ea3c85bf0 --- /dev/null +++ b/websocketpp/config/boost_config.hpp @@ -0,0 +1,71 @@ +/* + * 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: + * * 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. + * + */ + + // This header defines WebSocket++ macros for C++11 compatibility based on the Boost.Config library. + // This will correctly configure most target platforms simply by including this header before + // any other WebSocket++ header. + +#ifndef WEBSOCKETPP_CONFIG_BOOST_CONFIG_HPP +#define WEBSOCKETPP_CONFIG_BOOST_CONFIG_HPP + +#include + +// _WEBSOCKETPP_CPP11_MEMORY_ and _WEBSOCKETPP_CPP11_FUNCTIONAL_ presently +// only work if either both or neither is defined. +#if !defined BOOST_NO_CXX11_SMART_PTR && !defined BOOST_NO_CXX11_HDR_FUNCTIONAL + #define _WEBSOCKETPP_CPP11_MEMORY_ + #define _WEBSOCKETPP_CPP11_FUNCTIONAL_ +#endif + +#ifndef BOOST_ASIO_HAS_STD_CHRONO + #define _WEBSOCKETPP_CPP11_CHRONO_ +#endif + +#ifndef BOOST_NO_CXX11_HDR_RANDOM + #define _WEBSOCKETPP_CPP11_RANDOM_DEVICE_ +#endif + +#ifndef BOOST_NO_CXX11_HDR_REGEX + #define _WEBSOCKETPP_CPP11_REGEX_ +#endif + +#ifndef BOOST_NO_CXX11_HDR_SYSTEM_ERROR + #define _WEBSOCKETPP_CPP11_SYSTEM_ERROR_ +#endif + +#ifndef BOOST_NO_CXX11_HDR_THREAD + #define _WEBSOCKETPP_CPP11_THREAD_ +#endif + +#ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST + #define _WEBSOCKETPP_INITIALIZER_LISTS_ +#endif + +#define _WEBSOCKETPP_NOEXCEPT_TOKEN_ BOOST_NOEXCEPT +#define _WEBSOCKETPP_CONSTEXPR_TOKEN_ BOOST_CONSTEXPR + +#endif // WEBSOCKETPP_CONFIG_CORE_HPP From cd8e1a25bbaf5557a5b9194dcbb348e2a56280a5 Mon Sep 17 00:00:00 2001 From: breyed Date: Sat, 8 Jun 2013 10:34:09 -0500 Subject: [PATCH 21/44] fixed comment at end of include guard --- websocketpp/config/boost_config.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/websocketpp/config/boost_config.hpp b/websocketpp/config/boost_config.hpp index 9ea3c85bf0..7ebd6786a5 100644 --- a/websocketpp/config/boost_config.hpp +++ b/websocketpp/config/boost_config.hpp @@ -34,7 +34,7 @@ #include -// _WEBSOCKETPP_CPP11_MEMORY_ and _WEBSOCKETPP_CPP11_FUNCTIONAL_ presently +// _WEBSOCKETPP_CPP11_MEMORY_ and _WEBSOCKETPP_CPP11_FUNCTIONAL_ presently // only work if either both or neither is defined. #if !defined BOOST_NO_CXX11_SMART_PTR && !defined BOOST_NO_CXX11_HDR_FUNCTIONAL #define _WEBSOCKETPP_CPP11_MEMORY_ @@ -68,4 +68,4 @@ #define _WEBSOCKETPP_NOEXCEPT_TOKEN_ BOOST_NOEXCEPT #define _WEBSOCKETPP_CONSTEXPR_TOKEN_ BOOST_CONSTEXPR -#endif // WEBSOCKETPP_CONFIG_CORE_HPP +#endif // WEBSOCKETPP_CONFIG_BOOST_CONFIG_HPP From 808a8ce0a949e66b1e0977804fa16421df2b0ff3 Mon Sep 17 00:00:00 2001 From: breyed Date: Sat, 8 Jun 2013 11:03:11 -0500 Subject: [PATCH 22/44] fixed spelling, including "experimental" in API --- SConstruct | 2 +- examples/associative_storage/associative_storage.cpp | 2 +- examples/broadcast_server/SConscript | 2 +- examples/echo_client/SConscript | 2 +- examples/echo_server/SConscript | 2 +- examples/echo_server_tls/SConscript | 2 +- examples/iostream_server/SConscript | 2 +- examples/print_server/SConscript | 2 +- examples/subprotocol_server/SConscript | 2 +- examples/telemetry_client/SConscript | 2 +- examples/testee_server/SConscript | 2 +- examples/utility_client/SConscript | 2 +- readme.md | 8 ++++---- test/roles/server.cpp | 2 +- websocketpp/config/core.hpp | 2 +- websocketpp/config/core_client.hpp | 2 +- websocketpp/config/debug.hpp | 2 +- websocketpp/connection.hpp | 8 ++++---- websocketpp/extensions/extension.hpp | 6 +++--- websocketpp/extensions/permessage_deflate/disabled.hpp | 4 ++-- websocketpp/extensions/permessage_deflate/enabled.hpp | 8 ++++---- websocketpp/frame.hpp | 2 +- websocketpp/http/constants.hpp | 4 ++-- websocketpp/http/impl/response.hpp | 2 +- websocketpp/http/request.hpp | 2 +- websocketpp/http/response.hpp | 2 +- websocketpp/impl/connection_impl.hpp | 6 +++--- websocketpp/message_buffer/message.hpp | 4 ++-- websocketpp/message_buffer/pool.hpp | 2 +- websocketpp/processors/base.hpp | 10 +++++----- websocketpp/processors/hybi00.hpp | 2 +- websocketpp/processors/hybi13.hpp | 4 ++-- websocketpp/processors/processor.hpp | 8 ++++---- websocketpp/transport/asio/connection.hpp | 6 +++--- websocketpp/transport/asio/endpoint.hpp | 2 +- websocketpp/transport/asio/security/base.hpp | 4 ++-- websocketpp/transport/asio/security/none.hpp | 8 ++++---- websocketpp/transport/asio/security/tls.hpp | 8 ++++---- websocketpp/transport/base/endpoint.hpp | 2 +- websocketpp/transport/iostream/connection.hpp | 8 ++++---- 40 files changed, 76 insertions(+), 76 deletions(-) diff --git a/SConstruct b/SConstruct index b930d4d3ab..3eee6f59a2 100644 --- a/SConstruct +++ b/SConstruct @@ -128,7 +128,7 @@ env.Append(CPPPATH = ['#']) ##### Set up C++11 environment polyfill_libs = [] # boost libraries used as drop in replacements for incomplete - # C++11 STL implimentations + # C++11 STL implementations env_cpp11 = env.Clone () if env_cpp11['CXX'].startswith('g++'): diff --git a/examples/associative_storage/associative_storage.cpp b/examples/associative_storage/associative_storage.cpp index c5a0194a1c..a5dd3e32fb 100644 --- a/examples/associative_storage/associative_storage.cpp +++ b/examples/associative_storage/associative_storage.cpp @@ -63,7 +63,7 @@ public: if (it == m_connections.end()) { // this connection is not in the list. This really shouldn't happen // and probably means something else is wrong. - throw std::invalid_argument("No data avaliable for session"); + throw std::invalid_argument("No data available for session"); } return it->second; diff --git a/examples/broadcast_server/SConscript b/examples/broadcast_server/SConscript index e2d28ccec8..a9938b871a 100644 --- a/examples/broadcast_server/SConscript +++ b/examples/broadcast_server/SConscript @@ -12,7 +12,7 @@ env_cpp11 = env_cpp11.Clone () prgs = [] -# if a C++11 environment is avaliable build using that, otherwise use boost +# 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('broadcast_server', ["broadcast_server.cpp"], LIBS = ALL_LIBS) diff --git a/examples/echo_client/SConscript b/examples/echo_client/SConscript index 291ade5df0..b167f741f6 100644 --- a/examples/echo_client/SConscript +++ b/examples/echo_client/SConscript @@ -12,7 +12,7 @@ env_cpp11 = env_cpp11.Clone () prgs = [] -# if a C++11 environment is avaliable build using that, otherwise use boost +# 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('echo_client', ["echo_client.cpp"], LIBS = ALL_LIBS) diff --git a/examples/echo_server/SConscript b/examples/echo_server/SConscript index ff7ed0e9dd..2de8e5e793 100644 --- a/examples/echo_server/SConscript +++ b/examples/echo_server/SConscript @@ -12,7 +12,7 @@ env_cpp11 = env_cpp11.Clone () prgs = [] -# if a C++11 environment is avaliable build using that, otherwise use boost +# 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('echo_server', ["echo_server.cpp"], LIBS = ALL_LIBS) diff --git a/examples/echo_server_tls/SConscript b/examples/echo_server_tls/SConscript index 988110f0d6..d0893b4a3e 100644 --- a/examples/echo_server_tls/SConscript +++ b/examples/echo_server_tls/SConscript @@ -13,7 +13,7 @@ env_cpp11 = env_cpp11.Clone () prgs = [] -# if a C++11 environment is avaliable build using that, otherwise use boost +# 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('echo_server_tls', ["echo_server_tls.cpp"], LIBS = ALL_LIBS) diff --git a/examples/iostream_server/SConscript b/examples/iostream_server/SConscript index 3ea3f68e3f..f6b24ed3d4 100644 --- a/examples/iostream_server/SConscript +++ b/examples/iostream_server/SConscript @@ -12,7 +12,7 @@ env_cpp11 = env_cpp11.Clone () prgs = [] -# if a C++11 environment is avaliable build using that, otherwise use boost +# 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('iostream_server', ["iostream_server.cpp"], LIBS = ALL_LIBS) diff --git a/examples/print_server/SConscript b/examples/print_server/SConscript index 6e0724e5f8..725ed77e39 100644 --- a/examples/print_server/SConscript +++ b/examples/print_server/SConscript @@ -12,7 +12,7 @@ env_cpp11 = env_cpp11.Clone () prgs = [] -# if a C++11 environment is avaliable build using that, otherwise use boost +# 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('print_server', ["print_server.cpp"], LIBS = ALL_LIBS) diff --git a/examples/subprotocol_server/SConscript b/examples/subprotocol_server/SConscript index 2ce12359f1..fce0525d20 100644 --- a/examples/subprotocol_server/SConscript +++ b/examples/subprotocol_server/SConscript @@ -12,7 +12,7 @@ env_cpp11 = env_cpp11.Clone () prgs = [] -# if a C++11 environment is avaliable build using that, otherwise use boost +# 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('subprotocol_server', ["subprotocol_server.cpp"], LIBS = ALL_LIBS) diff --git a/examples/telemetry_client/SConscript b/examples/telemetry_client/SConscript index 41a1bb067e..eef1c362a8 100644 --- a/examples/telemetry_client/SConscript +++ b/examples/telemetry_client/SConscript @@ -12,7 +12,7 @@ env_cpp11 = env_cpp11.Clone () prgs = [] -# if a C++11 environment is avaliable build using that, otherwise use boost +# 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('telemetry_client', ["telemetry_client.cpp"], LIBS = ALL_LIBS) diff --git a/examples/testee_server/SConscript b/examples/testee_server/SConscript index 2694201060..f0551b8118 100644 --- a/examples/testee_server/SConscript +++ b/examples/testee_server/SConscript @@ -12,7 +12,7 @@ env_cpp11 = env_cpp11.Clone () prgs = [] -# if a C++11 environment is avaliable build using that, otherwise use boost +# 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('testee_server', ["testee_server.cpp"], LIBS = ALL_LIBS) diff --git a/examples/utility_client/SConscript b/examples/utility_client/SConscript index 8678c6264b..82625876aa 100644 --- a/examples/utility_client/SConscript +++ b/examples/utility_client/SConscript @@ -13,7 +13,7 @@ env_cpp11 = env_cpp11.Clone () prgs = [] -# if a C++11 environment is avaliable build using that, otherwise use boost +# 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('utility_client', ["utility_client.cpp"], LIBS = ALL_LIBS) diff --git a/readme.md b/readme.md index ed19b3d3ed..61b3951305 100644 --- a/readme.md +++ b/readme.md @@ -1,16 +1,16 @@ WebSocket++ (0.3.x branch) ========================== -WebSocket++ is a header only C++ library that impliments RFC6455 The WebSocket +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 interchangable network transport modules including one +C++ programs. It uses interchangeable network transport modules including one based on C++ iostreams and one based on Boost Asio. *This branch is no longer "experimental". It represents the current edge release of the WebSocket++ library. The API of 0.3.x has some significant changes from 0.2.x, so care should be taken when upgrading.* -*This branch's API is relatively stable now. Features implimented so far are +*This branch's API is relatively stable now. Features implemented so far are unlikely to change (except where explicitly noted). New features will be added regularly until parity with the 0.2 branch is reached.* @@ -25,7 +25,7 @@ Major Features * Message/event based interface * Supports secure WebSockets (TLS), IPv6, and explicit proxies. * Flexible dependency management (C++11 Standard Library or Boost) -* Interchangable network transport modules (iostream and Boost Asio) +* Interchangeable network transport modules (iostream and Boost Asio) * Portible, cross platform and architecture design Get Involved diff --git a/test/roles/server.cpp b/test/roles/server.cpp index bf47bfba58..9bd4372683 100644 --- a/test/roles/server.cpp +++ b/test/roles/server.cpp @@ -136,7 +136,7 @@ BOOST_AUTO_TEST_CASE( invalid_websocket_version ) { BOOST_CHECK_EQUAL(run_server_test(s,input), output); } -BOOST_AUTO_TEST_CASE( unimplimented_websocket_version ) { +BOOST_AUTO_TEST_CASE( unimplemented_websocket_version ) { std::string input = "GET / HTTP/1.1\r\nHost: www.example.com\r\nConnection: upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 14\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nOrigin: http://www.example.com\r\n\r\n"; std::string output = "HTTP/1.1 400 Bad Request\r\nSec-WebSocket-Version: 0,7,8,13\r\nServer: test\r\n\r\n"; diff --git a/websocketpp/config/core.hpp b/websocketpp/config/core.hpp index 48e24a9a1f..f9fa5cb00e 100644 --- a/websocketpp/config/core.hpp +++ b/websocketpp/config/core.hpp @@ -197,7 +197,7 @@ struct core { * for debugging and presenting useful errors to end users but may be * undesirable for security reasons in some production environments. * Close reasons could be used by an attacker to confirm that the endpoint - * is out of resources or be used to identify the WebSocket implimentation + * is out of resources or be used to identify the WebSocket implementation * in use. * * Note: this will suppress *all* close codes, including those explicitly diff --git a/websocketpp/config/core_client.hpp b/websocketpp/config/core_client.hpp index fb68209ce3..1718751f2e 100644 --- a/websocketpp/config/core_client.hpp +++ b/websocketpp/config/core_client.hpp @@ -198,7 +198,7 @@ struct core_client { * for debugging and presenting useful errors to end users but may be * undesirable for security reasons in some production environments. * Close reasons could be used by an attacker to confirm that the endpoint - * is out of resources or be used to identify the WebSocket implimentation + * is out of resources or be used to identify the WebSocket implementation * in use. * * Note: this will suppress *all* close codes, including those explicitly diff --git a/websocketpp/config/debug.hpp b/websocketpp/config/debug.hpp index 5d9d6bbaed..f1f8da3089 100644 --- a/websocketpp/config/debug.hpp +++ b/websocketpp/config/debug.hpp @@ -198,7 +198,7 @@ struct debug_core { * for debugging and presenting useful errors to end users but may be * undesirable for security reasons in some production environments. * Close reasons could be used by an attacker to confirm that the endpoint - * is out of resources or be used to identify the WebSocket implimentation + * is out of resources or be used to identify the WebSocket implementation * in use. * * Note: this will suppress *all* close codes, including those explicitly diff --git a/websocketpp/connection.hpp b/websocketpp/connection.hpp index 11e401437c..409686ad5f 100644 --- a/websocketpp/connection.hpp +++ b/websocketpp/connection.hpp @@ -88,7 +88,7 @@ namespace status { GOOD = 0, // no failure yet! SYSTEM = 1, // system call returned error, check that code WEBSOCKET = 2, // websocket close codes contain error - UNKNOWN = 3, // No failure information is avaliable + UNKNOWN = 3, // No failure information is available TIMEOUT_TLS = 4, // TLS handshake timed out TIMEOUT_WS = 5 // WS handshake timed out }; @@ -97,8 +97,8 @@ namespace status { namespace internal_state { // More granular internal states. These are used for multi-threaded - // connection syncronization and preventing values that are not yet or no - // longer avaliable from being used. + // connection synchronization and preventing values that are not yet or no + // longer available from being used. enum value { USER_INIT = 0, @@ -271,7 +271,7 @@ public: * period. It is specified in milliseconds. * * This can be used to probe the health of the remote endpoint's WebSocket - * implimentation. This does not guarantee that the remote application + * implementation. This does not guarantee that the remote application * itself is still healthy but can be a useful diagnostic. * * Note: receipt of this callback doesn't mean the pong will never come. diff --git a/websocketpp/extensions/extension.hpp b/websocketpp/extensions/extension.hpp index 4b89a9ed80..5f687f37ae 100644 --- a/websocketpp/extensions/extension.hpp +++ b/websocketpp/extensions/extension.hpp @@ -39,9 +39,9 @@ namespace websocketpp { /** * Some generic information about extensions * - * Each extension object has an implimented flag. It can be retrieved by calling - * is_implimented(). This compile time flag indicates whether or not the object - * in question actually impliments the extension or if it is a placeholder stub + * Each extension object has an implemented flag. It can be retrieved by calling + * is_implemented(). This compile time flag indicates whether or not the object + * in question actually implements the extension or if it is a placeholder stub * * Each extension object also has an enabled flag. It can be retrieved by * calling is_enabled(). This runtime flag indicates whether or not the diff --git a/websocketpp/extensions/permessage_deflate/disabled.hpp b/websocketpp/extensions/permessage_deflate/disabled.hpp index b9ad025f38..e07ab3fc8b 100644 --- a/websocketpp/extensions/permessage_deflate/disabled.hpp +++ b/websocketpp/extensions/permessage_deflate/disabled.hpp @@ -43,7 +43,7 @@ namespace permessage_deflate { /// Stub class for use when disabling permessage_deflate extension /** - * This class is a stub that impliments the permessage_deflate interface + * This class is a stub that implements the permessage_deflate interface * with minimal dependencies. It is used to disable permessage_deflate * functionality at compile time without loading any unnecessary code. */ @@ -59,7 +59,7 @@ public: /// Returns true if the extension is capable of providing /// permessage_deflate functionality - bool is_implimented() const { + bool is_implemented() const { return false; } diff --git a/websocketpp/extensions/permessage_deflate/enabled.hpp b/websocketpp/extensions/permessage_deflate/enabled.hpp index 937a81963d..4511cf6e46 100644 --- a/websocketpp/extensions/permessage_deflate/enabled.hpp +++ b/websocketpp/extensions/permessage_deflate/enabled.hpp @@ -410,7 +410,7 @@ private: * Template parameter econfig defines compile time types, constants, and * settings. It should be a struct with the following members: * - * request_type (type) A type that impliments the http::request interface + * request_type (type) A type that implements the http::request interface * * allow_disabling_context_takeover (static const bool) whether or not to * disable context takeover when the other endpoint requests it. @@ -422,7 +422,7 @@ private: * * * Methods: - * permessage_deflate::enabled does not define or impliment any methods + * permessage_deflate::enabled does not define or implement any methods * itself. It uses the attribute list to determine * * @@ -533,8 +533,8 @@ public: return ret; } - /// Returns true if this object impliments permessage_deflate functionality - bool is_implimented() const { + /// Returns true if this object implements permessage_deflate functionality + bool is_implemented() const { return true; } diff --git a/websocketpp/frame.hpp b/websocketpp/frame.hpp index afe359515d..6d7420e367 100644 --- a/websocketpp/frame.hpp +++ b/websocketpp/frame.hpp @@ -773,7 +773,7 @@ inline void word_mask_exact(uint8_t* data, size_t length, const * * word_mask returns a copy of prepared_key circularly shifted based on the * length value. The returned value may be fed back into word_mask when more - * data is avaliable. + * data is available. * * input and output must both have length at least: * ceil(length/sizeof(size_t))*sizeof(size_t) diff --git a/websocketpp/http/constants.hpp b/websocketpp/http/constants.hpp index c4a8dee817..5df6ddc0f6 100644 --- a/websocketpp/http/constants.hpp +++ b/websocketpp/http/constants.hpp @@ -129,7 +129,7 @@ namespace http { request_header_fields_too_large = 431, internal_server_error = 500, - not_implimented = 501, + not_implemented = 501, bad_gateway = 502, service_unavailable = 503, gateway_timeout = 504, @@ -223,7 +223,7 @@ namespace http { return "Request Header Fields Too Large"; case internal_server_error: return "Internal Server Error"; - case not_implimented: + case not_implemented: return "Not Implimented"; case bad_gateway: return "Bad Gateway"; diff --git a/websocketpp/http/impl/response.hpp b/websocketpp/http/impl/response.hpp index e25a0e3cc6..44a1f5e0e4 100644 --- a/websocketpp/http/impl/response.hpp +++ b/websocketpp/http/impl/response.hpp @@ -273,7 +273,7 @@ inline size_t response::process_body(const char *buf, size_t len) { to_read = m_read; m_state = DONE; } else { - // we need more bytes than are avaliable, read them all + // we need more bytes than are available, read them all to_read = len; } diff --git a/websocketpp/http/request.hpp b/websocketpp/http/request.hpp index b3e0953f89..87d90feb94 100644 --- a/websocketpp/http/request.hpp +++ b/websocketpp/http/request.hpp @@ -67,7 +67,7 @@ public: * final header delimiters. * * Consume is a streaming processor. It may be called multiple times on one - * request and the full headers need not be avaliable before processing can + * request and the full headers need not be available before processing can * begin. If the end of the request was reached during this call to consume * the ready flag will be set. Further calls to consume once ready will be * ignored. diff --git a/websocketpp/http/response.hpp b/websocketpp/http/response.hpp index 0cab36d867..f3faf91154 100644 --- a/websocketpp/http/response.hpp +++ b/websocketpp/http/response.hpp @@ -69,7 +69,7 @@ public: * final header delimiters. * * Consume is a streaming processor. It may be called multiple times on one - * response and the full headers need not be avaliable before processing can + * response and the full headers need not be available before processing can * begin. If the end of the response was reached during this call to consume * the ready flag will be set. Further calls to consume once ready will be * ignored. diff --git a/websocketpp/impl/connection_impl.hpp b/websocketpp/impl/connection_impl.hpp index 4f1772350c..97b973366e 100644 --- a/websocketpp/impl/connection_impl.hpp +++ b/websocketpp/impl/connection_impl.hpp @@ -564,7 +564,7 @@ void connection::start() { "Start must be called from user init state" ); - // Depending on how the transport impliments init this function may return + // Depending on how the transport implements init this function may return // immediately and call handle_transport_init later or call // handle_transport_init from this function. transport_con_type::init( @@ -994,7 +994,7 @@ bool connection::process_handshake_request() { m_response.set_status(http::status_code::bad_request); return false; } else { - // extension negotiation succeded, set response header accordingly + // extension negotiation succeeded, set response header accordingly // we don't send an empty extensions header because it breaks many // clients. if (neg_results.second.size() > 0) { @@ -1660,7 +1660,7 @@ lib::error_code connection::send_close_frame(close::status::value code, const std::string &reason, bool ack, bool terminal) { m_alog.write(log::alevel::devel,"send_close_frame"); - // If silent close is set, repsect it and blank out close information + // If silent close is set, respect it and blank out close information // Otherwise use whatever has been specified in the parameters. If // parameters specifies close::status::blank then determine what to do // based on whether or not this is an ack. If it is not an ack just diff --git a/websocketpp/message_buffer/message.hpp b/websocketpp/message_buffer/message.hpp index 6fc9ee82ee..dde75798e2 100644 --- a/websocketpp/message_buffer/message.hpp +++ b/websocketpp/message_buffer/message.hpp @@ -50,7 +50,7 @@ namespace message_buffer { * requested from the manager the requester and it's associated downstream code * may keep a pointer to the message indefinitely at a cost of extra resource * usage. Once the reference count drops to the point where the manager is the - * only reference the messages is recycled using whatever method is implimented + * only reference the messages is recycled using whatever method is implemented * in the manager. * * # endpoint_message_manager: @@ -156,7 +156,7 @@ public: /// Get whether or not the message is terminal /** * Messages can be flagged as terminal, which results in the connection - * being close after they are written rather than the implimentation going + * being close after they are written rather than the implementation going * on to the next message in the queue. This is typically used internally * for close messages only. */ diff --git a/websocketpp/message_buffer/pool.hpp b/websocketpp/message_buffer/pool.hpp index 0163682e46..d14259fd7d 100644 --- a/websocketpp/message_buffer/pool.hpp +++ b/websocketpp/message_buffer/pool.hpp @@ -49,7 +49,7 @@ namespace message_buffer { * requested from the manager the requester and it's associated downstream code * may keep a pointer to the message indefinitely at a cost of extra resource * usage. Once the reference count drops to the point where the manager is the - * only reference the messages is recycled using whatever method is implimented + * only reference the messages is recycled using whatever method is implemented * in the manager. * * # endpoint_message_manager: diff --git a/websocketpp/processors/base.hpp b/websocketpp/processors/base.hpp index 61f329d70c..4c6064a33f 100644 --- a/websocketpp/processors/base.hpp +++ b/websocketpp/processors/base.hpp @@ -124,8 +124,8 @@ enum processor_errors { /// Invalid UTF-8 encoding invalid_utf8, - /// Operation required not implimented functionality - not_implimented, + /// Operation required not implemented functionality + not_implemented, /// Invalid HTTP method invalid_http_method, @@ -206,8 +206,8 @@ public: return "64 bit frames are not supported on 32 bit systems"; case error::invalid_utf8: return "Invalid UTF8 encoding"; - case error::not_implimented: - return "Operation required not implimented functionality"; + case error::not_implemented: + return "Operation required not implemented functionality"; case error::invalid_http_method: return "Invalid HTTP method."; case error::invalid_http_version: @@ -256,7 +256,7 @@ inline lib::error_code make_error_code(error::processor_errors e) { * returned. * * If the error isn't normally associated with reasons to close a connection - * (such as errors intended to be used interally or delivered to client + * (such as errors intended to be used internally or delivered to client * applications, ex: invalid arguments) then * close::status::internal_endpoint_error is returned. */ diff --git a/websocketpp/processors/hybi00.hpp b/websocketpp/processors/hybi00.hpp index 3ded374070..d40cbffe59 100644 --- a/websocketpp/processors/hybi00.hpp +++ b/websocketpp/processors/hybi00.hpp @@ -260,7 +260,7 @@ public: // 0x00, the message is complete and is dispatched. Then we go back to // header state. - //ec = make_error_code(error::not_implimented); + //ec = make_error_code(error::not_implemented); return p; } diff --git a/websocketpp/processors/hybi13.hpp b/websocketpp/processors/hybi13.hpp index 6231d678f6..1d2015b9dc 100644 --- a/websocketpp/processors/hybi13.hpp +++ b/websocketpp/processors/hybi13.hpp @@ -88,7 +88,7 @@ public: } bool has_permessage_deflate() const { - return m_permessage_deflate.is_implimented(); + return m_permessage_deflate.is_implemented(); } err_str_pair negotiate_extensions(const request_type& req) { @@ -117,7 +117,7 @@ public: typename request_type::parameter_list::const_iterator it; - if (m_permessage_deflate.is_implimented()) { + if (m_permessage_deflate.is_implemented()) { err_str_pair neg_ret; for (it = p.begin(); it != p.end(); ++it) { // look through each extension, if the key is permessage-deflate diff --git a/websocketpp/processors/processor.hpp b/websocketpp/processors/processor.hpp index 60c62e1555..b393696d56 100644 --- a/websocketpp/processors/processor.hpp +++ b/websocketpp/processors/processor.hpp @@ -173,9 +173,9 @@ public: /// understands. virtual int get_version() const = 0; - /// Returns whether or not the permessage_compress extension is implimented + /// Returns whether or not the permessage_compress extension is implemented /** - * Compile time flag that indicates whether this processor has implimented + * Compile time flag that indicates whether this processor has implemented * the permessage_compress extension. By default this is false. */ virtual bool has_permessage_compress() const { @@ -289,10 +289,10 @@ public: /// Retrieves the most recently processed message /** * Retrieves a shared pointer to the recently completed message if there is - * one. If ready() returns true then there is a message avaliable. + * one. If ready() returns true then there is a message available. * Retrieving the message with get_message will reset the state of ready. * As such, each new message may be retrieved only once. Calling get_message - * when there is no message avaliable will result in a null pointer being + * when there is no message available will result in a null pointer being * returned. * * @return A pointer to the most recently processed message or a null shared diff --git a/websocketpp/transport/asio/connection.hpp b/websocketpp/transport/asio/connection.hpp index 459d0df6fe..0dd85db291 100644 --- a/websocketpp/transport/asio/connection.hpp +++ b/websocketpp/transport/asio/connection.hpp @@ -53,7 +53,7 @@ typedef lib::function tcp_init_handler; /// Boost Asio based connection transport component /** - * transport::asio::connection impliments a connection transport component using + * transport::asio::connection implements a connection transport component using * Boost ASIO that works with the transport::asio::endpoint endpoint transport * component. */ @@ -349,7 +349,7 @@ protected: m_alog.write(log::alevel::devel,"asio connection init"); } - // TODO: pre-init timeout. Right now no implimented socket policies + // TODO: pre-init timeout. Right now no implemented socket policies // actually have an asyncronous pre-init socket_con_type::pre_init( @@ -620,7 +620,7 @@ protected: if (m_proxy_data->res.get_status_code() != http::status_code::ok) { // got an error response back - // TODO: expose this error in a programatically accessible way? + // TODO: expose this error in a programmatically accessible way? // if so, see below for an option on how to do this. std::stringstream s; s << "Proxy connection error: " diff --git a/websocketpp/transport/asio/endpoint.hpp b/websocketpp/transport/asio/endpoint.hpp index d95d88398a..532fecf86a 100644 --- a/websocketpp/transport/asio/endpoint.hpp +++ b/websocketpp/transport/asio/endpoint.hpp @@ -46,7 +46,7 @@ namespace asio { /// Boost Asio based endpoint transport component /** - * transport::asio::endpoint impliments an endpoint transport component using + * transport::asio::endpoint implements an endpoint transport component using * Boost ASIO. */ template diff --git a/websocketpp/transport/asio/security/base.hpp b/websocketpp/transport/asio/security/base.hpp index 5760e958da..9414accd89 100644 --- a/websocketpp/transport/asio/security/base.hpp +++ b/websocketpp/transport/asio/security/base.hpp @@ -39,13 +39,13 @@ #include #include -// Interface that sockets/security policies must impliment +// Interface that sockets/security policies must implement /** * Endpoint Interface * * bool is_secure() const; - * @return Wether or not the endpoint creates secure connections + * @return Whether or not the endpoint creates secure connections * * lib::error_code init(socket_con_ptr scon); * Called by the transport after a new connection is created to initialize diff --git a/websocketpp/transport/asio/security/none.hpp b/websocketpp/transport/asio/security/none.hpp index 2c9f5c97da..e31e2ea825 100644 --- a/websocketpp/transport/asio/security/none.hpp +++ b/websocketpp/transport/asio/security/none.hpp @@ -45,7 +45,7 @@ typedef lib::function /// Basic Boost ASIO connection socket component /** - * transport::asio::basic_socket::connection impliments a connection socket + * transport::asio::basic_socket::connection implements a connection socket * component using Boost ASIO ip::tcp::socket. */ class connection { @@ -67,7 +67,7 @@ public: /// Check whether or not this connection is secure /** - * @return Wether or not this connection is secure + * @return Whether or not this connection is secure */ bool is_secure() const { return false; @@ -235,7 +235,7 @@ private: /// Basic ASIO endpoint socket component /** - * transport::asio::basic_socket::endpoint impliments an endpoint socket + * transport::asio::basic_socket::endpoint implements an endpoint socket * component that uses Boost ASIO's ip::tcp::socket. */ class endpoint { @@ -253,7 +253,7 @@ public: /// Checks whether the endpoint creates secure connections /** - * @return Wether or not the endpoint creates secure connections + * @return Whether or not the endpoint creates secure connections */ bool is_secure() const { return false; diff --git a/websocketpp/transport/asio/security/tls.hpp b/websocketpp/transport/asio/security/tls.hpp index a56aa56eaa..bdfe7b2d81 100644 --- a/websocketpp/transport/asio/security/tls.hpp +++ b/websocketpp/transport/asio/security/tls.hpp @@ -52,7 +52,7 @@ typedef lib::function(connection_hdl) /// TLS enabled Boost ASIO connection socket component /** - * transport::asio::tls_socket::connection impliments a secure connection socket + * transport::asio::tls_socket::connection implements a secure connection socket * component that uses Boost ASIO's ssl::stream to wrap an ip::tcp::socket. */ class connection { @@ -80,7 +80,7 @@ public: /// Check whether or not this connection is secure /** - * @return Wether or not this connection is secure + * @return Whether or not this connection is secure */ bool is_secure() const { return true; @@ -286,7 +286,7 @@ private: /// TLS enabled Boost ASIO endpoint socket component /** - * transport::asio::tls_socket::endpoint impliments a secure endpoint socket + * transport::asio::tls_socket::endpoint implements a secure endpoint socket * component that uses Boost ASIO's ssl::stream to wrap an ip::tcp::socket. */ class endpoint { @@ -304,7 +304,7 @@ public: /// Checks whether the endpoint creates secure connections /** - * @return Wether or not the endpoint creates secure connections + * @return Whether or not the endpoint creates secure connections */ bool is_secure() const { return true; diff --git a/websocketpp/transport/base/endpoint.hpp b/websocketpp/transport/base/endpoint.hpp index 3d203c2f6d..6d51680ea1 100644 --- a/websocketpp/transport/base/endpoint.hpp +++ b/websocketpp/transport/base/endpoint.hpp @@ -47,7 +47,7 @@ typedef lib::function connect_handl typedef lib::function endpoint_lock; // Endpoint interface -// Methods a transport endpoint must impliment +// Methods a transport endpoint must implement /// Initialize a connection /** diff --git a/websocketpp/transport/iostream/connection.hpp b/websocketpp/transport/iostream/connection.hpp index 63b250b9f3..aea5202d31 100644 --- a/websocketpp/transport/iostream/connection.hpp +++ b/websocketpp/transport/iostream/connection.hpp @@ -95,7 +95,7 @@ public: /// Overloaded stream input operator /** * Attempts to read input from the given stream into the transport. Bytes - * will be extracted from the input stream to fullfill any pending reads. + * will be extracted from the input stream to fulfill any pending reads. * Input in this manner will only read until the current read buffer has * been filled. Then it will signal the library to process the input. If the * library's input handler adds a new async_read, additional bytes will be @@ -103,7 +103,7 @@ public: * * When this function returns one of the following conditions is true: * - There is no outstanding read operation - * - There are no more bytes avaliable in the input stream + * - There are no more bytes available in the input stream * * You can use tellg() on the input stream to determine if all of the input * bytes were read or not. @@ -123,7 +123,7 @@ public: /// Manual input supply /** * Copies bytes from buf into WebSocket++'s input buffers. Bytes will be - * copied from the supplied buffer to fullfull any pending library reads. It + * copied from the supplied buffer to fulfill any pending library reads. It * will return the number of bytes successfully processed. If there are no * pending reads readsome will return immediately. Not all of the bytes may * be able to be read in one call @@ -171,7 +171,7 @@ public: /// Call back a function after a period of time. /** - * Timers are not implimented in this transport. The timer pointer will + * Timers are not implemented in this transport. The timer pointer will * always be empty. The handler will never be called. * * @param duration Length of time to wait in milliseconds From 196523ba42756b8ff33bbe3328f4cbcc5565e52e Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Sat, 8 Jun 2013 10:38:01 -0500 Subject: [PATCH 23/44] adds a machine readable internal error code To be used for storing detailed error codes for why connections failed or were closed --- websocketpp/connection.hpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/websocketpp/connection.hpp b/websocketpp/connection.hpp index 409686ad5f..c212d2a77f 100644 --- a/websocketpp/connection.hpp +++ b/websocketpp/connection.hpp @@ -775,6 +775,19 @@ public: */ session::state::value get_state() const; + /// Get the internal error code for a closed/failed connection + /** + * Retrieves a machine readable detailed error code indicating the reason + * that the connection was closed or failed. Valid only after the close or + * fail handler is called. + * + * @return Error code indicating the reason the connection was closed or + * failed + */ + lib::error_code get_ec() const { + return m_ec; + } + //////////////////////////////////////////////////////////////////////// // The remaining public member functions are for internal/policy use // // only. Do not call from application code unless you understand what // @@ -1117,6 +1130,9 @@ private: /// Close reason that was received on the wire from the remote endpoint std::string m_remote_close_reason; + /// Detailed internal error code + lib::error_code m_ec; + /// Whether or not this endpoint initiated the closing handshake. bool m_closed_by_me; From 0f02119d48fd8624147f41588e6ee35dafc7ea94 Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Sat, 8 Jun 2013 10:38:25 -0500 Subject: [PATCH 24/44] adds new error codes for handshake timeouts --- websocketpp/error.hpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/websocketpp/error.hpp b/websocketpp/error.hpp index c7e49d901f..7710bba7ad 100644 --- a/websocketpp/error.hpp +++ b/websocketpp/error.hpp @@ -102,7 +102,13 @@ enum value { server_only, /// HTTP connection ended - http_connection_ended + http_connection_ended, + + /// WebSocket opening handshake timed out + open_handshake_timeout, + + /// WebSocket close handshake timed out + close_handshake_timeout }; // enum value @@ -158,6 +164,10 @@ public: return "Feature not available on client endpoints"; case error::http_connection_ended: return "HTTP connection ended"; + case error::open_handshake_timeout: + return "The opening handshake timed out"; + case error::close_handshake_timeout: + return "The closing handshake timed out"; default: return "Unknown"; } From c86601f12390b772d67c56f9105453d374278136 Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Sat, 8 Jun 2013 16:22:19 -0500 Subject: [PATCH 25/44] add methods to retrieve WebSocket close codes & reasons --- websocketpp/connection.hpp | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/websocketpp/connection.hpp b/websocketpp/connection.hpp index c212d2a77f..adba32f67b 100644 --- a/websocketpp/connection.hpp +++ b/websocketpp/connection.hpp @@ -775,6 +775,39 @@ public: */ session::state::value get_state() const; + + /// Get the WebSocket close code sent by this endpoint. + /** + * @return The WebSocket close code sent by this endpoint. + */ + close::status::value get_local_close_code() const { + return m_local_close_code; + } + + /// Get the WebSocket close reason sent by this endpoint. + /** + * @return The WebSocket close reason sent by this endpoint. + */ + std::string const & get_local_close_reason() const { + return m_local_close_reason; + } + + /// Get the WebSocket close code sent by the remote endpoint. + /** + * @return The WebSocket close code sent by the remote endpoint. + */ + close::status::value get_remote_close_code() const { + return m_remote_close_code; + } + + /// Get the WebSocket close reason sent by the remote endpoint. + /** + * @return The WebSocket close reason sent by the remote endpoint. + */ + std::string const & get_remote_close_reason() const { + return m_remote_close_reason; + } + /// Get the internal error code for a closed/failed connection /** * Retrieves a machine readable detailed error code indicating the reason From 8ee6a4a64b8947819234ac8e9a1fff902e72ffc3 Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Sat, 8 Jun 2013 16:57:22 -0500 Subject: [PATCH 26/44] set state to closing after we send our close frame --- websocketpp/impl/connection_impl.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/websocketpp/impl/connection_impl.hpp b/websocketpp/impl/connection_impl.hpp index 97b973366e..99a4423697 100644 --- a/websocketpp/impl/connection_impl.hpp +++ b/websocketpp/impl/connection_impl.hpp @@ -1712,6 +1712,8 @@ lib::error_code connection::send_close_frame(close::status::value code, msg->set_terminal(true); } + m_state = session::state::closing; + bool needs_writing = false; { scoped_lock_type lock(m_write_lock); From 1892e0f13b09960d0e748ff0d5e8e1d85c592305 Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Sat, 8 Jun 2013 16:57:46 -0500 Subject: [PATCH 27/44] remove unused code --- websocketpp/connection.hpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/websocketpp/connection.hpp b/websocketpp/connection.hpp index adba32f67b..23fded1036 100644 --- a/websocketpp/connection.hpp +++ b/websocketpp/connection.hpp @@ -843,10 +843,7 @@ public: void start(); - void read_handshake(size_t num_bytes); - - //void write(std::string msg); - //void handle_write(const lib::error_code& ec); + void read_handshake(size_t num_bytes); void handle_read_handshake(const lib::error_code& ec, size_t bytes_transferred); From f2486d4aefbdbbccd5d70c7bdd3961cc13bdf545 Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Sat, 8 Jun 2013 16:58:13 -0500 Subject: [PATCH 28/44] add handshake timer & associated handlers --- websocketpp/connection.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/websocketpp/connection.hpp b/websocketpp/connection.hpp index 23fded1036..1536a644bc 100644 --- a/websocketpp/connection.hpp +++ b/websocketpp/connection.hpp @@ -853,6 +853,9 @@ public: void handle_send_http_response(const lib::error_code& ec); void handle_send_http_request(const lib::error_code& ec); + void handle_open_handshake_timeout(lib::error_code const & ec); + void handle_close_handshake_timeout(lib::error_code const & ec); + void handle_read_frame(const lib::error_code& ec, size_t bytes_transferred); @@ -1086,6 +1089,7 @@ private: size_t m_buf_cursor; termination_handler m_termination_handler; con_msg_manager_ptr m_msg_manager; + timer_ptr m_handshake_timer; timer_ptr m_ping_timer; // TODO: this is not memory efficient. this value is not used after the From b591e9fa7e0dbbff4ed83629840705cd77584d20 Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Sat, 8 Jun 2013 16:59:02 -0500 Subject: [PATCH 29/44] add handshake timeout handlers --- websocketpp/impl/connection_impl.hpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/websocketpp/impl/connection_impl.hpp b/websocketpp/impl/connection_impl.hpp index 99a4423697..2b6c9b72a1 100644 --- a/websocketpp/impl/connection_impl.hpp +++ b/websocketpp/impl/connection_impl.hpp @@ -1317,6 +1317,30 @@ void connection::handle_read_http_response(const lib::error_code& ec, } } +template +void connection::handle_open_handshake_timeout( + lib::error_code const & ec) +{ + if (ec == transport::error::operation_aborted) { + m_alog.write(log::alevel::devel, + "asio open handshake timer cancelled"); + } else if (ec) { + m_alog.write(log::alevel::devel, + "asio open handle_open_handshake_timeout error: "+ec.message()); + // TODO: ignore or fail here? + } else { + m_alog.write(log::alevel::devel, "asio open handshake timer expired"); + terminate(make_error_code(error::open_handshake_timeout)); + } +} + +template +void connection::handle_close_handshake_timeout( + lib::error_code const & ec) +{ + +} + template void connection::terminate(const lib::error_code & ec) { if (m_alog.static_test(log::alevel::devel)) { From 408639a0b54c3f6b7891c7f33036abf3c5e1e7bf Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Sat, 8 Jun 2013 16:59:17 -0500 Subject: [PATCH 30/44] whitespace --- websocketpp/impl/connection_impl.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/websocketpp/impl/connection_impl.hpp b/websocketpp/impl/connection_impl.hpp index 2b6c9b72a1..4b0488e79e 100644 --- a/websocketpp/impl/connection_impl.hpp +++ b/websocketpp/impl/connection_impl.hpp @@ -1488,16 +1488,16 @@ void connection::handle_write_frame(bool terminate, if (m_alog.static_test(log::alevel::devel)) { m_alog.write(log::alevel::devel,"connection handle_write_frame"); } - + m_send_buffer.clear(); m_current_msg.reset(); - + if (ec) { m_elog.write(log::elevel::fatal,"error in handle_write_frame: "+ec.message()); this->terminate(ec); return; } - + if (terminate) { this->terminate(lib::error_code()); return; From 593c26f087d5b5ee7e650e5fdd6862d9922a01b2 Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Sat, 8 Jun 2013 16:59:42 -0500 Subject: [PATCH 31/44] fix devel debug comment --- websocketpp/impl/connection_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/websocketpp/impl/connection_impl.hpp b/websocketpp/impl/connection_impl.hpp index 4b0488e79e..3e4f25f088 100644 --- a/websocketpp/impl/connection_impl.hpp +++ b/websocketpp/impl/connection_impl.hpp @@ -1344,7 +1344,7 @@ void connection::handle_close_handshake_timeout( template void connection::terminate(const lib::error_code & ec) { if (m_alog.static_test(log::alevel::devel)) { - m_alog.write(log::alevel::devel,"connection "); + m_alog.write(log::alevel::devel,"connection terminate"); } terminate_status tstat = unknown; From dfcd8a2967462ad0dde35aff682cccf4711ad901 Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Sat, 8 Jun 2013 16:59:56 -0500 Subject: [PATCH 32/44] set detailed error code on terminate --- websocketpp/impl/connection_impl.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/websocketpp/impl/connection_impl.hpp b/websocketpp/impl/connection_impl.hpp index 3e4f25f088..65b679b421 100644 --- a/websocketpp/impl/connection_impl.hpp +++ b/websocketpp/impl/connection_impl.hpp @@ -1349,6 +1349,7 @@ void connection::terminate(const lib::error_code & ec) { terminate_status tstat = unknown; if (ec) { + m_ec = ec; m_local_close_code = close::status::abnormal_close; m_local_close_reason = ec.message(); } From cff860414816a515e4eee16629b2af5ecbf35410 Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Sat, 8 Jun 2013 17:00:45 -0500 Subject: [PATCH 33/44] cancel handshake timers when handshake is complete --- websocketpp/impl/connection_impl.hpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/websocketpp/impl/connection_impl.hpp b/websocketpp/impl/connection_impl.hpp index 65b679b421..6af9936e6b 100644 --- a/websocketpp/impl/connection_impl.hpp +++ b/websocketpp/impl/connection_impl.hpp @@ -1133,7 +1133,10 @@ void connection::handle_send_http_response( return; } - // TODO: cancel handshake timer + if (m_handshake_timer) { + m_handshake_timer->cancel(); + m_handshake_timer.reset(); + } this->atomic_state_change( istate::PROCESS_HTTP_REQUEST, @@ -1277,7 +1280,7 @@ void connection::handle_read_http_response(const lib::error_code& ec, this->terminate(ec); return; } - + // response is valid, connection can now be assumed to be open this->atomic_state_change( istate::READ_HTTP_RESPONSE, @@ -1287,14 +1290,17 @@ void connection::handle_read_http_response(const lib::error_code& ec, "handle_read_http_response must be called from READ_HTTP_RESPONSE state" ); + if (m_handshake_timer) { + m_handshake_timer->cancel(); + m_handshake_timer.reset(); + } + this->log_open_result(); if (m_open_handler) { m_open_handler(m_connection_hdl); } - - // TODO: cancel handshake timer - + // The remaining bytes in m_buf are frame data. Copy them to the // beginning of the buffer and note the length. They will be read after // the handshake completes and before more bytes are read. From c6381a2311a0575221cc5710bf95b7ac6d9d2fd1 Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Sat, 8 Jun 2013 17:01:00 -0500 Subject: [PATCH 34/44] start client handshake timer --- websocketpp/impl/connection_impl.hpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/websocketpp/impl/connection_impl.hpp b/websocketpp/impl/connection_impl.hpp index 6af9936e6b..0f44413cf0 100644 --- a/websocketpp/impl/connection_impl.hpp +++ b/websocketpp/impl/connection_impl.hpp @@ -623,6 +623,8 @@ template void connection::read_handshake(size_t num_bytes) { m_alog.write(log::alevel::devel,"connection read"); + // start timer + transport_con_type::async_read_at_least( num_bytes, m_buf, @@ -1189,6 +1191,15 @@ void connection::send_http_request() { "Raw Handshake request:\n"+m_handshake_buffer); } + m_handshake_timer = transport_con_type::set_timer( + config::timeout_open_handshake, + lib::bind( + &type::handle_open_handshake_timeout, + type::shared_from_this(), + lib::placeholders::_1 + ) + ); + transport_con_type::async_write( m_handshake_buffer.data(), m_handshake_buffer.size(), @@ -1215,9 +1226,7 @@ void connection::handle_send_http_request(const lib::error_code& ec) { this->terminate(ec); return; } - - // TODO: start read response timer? - + this->atomic_state_change( istate::WRITE_HTTP_REQUEST, istate::READ_HTTP_RESPONSE, From 96270a9f3daa892fd011051a97152b8383bec78e Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Sat, 8 Jun 2013 17:05:13 -0500 Subject: [PATCH 35/44] add test for client opening handshake --- test/transport/integration.cpp | 106 ++++++++++++++++++++++++++++----- 1 file changed, 91 insertions(+), 15 deletions(-) diff --git a/test/transport/integration.cpp b/test/transport/integration.cpp index d9bae9d54f..cc52e51e15 100644 --- a/test/transport/integration.cpp +++ b/test/transport/integration.cpp @@ -66,6 +66,9 @@ struct config : public websocketpp::config::asio_client { typedef websocketpp::transport::asio::endpoint transport_type; + //static const websocketpp::log::level elog_level = websocketpp::log::elevel::all; + //static const websocketpp::log::level alog_level = websocketpp::log::alevel::all; + /// Length of time before an opening handshake is aborted static const long timeout_open_handshake = 500; /// Length of time before a closing handshake is aborted @@ -81,9 +84,14 @@ using websocketpp::lib::placeholders::_1; using websocketpp::lib::placeholders::_2; using websocketpp::lib::bind; -void run_server(server * s, int port) { - s->clear_access_channels(websocketpp::log::alevel::all); - s->clear_error_channels(websocketpp::log::elevel::all); +void run_server(server * s, int port, bool log = false) { + if (log) { + s->set_access_channels(websocketpp::log::alevel::all); + s->set_error_channels(websocketpp::log::elevel::all); + } else { + s->clear_access_channels(websocketpp::log::alevel::all); + s->clear_error_channels(websocketpp::log::elevel::all); + } s->init_asio(); @@ -92,10 +100,14 @@ void run_server(server * s, int port) { s->run(); } -void run_client(client & c, std::string uri) { - c.clear_access_channels(websocketpp::log::alevel::all); - c.clear_error_channels(websocketpp::log::elevel::all); - +void run_client(client & c, std::string uri, bool log = false) { + if (log) { + c.set_access_channels(websocketpp::log::alevel::all); + c.set_error_channels(websocketpp::log::elevel::all); + } else { + c.clear_access_channels(websocketpp::log::alevel::all); + c.clear_error_channels(websocketpp::log::elevel::all); + } c.init_asio(); websocketpp::lib::error_code ec; @@ -106,6 +118,33 @@ void run_client(client & c, std::string uri) { c.run(); } +void run_dummy_server(int port) { + using boost::asio::ip::tcp; + + try { + boost::asio::io_service io_service; + tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v6(), port)); + tcp::socket socket(io_service); + + acceptor.accept(socket); + for (;;) { + char data[512]; + boost::system::error_code ec; + socket.read_some(boost::asio::buffer(data), ec); + if (ec == boost::asio::error::eof) { + break; + } else if (ec) { + // other error + throw ec; + } + } + } catch (std::exception & e) { + std::cout << e.what() << std::endl; + } catch (boost::system::error_code & ec) { + std::cout << ec.message() << std::endl; + } +} + bool on_ping(websocketpp::connection_hdl, std::string payload) { return false; } @@ -115,6 +154,9 @@ void cancel_on_open(server * s, websocketpp::connection_hdl hdl) { } void stop_on_close(server * s, websocketpp::connection_hdl hdl) { + server::connection_ptr con = s->get_con_from_hdl(hdl); + //BOOST_CHECK_EQUAL( con->get_local_close_code(), websocketpp::close::status::normal ); + //BOOST_CHECK_EQUAL( con->get_remote_close_code(), websocketpp::close::status::normal ); s->stop(); } @@ -125,7 +167,21 @@ void ping_on_open(T * c, std::string payload, websocketpp::connection_hdl hdl) { } void fail_on_pong(websocketpp::connection_hdl hdl, std::string payload) { - BOOST_FAIL( "expected no pong" ); + BOOST_FAIL( "expected no pong handler" ); +} + +void fail_on_open(websocketpp::connection_hdl hdl) { + BOOST_FAIL( "expected no open handler" ); +} + +template +void check_ec(T * c, websocketpp::lib::error_code ec, + websocketpp::connection_hdl hdl) +{ + typename T::connection_ptr con = c->get_con_from_hdl(hdl); + BOOST_CHECK_EQUAL( con->get_ec(), ec ); + //BOOST_CHECK_EQUAL( con->get_local_close_code(), websocketpp::close::status::normal ); + //BOOST_CHECK_EQUAL( con->get_remote_close_code(), websocketpp::close::status::normal ); } template @@ -139,15 +195,12 @@ void req_pong_timeout(T * c, std::string expected_payload, // Wait for the specified time period then fail the test void run_test_timer(long value) { - /*boost::asio::io_service ios; - boost::asio::deadline_timer t(ios,boost::posix_time::milliseconds(value)); - boost::system::error_code ec; - t.wait(ec);*/ sleep(value); BOOST_FAIL( "Test timed out" ); } BOOST_AUTO_TEST_CASE( pong_timeout ) { + try{ server s; client c; @@ -157,13 +210,36 @@ BOOST_AUTO_TEST_CASE( pong_timeout ) { c.set_pong_handler(bind(&fail_on_pong,::_1,::_2)); c.set_open_handler(bind(&ping_on_open,&c,"foo",::_1)); c.set_pong_timeout_handler(bind(&req_pong_timeout,&c,"foo",::_1,::_2)); - - websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005)); + c.set_close_handler(bind(&check_ec,&c, + websocketpp::lib::error_code(),::_1)); + + websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005,false)); websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,6)); tthread.detach(); - run_client(c, "http://localhost:9005"); + run_client(c, "http://localhost:9005",false); sthread.join(); + } catch (std::exception & ec) { + std::cout << ec.what() << std::endl; + } +} + +BOOST_AUTO_TEST_CASE( open_handshake_timeout ) { + server s; + client c; + + // set open handler to fail test + c.set_open_handler(bind(&fail_on_open,::_1)); + // set fail hander to test for the right fail error code + c.set_fail_handler(bind(&check_ec,&c, + websocketpp::error::open_handshake_timeout,::_1)); + + websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_dummy_server,9005)); + websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,6)); + sthread.detach(); + tthread.detach(); + + run_client(c, "http://localhost:9005"); } From 88c553f1fc570a2384010f177fb7cdf1528b0b1b Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Sat, 8 Jun 2013 18:29:12 -0500 Subject: [PATCH 36/44] silence unit tests --- test/connection/connection.cpp | 2 -- test/connection/connection_tu2.cpp | 3 +++ test/roles/client.cpp | 11 +++++------ test/roles/server.cpp | 2 ++ 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/test/connection/connection.cpp b/test/connection/connection.cpp index 38b147da9d..87e27262d8 100644 --- a/test/connection/connection.cpp +++ b/test/connection/connection.cpp @@ -41,8 +41,6 @@ BOOST_AUTO_TEST_CASE( basic_http_request ) { std::string o2 = run_server_test(input); - std::cout << "output: " << o2 << std::endl; - BOOST_CHECK(o2 == output); } diff --git a/test/connection/connection_tu2.cpp b/test/connection/connection_tu2.cpp index bbbc0287ec..5b66238063 100644 --- a/test/connection/connection_tu2.cpp +++ b/test/connection/connection_tu2.cpp @@ -40,6 +40,9 @@ std::string run_server_test(server& s, std::string input) { server::connection_ptr con; std::stringstream output; + s.clear_access_channels(websocketpp::log::alevel::all); + s.clear_error_channels(websocketpp::log::elevel::all); + s.register_ostream(&output); con = s.get_connection(); diff --git a/test/roles/client.cpp b/test/roles/client.cpp index 2dcbc18065..d6509384db 100644 --- a/test/roles/client.cpp +++ b/test/roles/client.cpp @@ -56,6 +56,9 @@ struct stub_config : public websocketpp::config::core { typedef core::transport_type transport_type; typedef core::endpoint_base endpoint_base; + + static const websocketpp::log::level elog_level = websocketpp::log::elevel::none; + static const websocketpp::log::level alog_level = websocketpp::log::alevel::none; }; typedef websocketpp::client client; @@ -124,9 +127,7 @@ BOOST_AUTO_TEST_CASE( connect_con ) { // connection should have written out an opening handshake request and be in // the read response internal state - - std::cout << "output: " << out.str() << std::endl; - + // TODO: more tests related to reading the HTTP response std::stringstream channel2; channel2 << "e\r\n\r\n"; @@ -185,9 +186,7 @@ BOOST_AUTO_TEST_CASE( add_subprotocols ) { o = out.str(); websocketpp::http::parser::request r; r.consume(o.data(),o.size()); - - std::cout << o << std::endl; - + BOOST_CHECK( r.ready() ); BOOST_CHECK_EQUAL( r.get_header("Sec-WebSocket-Protocol"), "foo, bar"); } diff --git a/test/roles/server.cpp b/test/roles/server.cpp index 9bd4372683..edb3f6ed34 100644 --- a/test/roles/server.cpp +++ b/test/roles/server.cpp @@ -68,6 +68,8 @@ std::string run_server_test(server& s, std::string input) { std::stringstream output; s.register_ostream(&output); + s.clear_access_channels(websocketpp::log::alevel::all); + s.clear_error_channels(websocketpp::log::elevel::all); con = s.get_connection(); con->start(); From bf582aa2c1f51d325dce16dc3ce42725b156a9a1 Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Sat, 8 Jun 2013 18:29:50 -0500 Subject: [PATCH 37/44] add unit test for server open handshake timeout --- test/transport/integration.cpp | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/test/transport/integration.cpp b/test/transport/integration.cpp index cc52e51e15..b6bdf5c4fa 100644 --- a/test/transport/integration.cpp +++ b/test/transport/integration.cpp @@ -184,6 +184,17 @@ void check_ec(T * c, websocketpp::lib::error_code ec, //BOOST_CHECK_EQUAL( con->get_remote_close_code(), websocketpp::close::status::normal ); } +template +void check_ec_and_stop(T * c, websocketpp::lib::error_code ec, + websocketpp::connection_hdl hdl) +{ + typename T::connection_ptr con = c->get_con_from_hdl(hdl); + BOOST_CHECK_EQUAL( con->get_ec(), ec ); + //BOOST_CHECK_EQUAL( con->get_local_close_code(), websocketpp::close::status::normal ); + //BOOST_CHECK_EQUAL( con->get_remote_close_code(), websocketpp::close::status::normal ); + c->stop(); +} + template void req_pong_timeout(T * c, std::string expected_payload, websocketpp::connection_hdl hdl, std::string payload) @@ -225,8 +236,7 @@ BOOST_AUTO_TEST_CASE( pong_timeout ) { } } -BOOST_AUTO_TEST_CASE( open_handshake_timeout ) { - server s; +BOOST_AUTO_TEST_CASE( client_open_handshake_timeout ) { client c; // set open handler to fail test @@ -243,3 +253,20 @@ BOOST_AUTO_TEST_CASE( open_handshake_timeout ) { run_client(c, "http://localhost:9005"); } +BOOST_AUTO_TEST_CASE( server_open_handshake_timeout ) { + server s; + + // set open handler to fail test + s.set_open_handler(bind(&fail_on_open,::_1)); + // set fail hander to test for the right fail error code + s.set_fail_handler(bind(&check_ec_and_stop,&s, + websocketpp::error::open_handshake_timeout,::_1)); + + websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005,false)); + websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,6)); + tthread.detach(); + + run_dummy_client("9005"); + + sthread.join(); +} From 33a0d89633900d04baf76bac233406b4fce8d3fc Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Sat, 8 Jun 2013 18:30:33 -0500 Subject: [PATCH 38/44] add transport integration dummy TCP client client connects and never sends anything. the client ends on EOF --- test/transport/integration.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/test/transport/integration.cpp b/test/transport/integration.cpp index b6bdf5c4fa..dadc31d0b3 100644 --- a/test/transport/integration.cpp +++ b/test/transport/integration.cpp @@ -145,6 +145,35 @@ void run_dummy_server(int port) { } } +void run_dummy_client(std::string port) { + using boost::asio::ip::tcp; + + try { + boost::asio::io_service io_service; + tcp::resolver resolver(io_service); + tcp::resolver::query query("localhost", port); + tcp::resolver::iterator iterator = resolver.resolve(query); + tcp::socket socket(io_service); + + boost::asio::connect(socket, iterator); + for (;;) { + char data[512]; + boost::system::error_code ec; + socket.read_some(boost::asio::buffer(data), ec); + if (ec == boost::asio::error::eof) { + break; + } else if (ec) { + // other error + throw ec; + } + } + } catch (std::exception & e) { + std::cout << e.what() << std::endl; + } catch (boost::system::error_code & ec) { + std::cout << ec.message() << std::endl; + } +} + bool on_ping(websocketpp::connection_hdl, std::string payload) { return false; } From f35918ce6e5009abeb702ffd724a69e982b36fb5 Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Sat, 8 Jun 2013 18:31:21 -0500 Subject: [PATCH 39/44] split log_fail_result from log_close_result --- websocketpp/connection.hpp | 7 ++++++- websocketpp/impl/connection_impl.hpp | 11 +++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/websocketpp/connection.hpp b/websocketpp/connection.hpp index 1536a644bc..b2c6ee0677 100644 --- a/websocketpp/connection.hpp +++ b/websocketpp/connection.hpp @@ -1040,11 +1040,16 @@ private: /// Prints information about a connection being closed to the access log /** - * Prints information about a connection being closed to the access log. * Includes: local and remote close codes and reasons */ void log_close_result(); + /// Prints information about a connection being failed to the access log + /** + * Includes: error code and message for why it was failed + */ + void log_fail_result(); + // static settings const std::string m_user_agent; diff --git a/websocketpp/impl/connection_impl.hpp b/websocketpp/impl/connection_impl.hpp index 0f44413cf0..bbdb9e8252 100644 --- a/websocketpp/impl/connection_impl.hpp +++ b/websocketpp/impl/connection_impl.hpp @@ -1409,8 +1409,7 @@ void connection::handle_terminate(terminate_status tstat, if (m_fail_handler) { m_fail_handler(m_connection_hdl); } - // TODO: custom fail output log format? - log_close_result(); + log_fail_result(); } else if (tstat == closed) { if (m_close_handler) { m_close_handler(m_connection_hdl); @@ -1912,6 +1911,14 @@ void connection::log_close_result() m_alog.write(log::alevel::disconnect,s.str()); } +template +void connection::log_fail_result() +{ + // TODO: include more information about the connection? + // should this be filed under connect rather than disconnect? + m_alog.write(log::alevel::disconnect,"Failed: "+m_ec.message()); +} + } // namespace websocketpp #endif // WEBSOCKETPP_CONNECTION_IMPL_HPP From c228f70a9f1476093677607a7d93372e85500494 Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Sat, 8 Jun 2013 18:32:06 -0500 Subject: [PATCH 40/44] complete handshake timeout references #226 --- websocketpp/impl/connection_impl.hpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/websocketpp/impl/connection_impl.hpp b/websocketpp/impl/connection_impl.hpp index bbdb9e8252..cc17b03eba 100644 --- a/websocketpp/impl/connection_impl.hpp +++ b/websocketpp/impl/connection_impl.hpp @@ -623,7 +623,14 @@ template void connection::read_handshake(size_t num_bytes) { m_alog.write(log::alevel::devel,"connection read"); - // start timer + m_handshake_timer = transport_con_type::set_timer( + config::timeout_open_handshake, + lib::bind( + &type::handle_open_handshake_timeout, + type::shared_from_this(), + lib::placeholders::_1 + ) + ); transport_con_type::async_read_at_least( num_bytes, @@ -652,6 +659,14 @@ void connection::handle_read_handshake(const lib::error_code& ec, ); if (ec) { + if (ec == transport::error::eof) { + // we expect to get eof if the connection is closed already + if (m_state == session::state::closed) { + m_alog.write(log::alevel::devel,"got eof from closed con"); + return; + } + } + std::stringstream s; s << "error in handle_read_handshake: "<< ec.message(); m_elog.write(log::elevel::fatal,s.str()); From 56e81cb6eba858841812e85b1a690a51ce9903dd Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Sun, 9 Jun 2013 07:33:30 -0500 Subject: [PATCH 41/44] impliment close handshake timeouts references #226 --- test/transport/integration.cpp | 55 ++++++++++++++++++++++++++++ websocketpp/impl/connection_impl.hpp | 31 +++++++++++++++- 2 files changed, 84 insertions(+), 2 deletions(-) diff --git a/test/transport/integration.cpp b/test/transport/integration.cpp index dadc31d0b3..82a55f20ac 100644 --- a/test/transport/integration.cpp +++ b/test/transport/integration.cpp @@ -299,3 +299,58 @@ BOOST_AUTO_TEST_CASE( server_open_handshake_timeout ) { sthread.join(); } + +BOOST_AUTO_TEST_CASE( client_self_initiated_close_handshake_timeout ) { + server s; + client c; + + // on open server sleeps for longer than the timeout + // on open client sends close handshake + // client handshake timer should be triggered + s.set_open_handler(bind(&delay,::_1,1)); + s.set_close_handler(bind(&stop_on_close,&s,::_1)); + + c.set_open_handler(bind(&close,&c,::_1)); + c.set_close_handler(bind(&check_ec,&c, + websocketpp::error::close_handshake_timeout,::_1)); + + websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005,false)); + websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,6)); + tthread.detach(); + + run_client(c, "http://localhost:9005",false); + + sthread.join(); +} + +BOOST_AUTO_TEST_CASE( client_peer_initiated_close_handshake_timeout ) { + // on open server sends close + // client should ack normally and then wait + // server leaves TCP connection open + // client handshake timer should be triggered + + // TODO: how to make a mock server that leaves the TCP connection open? +} + +BOOST_AUTO_TEST_CASE( server_self_initiated_close_handshake_timeout ) { + server s; + client c; + + // on open server sends close + // on open client sleeps for longer than the timeout + // server handshake timer should be triggered + + s.set_open_handler(bind(&close,&s,::_1)); + s.set_close_handler(bind(&check_ec_and_stop,&s, + websocketpp::error::close_handshake_timeout,::_1)); + + c.set_open_handler(bind(&delay,::_1,1)); + + websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005,false)); + websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,6)); + tthread.detach(); + + run_client(c, "http://localhost:9005",false); + + sthread.join(); +} diff --git a/websocketpp/impl/connection_impl.hpp b/websocketpp/impl/connection_impl.hpp index cc17b03eba..2429598a79 100644 --- a/websocketpp/impl/connection_impl.hpp +++ b/websocketpp/impl/connection_impl.hpp @@ -1368,7 +1368,17 @@ template void connection::handle_close_handshake_timeout( lib::error_code const & ec) { - + if (ec == transport::error::operation_aborted) { + m_alog.write(log::alevel::devel, + "asio close handshake timer cancelled"); + } else if (ec) { + m_alog.write(log::alevel::devel, + "asio open handle_close_handshake_timeout error: "+ec.message()); + // TODO: ignore or fail here? + } else { + m_alog.write(log::alevel::devel, "asio close handshake timer expired"); + terminate(make_error_code(error::close_handshake_timeout)); + } } template @@ -1376,7 +1386,13 @@ void connection::terminate(const lib::error_code & ec) { if (m_alog.static_test(log::alevel::devel)) { m_alog.write(log::alevel::devel,"connection terminate"); } - + + // Cancel close handshake timer + if (m_handshake_timer) { + m_handshake_timer->cancel(); + m_handshake_timer.reset(); + } + terminate_status tstat = unknown; if (ec) { m_ec = ec; @@ -1768,6 +1784,17 @@ lib::error_code connection::send_close_frame(close::status::value code, m_state = session::state::closing; + // Start a timer so we don't wait forever for the acknowledgement close + // frame + m_handshake_timer = transport_con_type::set_timer( + config::timeout_close_handshake, + lib::bind( + &type::handle_close_handshake_timeout, + type::shared_from_this(), + lib::placeholders::_1 + ) + ); + bool needs_writing = false; { scoped_lock_type lock(m_write_lock); From b9c66e9a7f715c887d82de70f21394a1755f60be Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Sun, 9 Jun 2013 07:33:48 -0500 Subject: [PATCH 42/44] transport integration test formatting cleanup --- test/transport/integration.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/test/transport/integration.cpp b/test/transport/integration.cpp index 82a55f20ac..6dcc436e69 100644 --- a/test/transport/integration.cpp +++ b/test/transport/integration.cpp @@ -214,14 +214,14 @@ void check_ec(T * c, websocketpp::lib::error_code ec, } template -void check_ec_and_stop(T * c, websocketpp::lib::error_code ec, +void check_ec_and_stop(T * e, websocketpp::lib::error_code ec, websocketpp::connection_hdl hdl) { - typename T::connection_ptr con = c->get_con_from_hdl(hdl); + typename T::connection_ptr con = e->get_con_from_hdl(hdl); BOOST_CHECK_EQUAL( con->get_ec(), ec ); //BOOST_CHECK_EQUAL( con->get_local_close_code(), websocketpp::close::status::normal ); //BOOST_CHECK_EQUAL( con->get_remote_close_code(), websocketpp::close::status::normal ); - c->stop(); + e->stop(); } template @@ -240,7 +240,6 @@ void run_test_timer(long value) { } BOOST_AUTO_TEST_CASE( pong_timeout ) { - try{ server s; client c; @@ -260,9 +259,6 @@ BOOST_AUTO_TEST_CASE( pong_timeout ) { run_client(c, "http://localhost:9005",false); sthread.join(); - } catch (std::exception & ec) { - std::cout << ec.what() << std::endl; - } } BOOST_AUTO_TEST_CASE( client_open_handshake_timeout ) { From 0ab1333a2fabe6aeadaa4f3a740f38347afc9a3d Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Sun, 9 Jun 2013 07:34:10 -0500 Subject: [PATCH 43/44] add transport integration helper handlers delay and close --- test/transport/integration.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/transport/integration.cpp b/test/transport/integration.cpp index 6dcc436e69..9d19778c18 100644 --- a/test/transport/integration.cpp +++ b/test/transport/integration.cpp @@ -203,6 +203,10 @@ void fail_on_open(websocketpp::connection_hdl hdl) { BOOST_FAIL( "expected no open handler" ); } +void delay(websocketpp::connection_hdl hdl, long duration) { + sleep(duration); +} + template void check_ec(T * c, websocketpp::lib::error_code ec, websocketpp::connection_hdl hdl) @@ -233,6 +237,11 @@ void req_pong_timeout(T * c, std::string expected_payload, con->close(websocketpp::close::status::normal,""); } +template +void close(T * e, websocketpp::connection_hdl hdl) { + e->get_con_from_hdl(hdl)->close(websocketpp::close::status::normal,""); +} + // Wait for the specified time period then fail the test void run_test_timer(long value) { sleep(value); From dd563c66477116c7a1a31542d90ce2e5f4ff7eca Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Sun, 9 Jun 2013 07:36:55 -0500 Subject: [PATCH 44/44] corrects TCP close behavior references #227 fixes #25 Per RFC6455 clients prefer to wait for servers to initiate TCP close. timers ensure that clients don't wait forever. Servers close TCP immediately. --- websocketpp/impl/connection_impl.hpp | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/websocketpp/impl/connection_impl.hpp b/websocketpp/impl/connection_impl.hpp index 2429598a79..f23144f4ac 100644 --- a/websocketpp/impl/connection_impl.hpp +++ b/websocketpp/impl/connection_impl.hpp @@ -800,10 +800,17 @@ void connection::handle_read_frame(const lib::error_code& ec, if (ec) { if (ec == transport::error::eof) { - // we expect to get eof if the connection is closed already if (m_state == session::state::closed) { + // we expect to get eof if the connection is closed already + // just ignore it m_alog.write(log::alevel::devel,"got eof from closed con"); return; + } else if (m_state == session::state::closing && !m_is_server) { + // If we are a client we expect to get eof in the closing state, + // this is a signal to terminate our end of the connection after + // the closing handshake + terminate(lib::error_code()); + return; } } if (ec == transport::error::tls_short_read) { @@ -1706,7 +1713,17 @@ void connection::process_control_frame(typename } else if (m_state == session::state::closing) { // ack of our close m_alog.write(log::alevel::devel,"Got acknowledgement of close"); - this->terminate(lib::error_code()); + + // If we are a server terminate the connection now. Clients should + // leave the connection open to give the server an opportunity to + // initiate the TCP close. The client's timer will handle closing + // its side of the connection if the server misbehaves. + // + // TODO: different behavior if the underlying transport doesn't + // support timers? + if (m_is_server) { + terminate(lib::error_code()); + } } else { // spurious, ignore m_elog.write(log::elevel::devel,"Got close frame in wrong state"); @@ -1776,7 +1793,7 @@ lib::error_code connection::send_close_frame(close::status::value code, } // Messages flagged terminal will result in the TCP connection being dropped - // after the message has been written. This is typically used when clients + // after the message has been written. This is typically used when servers // send an ack and when any endpoint encounters a protocol error if (terminal) { msg->set_terminal(true);