mirror of
https://github.com/XRPLF/rippled.git
synced 2026-04-29 15:37:57 +00:00
Merge branch 'experimental' into 0.3.x-cmake
This commit is contained in:
@@ -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
|
||||
|
||||
8
Doxyfile
8
Doxyfile
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
11
readme.md
11
readme.md
@@ -1,16 +1,16 @@
|
||||
WebSocket++ (0.3.x branch)
|
||||
==========================
|
||||
|
||||
WebSocket++ is a header only C++ library that impliments RFC6455 The WebSocket
|
||||
WebSocket++ is a header only C++ library that implements RFC6455 The WebSocket
|
||||
Protocol. It allows integrating WebSocket client and server functionality into
|
||||
C++ programs. It uses interchangable network transport modules including one
|
||||
C++ programs. It uses interchangeable network transport modules including one
|
||||
based on C++ iostreams and one based on Boost Asio.
|
||||
|
||||
*This branch is no longer "experimental". It represents the current edge release
|
||||
of the WebSocket++ library. The API of 0.3.x has some significant changes from
|
||||
0.2.x, so care should be taken when upgrading.*
|
||||
|
||||
*This branch's API is relatively stable now. Features implimented so far are
|
||||
*This branch's API is relatively stable now. Features implemented so far are
|
||||
unlikely to change (except where explicitly noted). New features will be added
|
||||
regularly until parity with the 0.2 branch is reached.*
|
||||
|
||||
@@ -25,7 +25,7 @@ Major Features
|
||||
* Message/event based interface
|
||||
* Supports secure WebSockets (TLS), IPv6, and explicit proxies.
|
||||
* Flexible dependency management (C++11 Standard Library or Boost)
|
||||
* Interchangable network transport modules (iostream and Boost Asio)
|
||||
* Interchangeable network transport modules (iostream and Boost Asio)
|
||||
* 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/
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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
24
test/transport/SConscript
Normal 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')
|
||||
361
test/transport/integration.cpp
Normal file
361
test/transport/integration.cpp
Normal 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();
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -33,6 +33,7 @@
|
||||
namespace websocketpp {
|
||||
namespace concurrency {
|
||||
|
||||
/// Concurrency policy that uses std::mutex / boost::mutex
|
||||
class basic {
|
||||
public:
|
||||
typedef lib::mutex mutex_type;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
namespace websocketpp {
|
||||
namespace log {
|
||||
|
||||
/// Basic logger that outputs to an ostream
|
||||
template <typename concurrency, typename names>
|
||||
class basic {
|
||||
public:
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
namespace websocketpp {
|
||||
namespace random {
|
||||
/// Stub RNG policy that always returns 0
|
||||
namespace none {
|
||||
|
||||
/// Thread safe stub "random" integer generator.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
namespace websocketpp {
|
||||
|
||||
/// Provides SHA1 hashing functionality
|
||||
class SHA1
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -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 &)>
|
||||
|
||||
@@ -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: "
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
/**
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
Reference in New Issue
Block a user