mirror of
https://github.com/XRPLF/rippled.git
synced 2026-04-29 15:37:57 +00:00
Merge pull request #228 from zaphoyd/experimental
Merge experimental into 0.3.x-cmake
This commit is contained in:
20
SConstruct
20
SConstruct
@@ -2,10 +2,12 @@ import os, sys, commands
|
||||
env = Environment(ENV = os.environ)
|
||||
|
||||
# figure out a better way to configure this
|
||||
#env["CXX"] = "clang++"
|
||||
if os.environ.has_key('CXX'):
|
||||
env['CXX'] = os.environ['CXX']
|
||||
|
||||
if os.environ.has_key('DEBUG'):
|
||||
env['DEBUG'] = os.environ['DEBUG']
|
||||
|
||||
if os.environ.has_key('CXXFLAGS'):
|
||||
#env['CXXFLAGS'] = os.environ['CXXFLAGS']
|
||||
env.Append(CXXFLAGS = os.environ['CXXFLAGS'])
|
||||
@@ -69,14 +71,20 @@ if env['PLATFORM'].startswith('win'):
|
||||
env['CCFLAGS'] = '%s /EHsc /GR /GS- /MD /nologo %s %s' % (warn_flags, arch_flags, opt_flags)
|
||||
env['LINKFLAGS'] = '/INCREMENTAL:NO /MANIFEST /NOLOGO /OPT:REF /OPT:ICF /MACHINE:X86'
|
||||
elif env['PLATFORM'] == 'posix':
|
||||
env.Append(CPPDEFINES = ['NDEBUG'])
|
||||
if env.has_key('DEBUG'):
|
||||
env.Append(CCFLAGS = ['-g', '-O0'])
|
||||
else:
|
||||
env.Append(CPPDEFINES = ['NDEBUG'])
|
||||
env.Append(CCFLAGS = ['-O3', '-fomit-frame-pointer'])
|
||||
env.Append(CCFLAGS = ['-Wall'])
|
||||
#env.Append(CCFLAGS = ['-O3', '-fomit-frame-pointer'])
|
||||
#env['LINKFLAGS'] = ''
|
||||
elif env['PLATFORM'] == 'darwin':
|
||||
#env.Append(CPPDEFINES = ['NDEBUG'])
|
||||
env.Append(CCFLAGS = ['-Wall','-O0'])
|
||||
#env.Append(CCFLAGS = ['-O3', '-fomit-frame-pointer'])
|
||||
if env.has_key('DEBUG'):
|
||||
env.Append(CCFLAGS = ['-g', '-O0'])
|
||||
else:
|
||||
env.Append(CPPDEFINES = ['NDEBUG'])
|
||||
env.Append(CCFLAGS = ['-O3', '-fomit-frame-pointer'])
|
||||
env.Append(CCFLAGS = ['-Wall'])
|
||||
#env['LINKFLAGS'] = ''
|
||||
|
||||
if env['PLATFORM'].startswith('win'):
|
||||
|
||||
@@ -43,6 +43,10 @@ public:
|
||||
websocketpp::lib::error_code ec;
|
||||
client::connection_ptr con = m_endpoint.get_connection(uri, ec);
|
||||
|
||||
if (ec) {
|
||||
m_endpoint.get_alog().write(websocketpp::log::alevel::app,ec.message());
|
||||
}
|
||||
|
||||
//con->set_proxy("http://humupdates.uchicago.edu:8443");
|
||||
|
||||
m_endpoint.connect(con);
|
||||
|
||||
@@ -18,7 +18,7 @@ prgs = env.Program('test_base_boost', ["base_boost.o"], LIBS = BOOST_LIBS)
|
||||
#prgs += env.Program('test_utility_boost', ["utilities_boost.o"], LIBS = BOOST_LIBS)
|
||||
|
||||
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework'],env_cpp11) + [platform_libs] + [polyfill_libs]
|
||||
BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework','system'],env_cpp11) + [platform_libs] + [polyfill_libs]
|
||||
objs += env_cpp11.Object('base_stl.o', ["base.cpp"], LIBS = BOOST_LIBS_CPP11)
|
||||
prgs += env_cpp11.Program('test_base_stl', ["base_stl.o"], LIBS = BOOST_LIBS_CPP11)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
@@ -33,17 +33,17 @@
|
||||
#include <websocketpp/transport/asio/base.hpp>
|
||||
|
||||
BOOST_AUTO_TEST_CASE( blank_error ) {
|
||||
websocketpp::lib::error_code ec;
|
||||
|
||||
websocketpp::lib::error_code ec;
|
||||
|
||||
BOOST_CHECK( !ec );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( asio_error ) {
|
||||
using websocketpp::transport::asio::error::make_error_code;
|
||||
using websocketpp::transport::asio::error::general;
|
||||
|
||||
websocketpp::lib::error_code ec = make_error_code(general);
|
||||
|
||||
using websocketpp::transport::asio::error::make_error_code;
|
||||
using websocketpp::transport::asio::error::general;
|
||||
|
||||
websocketpp::lib::error_code ec = make_error_code(general);
|
||||
|
||||
BOOST_CHECK( ec == general );
|
||||
BOOST_CHECK( ec.value() == 1 );
|
||||
}
|
||||
@@ -407,7 +407,7 @@ BOOST_AUTO_TEST_CASE( continuous_word_mask ) {
|
||||
|
||||
pkey_temp = frame::word_mask_circ(input+7,output+7,8,pkey_temp);
|
||||
BOOST_CHECK( std::equal(output,output+16,masked) );
|
||||
BOOST_CHECK( pkey_temp == frame::circshift_prepared_key(pkey,3) );
|
||||
BOOST_CHECK_EQUAL( pkey_temp, frame::circshift_prepared_key(pkey,3) );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( continuous_word_mask_inplace ) {
|
||||
@@ -437,11 +437,11 @@ BOOST_AUTO_TEST_CASE( continuous_word_mask_inplace ) {
|
||||
|
||||
pkey_temp = frame::word_mask_circ(buffer,7,pkey);
|
||||
BOOST_CHECK( std::equal(buffer,buffer+7,masked) );
|
||||
BOOST_CHECK( pkey_temp == frame::circshift_prepared_key(pkey,3) );
|
||||
BOOST_CHECK_EQUAL( pkey_temp, frame::circshift_prepared_key(pkey,3) );
|
||||
|
||||
pkey_temp = frame::word_mask_circ(buffer+7,8,pkey_temp);
|
||||
BOOST_CHECK( std::equal(buffer,buffer+16,masked) );
|
||||
BOOST_CHECK( pkey_temp == frame::circshift_prepared_key(pkey,3) );
|
||||
BOOST_CHECK_EQUAL( pkey_temp, frame::circshift_prepared_key(pkey,3) );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( continuous_word_mask2 ) {
|
||||
|
||||
@@ -41,22 +41,23 @@ namespace config {
|
||||
|
||||
struct asio_tls_client : public core_client {
|
||||
typedef asio_tls_client type;
|
||||
typedef core_client base;
|
||||
|
||||
typedef core_client::concurrency_type concurrency_type;
|
||||
typedef base::concurrency_type concurrency_type;
|
||||
|
||||
typedef core_client::request_type request_type;
|
||||
typedef core_client::response_type response_type;
|
||||
typedef base::request_type request_type;
|
||||
typedef base::response_type response_type;
|
||||
|
||||
typedef core_client::message_type message_type;
|
||||
typedef core_client::con_msg_manager_type con_msg_manager_type;
|
||||
typedef core_client::endpoint_msg_manager_type endpoint_msg_manager_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 core_client::alog_type alog_type;
|
||||
typedef core_client::elog_type elog_type;
|
||||
typedef base::alog_type alog_type;
|
||||
typedef base::elog_type elog_type;
|
||||
|
||||
typedef core_client::rng_type rng_type;
|
||||
typedef base::rng_type rng_type;
|
||||
|
||||
struct transport_config {
|
||||
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;
|
||||
|
||||
@@ -36,22 +36,23 @@ namespace config {
|
||||
|
||||
struct asio : public core {
|
||||
typedef asio type;
|
||||
typedef core base;
|
||||
|
||||
typedef core::concurrency_type concurrency_type;
|
||||
typedef base::concurrency_type concurrency_type;
|
||||
|
||||
typedef core::request_type request_type;
|
||||
typedef core::response_type response_type;
|
||||
typedef base::request_type request_type;
|
||||
typedef base::response_type response_type;
|
||||
|
||||
typedef core::message_type message_type;
|
||||
typedef core::con_msg_manager_type con_msg_manager_type;
|
||||
typedef core::endpoint_msg_manager_type endpoint_msg_manager_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 core::alog_type alog_type;
|
||||
typedef core::elog_type elog_type;
|
||||
typedef base::alog_type alog_type;
|
||||
typedef base::elog_type elog_type;
|
||||
|
||||
typedef core::rng_type rng_type;
|
||||
typedef base::rng_type rng_type;
|
||||
|
||||
struct transport_config {
|
||||
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;
|
||||
|
||||
@@ -36,22 +36,23 @@ namespace config {
|
||||
|
||||
struct asio_client : public core_client {
|
||||
typedef asio_client type;
|
||||
typedef core_client base;
|
||||
|
||||
typedef core_client::concurrency_type concurrency_type;
|
||||
typedef base::concurrency_type concurrency_type;
|
||||
|
||||
typedef core_client::request_type request_type;
|
||||
typedef core_client::response_type response_type;
|
||||
typedef base::request_type request_type;
|
||||
typedef base::response_type response_type;
|
||||
|
||||
typedef core_client::message_type message_type;
|
||||
typedef core_client::con_msg_manager_type con_msg_manager_type;
|
||||
typedef core_client::endpoint_msg_manager_type endpoint_msg_manager_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 core_client::alog_type alog_type;
|
||||
typedef core_client::elog_type elog_type;
|
||||
typedef base::alog_type alog_type;
|
||||
typedef base::elog_type elog_type;
|
||||
|
||||
typedef core_client::rng_type rng_type;
|
||||
typedef base::rng_type rng_type;
|
||||
|
||||
struct transport_config {
|
||||
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;
|
||||
|
||||
@@ -97,6 +97,17 @@ struct core {
|
||||
typedef type::alog_type alog_type;
|
||||
typedef type::request_type request_type;
|
||||
typedef type::response_type response_type;
|
||||
|
||||
/// Default timer values (in ms)
|
||||
|
||||
/// Length of time to wait before a proxy handshake is aborted
|
||||
static const long timeout_proxy = 5000;
|
||||
/// Length of time to wait before a tls handshake is aborted
|
||||
static const long timeout_tls_handshake = 5000;
|
||||
/// Length of time to wait for dns resolution
|
||||
static const long timeout_dns_resolve = 5000;
|
||||
/// Length of time to wait for socket shutdown
|
||||
static const long timeout_socket_shutdown = 5000;
|
||||
};
|
||||
|
||||
/// Transport Endpoint Component
|
||||
@@ -108,6 +119,15 @@ struct core {
|
||||
/// User overridable Connection base class
|
||||
typedef websocketpp::connection_base connection_base;
|
||||
|
||||
/// Default timer values (in ms)
|
||||
|
||||
/// Length of time before an opening handshake is aborted
|
||||
static const long timeout_open_handshake = 5000;
|
||||
/// Length of time before a closing handshake is aborted
|
||||
static const long timeout_close_handshake = 5000;
|
||||
/// Length of time to wait for a pong after a ping
|
||||
static const long timeout_pong = 5000;
|
||||
|
||||
/// WebSocket Protocol version to use as a client
|
||||
/**
|
||||
* What version of the WebSocket Protocol to use for outgoing client
|
||||
|
||||
@@ -96,6 +96,17 @@ struct core_client {
|
||||
typedef type::alog_type alog_type;
|
||||
typedef type::request_type request_type;
|
||||
typedef type::response_type response_type;
|
||||
|
||||
/// Default timer values (in ms)
|
||||
|
||||
/// Length of time to wait before a proxy handshake is aborted
|
||||
static const long timeout_proxy = 5000;
|
||||
/// Length of time to wait before a tls handshake is aborted
|
||||
static const long timeout_tls_handshake = 5000;
|
||||
/// Length of time to wait for dns resolution
|
||||
static const long timeout_dns_resolve = 5000;
|
||||
/// Length of time to wait for socket shutdown
|
||||
static const long timeout_socket_shutdown = 5000;
|
||||
};
|
||||
|
||||
/// Transport Endpoint Component
|
||||
@@ -107,6 +118,15 @@ struct core_client {
|
||||
/// User overridable Connection base class
|
||||
typedef websocketpp::connection_base connection_base;
|
||||
|
||||
/// Default timer values (in ms)
|
||||
|
||||
/// Length of time before an opening handshake is aborted
|
||||
static const long timeout_open_handshake = 5000;
|
||||
/// Length of time before a closing handshake is aborted
|
||||
static const long timeout_close_handshake = 5000;
|
||||
/// Length of time to wait for a pong after a ping
|
||||
static const long timeout_pong = 5000;
|
||||
|
||||
/// WebSocket Protocol version to use as a client
|
||||
/**
|
||||
* What version of the WebSocket Protocol to use for outgoing client
|
||||
|
||||
@@ -97,6 +97,17 @@ struct debug_core {
|
||||
typedef type::alog_type alog_type;
|
||||
typedef type::request_type request_type;
|
||||
typedef type::response_type response_type;
|
||||
|
||||
/// Default timer values (in ms)
|
||||
|
||||
/// Length of time to wait before a proxy handshake is aborted
|
||||
static const long timeout_proxy = 5000;
|
||||
/// Length of time to wait before a tls handshake is aborted
|
||||
static const long timeout_tls_handshake = 5000;
|
||||
/// Length of time to wait for dns resolution
|
||||
static const long timeout_dns_resolve = 5000;
|
||||
/// Length of time to wait for socket shutdown
|
||||
static const long timeout_socket_shutdown = 5000;
|
||||
};
|
||||
|
||||
/// Transport Endpoint Component
|
||||
@@ -108,6 +119,15 @@ struct debug_core {
|
||||
/// User overridable Connection base class
|
||||
typedef websocketpp::connection_base connection_base;
|
||||
|
||||
/// Default timer values (in ms)
|
||||
|
||||
/// Length of time before an opening handshake is aborted
|
||||
static const long timeout_open_handshake = 5000;
|
||||
/// Length of time before a closing handshake is aborted
|
||||
static const long timeout_close_handshake = 5000;
|
||||
/// Length of time to wait for a pong after a ping
|
||||
static const long timeout_pong = 5000;
|
||||
|
||||
/// WebSocket Protocol version to use as a client
|
||||
/**
|
||||
* What version of the WebSocket Protocol to use for outgoing client
|
||||
|
||||
@@ -57,7 +57,7 @@ struct debug_asio_tls : public debug_core {
|
||||
|
||||
typedef base::rng_type rng_type;
|
||||
|
||||
struct transport_config {
|
||||
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;
|
||||
|
||||
@@ -52,7 +52,7 @@ struct debug_asio : public debug_core {
|
||||
|
||||
typedef base::rng_type rng_type;
|
||||
|
||||
struct transport_config {
|
||||
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;
|
||||
|
||||
@@ -167,6 +167,14 @@ public:
|
||||
// Misc Convenience Types
|
||||
typedef session::internal_state::value istate_type;
|
||||
|
||||
private:
|
||||
enum terminate_status {
|
||||
failed = 1,
|
||||
closed,
|
||||
unknown
|
||||
};
|
||||
public:
|
||||
|
||||
explicit connection(bool is_server, const std::string& ua, alog_type& alog,
|
||||
elog_type& elog, rng_type & rng)
|
||||
: transport_con_type(is_server,alog,elog)
|
||||
@@ -773,14 +781,12 @@ public:
|
||||
|
||||
void start();
|
||||
|
||||
void read(size_t num_bytes);
|
||||
void handle_read(const lib::error_code& ec, size_t bytes_transferred);
|
||||
|
||||
void read_handshake(size_t num_bytes);
|
||||
|
||||
void write(std::string msg);
|
||||
void handle_write(const lib::error_code& ec);
|
||||
//void write(std::string msg);
|
||||
//void handle_write(const lib::error_code& ec);
|
||||
|
||||
void handle_handshake_read(const lib::error_code& ec,
|
||||
void handle_read_handshake(const lib::error_code& ec,
|
||||
size_t bytes_transferred);
|
||||
void handle_read_http_response(const lib::error_code& ec,
|
||||
size_t bytes_transferred);
|
||||
@@ -798,7 +804,8 @@ public:
|
||||
/// internally by the endpoint class.
|
||||
void set_termination_handler(termination_handler new_handler);
|
||||
|
||||
void terminate();
|
||||
void terminate(const lib::error_code & ec);
|
||||
void handle_terminate(terminate_status tstat, const lib::error_code& ec);
|
||||
|
||||
/// Checks if there are frames in the send queue and if there are sends one
|
||||
/**
|
||||
|
||||
@@ -100,6 +100,9 @@ enum value {
|
||||
|
||||
/// Attempted to use a server specific feature on a client endpoint
|
||||
server_only,
|
||||
|
||||
/// HTTP connection ended
|
||||
http_connection_ended
|
||||
}; // enum value
|
||||
|
||||
|
||||
@@ -153,6 +156,8 @@ public:
|
||||
return "Feature not available on server endpoints";
|
||||
case error::server_only:
|
||||
return "Feature not available on client endpoints";
|
||||
case error::http_connection_ended:
|
||||
return "HTTP connection ended";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
@@ -552,30 +552,23 @@ void connection<config>::handle_transport_init(const lib::error_code& ec) {
|
||||
s << "handle_transport_init recieved error: "<< ec.message();
|
||||
m_elog.write(log::elevel::fatal,s.str());
|
||||
|
||||
this->terminate();
|
||||
this->terminate(ec);
|
||||
return;
|
||||
}
|
||||
|
||||
// At this point the transport is ready to read and write bytes.
|
||||
|
||||
if (m_is_server) {
|
||||
this->read(1);
|
||||
this->read_handshake(1);
|
||||
} else {
|
||||
// We are a client. Set the processor to the version specified in the
|
||||
// config file and send a handshake request.
|
||||
m_processor = get_processor(config::client_version);
|
||||
this->send_http_request();
|
||||
}
|
||||
|
||||
// TODO: Begin websocket handshake
|
||||
// server: read/process/write/go
|
||||
// client: process/write/read/process/go
|
||||
|
||||
//this->read();
|
||||
}
|
||||
|
||||
template <typename config>
|
||||
void connection<config>::read(size_t num_bytes) {
|
||||
void connection<config>::read_handshake(size_t num_bytes) {
|
||||
m_alog.write(log::alevel::devel,"connection read");
|
||||
|
||||
transport_con_type::async_read_at_least(
|
||||
@@ -583,7 +576,7 @@ void connection<config>::read(size_t num_bytes) {
|
||||
m_buf,
|
||||
config::connection_read_buffer_size,
|
||||
lib::bind(
|
||||
&type::handle_handshake_read,
|
||||
&type::handle_read_handshake,
|
||||
type::shared_from_this(),
|
||||
lib::placeholders::_1,
|
||||
lib::placeholders::_2
|
||||
@@ -594,28 +587,28 @@ void connection<config>::read(size_t num_bytes) {
|
||||
// All exit paths for this function need to call send_http_response() or submit
|
||||
// a new read request with this function as the handler.
|
||||
template <typename config>
|
||||
void connection<config>::handle_handshake_read(const lib::error_code& ec,
|
||||
void connection<config>::handle_read_handshake(const lib::error_code& ec,
|
||||
size_t bytes_transferred)
|
||||
{
|
||||
m_alog.write(log::alevel::devel,"connection handle_handshake_read");
|
||||
m_alog.write(log::alevel::devel,"connection handle_read_handshake");
|
||||
|
||||
this->atomic_state_check(
|
||||
istate::READ_HTTP_REQUEST,
|
||||
"handle_handshake_read must be called from READ_HTTP_REQUEST state"
|
||||
"handle_read_handshake must be called from READ_HTTP_REQUEST state"
|
||||
);
|
||||
|
||||
if (ec) {
|
||||
std::stringstream s;
|
||||
s << "error in handle_read_handshake: "<< ec.message();
|
||||
m_elog.write(log::elevel::fatal,s.str());
|
||||
this->terminate();
|
||||
this->terminate(ec);
|
||||
return;
|
||||
}
|
||||
|
||||
// Boundaries checking. TODO: How much of this should be done?
|
||||
if (bytes_transferred > config::connection_read_buffer_size) {
|
||||
m_elog.write(log::elevel::fatal,"Fatal boundaries checking error.");
|
||||
this->terminate();
|
||||
this->terminate(make_error_code(error::general));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -634,7 +627,7 @@ void connection<config>::handle_handshake_read(const lib::error_code& ec,
|
||||
// TODO: Is this overkill?
|
||||
if (bytes_processed > config::connection_read_buffer_size) {
|
||||
m_elog.write(log::elevel::fatal,"Fatal boundaries checking error.");
|
||||
this->terminate();
|
||||
this->terminate(make_error_code(error::general));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -699,7 +692,7 @@ void connection<config>::handle_handshake_read(const lib::error_code& ec,
|
||||
m_buf,
|
||||
config::connection_read_buffer_size,
|
||||
lib::bind(
|
||||
&type::handle_handshake_read,
|
||||
&type::handle_read_handshake,
|
||||
type::shared_from_this(),
|
||||
lib::placeholders::_1,
|
||||
lib::placeholders::_2
|
||||
@@ -745,21 +738,22 @@ void connection<config>::handle_read_frame(const lib::error_code& ec,
|
||||
}
|
||||
}
|
||||
if (ec == transport::error::tls_short_read) {
|
||||
m_elog.write(log::elevel::rerror,"got TLS short read, ignore for the moment");
|
||||
m_elog.write(log::elevel::rerror,"got TLS short read, killing connection for now");
|
||||
this->terminate(ec);
|
||||
return;
|
||||
}
|
||||
|
||||
std::stringstream s;
|
||||
s << "error in handle_read_frame: " << ec.message() << " (" << ec << ")";
|
||||
m_elog.write(log::elevel::fatal,s.str());
|
||||
this->terminate();
|
||||
this->terminate(ec);
|
||||
return;
|
||||
}
|
||||
|
||||
// Boundaries checking. TODO: How much of this should be done?
|
||||
if (bytes_transferred > config::connection_read_buffer_size) {
|
||||
m_elog.write(log::elevel::fatal,"Fatal boundaries checking error");
|
||||
this->terminate();
|
||||
this->terminate(make_error_code(error::general));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -795,7 +789,7 @@ void connection<config>::handle_read_frame(const lib::error_code& ec,
|
||||
m_elog.write(log::elevel::rerror,"consume error: "+ec.message());
|
||||
|
||||
if (config::drop_on_protocol_error) {
|
||||
this->terminate();
|
||||
this->terminate(ec);
|
||||
return;
|
||||
} else {
|
||||
lib::error_code close_ec;
|
||||
@@ -805,7 +799,7 @@ void connection<config>::handle_read_frame(const lib::error_code& ec,
|
||||
m_elog.write(log::elevel::fatal,
|
||||
"Failed to send a close frame after protocol error: "
|
||||
+close_ec.message());
|
||||
this->terminate();
|
||||
this->terminate(close_ec);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -992,62 +986,7 @@ bool connection<config>::process_handshake_request() {
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: does this function still need to be here?
|
||||
template <typename config>
|
||||
void connection<config>::handle_read(const lib::error_code& ec,
|
||||
size_t bytes_transferred)
|
||||
{
|
||||
if (ec) {
|
||||
m_elog.write(log::elevel::rerror,"error in handle_read"+ec.message());
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: assert bytes_transferred < m_buf size.
|
||||
|
||||
m_alog.write(log::alevel::devel,"connection handle_read");
|
||||
|
||||
std::string foo(m_buf,bytes_transferred);
|
||||
|
||||
// process bytes
|
||||
|
||||
if (foo == "close") {
|
||||
this->terminate();
|
||||
return;
|
||||
}
|
||||
|
||||
//m_handler->on_message(type::shared_from_this(),foo);
|
||||
|
||||
this->read();
|
||||
}
|
||||
|
||||
|
||||
template <typename config>
|
||||
void connection<config>::write(std::string msg) {
|
||||
m_alog.write(log::alevel::devel,"connection write");
|
||||
|
||||
transport_con_type::async_write(
|
||||
msg.data(),
|
||||
msg.size(),
|
||||
lib::bind(
|
||||
&type::handle_write,
|
||||
type::shared_from_this(),
|
||||
lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
template <typename config>
|
||||
void connection<config>::handle_write(const lib::error_code& ec) {
|
||||
if (ec) {
|
||||
m_elog.write(log::elevel::rerror,
|
||||
"error in handle_write: "+ec.message());
|
||||
return;
|
||||
}
|
||||
|
||||
m_alog.write(log::alevel::devel,"connection handle_write");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename config>
|
||||
void connection<config>::send_http_response() {
|
||||
@@ -1106,7 +1045,7 @@ void connection<config>::handle_send_http_response(
|
||||
if (ec) {
|
||||
m_elog.write(log::elevel::rerror,
|
||||
"error in handle_send_http_response: "+ec.message());
|
||||
this->terminate();
|
||||
this->terminate(ec);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1124,7 +1063,7 @@ void connection<config>::handle_send_http_response(
|
||||
<< m_response.get_status_code();
|
||||
m_elog.write(log::elevel::rerror,s.str());
|
||||
}
|
||||
this->terminate();
|
||||
this->terminate(make_error_code(error::http_connection_ended));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1204,7 +1143,7 @@ void connection<config>::handle_send_http_request(const lib::error_code& ec) {
|
||||
if (ec) {
|
||||
m_elog.write(log::elevel::rerror,
|
||||
"error in handle_send_http_request: "+ec.message());
|
||||
this->terminate();
|
||||
this->terminate(ec);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1243,16 +1182,17 @@ void connection<config>::handle_read_http_response(const lib::error_code& ec,
|
||||
if (ec) {
|
||||
m_elog.write(log::elevel::rerror,
|
||||
"error in handle_read_http_response: "+ec.message());
|
||||
this->terminate();
|
||||
this->terminate(ec);
|
||||
return;
|
||||
}
|
||||
size_t bytes_processed = 0;
|
||||
// TODO: refactor this to use error codes rather than exceptions
|
||||
try {
|
||||
bytes_processed = m_response.consume(m_buf,bytes_transferred);
|
||||
} catch (http::exception & e) {
|
||||
m_elog.write(log::elevel::rerror,
|
||||
std::string("error in handle_read_http_response: ")+e.what());
|
||||
this->terminate();
|
||||
this->terminate(make_error_code(error::general));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1268,7 +1208,7 @@ void connection<config>::handle_read_http_response(const lib::error_code& ec,
|
||||
std::string("Server handshake response was invalid: ")+
|
||||
ec.message()
|
||||
);
|
||||
this->terminate();
|
||||
this->terminate(ec);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1312,32 +1252,68 @@ void connection<config>::handle_read_http_response(const lib::error_code& ec,
|
||||
}
|
||||
|
||||
template <typename config>
|
||||
void connection<config>::terminate() {
|
||||
try {
|
||||
m_alog.write(log::alevel::devel,"connection terminate");
|
||||
|
||||
transport_con_type::shutdown();
|
||||
|
||||
if (m_state == session::state::connecting) {
|
||||
m_state = session::state::closed;
|
||||
if (m_fail_handler) {
|
||||
m_fail_handler(m_connection_hdl);
|
||||
}
|
||||
} else if (m_state != session::state::closed) {
|
||||
m_state = session::state::closed;
|
||||
if (m_close_handler) {
|
||||
m_close_handler(m_connection_hdl);
|
||||
}
|
||||
} else {
|
||||
m_alog.write(log::alevel::devel,"terminate called on connection that was already terminated");
|
||||
return;
|
||||
}
|
||||
|
||||
log_close_result();
|
||||
} catch (const std::exception& e) {
|
||||
m_elog.write(log::elevel::warn,
|
||||
std::string("terminate failed. Reason was: ") + e.what());
|
||||
void connection<config>::terminate(const lib::error_code & ec) {
|
||||
if (m_alog.static_test(log::alevel::devel)) {
|
||||
m_alog.write(log::alevel::devel,"connection ");
|
||||
}
|
||||
|
||||
terminate_status tstat = unknown;
|
||||
if (ec) {
|
||||
m_local_close_code = close::status::abnormal_close;
|
||||
m_local_close_reason = ec.message();
|
||||
}
|
||||
|
||||
if (m_state == session::state::connecting) {
|
||||
m_state = session::state::closed;
|
||||
tstat = failed;
|
||||
} else if (m_state != session::state::closed) {
|
||||
m_state = session::state::closed;
|
||||
tstat = closed;
|
||||
} else {
|
||||
m_alog.write(log::alevel::devel,
|
||||
"terminate called on connection that was already terminated");
|
||||
return;
|
||||
}
|
||||
|
||||
transport_con_type::async_shutdown(
|
||||
lib::bind(
|
||||
&type::handle_terminate,
|
||||
type::shared_from_this(),
|
||||
tstat,
|
||||
lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
template <typename config>
|
||||
void connection<config>::handle_terminate(terminate_status tstat,
|
||||
const lib::error_code& ec)
|
||||
{
|
||||
if (m_alog.static_test(log::alevel::devel)) {
|
||||
m_alog.write(log::alevel::devel,"connection handle_terminate");
|
||||
}
|
||||
|
||||
if (ec) {
|
||||
// there was an error actually shutting down the connection
|
||||
m_elog.write(log::elevel::rerror,ec.message());
|
||||
}
|
||||
|
||||
// clean shutdown
|
||||
if (tstat == failed) {
|
||||
if (m_fail_handler) {
|
||||
m_fail_handler(m_connection_hdl);
|
||||
}
|
||||
// TODO: custom fail output log format?
|
||||
log_close_result();
|
||||
} else if (tstat == closed) {
|
||||
if (m_close_handler) {
|
||||
m_close_handler(m_connection_hdl);
|
||||
}
|
||||
log_close_result();
|
||||
} else {
|
||||
m_elog.write(log::elevel::rerror,"Unknown terminate_status");
|
||||
}
|
||||
|
||||
// call the termination handler if it exists
|
||||
// if it exists it might (but shouldn't) refer to a bad memory location.
|
||||
// If it does, we don't care and should catch and ignore it.
|
||||
@@ -1419,19 +1395,21 @@ template <typename config>
|
||||
void connection<config>::handle_write_frame(bool terminate,
|
||||
const lib::error_code& ec)
|
||||
{
|
||||
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();
|
||||
this->terminate(ec);
|
||||
return;
|
||||
}
|
||||
|
||||
m_alog.write(log::alevel::devel,"connection handle_write_frame");
|
||||
|
||||
if (terminate) {
|
||||
this->terminate();
|
||||
this->terminate(lib::error_code());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1544,7 +1522,7 @@ void connection<config>::process_control_frame(typename
|
||||
s << "Received invalid close code " << m_remote_close_code
|
||||
<< " dropping connection per config.";
|
||||
m_elog.write(log::elevel::devel,s.str());
|
||||
this->terminate();
|
||||
this->terminate(ec);
|
||||
} else {
|
||||
s << "Received invalid close code " << m_remote_close_code
|
||||
<< " sending acknowledgement and closing";
|
||||
@@ -1564,7 +1542,7 @@ void connection<config>::process_control_frame(typename
|
||||
if (config::drop_on_protocol_error) {
|
||||
m_elog.write(log::elevel::devel,
|
||||
"Received invalid close reason. Dropping connection per config");
|
||||
this->terminate();
|
||||
this->terminate(ec);
|
||||
} else {
|
||||
m_elog.write(log::elevel::devel,
|
||||
"Received invalid close reason. Sending acknowledgement and closing");
|
||||
@@ -1592,7 +1570,7 @@ 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();
|
||||
this->terminate(lib::error_code());
|
||||
} else {
|
||||
// spurious, ignore
|
||||
m_elog.write(log::elevel::devel,"Got close frame in wrong state");
|
||||
|
||||
@@ -155,7 +155,7 @@ private:
|
||||
} else if (ec) {
|
||||
// TODO
|
||||
// Set connection's failure reasons
|
||||
con->terminate();
|
||||
con->terminate(ec);
|
||||
|
||||
endpoint_type::m_elog.write(log::elevel::rerror,
|
||||
"handle_connect error: "+ec.message());
|
||||
|
||||
@@ -114,7 +114,7 @@ public:
|
||||
//con->terminate();
|
||||
} else {
|
||||
if (ec) {
|
||||
con->terminate();
|
||||
con->terminate(ec);
|
||||
|
||||
endpoint_type::m_elog.write(log::elevel::rerror,
|
||||
"handle_accept error: "+ec.message());
|
||||
|
||||
@@ -28,8 +28,11 @@
|
||||
#ifndef WEBSOCKETPP_TRANSPORT_ASIO_BASE_HPP
|
||||
#define WEBSOCKETPP_TRANSPORT_ASIO_BASE_HPP
|
||||
|
||||
#include <websocketpp/common/system_error.hpp>
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
#include <websocketpp/common/functional.hpp>
|
||||
#include <websocketpp/common/system_error.hpp>
|
||||
|
||||
#include <boost/system/error_code.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
@@ -37,6 +40,9 @@ namespace websocketpp {
|
||||
namespace transport {
|
||||
namespace asio {
|
||||
|
||||
typedef lib::function<void(const boost::system::error_code &)>
|
||||
socket_shutdown_handler;
|
||||
|
||||
/**
|
||||
* This policy uses a single boost::asio io_service to provide transport
|
||||
* services to a WebSocket++ endpoint.
|
||||
|
||||
@@ -80,7 +80,9 @@ public:
|
||||
|
||||
/// Type of a pointer to the ASIO io_service being used
|
||||
typedef boost::asio::io_service* io_service_ptr;
|
||||
|
||||
/// Type of a pointer to the ASIO timer class
|
||||
typedef lib::shared_ptr<boost::asio::deadline_timer> timer_ptr;
|
||||
|
||||
// generate and manage our own io_service
|
||||
explicit connection(bool is_server, alog_type& alog, elog_type& elog)
|
||||
: m_is_server(is_server)
|
||||
@@ -121,18 +123,94 @@ public:
|
||||
m_tcp_init_handler = h;
|
||||
}
|
||||
|
||||
void set_proxy(const std::string & proxy) {
|
||||
m_proxy = proxy;
|
||||
/// Set the proxy to connect through (exception free)
|
||||
/**
|
||||
* The URI passed should be a complete URI including scheme. For example:
|
||||
* http://proxy.example.com:8080/
|
||||
*
|
||||
* The proxy must be set up as an explicit (CONNECT) proxy allowed to
|
||||
* connect to the port you specify. Traffic to the proxy is not encrypted.
|
||||
*
|
||||
* @param uri The full URI of the proxy to connect to.
|
||||
*
|
||||
* @param ec A status value
|
||||
*/
|
||||
void set_proxy(const std::string & uri, lib::error_code & ec) {
|
||||
// TODO: return errors for illegal URIs here?
|
||||
// TODO: should https urls be illegal for the moment?
|
||||
m_proxy = uri;
|
||||
m_proxy_data.reset(new proxy_data());
|
||||
ec = lib::error_code();
|
||||
}
|
||||
void set_proxy_basic_auth(const std::string & u, const std::string & p) {
|
||||
if (m_proxy_data) {
|
||||
std::string val = "Basic "+base64_encode(u + ":" + p);
|
||||
m_proxy_data->req.replace_header("Proxy-Authorization",val);
|
||||
} else {
|
||||
// TODO: should we throw errors with invalid stuff here or just
|
||||
// silently ignore?
|
||||
|
||||
/// Set the proxy to connect through (exception)
|
||||
void set_proxy(const std::string & uri) {
|
||||
lib::error_code ec;
|
||||
set_proxy(uri,ec);
|
||||
if (ec) { throw ec; }
|
||||
}
|
||||
|
||||
/// Set the basic auth credentials to use (exception free)
|
||||
/**
|
||||
* The URI passed should be a complete URI including scheme. For example:
|
||||
* http://proxy.example.com:8080/
|
||||
*
|
||||
* The proxy must be set up as an explicit proxy
|
||||
*
|
||||
* @param username The username to send
|
||||
*
|
||||
* @param password The password to send
|
||||
*
|
||||
* @param ec A status value
|
||||
*/
|
||||
void set_proxy_basic_auth(const std::string & username, const
|
||||
std::string & password, lib::error_code & ec)
|
||||
{
|
||||
if (!m_proxy_data) {
|
||||
ec = make_error_code(websocketpp::error::invalid_state);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: username can't contain ':'
|
||||
std::string val = "Basic "+base64_encode(username + ":" + password);
|
||||
m_proxy_data->req.replace_header("Proxy-Authorization",val);
|
||||
ec = lib::error_code();
|
||||
}
|
||||
|
||||
/// Set the basic auth credentials to use (exception)
|
||||
void set_proxy_basic_auth(const std::string & username, const
|
||||
std::string & password)
|
||||
{
|
||||
lib::error_code ec;
|
||||
set_proxy_basic_auth(username,password,ec);
|
||||
if (ec) { throw ec; }
|
||||
}
|
||||
|
||||
/// Set the proxy timeout duration (exception free)
|
||||
/**
|
||||
* Duration is in milliseconds. Default value is based on the transport
|
||||
* config
|
||||
*
|
||||
* @param duration The number of milliseconds to wait before aborting the
|
||||
* proxy connection.
|
||||
*
|
||||
* @param ec A status value
|
||||
*/
|
||||
void set_proxy_timeout(long duration, lib::error_code & ec) {
|
||||
if (!m_proxy_data) {
|
||||
ec = make_error_code(websocketpp::error::invalid_state);
|
||||
return;
|
||||
}
|
||||
|
||||
m_proxy_data->timeout_proxy = duration;
|
||||
ec = lib::error_code();
|
||||
}
|
||||
|
||||
/// Set the proxy timeout duration (exception)
|
||||
void set_proxy_timeout(long duration) {
|
||||
lib::error_code ec;
|
||||
set_proxy_timeout(duration,ec);
|
||||
if (ec) { throw ec; }
|
||||
}
|
||||
|
||||
const std::string & get_proxy() const {
|
||||
@@ -175,7 +253,8 @@ public:
|
||||
*/
|
||||
lib::error_code proxy_init(const std::string & authority) {
|
||||
if (!m_proxy_data) {
|
||||
return websocketpp::error::make_error_code(websocketpp::error::invalid_state);
|
||||
return websocketpp::error::make_error_code(
|
||||
websocketpp::error::invalid_state);
|
||||
}
|
||||
m_proxy_data->req.set_version("HTTP/1.1");
|
||||
m_proxy_data->req.set_method("CONNECT");
|
||||
@@ -185,7 +264,67 @@ public:
|
||||
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
/// Call back a function after a period of time.
|
||||
/**
|
||||
* Sets a timer that calls back a function after the specified period of
|
||||
* milliseconds. Returns a handle that can be used to cancel the timer.
|
||||
* A cancelled timer will return the error code error::operation_aborted
|
||||
* A timer that expired will return no error.
|
||||
*
|
||||
* @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) {
|
||||
timer_ptr new_timer(
|
||||
new boost::asio::deadline_timer(
|
||||
*m_io_service,
|
||||
boost::posix_time::milliseconds(duration)
|
||||
)
|
||||
);
|
||||
|
||||
new_timer->async_wait(
|
||||
lib::bind(
|
||||
&type::handle_timer,
|
||||
this,
|
||||
new_timer,
|
||||
callback,
|
||||
lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
|
||||
return new_timer;
|
||||
}
|
||||
|
||||
/// Timer callback
|
||||
/**
|
||||
* The timer pointer is included to ensure the timer isn't destroyed until
|
||||
* after it has expired.
|
||||
*
|
||||
* @param t Pointer to the timer in question
|
||||
*
|
||||
* @param callback The function to call back
|
||||
*
|
||||
* @param ec The status code
|
||||
*/
|
||||
void handle_timer(timer_ptr t, timer_handler callback, const
|
||||
boost::system::error_code& ec)
|
||||
{
|
||||
if (ec) {
|
||||
if (ec == boost::asio::error::operation_aborted) {
|
||||
callback(make_error_code(transport::error::operation_aborted));
|
||||
} else {
|
||||
log_err(log::elevel::info,"asio handle_timer",ec);
|
||||
callback(make_error_code(error::pass_through));
|
||||
}
|
||||
} else {
|
||||
callback(lib::error_code());
|
||||
}
|
||||
}
|
||||
protected:
|
||||
/// Initialize transport for reading
|
||||
/**
|
||||
@@ -232,7 +371,8 @@ protected:
|
||||
callback(ec);
|
||||
}
|
||||
|
||||
// If we have a proxy set issue a proxy connect, otherwise skip to post_init
|
||||
// If we have a proxy set issue a proxy connect, otherwise skip to
|
||||
// post_init
|
||||
if (!m_proxy.empty()) {
|
||||
proxy_write(callback);
|
||||
} else {
|
||||
@@ -281,7 +421,19 @@ protected:
|
||||
m_proxy_data->write_buf.size()));
|
||||
|
||||
m_alog.write(log::alevel::devel,m_proxy_data->write_buf);
|
||||
|
||||
|
||||
// Set a timer so we don't wait forever for the proxy to respond
|
||||
m_proxy_data->timer = this->set_timer(
|
||||
m_proxy_data->timeout_proxy,
|
||||
lib::bind(
|
||||
&type::handle_proxy_timeout,
|
||||
this,
|
||||
callback,
|
||||
lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
|
||||
// Send proxy request
|
||||
boost::asio::async_write(
|
||||
socket_con_type::get_next_layer(),
|
||||
m_bufs,
|
||||
@@ -294,6 +446,21 @@ protected:
|
||||
);
|
||||
}
|
||||
|
||||
void handle_proxy_timeout(init_handler callback, const lib::error_code & ec) {
|
||||
if (ec == transport::error::operation_aborted) {
|
||||
m_alog.write(log::alevel::devel,
|
||||
"asio handle_proxy_write timer cancelled");
|
||||
return;
|
||||
} else if (ec) {
|
||||
log_err(log::elevel::devel,"asio handle_proxy_write",ec);
|
||||
callback(ec);
|
||||
} else {
|
||||
m_alog.write(log::alevel::devel,
|
||||
"asio handle_proxy_write timer expired");
|
||||
callback(make_error_code(transport::error::timeout));
|
||||
}
|
||||
}
|
||||
|
||||
void handle_proxy_write(init_handler callback, const
|
||||
boost::system::error_code& ec)
|
||||
{
|
||||
@@ -304,8 +471,8 @@ protected:
|
||||
m_bufs.clear();
|
||||
|
||||
if (ec) {
|
||||
m_elog.write(log::elevel::info,
|
||||
"asio handle_proxy_write error: "+ec.message());
|
||||
log_err(log::elevel::info,"asio handle_proxy_write",ec);
|
||||
m_proxy_data->timer->cancel();
|
||||
callback(make_error_code(error::pass_through));
|
||||
} else {
|
||||
proxy_read(callback);
|
||||
@@ -320,6 +487,7 @@ protected:
|
||||
if (!m_proxy_data) {
|
||||
m_elog.write(log::elevel::library,
|
||||
"assertion failed: !m_proxy_data in asio::connection::proxy_read");
|
||||
m_proxy_data->timer->cancel();
|
||||
callback(make_error_code(error::general));
|
||||
return;
|
||||
}
|
||||
@@ -345,6 +513,9 @@ protected:
|
||||
m_alog.write(log::alevel::devel,"asio connection handle_proxy_read");
|
||||
}
|
||||
|
||||
// At this point there is no need to wait for the timer anymore
|
||||
m_proxy_data->timer->cancel();
|
||||
|
||||
if (ec) {
|
||||
m_elog.write(log::elevel::info,
|
||||
"asio handle_proxy_read error: "+ec.message());
|
||||
@@ -453,13 +624,7 @@ protected:
|
||||
handler(make_error_code(transport::error::tls_short_read),
|
||||
bytes_transferred);
|
||||
} else {
|
||||
// other error that we cannot translate into a WebSocket++
|
||||
// transport error. Use pass through and print an info warning
|
||||
// with the original error.
|
||||
std::stringstream s;
|
||||
s << "asio async_read_at_least error: "
|
||||
<< ec << " (" << ec.message() << ")";
|
||||
m_elog.write(log::elevel::info,s.str());
|
||||
log_err(log::elevel::info,"asio async_read_at_least",ec);
|
||||
handler(make_error_code(transport::error::pass_through),
|
||||
bytes_transferred);
|
||||
}
|
||||
@@ -503,9 +668,9 @@ protected:
|
||||
boost::system::error_code& ec)
|
||||
{
|
||||
m_bufs.clear();
|
||||
// TODO: translate this better
|
||||
if (ec) {
|
||||
handler(make_error_code(error::pass_through));
|
||||
log_err(log::elevel::info,"asio async_write",ec);
|
||||
handler(make_error_code(transport::error::pass_through));
|
||||
} else {
|
||||
handler(lib::error_code());
|
||||
}
|
||||
@@ -544,44 +709,58 @@ protected:
|
||||
}*/
|
||||
|
||||
/// close and clean up the underlying socket
|
||||
void shutdown() {
|
||||
socket_con_type::shutdown();
|
||||
void async_shutdown(shutdown_handler h) {
|
||||
if (m_alog.static_test(log::alevel::devel)) {
|
||||
m_alog.write(log::alevel::devel,"asio connection async_shutdown");
|
||||
}
|
||||
|
||||
socket_con_type::async_shutdown(
|
||||
lib::bind(
|
||||
&type::handle_async_shutdown,
|
||||
this,
|
||||
h,
|
||||
lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
typedef lib::shared_ptr<boost::asio::deadline_timer> timer_ptr;
|
||||
|
||||
timer_ptr set_timer(long duration, timer_handler handler) {
|
||||
timer_ptr timer(new boost::asio::deadline_timer(*m_io_service));
|
||||
timer->expires_from_now(boost::posix_time::milliseconds(duration));
|
||||
timer->async_wait(lib::bind(&type::timer_handler, this, handler,
|
||||
lib::placeholders::_1));
|
||||
return timer;
|
||||
}
|
||||
|
||||
void timer_handler(timer_handler h, const boost::system::error_code& ec) {
|
||||
if (ec == boost::asio::error::operation_aborted) {
|
||||
h(make_error_code(transport::error::operation_aborted));
|
||||
} else if (ec) {
|
||||
std::stringstream s;
|
||||
s << "asio async_wait error::pass_through"
|
||||
<< "Original Error: " << ec << " (" << ec.message() << ")";
|
||||
m_elog.write(log::elevel::devel,s.str());
|
||||
void handle_async_shutdown(shutdown_handler h, const
|
||||
boost::system::error_code & ec)
|
||||
{
|
||||
if (m_alog.static_test(log::alevel::devel)) {
|
||||
m_alog.write(log::alevel::devel,"asio con handle_async_shutdown");
|
||||
}
|
||||
|
||||
if (ec) {
|
||||
log_err(log::elevel::info,"asio async_shutdown",ec);
|
||||
h(make_error_code(transport::error::pass_through));
|
||||
} else {
|
||||
h(lib::error_code());
|
||||
}
|
||||
}
|
||||
private:
|
||||
/// Convenience method for logging the code and message for an error_code
|
||||
std::string log_err(log::level l,const char * msg, lib::error_code & ec)
|
||||
{
|
||||
std::stringstream s;
|
||||
s << msg << " error: " << ec << " (" << ec.message() << ")";
|
||||
m_elog->write(l,s.str());
|
||||
}
|
||||
|
||||
// static settings
|
||||
const bool m_is_server;
|
||||
const bool m_is_server;
|
||||
alog_type& m_alog;
|
||||
elog_type& m_elog;
|
||||
|
||||
struct proxy_data {
|
||||
proxy_data() : timeout_proxy(config::timeout_proxy) {}
|
||||
|
||||
request_type req;
|
||||
response_type res;
|
||||
std::string write_buf;
|
||||
boost::asio::streambuf read_buf;
|
||||
long timeout_proxy;
|
||||
timer_ptr timer;
|
||||
};
|
||||
|
||||
std::string m_proxy;
|
||||
|
||||
@@ -74,14 +74,16 @@ public:
|
||||
/// Type of a shared pointer to the connection transport component
|
||||
/// associated with this endpoint transport component
|
||||
typedef typename transport_con_type::ptr transport_con_ptr;
|
||||
|
||||
|
||||
/// Type of a pointer to the ASIO io_service being used
|
||||
typedef boost::asio::io_service* io_service_ptr;
|
||||
/// Type of a shared pointer to the acceptor being used
|
||||
typedef lib::shared_ptr<boost::asio::ip::tcp::acceptor> acceptor_ptr;
|
||||
/// Type of a shared pointer to the resolver being used
|
||||
typedef lib::shared_ptr<boost::asio::ip::tcp::resolver> resolver_ptr;
|
||||
|
||||
/// Type of timer handle
|
||||
typedef lib::shared_ptr<boost::asio::deadline_timer> timer_ptr;
|
||||
|
||||
// generate and manage our own io_service
|
||||
explicit endpoint()
|
||||
: m_external_io_service(false)
|
||||
@@ -293,28 +295,68 @@ public:
|
||||
listen(*endpoint_iterator);
|
||||
}
|
||||
|
||||
typedef lib::shared_ptr<boost::asio::deadline_timer> timer_ptr;
|
||||
|
||||
timer_ptr set_timer(long duration, timer_handler handler) {
|
||||
timer_ptr timer(new boost::asio::deadline_timer(*m_io_service));
|
||||
timer->expires_from_now(boost::posix_time::milliseconds(duration));
|
||||
timer->async_wait(lib::bind(&type::timer_handler, this, handler,
|
||||
lib::placeholders::_1));
|
||||
return timer;
|
||||
}
|
||||
|
||||
void timer_handler(timer_handler h, const boost::system::error_code& ec) {
|
||||
if (ec == boost::asio::error::operation_aborted) {
|
||||
h(make_error_code(transport::error::operation_aborted));
|
||||
} else if (ec) {
|
||||
std::stringstream s;
|
||||
s << "asio async_wait error: " << ec << " (" << ec.message() << ")";
|
||||
m_elog->write(log::elevel::devel,s.str());
|
||||
h(make_error_code(transport::error::pass_through));
|
||||
/// Call back a function after a period of time.
|
||||
/**
|
||||
* Sets a timer that calls back a function after the specified period of
|
||||
* milliseconds. Returns a handle that can be used to cancel the timer.
|
||||
* A cancelled timer will return the error code error::operation_aborted
|
||||
* A timer that expired will return no error.
|
||||
*
|
||||
* @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) {
|
||||
timer_ptr new_timer(
|
||||
new boost::asio::deadline_timer(
|
||||
*m_io_service,
|
||||
boost::posix_time::milliseconds(duration)
|
||||
)
|
||||
);
|
||||
|
||||
new_timer->async_wait(
|
||||
lib::bind(
|
||||
&type::handle_timer,
|
||||
this,
|
||||
new_timer,
|
||||
callback,
|
||||
lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
|
||||
return new_timer;
|
||||
}
|
||||
|
||||
/// Timer callback
|
||||
/**
|
||||
* The timer pointer is included to ensure the timer isn't destroyed until
|
||||
* after it has expired.
|
||||
*
|
||||
* @param t Pointer to the timer in question
|
||||
*
|
||||
* @param callback The function to call back
|
||||
*
|
||||
* @param ec The status code
|
||||
*/
|
||||
void handle_timer(timer_ptr t, timer_handler callback, const
|
||||
boost::system::error_code& ec)
|
||||
{
|
||||
if (ec) {
|
||||
if (ec == boost::asio::error::operation_aborted) {
|
||||
callback(make_error_code(transport::error::operation_aborted));
|
||||
} else {
|
||||
m_elog->write(log::elevel::info,
|
||||
"asio handle_timer error: "+ec.message());
|
||||
log_err(log::elevel::info,"asio handle_timer",ec);
|
||||
callback(make_error_code(error::pass_through));
|
||||
}
|
||||
} else {
|
||||
h(lib::error_code());
|
||||
callback(lib::error_code());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boost::asio::io_service& get_io_service() {
|
||||
return *m_io_service;
|
||||
@@ -396,12 +438,25 @@ protected:
|
||||
"starting async DNS resolve for "+host+":"+port);
|
||||
}
|
||||
|
||||
timer_ptr dns_timer = tcon->set_timer(
|
||||
config::timeout_dns,
|
||||
lib::bind(
|
||||
&type::handle_resolve_timeout,
|
||||
this,
|
||||
tcon,
|
||||
dns_timer,
|
||||
cb,
|
||||
lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
|
||||
m_resolver->async_resolve(
|
||||
query,
|
||||
lib::bind(
|
||||
&type::handle_resolve,
|
||||
this,
|
||||
tcon,
|
||||
dns_timer,
|
||||
cb,
|
||||
lib::placeholders::_1,
|
||||
lib::placeholders::_2
|
||||
@@ -409,28 +464,48 @@ protected:
|
||||
);
|
||||
}
|
||||
|
||||
void handle_resolve_timeout(transport_con_ptr tcon, timer_ptr dns_timer,
|
||||
connect_handler callback, const lib::error_code & ec)
|
||||
{
|
||||
m_resolver->cancel();
|
||||
|
||||
if (ec == transport::error::operation_aborted) {
|
||||
m_alog->write(log::alevel::devel,
|
||||
"asio handle_resolve_timeout timer cancelled");
|
||||
} else if (ec) {
|
||||
log_err(log::elevel::devel,"asio handle_resolve_timeout",ec);
|
||||
callback(tcon->get_handle(),ec);
|
||||
} else {
|
||||
m_alog->write(log::alevel::devel,
|
||||
"asio handle_resolve_timeout timer expired");
|
||||
callback(tcon->get_handle(),
|
||||
make_error_code(transport::error::timeout));
|
||||
}
|
||||
}
|
||||
|
||||
void handle_resolve(transport_con_ptr tcon, connect_handler callback,
|
||||
const boost::system::error_code& ec,
|
||||
timer_ptr dns_timer, const boost::system::error_code& ec,
|
||||
boost::asio::ip::tcp::resolver::iterator iterator)
|
||||
{
|
||||
dns_timer->cancel();
|
||||
|
||||
if (ec) {
|
||||
//con->terminate();
|
||||
// TODO: Better translation of errors at this point
|
||||
std::stringstream s;
|
||||
s << "asio async_resolve error:"
|
||||
<< ec << " (" << ec.message() << ")";
|
||||
m_elog->write(log::elevel::info,s.str());
|
||||
if (ec == boost::asio::error::operation_aborted) {
|
||||
m_alog->write(log::alevel::devel,
|
||||
"asio handle_resolve resolve cancelled");
|
||||
return;
|
||||
}
|
||||
|
||||
log_err(log::elevel::info,"asio async_resolve",ec);
|
||||
callback(tcon->get_handle(),make_error_code(error::pass_through));
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_alog->static_test(log::alevel::devel)) {
|
||||
std::stringstream s;
|
||||
|
||||
s << "Async DNS resolve successful. Results: ";
|
||||
|
||||
boost::asio::ip::tcp::resolver::iterator it, end;
|
||||
|
||||
for (it = iterator; it != end; ++it) {
|
||||
s << (*it).endpoint() << " ";
|
||||
}
|
||||
@@ -456,12 +531,7 @@ protected:
|
||||
const boost::system::error_code& ec)
|
||||
{
|
||||
if (ec) {
|
||||
//con->terminate();
|
||||
// TODO: Better translation of errors at this point
|
||||
std::stringstream s;
|
||||
s << "asio async_connect error: "
|
||||
<< ec << " (" << ec.message() << ")";
|
||||
m_elog->write(log::elevel::info,s.str());
|
||||
log_err(log::elevel::info,"asio async_connect",ec);
|
||||
callback(tcon->get_handle(),make_error_code(error::pass_through));
|
||||
return;
|
||||
}
|
||||
@@ -506,6 +576,14 @@ protected:
|
||||
return lib::error_code();
|
||||
}
|
||||
private:
|
||||
/// Convenience method for logging the code and message for an error_code
|
||||
std::string log_err(log::level l,const char * msg, lib::error_code & ec)
|
||||
{
|
||||
std::stringstream s;
|
||||
s << msg << " error: " << ec << " (" << ec.message() << ")";
|
||||
m_elog->write(l,s.str());
|
||||
}
|
||||
|
||||
enum state {
|
||||
UNINITIALIZED = 0,
|
||||
READY = 1,
|
||||
|
||||
@@ -205,11 +205,10 @@ protected:
|
||||
m_hdl = hdl;
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
void async_shutdown(socket_shutdown_handler h) {
|
||||
boost::system::error_code ec;
|
||||
m_socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both,ec);
|
||||
|
||||
// TODO: handle errors
|
||||
h(ec);
|
||||
}
|
||||
private:
|
||||
enum state {
|
||||
|
||||
@@ -291,20 +291,23 @@ protected:
|
||||
callback(lib::error_code());
|
||||
}
|
||||
|
||||
void handle_shutdown(socket_ptr s, const boost::system::error_code& ec) {
|
||||
// TODO: error handling?
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
void async_shutdown(socket_shutdown_handler h) {
|
||||
m_socket->async_shutdown(
|
||||
lib::bind(
|
||||
&type::handle_shutdown,
|
||||
lib::bind(
|
||||
&type::handle_async_shutdown,
|
||||
this,
|
||||
m_socket,
|
||||
h,
|
||||
lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void handle_async_shutdown(socket_ptr s, socket_shutdown_handler h, const
|
||||
boost::system::error_code& ec)
|
||||
{
|
||||
h(ec);
|
||||
}
|
||||
private:
|
||||
socket_type::handshake_type get_handshake_type() {
|
||||
if (m_is_server) {
|
||||
|
||||
@@ -70,6 +70,7 @@ typedef lib::function<void(const lib::error_code&)> init_handler;
|
||||
typedef lib::function<void(const lib::error_code&,size_t)> read_handler;
|
||||
typedef lib::function<void(const lib::error_code&)> write_handler;
|
||||
typedef lib::function<void(const lib::error_code&)> timer_handler;
|
||||
typedef lib::function<void(const lib::error_code&)> shutdown_handler;
|
||||
typedef lib::function<void()> inturrupt_handler;
|
||||
typedef lib::function<void()> dispatch_handler;
|
||||
|
||||
@@ -107,7 +108,10 @@ enum value {
|
||||
eof,
|
||||
|
||||
/// TLS short read
|
||||
tls_short_read
|
||||
tls_short_read,
|
||||
|
||||
/// Timer expired
|
||||
timeout
|
||||
};
|
||||
|
||||
class category : public lib::error_category {
|
||||
@@ -134,6 +138,8 @@ class category : public lib::error_category {
|
||||
return "End of File";
|
||||
case tls_short_read:
|
||||
return "TLS Short Read";
|
||||
case timeout:
|
||||
return "Timer Expired";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
@@ -313,8 +313,8 @@ protected:
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
// TODO:
|
||||
void async_shutdown(shutdown_handler h) {
|
||||
h(lib::error_code());
|
||||
}
|
||||
private:
|
||||
void read(std::istream &in) {
|
||||
|
||||
Reference in New Issue
Block a user