Merge branch 'experimental' into 0.3.x-cmake

This commit is contained in:
Peter Thorson
2013-06-09 08:13:02 -05:00
76 changed files with 1276 additions and 911 deletions

View File

@@ -2,13 +2,12 @@ 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-dev libboost-system1.48-dev libboost-thread1.48-dev libboost-test1.48-dev libboost-random1.48-dev -y
env:
global:
- BOOST_INCLUDES=/usr/include
- BOOST_LIBS=/usr/lib
script: scons && scons test
script: scons -j 2 && scons test
branches:
only:
- experimental

View File

@@ -670,7 +670,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
@@ -950,13 +950,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
@@ -965,7 +965,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

View File

@@ -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++'):
@@ -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)

View File

@@ -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;

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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 <websocketpp/config/asio_client.hpp>
#include <websocketpp/client.hpp>
@@ -24,7 +29,6 @@ public:
typedef std::chrono::duration<int,std::micro> 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);

View File

@@ -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)
* Portable, cross platform and architecture design
Get Involved
@@ -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/

View File

@@ -41,4 +41,5 @@ Needs work:
Non-release blocking feature roadmap
- Extension support
- permessage_compress extension
- Message buffer pool
- Message buffer pool
- CMake build/install support

View File

@@ -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);
}

View File

@@ -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();

View File

@@ -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)

View File

@@ -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<stub_config> 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");
}

View File

@@ -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();
@@ -136,7 +138,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";

24
test/transport/SConscript Normal file
View File

@@ -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')

View File

@@ -0,0 +1,361 @@
/*
* 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 <boost/test/unit_test.hpp>
#include <websocketpp/common/thread.hpp>
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/config/asio_no_tls_client.hpp>
#include <websocketpp/server.hpp>
#include <websocketpp/client.hpp>
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_config>
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
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<config> server;
typedef websocketpp::client<config> client;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;
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();
s->listen(port);
s->start_accept();
s->run();
}
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;
client::connection_ptr con = c.get_connection(uri,ec);
BOOST_CHECK( !ec );
c.connect(con);
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;
}
}
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;
}
void cancel_on_open(server * s, websocketpp::connection_hdl hdl) {
s->cancel();
}
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();
}
template <typename T>
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 handler" );
}
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 <typename T>
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 <typename T>
void check_ec_and_stop(T * e, websocketpp::lib::error_code ec,
websocketpp::connection_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 );
e->stop();
}
template <typename T>
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,"");
}
template <typename T>
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);
BOOST_FAIL( "Test timed out" );
}
BOOST_AUTO_TEST_CASE( pong_timeout ) {
server s;
client c;
s.set_ping_handler(on_ping);
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<client>,&c,"foo",::_1));
c.set_pong_timeout_handler(bind(&req_pong_timeout<client>,&c,"foo",::_1,::_2));
c.set_close_handler(bind(&check_ec<client>,&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",false);
sthread.join();
}
BOOST_AUTO_TEST_CASE( client_open_handshake_timeout ) {
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<client>,&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");
}
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<server>,&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();
}
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<client>,&c,::_1));
c.set_close_handler(bind(&check_ec<client>,&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<server>,&s,::_1));
s.set_close_handler(bind(&check_ec_and_stop<server>,&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();
}

View File

@@ -52,6 +52,8 @@ typedef websocketpp::transport::iostream::connection<config> 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" );
}
}
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 );
}

View File

@@ -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 <websocketpp/error.hpp>
#include <websocketpp/common/network.hpp>
#include <websocketpp/common/stdint.hpp>
@@ -37,60 +41,137 @@
#include <string>
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;
}

View File

@@ -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,8 @@
#include <string>
#include <cstring>
namespace websocketpp {
/// Provides MD5 hashing functionality
namespace md5 {
typedef unsigned char md5_byte_t; /* 8-bit byte */
@@ -86,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]);
@@ -164,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];
@@ -177,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
{
@@ -187,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 */
{
@@ -197,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);
@@ -345,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;
@@ -355,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);
@@ -393,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,
@@ -417,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;
@@ -435,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;
@@ -448,5 +442,6 @@ inline std::string md5_hash_hex(const std::string& input) {
}
} // md5
} // websocketpp
#endif // md5_INCLUDED
#endif // WEBSOCKETPP_COMMON_MD5_HPP

View File

@@ -33,6 +33,7 @@
namespace websocketpp {
namespace concurrency {
/// Concurrency policy that uses std::mutex / boost::mutex
class basic {
public:
typedef lib::mutex mutex_type;

View File

@@ -28,36 +28,24 @@
#ifndef WEBSOCKETPP_CONCURRENCY_NONE_HPP
#define WEBSOCKETPP_CONCURRENCY_NONE_HPP
//#include <iostream>
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
class none {
public:
typedef none_impl::fake_mutex mutex_type;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -25,20 +25,47 @@
*
*/
#ifndef WEBSOCKETPP_SERVER_ROLE_HPP
#define WEBSOCKETPP_SERVER_ROLE_HPP
// 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.
#include <iostream>
#ifndef WEBSOCKETPP_CONFIG_BOOST_CONFIG_HPP
#define WEBSOCKETPP_CONFIG_BOOST_CONFIG_HPP
namespace websocketpp {
namespace role {
#include <boost/config.hpp>
class server {
public:
static bool is_server = true;
}
// _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
} // namespace role
} // namespace websocketpp
#ifndef BOOST_ASIO_HAS_STD_CHRONO
#define _WEBSOCKETPP_CPP11_CHRONO_
#endif
#endif //WEBSOCKETPP_SERVER_ROLE_HPP
#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_BOOST_CONFIG_HPP

View File

@@ -63,6 +63,7 @@
namespace websocketpp {
namespace config {
/// Server config with iostream transport
struct core {
typedef core type;
@@ -196,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

View File

@@ -63,6 +63,7 @@
namespace websocketpp {
namespace config {
/// Client config with iostream transport
struct core_client {
typedef core_client type;
@@ -197,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

View File

@@ -64,6 +64,7 @@
namespace websocketpp {
namespace config {
/// Client/Server debug config with iostream transport
struct debug_core {
typedef debug_core type;
@@ -197,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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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,
@@ -113,7 +113,7 @@ namespace internal_state {
} // namespace internal_state
} // namespace session
// impliments the websocket state machine
/// Represents an individual WebSocket connection
template <typename config>
class connection
: public config::transport_type::transport_con_type
@@ -163,7 +163,10 @@ public:
// Message handler (needs to know message type)
typedef lib::function<void(connection_hdl,message_ptr)> 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
* 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.
* 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.
@@ -759,6 +775,52 @@ 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
* 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 //
@@ -781,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);
@@ -794,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);
@@ -978,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;
@@ -1027,6 +1094,8 @@ 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
// handshake.
@@ -1100,6 +1169,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;

View File

@@ -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 <typename connection, typename config>
class endpoint : public config::transport_type, public config::endpoint_base {
public:

View File

@@ -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";
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -36,32 +36,42 @@
#include <websocketpp/utilities.hpp>
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 <typename iter_type>
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 <typename iter_type>
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
@@ -725,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)

View File

@@ -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";

View File

@@ -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;
}

View File

@@ -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.

View File

@@ -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.

View File

@@ -139,21 +139,45 @@ lib::error_code connection<config>::send(typename config::message_type::ptr msg)
}
template <typename config>
void connection<config>::ping(const std::string& payload) {
void connection<config>::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<config>::ping(const std::string& payload) {
type::shared_from_this()
));
}
ec = lib::error_code();
}
template<typename config>
void connection<config>::ping(const std::string& payload) {
lib::error_code ec;
ping(payload,ec);
if (ec) {
throw ec;
}
}
template<typename config>
void connection<config>::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 <typename config>
@@ -187,9 +241,7 @@ void connection<config>::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;
{
@@ -512,7 +564,7 @@ void connection<config>::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(
@@ -571,6 +623,15 @@ template <typename config>
void connection<config>::read_handshake(size_t num_bytes) {
m_alog.write(log::alevel::devel,"connection read");
m_handshake_timer = transport_con_type::set_timer(
config::timeout_open_handshake,
lib::bind(
&type::handle_open_handshake_timeout,
type::shared_from_this(),
lib::placeholders::_1
)
);
transport_con_type::async_read_at_least(
num_bytes,
m_buf,
@@ -598,6 +659,14 @@ void connection<config>::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());
@@ -731,10 +800,17 @@ void connection<config>::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) {
@@ -942,7 +1018,7 @@ bool connection<config>::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) {
@@ -1081,7 +1157,10 @@ void connection<config>::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,
@@ -1134,6 +1213,15 @@ void connection<config>::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(),
@@ -1160,9 +1248,7 @@ void connection<config>::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,
@@ -1225,7 +1311,7 @@ void connection<config>::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,
@@ -1235,14 +1321,17 @@ void connection<config>::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.
@@ -1265,14 +1354,55 @@ void connection<config>::handle_read_http_response(const lib::error_code& ec,
}
}
template <typename config>
void connection<config>::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 <typename config>
void connection<config>::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 <typename config>
void connection<config>::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");
}
// 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;
m_local_close_code = close::status::abnormal_close;
m_local_close_reason = ec.message();
}
@@ -1317,8 +1447,7 @@ void connection<config>::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);
@@ -1412,16 +1541,16 @@ void connection<config>::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;
@@ -1584,7 +1713,17 @@ void connection<config>::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");
@@ -1608,7 +1747,7 @@ lib::error_code connection<config>::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
@@ -1654,12 +1793,25 @@ lib::error_code connection<config>::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);
}
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);
@@ -1818,6 +1970,14 @@ void connection<config>::log_close_result()
m_alog.write(log::alevel::disconnect,s.str());
}
template <typename config>
void connection<config>::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

View File

@@ -49,6 +49,7 @@
namespace websocketpp {
namespace log {
/// Basic logger that outputs to an ostream
template <typename concurrency, typename names>
class basic {
public:

View File

@@ -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";

View File

@@ -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) {}

View File

@@ -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
<ghost@aladdin.com>. 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 <string.h>
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 <stdio.h> 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 <string.h>
#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));
}

View File

@@ -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
<ghost@aladdin.com>. 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 <purschke@bnl.gov>.
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 <stddef.h>
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 */

View File

@@ -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.
*/

View File

@@ -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:

View File

@@ -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.
*/

View File

@@ -42,7 +42,7 @@
#include <websocketpp/frame.hpp>
#include <websocketpp/utf8_validator.hpp>
#include <websocketpp/md5/md5.hpp>
#include <websocketpp/common/md5.hpp>
namespace websocketpp {
namespace processor {
@@ -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;
}

View File

@@ -54,6 +54,7 @@
namespace websocketpp {
namespace processor {
/// Processor for Hybi version 13 (RFC6455)
template <typename config>
class hybi13 : public processor<config> {
public:
@@ -87,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) {
@@ -116,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

View File

@@ -153,6 +153,7 @@ uri_ptr get_uri_from_host(request_type & request, std::string scheme) {
// }
// }
/// WebSocket protocol processor base class
template <typename config>
class processor {
public:
@@ -172,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 {
@@ -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
@@ -288,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

View File

@@ -30,6 +30,7 @@
namespace websocketpp {
namespace random {
/// Stub RNG policy that always returns 0
namespace none {
/// Thread safe stub "random" integer generator.

View File

@@ -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.

View File

@@ -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 <iostream>
namespace websocketpp {
namespace role {
class client {
public:
static bool is_server = false;
}
} // namespace role
} // namespace websocketpp
#endif //WEBSOCKETPP_CLIENT_ROLE_HPP

View File

@@ -30,6 +30,7 @@
namespace websocketpp {
/// Provides SHA1 hashing functionality
class SHA1
{
public:

View File

@@ -38,6 +38,7 @@
namespace websocketpp {
namespace transport {
/// Transport policy that uses boost::asio
namespace asio {
typedef lib::function<void(const boost::system::error_code &)>

View File

@@ -53,7 +53,7 @@ typedef lib::function<void(connection_hdl)> 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: "

View File

@@ -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 <typename config>

View File

@@ -39,13 +39,13 @@
#include <iostream>
#include <string>
// 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

View File

@@ -45,7 +45,7 @@ typedef lib::function<void(connection_hdl,boost::asio::ip::tcp::socket&)>
/// 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;

View File

@@ -52,7 +52,7 @@ typedef lib::function<lib::shared_ptr<boost::asio::ssl::context>(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;

View File

@@ -37,6 +37,7 @@
#include <iostream>
namespace websocketpp {
/// Transport policies provide network connectivity and timers
namespace transport {
// Endpoint callbacks
@@ -46,7 +47,7 @@ typedef lib::function<void(connection_hdl,const lib::error_code&)> connect_handl
typedef lib::function<void()> endpoint_lock;
// Endpoint interface
// Methods a transport endpoint must impliment
// Methods a transport endpoint must implement
/// Initialize a connection
/**

View File

@@ -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 {

View File

@@ -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 <typename config>
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> timer_ptr;
explicit connection(bool is_server, alog_type& alog, elog_type& elog)
: m_output_stream(NULL)
, m_reading(false)
@@ -87,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
@@ -95,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.
@@ -115,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
@@ -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 implemented in this transport. The timer pointer will
* always be empty. The handler will never be called.
*
* @param duration Length of time to wait in milliseconds
*
* @param callback The function to call back when the timer has expired
*
* @return A handle that can be used to cancel the timer if it is no longer
* needed.
*/
timer_ptr set_timer(long duration, timer_handler callback) {
return timer_ptr();
}
protected:
void init(init_handler callback) {
m_alog.write(log::alevel::devel,"iostream connection init");

View File

@@ -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) {}