Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -1,123 +0,0 @@
|
||||
/*
|
||||
base64.cpp and base64.h
|
||||
|
||||
Copyright (C) 2004-2008 René Nyffenegger
|
||||
|
||||
This source code is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the author 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 source code must not be misrepresented; you must not
|
||||
claim that you wrote the original source code. If you use this source code
|
||||
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 source code.
|
||||
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
|
||||
|
||||
*/
|
||||
|
||||
#include "base64.h"
|
||||
#include <iostream>
|
||||
|
||||
static const std::string base64_chars =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
|
||||
|
||||
static inline bool is_base64(unsigned char c) {
|
||||
return (isalnum(c) || (c == '+') || (c == '/'));
|
||||
}
|
||||
|
||||
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
|
||||
std::string ret;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
unsigned char char_array_3[3];
|
||||
unsigned char char_array_4[4];
|
||||
|
||||
while (in_len--) {
|
||||
char_array_3[i++] = *(bytes_to_encode++);
|
||||
if (i == 3) {
|
||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||
|
||||
for(i = 0; (i <4) ; i++)
|
||||
ret += base64_chars[char_array_4[i]];
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i)
|
||||
{
|
||||
for(j = i; j < 3; j++)
|
||||
char_array_3[j] = '\0';
|
||||
|
||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||
|
||||
for (j = 0; (j < i + 1); j++)
|
||||
ret += base64_chars[char_array_4[j]];
|
||||
|
||||
while((i++ < 3))
|
||||
ret += '=';
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
std::string base64_decode(std::string const& encoded_string) {
|
||||
size_t in_len = encoded_string.size();
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int in_ = 0;
|
||||
unsigned char char_array_4[4], char_array_3[3];
|
||||
std::string ret;
|
||||
|
||||
while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
|
||||
char_array_4[i++] = encoded_string[in_]; in_++;
|
||||
if (i ==4) {
|
||||
for (i = 0; i <4; i++)
|
||||
char_array_4[i] = static_cast<unsigned char>(base64_chars.find(char_array_4[i]));
|
||||
|
||||
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||
|
||||
for (i = 0; (i < 3); i++)
|
||||
ret += char_array_3[i];
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i) {
|
||||
for (j = i; j <4; j++)
|
||||
char_array_4[j] = 0;
|
||||
|
||||
for (j = 0; j <4; j++)
|
||||
char_array_4[j] = static_cast<unsigned char>(base64_chars.find(char_array_4[j]));
|
||||
|
||||
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||
|
||||
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
#include <string>
|
||||
|
||||
std::string base64_encode(unsigned char const* , unsigned int len);
|
||||
std::string base64_decode(std::string const& s);
|
||||
@@ -38,7 +38,9 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
static const std::string base64_chars =
|
||||
namespace websocketpp {
|
||||
|
||||
static std::string const base64_chars =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
@@ -50,7 +52,7 @@ static inline bool is_base64(unsigned char c) {
|
||||
(c >= 97 && c <= 122)); // a-z
|
||||
}
|
||||
|
||||
inline std::string base64_encode(unsigned char const* bytes_to_encode, unsigned
|
||||
inline std::string base64_encode(unsigned char const * bytes_to_encode, unsigned
|
||||
int in_len)
|
||||
{
|
||||
std::string ret;
|
||||
@@ -100,11 +102,11 @@ inline std::string base64_encode(unsigned char const* bytes_to_encode, unsigned
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline std::string base64_encode(const std::string & data) {
|
||||
inline std::string base64_encode(std::string const & data) {
|
||||
return base64_encode(reinterpret_cast<const unsigned char *>(data.data()),data.size());
|
||||
}
|
||||
|
||||
inline std::string base64_decode(std::string const& encoded_string) {
|
||||
inline std::string base64_decode(std::string const & encoded_string) {
|
||||
size_t in_len = encoded_string.size();
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
@@ -149,4 +151,6 @@ inline std::string base64_decode(std::string const& encoded_string) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace websocketpp
|
||||
|
||||
#endif // _BASE64_HPP_
|
||||
|
||||
@@ -51,6 +51,26 @@ namespace status {
|
||||
/// A blank value for internal use.
|
||||
static value const blank = 0;
|
||||
|
||||
/// Close the connection without a WebSocket close handshake.
|
||||
/**
|
||||
* This special value requests that the WebSocket connection be closed
|
||||
* without performing the WebSocket closing handshake. This does not comply
|
||||
* with RFC6455, but should be safe to do if necessary. This could be useful
|
||||
* for clients that need to disconnect quickly and cannot afford the
|
||||
* complete handshake.
|
||||
*/
|
||||
static value const omit_handshake = 1;
|
||||
|
||||
/// Close the connection with a forced TCP drop.
|
||||
/**
|
||||
* This special value requests that the WebSocket connection be closed by
|
||||
* forcibly dropping the TCP connection. This will leave the other side of
|
||||
* the connection with a broken connection and some expensive timeouts. this
|
||||
* should not be done except in extreme cases or in cases of malicious
|
||||
* remote endpoints.
|
||||
*/
|
||||
static value const force_tcp_drop = 2;
|
||||
|
||||
/// Normal closure, meaning that the purpose for which the connection was
|
||||
/// established has been fulfilled.
|
||||
static value const normal = 1000;
|
||||
|
||||
+11
-1
@@ -91,6 +91,11 @@ struct core {
|
||||
/// RNG policies
|
||||
typedef websocketpp::random::none::int_generator<uint32_t> rng_type;
|
||||
|
||||
/// Controls compile time enabling/disabling of thread syncronization
|
||||
/// code Disabling can provide a minor performance improvement to single
|
||||
/// threaded applications
|
||||
static bool const enable_multithreading = true;
|
||||
|
||||
struct transport_config {
|
||||
typedef type::concurrency_type concurrency_type;
|
||||
typedef type::elog_type elog_type;
|
||||
@@ -98,6 +103,11 @@ struct core {
|
||||
typedef type::request_type request_type;
|
||||
typedef type::response_type response_type;
|
||||
|
||||
/// Controls compile time enabling/disabling of thread syncronization
|
||||
/// code Disabling can provide a minor performance improvement to single
|
||||
/// threaded applications
|
||||
static bool const enable_multithreading = true;
|
||||
|
||||
/// Default timer values (in ms)
|
||||
|
||||
/// Length of time to wait for socket pre-initialization
|
||||
@@ -179,7 +189,7 @@ struct core {
|
||||
websocketpp::log::alevel::all ^ websocketpp::log::alevel::devel;
|
||||
|
||||
///
|
||||
static const size_t connection_read_buffer_size = 512;
|
||||
static const size_t connection_read_buffer_size = 16384;
|
||||
|
||||
/// Drop connections immediately on protocol error.
|
||||
/**
|
||||
|
||||
@@ -92,6 +92,11 @@ struct core_client {
|
||||
typedef websocketpp::random::random_device::int_generator<uint32_t,
|
||||
concurrency_type> rng_type;
|
||||
|
||||
/// Controls compile time enabling/disabling of thread syncronization code
|
||||
/// Disabling can provide a minor performance improvement to single threaded
|
||||
/// applications
|
||||
static bool const enable_multithreading = true;
|
||||
|
||||
struct transport_config {
|
||||
typedef type::concurrency_type concurrency_type;
|
||||
typedef type::elog_type elog_type;
|
||||
@@ -99,6 +104,11 @@ struct core_client {
|
||||
typedef type::request_type request_type;
|
||||
typedef type::response_type response_type;
|
||||
|
||||
/// Controls compile time enabling/disabling of thread syncronization
|
||||
/// code Disabling can provide a minor performance improvement to single
|
||||
/// threaded applications
|
||||
static bool const enable_multithreading = true;
|
||||
|
||||
/// Default timer values (in ms)
|
||||
|
||||
/// Length of time to wait for socket pre-initialization
|
||||
@@ -180,7 +190,7 @@ struct core_client {
|
||||
websocketpp::log::alevel::all ^ websocketpp::log::alevel::devel;
|
||||
|
||||
///
|
||||
static const size_t connection_read_buffer_size = 512;
|
||||
static const size_t connection_read_buffer_size = 16384;
|
||||
|
||||
/// Drop connections immediately on protocol error.
|
||||
/**
|
||||
|
||||
+11
-1
@@ -92,6 +92,11 @@ struct debug_core {
|
||||
/// RNG policies
|
||||
typedef websocketpp::random::none::int_generator<uint32_t> rng_type;
|
||||
|
||||
/// Controls compile time enabling/disabling of thread syncronization
|
||||
/// code Disabling can provide a minor performance improvement to single
|
||||
/// threaded applications
|
||||
static bool const enable_multithreading = true;
|
||||
|
||||
struct transport_config {
|
||||
typedef type::concurrency_type concurrency_type;
|
||||
typedef type::elog_type elog_type;
|
||||
@@ -99,6 +104,11 @@ struct debug_core {
|
||||
typedef type::request_type request_type;
|
||||
typedef type::response_type response_type;
|
||||
|
||||
/// Controls compile time enabling/disabling of thread syncronization
|
||||
/// code Disabling can provide a minor performance improvement to single
|
||||
/// threaded applications
|
||||
static bool const enable_multithreading = true;
|
||||
|
||||
/// Default timer values (in ms)
|
||||
|
||||
/// Length of time to wait for socket pre-initialization
|
||||
@@ -180,7 +190,7 @@ struct debug_core {
|
||||
websocketpp::log::alevel::all;
|
||||
|
||||
///
|
||||
static const size_t connection_read_buffer_size = 512;
|
||||
static const size_t connection_read_buffer_size = 16384;
|
||||
|
||||
/// Drop connections immediately on protocol error.
|
||||
/**
|
||||
|
||||
+102
-2
@@ -149,6 +149,10 @@ typedef lib::function<bool(connection_hdl)> validate_handler;
|
||||
*/
|
||||
typedef lib::function<void(connection_hdl)> http_handler;
|
||||
|
||||
//
|
||||
typedef lib::function<void(lib::error_code const & ec, size_t bytes_transferred)> read_handler;
|
||||
typedef lib::function<void(lib::error_code const & ec)> write_frame_handler;
|
||||
|
||||
// constants related to the default WebSocket protocol versions available
|
||||
#ifdef _WEBSOCKETPP_INITIALIZER_LISTS_ // simplified C++11 version
|
||||
/// Container that stores the list of protocol versions supported
|
||||
@@ -278,7 +282,21 @@ public:
|
||||
explicit connection(bool is_server, std::string const & ua, alog_type& alog,
|
||||
elog_type& elog, rng_type & rng)
|
||||
: transport_con_type(is_server,alog,elog)
|
||||
, m_handle_read_frame(lib::bind(
|
||||
&type::handle_read_frame,
|
||||
this,
|
||||
lib::placeholders::_1,
|
||||
lib::placeholders::_2
|
||||
))
|
||||
, m_write_frame_handler(lib::bind(
|
||||
&type::handle_write_frame,
|
||||
this,
|
||||
lib::placeholders::_1
|
||||
))
|
||||
, m_user_agent(ua)
|
||||
, m_open_handshake_timeout_dur(config::timeout_open_handshake)
|
||||
, m_close_handshake_timeout_dur(config::timeout_close_handshake)
|
||||
, m_pong_timeout_dur(config::timeout_pong)
|
||||
, m_state(session::state::connecting)
|
||||
, m_internal_state(session::internal_state::USER_INIT)
|
||||
, m_msg_manager(new con_msg_manager_type())
|
||||
@@ -437,6 +455,79 @@ public:
|
||||
m_message_handler = h;
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
// Connection timeouts //
|
||||
/////////////////////////
|
||||
|
||||
/// Set open handshake timeout
|
||||
/**
|
||||
* Sets the length of time the library will wait after an opening handshake
|
||||
* has been initiated before cancelling it. This can be used to prevent
|
||||
* excessive wait times for outgoing clients or excessive resource usage
|
||||
* from broken clients or DoS attacks on servers.
|
||||
*
|
||||
* Connections that time out will have their fail handlers called with the
|
||||
* open_handshake_timeout error code.
|
||||
*
|
||||
* The default value is specified via the compile time config value
|
||||
* 'timeout_open_handshake'. The default value in the core config
|
||||
* is 5000ms. A value of 0 will disable the timer entirely.
|
||||
*
|
||||
* To be effective, the transport you are using must support timers. See
|
||||
* the documentation for your transport policy for details about its
|
||||
* timer support.
|
||||
*
|
||||
* @param dur The length of the open handshake timeout in ms
|
||||
*/
|
||||
void set_open_handshake_timeout(long dur) {
|
||||
m_open_handshake_timeout_dur = dur;
|
||||
}
|
||||
|
||||
/// Set close handshake timeout
|
||||
/**
|
||||
* Sets the length of time the library will wait after a closing handshake
|
||||
* has been initiated before cancelling it. This can be used to prevent
|
||||
* excessive wait times for outgoing clients or excessive resource usage
|
||||
* from broken clients or DoS attacks on servers.
|
||||
*
|
||||
* Connections that time out will have their close handlers called with the
|
||||
* close_handshake_timeout error code.
|
||||
*
|
||||
* The default value is specified via the compile time config value
|
||||
* 'timeout_close_handshake'. The default value in the core config
|
||||
* is 5000ms. A value of 0 will disable the timer entirely.
|
||||
*
|
||||
* To be effective, the transport you are using must support timers. See
|
||||
* the documentation for your transport policy for details about its
|
||||
* timer support.
|
||||
*
|
||||
* @param dur The length of the close handshake timeout in ms
|
||||
*/
|
||||
void set_close_handshake_timeout(long dur) {
|
||||
m_close_handshake_timeout_dur = dur;
|
||||
}
|
||||
|
||||
/// Set pong timeout
|
||||
/**
|
||||
* Sets the length of time the library will wait for a pong response to a
|
||||
* ping. This can be used as a keepalive or to detect broken connections.
|
||||
*
|
||||
* Pong responses that time out will have the pong timeout handler called.
|
||||
*
|
||||
* The default value is specified via the compile time config value
|
||||
* 'timeout_pong'. The default value in the core config
|
||||
* is 5000ms. A value of 0 will disable the timer entirely.
|
||||
*
|
||||
* To be effective, the transport you are using must support timers. See
|
||||
* the documentation for your transport policy for details about its
|
||||
* timer support.
|
||||
*
|
||||
* @param dur The length of the pong timeout in ms
|
||||
*/
|
||||
void set_pong_timeout(long dur) {
|
||||
m_pong_timeout_dur = dur;
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
// Uncategorized public methods //
|
||||
//////////////////////////////////
|
||||
@@ -1034,7 +1125,7 @@ public:
|
||||
* @param ec A status code from the transport layer, zero on success,
|
||||
* non-zero otherwise.
|
||||
*/
|
||||
void handle_write_frame(bool terminate, lib::error_code const & ec);
|
||||
void handle_write_frame(lib::error_code const & ec);
|
||||
protected:
|
||||
void handle_transport_init(lib::error_code const & ec);
|
||||
|
||||
@@ -1190,8 +1281,12 @@ private:
|
||||
*/
|
||||
void log_fail_result();
|
||||
|
||||
// internal handler functions
|
||||
read_handler m_handle_read_frame;
|
||||
write_frame_handler m_write_frame_handler;
|
||||
|
||||
// static settings
|
||||
const std::string m_user_agent;
|
||||
std::string const m_user_agent;
|
||||
|
||||
/// Pointer to the connection handle
|
||||
connection_hdl m_connection_hdl;
|
||||
@@ -1208,6 +1303,11 @@ private:
|
||||
validate_handler m_validate_handler;
|
||||
message_handler m_message_handler;
|
||||
|
||||
/// constant values
|
||||
long m_open_handshake_timeout_dur;
|
||||
long m_close_handshake_timeout_dur;
|
||||
long m_pong_timeout_dur;
|
||||
|
||||
/// External connection state
|
||||
/**
|
||||
* Lock: m_connection_state_lock
|
||||
|
||||
+84
-1
@@ -91,6 +91,9 @@ public:
|
||||
: m_alog(config::alog_level, &std::cout)
|
||||
, m_elog(config::elog_level, &std::cerr)
|
||||
, m_user_agent(::websocketpp::user_agent)
|
||||
, m_open_handshake_timeout_dur(config::timeout_open_handshake)
|
||||
, m_close_handshake_timeout_dur(config::timeout_close_handshake)
|
||||
, m_pong_timeout_dur(config::timeout_pong)
|
||||
, m_is_server(is_server)
|
||||
{
|
||||
m_alog.set_channels(config::alog_level);
|
||||
@@ -269,6 +272,82 @@ public:
|
||||
m_message_handler = h;
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
// Connection timeouts //
|
||||
/////////////////////////
|
||||
|
||||
/// Set open handshake timeout
|
||||
/**
|
||||
* Sets the length of time the library will wait after an opening handshake
|
||||
* has been initiated before cancelling it. This can be used to prevent
|
||||
* excessive wait times for outgoing clients or excessive resource usage
|
||||
* from broken clients or DoS attacks on servers.
|
||||
*
|
||||
* Connections that time out will have their fail handlers called with the
|
||||
* open_handshake_timeout error code.
|
||||
*
|
||||
* The default value is specified via the compile time config value
|
||||
* 'timeout_open_handshake'. The default value in the core config
|
||||
* is 5000ms. A value of 0 will disable the timer entirely.
|
||||
*
|
||||
* To be effective, the transport you are using must support timers. See
|
||||
* the documentation for your transport policy for details about its
|
||||
* timer support.
|
||||
*
|
||||
* @param dur The length of the open handshake timeout in ms
|
||||
*/
|
||||
void set_open_handshake_timeout(long dur) {
|
||||
scoped_lock_type guard(m_mutex);
|
||||
m_open_handshake_timeout_dur = dur;
|
||||
}
|
||||
|
||||
/// Set close handshake timeout
|
||||
/**
|
||||
* Sets the length of time the library will wait after a closing handshake
|
||||
* has been initiated before cancelling it. This can be used to prevent
|
||||
* excessive wait times for outgoing clients or excessive resource usage
|
||||
* from broken clients or DoS attacks on servers.
|
||||
*
|
||||
* Connections that time out will have their close handlers called with the
|
||||
* close_handshake_timeout error code.
|
||||
*
|
||||
* The default value is specified via the compile time config value
|
||||
* 'timeout_close_handshake'. The default value in the core config
|
||||
* is 5000ms. A value of 0 will disable the timer entirely.
|
||||
*
|
||||
* To be effective, the transport you are using must support timers. See
|
||||
* the documentation for your transport policy for details about its
|
||||
* timer support.
|
||||
*
|
||||
* @param dur The length of the close handshake timeout in ms
|
||||
*/
|
||||
void set_close_handshake_timeout(long dur) {
|
||||
scoped_lock_type guard(m_mutex);
|
||||
m_close_handshake_timeout_dur = dur;
|
||||
}
|
||||
|
||||
/// Set pong timeout
|
||||
/**
|
||||
* Sets the length of time the library will wait for a pong response to a
|
||||
* ping. This can be used as a keepalive or to detect broken connections.
|
||||
*
|
||||
* Pong responses that time out will have the pong timeout handler called.
|
||||
*
|
||||
* The default value is specified via the compile time config value
|
||||
* 'timeout_pong'. The default value in the core config
|
||||
* is 5000ms. A value of 0 will disable the timer entirely.
|
||||
*
|
||||
* To be effective, the transport you are using must support timers. See
|
||||
* the documentation for your transport policy for details about its
|
||||
* timer support.
|
||||
*
|
||||
* @param dur The length of the pong timeout in ms
|
||||
*/
|
||||
void set_pong_timeout(long dur) {
|
||||
scoped_lock_type guard(m_mutex);
|
||||
m_pong_timeout_dur = dur;
|
||||
}
|
||||
|
||||
/*************************************/
|
||||
/* Connection pass through functions */
|
||||
/*************************************/
|
||||
@@ -415,13 +494,17 @@ private:
|
||||
validate_handler m_validate_handler;
|
||||
message_handler m_message_handler;
|
||||
|
||||
long m_open_handshake_timeout_dur;
|
||||
long m_close_handshake_timeout_dur;
|
||||
long m_pong_timeout_dur;
|
||||
|
||||
rng_type m_rng;
|
||||
|
||||
// static settings
|
||||
bool const m_is_server;
|
||||
|
||||
// endpoint state
|
||||
mutex_type m_mutex;
|
||||
mutable mutex_type m_mutex;
|
||||
};
|
||||
|
||||
} // namespace websocketpp
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace http {
|
||||
static char const header_delimiter[] = "\r\n";
|
||||
|
||||
/// Literal value of the HTTP header separator
|
||||
static char const header_separator[] = ": ";
|
||||
static char const header_separator[] = ":";
|
||||
|
||||
/// Literal value of an empty header
|
||||
static std::string const empty_header = "";
|
||||
|
||||
@@ -147,8 +147,8 @@ inline void parser::process_header(std::string::iterator begin,
|
||||
throw exception("Invalid header line",status_code::bad_request);
|
||||
}
|
||||
|
||||
append_header(std::string(begin,cursor),
|
||||
std::string(cursor+sizeof(header_separator)-1,end));
|
||||
append_header(strip_lws(std::string(begin,cursor)),
|
||||
strip_lws(std::string(cursor+sizeof(header_separator)-1,end)));
|
||||
}
|
||||
|
||||
inline std::string parser::raw_headers() const {
|
||||
|
||||
@@ -367,6 +367,13 @@ InputIterator extract_parameters(InputIterator begin, InputIterator end,
|
||||
return cursor;
|
||||
}
|
||||
|
||||
inline std::string strip_lws(std::string const & input) {
|
||||
std::string::const_iterator begin = extract_all_lws(input.begin(),input.end());
|
||||
std::string::const_reverse_iterator end = extract_all_lws(input.rbegin(),input.rend());
|
||||
|
||||
return std::string(begin,end.base());
|
||||
}
|
||||
|
||||
/// Base HTTP parser
|
||||
/**
|
||||
* Includes methods and data elements common to all types of HTTP messages such
|
||||
|
||||
@@ -163,15 +163,17 @@ void connection<config>::ping(const std::string& payload, lib::error_code& ec) {
|
||||
m_ping_timer->cancel();
|
||||
}
|
||||
|
||||
m_ping_timer = transport_con_type::set_timer(
|
||||
config::timeout_pong,
|
||||
lib::bind(
|
||||
&type::handle_pong_timeout,
|
||||
type::get_shared(),
|
||||
payload,
|
||||
lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
if (m_pong_timeout_dur > 0) {
|
||||
m_ping_timer = transport_con_type::set_timer(
|
||||
m_pong_timeout_dur,
|
||||
lib::bind(
|
||||
&type::handle_pong_timeout,
|
||||
type::get_shared(),
|
||||
payload,
|
||||
lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (!m_ping_timer) {
|
||||
// Our transport doesn't support timers
|
||||
@@ -270,8 +272,8 @@ void connection<config>::pong(const std::string& payload) {
|
||||
}
|
||||
|
||||
template <typename config>
|
||||
void connection<config>::close(const close::status::value code,
|
||||
const std::string & reason, lib::error_code & ec)
|
||||
void connection<config>::close(close::status::value const code,
|
||||
std::string const & reason, lib::error_code & ec)
|
||||
{
|
||||
m_alog.write(log::alevel::devel,"connection close");
|
||||
|
||||
@@ -288,8 +290,8 @@ void connection<config>::close(const close::status::value code,
|
||||
}
|
||||
|
||||
template<typename config>
|
||||
void connection<config>::close(const close::status::value code,
|
||||
const std::string & reason)
|
||||
void connection<config>::close(close::status::value const code,
|
||||
std::string const & reason)
|
||||
{
|
||||
lib::error_code ec;
|
||||
close(code,reason,ec);
|
||||
@@ -850,11 +852,11 @@ void connection<config>::handle_read_frame(const lib::error_code& ec,
|
||||
}
|
||||
|
||||
// Boundaries checking. TODO: How much of this should be done?
|
||||
if (bytes_transferred > config::connection_read_buffer_size) {
|
||||
/*if (bytes_transferred > config::connection_read_buffer_size) {
|
||||
m_elog.write(log::elevel::fatal,"Fatal boundaries checking error");
|
||||
this->terminate(make_error_code(error::general));
|
||||
return;
|
||||
}
|
||||
}*/
|
||||
|
||||
size_t p = 0;
|
||||
|
||||
@@ -942,12 +944,13 @@ void connection<config>::handle_read_frame(const lib::error_code& ec,
|
||||
1,
|
||||
m_buf,
|
||||
config::connection_read_buffer_size,
|
||||
lib::bind(
|
||||
/*lib::bind(
|
||||
&type::handle_read_frame,
|
||||
type::get_shared(),
|
||||
lib::placeholders::_1,
|
||||
lib::placeholders::_2
|
||||
)
|
||||
)*/
|
||||
m_handle_read_frame
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1253,14 +1256,16 @@ 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::get_shared(),
|
||||
lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
if (m_open_handshake_timeout_dur > 0) {
|
||||
m_handshake_timer = transport_con_type::set_timer(
|
||||
m_open_handshake_timeout_dur,
|
||||
lib::bind(
|
||||
&type::handle_open_handshake_timeout,
|
||||
type::get_shared(),
|
||||
lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
transport_con_type::async_write(
|
||||
m_handshake_buffer.data(),
|
||||
@@ -1429,7 +1434,7 @@ void connection<config>::handle_close_handshake_timeout(
|
||||
}
|
||||
|
||||
template <typename config>
|
||||
void connection<config>::terminate(const lib::error_code & ec) {
|
||||
void connection<config>::terminate(lib::error_code const & ec) {
|
||||
if (m_alog.static_test(log::alevel::devel)) {
|
||||
m_alog.write(log::alevel::devel,"connection terminate");
|
||||
}
|
||||
@@ -1459,6 +1464,8 @@ void connection<config>::terminate(const lib::error_code & ec) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: choose between shutdown and close based on error code sent
|
||||
|
||||
transport_con_type::async_shutdown(
|
||||
lib::bind(
|
||||
&type::handle_terminate,
|
||||
@@ -1471,7 +1478,7 @@ void connection<config>::terminate(const lib::error_code & ec) {
|
||||
|
||||
template <typename config>
|
||||
void connection<config>::handle_terminate(terminate_status tstat,
|
||||
const lib::error_code& ec)
|
||||
lib::error_code const & ec)
|
||||
{
|
||||
if (m_alog.static_test(log::alevel::devel)) {
|
||||
m_alog.write(log::alevel::devel,"connection handle_terminate");
|
||||
@@ -1540,8 +1547,8 @@ void connection<config>::write_frame() {
|
||||
m_write_flag = true;
|
||||
}
|
||||
|
||||
const std::string& header = m_current_msg->get_header();
|
||||
const std::string& payload = m_current_msg->get_payload();
|
||||
std::string const & header = m_current_msg->get_header();
|
||||
std::string const & payload = m_current_msg->get_payload();
|
||||
|
||||
m_send_buffer.push_back(transport::buffer(header.c_str(),header.size()));
|
||||
m_send_buffer.push_back(transport::buffer(payload.c_str(),payload.size()));
|
||||
@@ -1563,25 +1570,28 @@ void connection<config>::write_frame() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
transport_con_type::async_write(
|
||||
m_send_buffer,
|
||||
lib::bind(
|
||||
/*lib::bind(
|
||||
&type::handle_write_frame,
|
||||
type::get_shared(),
|
||||
m_current_msg->get_terminal(),
|
||||
lib::placeholders::_1
|
||||
)
|
||||
)*/
|
||||
m_write_frame_handler
|
||||
);
|
||||
}
|
||||
|
||||
template <typename config>
|
||||
void connection<config>::handle_write_frame(bool terminate,
|
||||
const lib::error_code& ec)
|
||||
void connection<config>::handle_write_frame(lib::error_code const & ec)
|
||||
{
|
||||
if (m_alog.static_test(log::alevel::devel)) {
|
||||
m_alog.write(log::alevel::devel,"connection handle_write_frame");
|
||||
}
|
||||
|
||||
bool terminate = m_current_msg->get_terminal();
|
||||
|
||||
m_send_buffer.clear();
|
||||
m_current_msg.reset();
|
||||
|
||||
@@ -1791,16 +1801,19 @@ void connection<config>::process_control_frame(typename
|
||||
|
||||
template <typename config>
|
||||
lib::error_code connection<config>::send_close_ack(close::status::value code,
|
||||
const std::string &reason)
|
||||
std::string const & reason)
|
||||
{
|
||||
return send_close_frame(code,reason,true,m_is_server);
|
||||
}
|
||||
|
||||
template <typename config>
|
||||
lib::error_code connection<config>::send_close_frame(close::status::value code,
|
||||
const std::string &reason, bool ack, bool terminal)
|
||||
std::string const & reason, bool ack, bool terminal)
|
||||
{
|
||||
m_alog.write(log::alevel::devel,"send_close_frame");
|
||||
|
||||
// check for special codes
|
||||
|
||||
// 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
|
||||
@@ -1861,14 +1874,16 @@ lib::error_code connection<config>::send_close_frame(close::status::value code,
|
||||
|
||||
// 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::get_shared(),
|
||||
lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
if (m_close_handshake_timeout_dur > 0) {
|
||||
m_handshake_timer = transport_con_type::set_timer(
|
||||
m_close_handshake_timeout_dur,
|
||||
lib::bind(
|
||||
&type::handle_close_handshake_timeout,
|
||||
type::get_shared(),
|
||||
lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
bool needs_writing = false;
|
||||
{
|
||||
|
||||
@@ -40,6 +40,7 @@ endpoint<connection,config>::create_connection() {
|
||||
return connection_ptr();
|
||||
}*/
|
||||
|
||||
//scoped_lock_type guard(m_mutex);
|
||||
// Create a connection on the heap and manage it using a shared pointer
|
||||
connection_ptr con(new connection_type(m_is_server,m_user_agent,m_alog,
|
||||
m_elog, m_rng));
|
||||
@@ -63,6 +64,16 @@ endpoint<connection,config>::create_connection() {
|
||||
con->set_http_handler(m_http_handler);
|
||||
con->set_validate_handler(m_validate_handler);
|
||||
con->set_message_handler(m_message_handler);
|
||||
|
||||
if (m_open_handshake_timeout_dur == config::timeout_open_handshake) {
|
||||
con->set_open_handshake_timeout(m_open_handshake_timeout_dur);
|
||||
}
|
||||
if (m_close_handshake_timeout_dur == config::timeout_close_handshake) {
|
||||
con->set_close_handshake_timeout(m_close_handshake_timeout_dur);
|
||||
}
|
||||
if (m_pong_timeout_dur == config::timeout_pong) {
|
||||
con->set_pong_timeout(m_pong_timeout_dur);
|
||||
}
|
||||
|
||||
lib::error_code ec;
|
||||
|
||||
|
||||
@@ -1,185 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2011, Micael Hildenborg
|
||||
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 Micael Hildenborg 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 Micael Hildenborg ''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 Micael Hildenborg 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
Contributors:
|
||||
Gustav
|
||||
Several members in the gamedev.se forum.
|
||||
Gregory Petrosyan
|
||||
*/
|
||||
|
||||
#include "sha1.h"
|
||||
|
||||
namespace sha1
|
||||
{
|
||||
namespace // local
|
||||
{
|
||||
// Rotate an integer value to left.
|
||||
inline const unsigned int rol(const unsigned int value,
|
||||
const unsigned int steps)
|
||||
{
|
||||
return ((value << steps) | (value >> (32 - steps)));
|
||||
}
|
||||
|
||||
// Sets the first 16 integers in the buffert to zero.
|
||||
// Used for clearing the W buffert.
|
||||
inline void clearWBuffert(unsigned int* buffert)
|
||||
{
|
||||
for (int pos = 16; --pos >= 0;)
|
||||
{
|
||||
buffert[pos] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void innerHash(unsigned int* result, unsigned int* w)
|
||||
{
|
||||
unsigned int a = result[0];
|
||||
unsigned int b = result[1];
|
||||
unsigned int c = result[2];
|
||||
unsigned int d = result[3];
|
||||
unsigned int e = result[4];
|
||||
|
||||
int round = 0;
|
||||
|
||||
#define sha1macro(func,val) \
|
||||
{ \
|
||||
const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \
|
||||
e = d; \
|
||||
d = c; \
|
||||
c = rol(b, 30); \
|
||||
b = a; \
|
||||
a = t; \
|
||||
}
|
||||
|
||||
while (round < 16)
|
||||
{
|
||||
sha1macro((b & c) | (~b & d), 0x5a827999)
|
||||
++round;
|
||||
}
|
||||
while (round < 20)
|
||||
{
|
||||
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
|
||||
sha1macro((b & c) | (~b & d), 0x5a827999)
|
||||
++round;
|
||||
}
|
||||
while (round < 40)
|
||||
{
|
||||
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
|
||||
sha1macro(b ^ c ^ d, 0x6ed9eba1)
|
||||
++round;
|
||||
}
|
||||
while (round < 60)
|
||||
{
|
||||
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
|
||||
sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc)
|
||||
++round;
|
||||
}
|
||||
while (round < 80)
|
||||
{
|
||||
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
|
||||
sha1macro(b ^ c ^ d, 0xca62c1d6)
|
||||
++round;
|
||||
}
|
||||
|
||||
#undef sha1macro
|
||||
|
||||
result[0] += a;
|
||||
result[1] += b;
|
||||
result[2] += c;
|
||||
result[3] += d;
|
||||
result[4] += e;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void calc(const void* src, const int bytelength, unsigned char* hash)
|
||||
{
|
||||
// Init the result array.
|
||||
unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 };
|
||||
|
||||
// Cast the void src pointer to be the byte array we can work with.
|
||||
const unsigned char* sarray = (const unsigned char*) src;
|
||||
|
||||
// The reusable round buffer
|
||||
unsigned int w[80];
|
||||
|
||||
// Loop through all complete 64byte blocks.
|
||||
const int endOfFullBlocks = bytelength - 64;
|
||||
int endCurrentBlock;
|
||||
int currentBlock = 0;
|
||||
|
||||
while (currentBlock <= endOfFullBlocks)
|
||||
{
|
||||
endCurrentBlock = currentBlock + 64;
|
||||
|
||||
// Init the round buffer with the 64 byte block data.
|
||||
for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4)
|
||||
{
|
||||
// This line will swap endian on big endian and keep endian on little endian.
|
||||
w[roundPos++] = (unsigned int) sarray[currentBlock + 3]
|
||||
| (((unsigned int) sarray[currentBlock + 2]) << 8)
|
||||
| (((unsigned int) sarray[currentBlock + 1]) << 16)
|
||||
| (((unsigned int) sarray[currentBlock]) << 24);
|
||||
}
|
||||
innerHash(result, w);
|
||||
}
|
||||
|
||||
// Handle the last and not full 64 byte block if existing.
|
||||
endCurrentBlock = bytelength - currentBlock;
|
||||
clearWBuffert(w);
|
||||
int lastBlockBytes = 0;
|
||||
for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes)
|
||||
{
|
||||
w[lastBlockBytes >> 2] |= (unsigned int) sarray[lastBlockBytes + currentBlock] << ((3 - (lastBlockBytes & 3)) << 3);
|
||||
}
|
||||
w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3);
|
||||
if (endCurrentBlock >= 56)
|
||||
{
|
||||
innerHash(result, w);
|
||||
clearWBuffert(w);
|
||||
}
|
||||
w[15] = bytelength << 3;
|
||||
innerHash(result, w);
|
||||
|
||||
// Store hash in result pointer, and make sure we get in in the correct order on both endian models.
|
||||
for (int hashByte = 20; --hashByte >= 0;)
|
||||
{
|
||||
hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
void toHexString(const unsigned char* hash, char* hexstring)
|
||||
{
|
||||
const char hexDigits[] = { "0123456789abcdef" };
|
||||
|
||||
for (int hashByte = 20; --hashByte >= 0;)
|
||||
{
|
||||
hexstring[hashByte << 1] = hexDigits[(hash[hashByte] >> 4) & 0xf];
|
||||
hexstring[(hashByte << 1) + 1] = hexDigits[hash[hashByte] & 0xf];
|
||||
}
|
||||
hexstring[40] = 0;
|
||||
}
|
||||
} // namespace sha1
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2011, Micael Hildenborg
|
||||
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 Micael Hildenborg 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 Micael Hildenborg ''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 Micael Hildenborg 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 SHA1_DEFINED
|
||||
#define SHA1_DEFINED
|
||||
|
||||
namespace sha1
|
||||
{
|
||||
|
||||
/**
|
||||
@param src points to any kind of data to be hashed.
|
||||
@param bytelength the number of bytes to hash from the src pointer.
|
||||
@param hash should point to a buffer of at least 20 bytes of size for storing the sha1 result in.
|
||||
*/
|
||||
void calc(const void* src, const int bytelength, unsigned char* hash);
|
||||
|
||||
/**
|
||||
@param hash is 20 bytes of sha1 hash. This is the same data that is the result from the calc function.
|
||||
@param hexstring should point to a buffer of at least 41 bytes of size for storing the hexadecimal representation of the hash. A zero will be written at position 40, so the buffer will be a valid zero ended string.
|
||||
*/
|
||||
void toHexString(const unsigned char* hash, char* hexstring);
|
||||
|
||||
} // namespace sha1
|
||||
|
||||
#endif // SHA1_DEFINED
|
||||
@@ -34,6 +34,10 @@
|
||||
|
||||
#include <boost/system/error_code.hpp>
|
||||
|
||||
#include <boost/aligned_storage.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/array.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace websocketpp {
|
||||
@@ -45,6 +49,110 @@ namespace transport {
|
||||
*/
|
||||
namespace asio {
|
||||
|
||||
//
|
||||
|
||||
// Class to manage the memory to be used for handler-based custom allocation.
|
||||
// It contains a single block of memory which may be returned for allocation
|
||||
// requests. If the memory is in use when an allocation request is made, the
|
||||
// allocator delegates allocation to the global heap.
|
||||
class handler_allocator
|
||||
: private boost::noncopyable
|
||||
{
|
||||
public:
|
||||
handler_allocator()
|
||||
: in_use_(false)
|
||||
{
|
||||
}
|
||||
|
||||
void* allocate(std::size_t size)
|
||||
{
|
||||
if (!in_use_ && size < storage_.size)
|
||||
{
|
||||
in_use_ = true;
|
||||
return storage_.address();
|
||||
}
|
||||
else
|
||||
{
|
||||
return ::operator new(size);
|
||||
}
|
||||
}
|
||||
|
||||
void deallocate(void* pointer)
|
||||
{
|
||||
if (pointer == storage_.address())
|
||||
{
|
||||
in_use_ = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
::operator delete(pointer);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// Storage space used for handler-based custom memory allocation.
|
||||
boost::aligned_storage<1024> storage_;
|
||||
|
||||
// Whether the handler-based custom allocation storage has been used.
|
||||
bool in_use_;
|
||||
};
|
||||
|
||||
// Wrapper class template for handler objects to allow handler memory
|
||||
// allocation to be customised. Calls to operator() are forwarded to the
|
||||
// encapsulated handler.
|
||||
template <typename Handler>
|
||||
class custom_alloc_handler
|
||||
{
|
||||
public:
|
||||
custom_alloc_handler(handler_allocator& a, Handler h)
|
||||
: allocator_(a),
|
||||
handler_(h)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Arg1>
|
||||
void operator()(Arg1 arg1)
|
||||
{
|
||||
handler_(arg1);
|
||||
}
|
||||
|
||||
template <typename Arg1, typename Arg2>
|
||||
void operator()(Arg1 arg1, Arg2 arg2)
|
||||
{
|
||||
handler_(arg1, arg2);
|
||||
}
|
||||
|
||||
friend void* asio_handler_allocate(std::size_t size,
|
||||
custom_alloc_handler<Handler>* this_handler)
|
||||
{
|
||||
return this_handler->allocator_.allocate(size);
|
||||
}
|
||||
|
||||
friend void asio_handler_deallocate(void* pointer, std::size_t /*size*/,
|
||||
custom_alloc_handler<Handler>* this_handler)
|
||||
{
|
||||
this_handler->allocator_.deallocate(pointer);
|
||||
}
|
||||
|
||||
private:
|
||||
handler_allocator& allocator_;
|
||||
Handler handler_;
|
||||
};
|
||||
|
||||
// Helper function to wrap a handler object to add custom allocation.
|
||||
template <typename Handler>
|
||||
inline custom_alloc_handler<Handler> make_custom_alloc_handler(
|
||||
handler_allocator& a, Handler h)
|
||||
{
|
||||
return custom_alloc_handler<Handler>(a, h);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Forward declaration of class endpoint so that it can be friended/referenced
|
||||
// before being included.
|
||||
template <typename config>
|
||||
@@ -53,6 +161,21 @@ class endpoint;
|
||||
typedef lib::function<void(boost::system::error_code const &)>
|
||||
socket_shutdown_handler;
|
||||
|
||||
typedef lib::function<void (boost::system::error_code const & ec,
|
||||
size_t bytes_transferred)> async_read_handler;
|
||||
|
||||
typedef lib::function<void (boost::system::error_code const & ec,
|
||||
size_t bytes_transferred)> async_write_handler;
|
||||
|
||||
typedef lib::function<void (lib::error_code const & ec)> pre_init_handler;
|
||||
|
||||
// handle_timer: dynamic parameters, multiple copies
|
||||
// handle_proxy_write
|
||||
// handle_proxy_read
|
||||
// handle_async_write
|
||||
// handle_pre_init
|
||||
|
||||
|
||||
/// Asio transport errors
|
||||
namespace error {
|
||||
enum value {
|
||||
|
||||
@@ -109,15 +109,47 @@ public:
|
||||
return socket_con_type::is_secure();
|
||||
}
|
||||
|
||||
/// Sets the tcp init handler
|
||||
/// Sets the tcp pre init handler
|
||||
/**
|
||||
* The tcp init handler is called after the tcp connection has been
|
||||
* established.
|
||||
* The tcp pre init handler is called after the raw tcp connection has been
|
||||
* established but before any additional wrappers (proxy connects, TLS
|
||||
* handshakes, etc) have been performed.
|
||||
*
|
||||
* @param h The handler to call on tcp init.
|
||||
* @since 0.4.0-alpha1
|
||||
*
|
||||
* @param h The handler to call on tcp pre init.
|
||||
*/
|
||||
void set_tcp_pre_init_handler(tcp_init_handler h) {
|
||||
m_tcp_pre_init_handler = h;
|
||||
}
|
||||
|
||||
/// Sets the tcp pre init handler (deprecated)
|
||||
/**
|
||||
* The tcp pre init handler is called after the raw tcp connection has been
|
||||
* established but before any additional wrappers (proxy connects, TLS
|
||||
* handshakes, etc) have been performed.
|
||||
*
|
||||
* @deprecated Use set_tcp_pre_init_handler instead
|
||||
*
|
||||
* @param h The handler to call on tcp pre init.
|
||||
*/
|
||||
void set_tcp_init_handler(tcp_init_handler h) {
|
||||
m_tcp_init_handler = h;
|
||||
set_tcp_pre_init_handler(h);
|
||||
}
|
||||
|
||||
/// Sets the tcp post init handler
|
||||
/**
|
||||
* The tcp post init handler is called after the tcp connection has been
|
||||
* established and all additional wrappers (proxy connects, TLS handshakes,
|
||||
* etc have been performed. This is fired before any bytes are read or any
|
||||
* WebSocket specific handshake logic has been performed.
|
||||
*
|
||||
* @since 0.4.0-alpha1
|
||||
*
|
||||
* @param h The handler to call on tcp post init.
|
||||
*/
|
||||
void set_tcp_post_init_handler(tcp_init_handler h) {
|
||||
m_tcp_post_init_handler = h;
|
||||
}
|
||||
|
||||
/// Set the proxy to connect through (exception free)
|
||||
@@ -264,15 +296,21 @@ public:
|
||||
)
|
||||
);
|
||||
|
||||
new_timer->async_wait(
|
||||
m_strand->wrap(lib::bind(
|
||||
&type::handle_timer,
|
||||
get_shared(),
|
||||
if (config::enable_multithreading) {
|
||||
new_timer->async_wait(m_strand->wrap(lib::bind(
|
||||
&type::handle_timer, get_shared(),
|
||||
new_timer,
|
||||
callback,
|
||||
lib::placeholders::_1
|
||||
))
|
||||
);
|
||||
)));
|
||||
} else {
|
||||
new_timer->async_wait(lib::bind(
|
||||
&type::handle_timer, get_shared(),
|
||||
new_timer,
|
||||
callback,
|
||||
lib::placeholders::_1
|
||||
));
|
||||
}
|
||||
|
||||
return new_timer;
|
||||
}
|
||||
@@ -288,8 +326,8 @@ public:
|
||||
* @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)
|
||||
void handle_timer(timer_ptr t, timer_handler callback,
|
||||
boost::system::error_code const & ec)
|
||||
{
|
||||
if (ec) {
|
||||
if (ec == boost::asio::error::operation_aborted) {
|
||||
@@ -333,11 +371,12 @@ protected:
|
||||
// TODO: pre-init timeout. Right now no implemented socket policies
|
||||
// actually have an asyncronous pre-init
|
||||
|
||||
m_init_handler = callback;
|
||||
|
||||
socket_con_type::pre_init(
|
||||
lib::bind(
|
||||
&type::handle_pre_init,
|
||||
get_shared(),
|
||||
callback,
|
||||
lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
@@ -379,34 +418,57 @@ protected:
|
||||
// do we need to store or use the io_service at this level?
|
||||
m_io_service = io_service;
|
||||
|
||||
m_strand.reset(new boost::asio::strand(*io_service));
|
||||
if (config::enable_multithreading) {
|
||||
m_strand.reset(new boost::asio::strand(*io_service));
|
||||
|
||||
m_async_read_handler = m_strand->wrap(lib::bind(
|
||||
&type::handle_async_read, get_shared(),
|
||||
lib::placeholders::_1, lib::placeholders::_2
|
||||
));
|
||||
|
||||
m_async_write_handler = m_strand->wrap(lib::bind(
|
||||
&type::handle_async_write, get_shared(),
|
||||
lib::placeholders::_1, lib::placeholders::_2
|
||||
));
|
||||
} else {
|
||||
// TODO: goal: not have this line here
|
||||
//m_strand.reset(new boost::asio::strand(*io_service));
|
||||
|
||||
m_async_read_handler = lib::bind(
|
||||
&type::handle_async_read, get_shared(),
|
||||
lib::placeholders::_1, lib::placeholders::_2
|
||||
);
|
||||
|
||||
m_async_write_handler = lib::bind(&type::handle_async_write,
|
||||
get_shared(), lib::placeholders::_1, lib::placeholders::_2);
|
||||
}
|
||||
|
||||
return socket_con_type::init_asio(io_service, m_strand, m_is_server);
|
||||
}
|
||||
|
||||
void handle_pre_init(init_handler callback, const lib::error_code& ec) {
|
||||
void handle_pre_init(lib::error_code const & ec) {
|
||||
if (m_alog.static_test(log::alevel::devel)) {
|
||||
m_alog.write(log::alevel::devel,"asio connection handle pre_init");
|
||||
}
|
||||
|
||||
if (m_tcp_init_handler) {
|
||||
m_tcp_init_handler(m_connection_hdl);
|
||||
if (m_tcp_pre_init_handler) {
|
||||
m_tcp_pre_init_handler(m_connection_hdl);
|
||||
}
|
||||
|
||||
if (ec) {
|
||||
callback(ec);
|
||||
m_init_handler(ec);
|
||||
}
|
||||
|
||||
// If we have a proxy set issue a proxy connect, otherwise skip to
|
||||
// post_init
|
||||
if (!m_proxy.empty()) {
|
||||
proxy_write(callback);
|
||||
proxy_write();
|
||||
} else {
|
||||
post_init(callback);
|
||||
post_init();
|
||||
}
|
||||
}
|
||||
|
||||
void post_init(init_handler callback) {
|
||||
void post_init() {
|
||||
if (m_alog.static_test(log::alevel::devel)) {
|
||||
m_alog.write(log::alevel::devel,"asio connection post_init");
|
||||
}
|
||||
@@ -418,7 +480,7 @@ protected:
|
||||
&type::handle_post_init_timeout,
|
||||
get_shared(),
|
||||
post_timer,
|
||||
callback,
|
||||
m_init_handler,
|
||||
lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
@@ -428,7 +490,7 @@ protected:
|
||||
&type::handle_post_init,
|
||||
get_shared(),
|
||||
post_timer,
|
||||
callback,
|
||||
m_init_handler,
|
||||
lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
@@ -477,10 +539,14 @@ protected:
|
||||
m_alog.write(log::alevel::devel,"asio connection handle_post_init");
|
||||
}
|
||||
|
||||
if (m_tcp_post_init_handler) {
|
||||
m_tcp_post_init_handler(m_connection_hdl);
|
||||
}
|
||||
|
||||
callback(ec);
|
||||
}
|
||||
|
||||
void proxy_write(init_handler callback) {
|
||||
void proxy_write() {
|
||||
if (m_alog.static_test(log::alevel::devel)) {
|
||||
m_alog.write(log::alevel::devel,"asio connection proxy_write");
|
||||
}
|
||||
@@ -488,7 +554,7 @@ protected:
|
||||
if (!m_proxy_data) {
|
||||
m_elog.write(log::elevel::library,
|
||||
"assertion failed: !m_proxy_data in asio::connection::proxy_write");
|
||||
callback(make_error_code(error::general));
|
||||
m_init_handler(make_error_code(error::general));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -505,25 +571,37 @@ protected:
|
||||
lib::bind(
|
||||
&type::handle_proxy_timeout,
|
||||
get_shared(),
|
||||
callback,
|
||||
m_init_handler,
|
||||
lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
|
||||
// Send proxy request
|
||||
boost::asio::async_write(
|
||||
socket_con_type::get_next_layer(),
|
||||
m_bufs,
|
||||
m_strand->wrap(lib::bind(
|
||||
&type::handle_proxy_write,
|
||||
get_shared(),
|
||||
callback,
|
||||
lib::placeholders::_1
|
||||
))
|
||||
);
|
||||
if (config::enable_multithreading) {
|
||||
boost::asio::async_write(
|
||||
socket_con_type::get_next_layer(),
|
||||
m_bufs,
|
||||
m_strand->wrap(lib::bind(
|
||||
&type::handle_proxy_write, get_shared(),
|
||||
m_init_handler,
|
||||
lib::placeholders::_1
|
||||
))
|
||||
);
|
||||
} else {
|
||||
boost::asio::async_write(
|
||||
socket_con_type::get_next_layer(),
|
||||
m_bufs,
|
||||
lib::bind(
|
||||
&type::handle_proxy_write, get_shared(),
|
||||
m_init_handler,
|
||||
lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void handle_proxy_timeout(init_handler callback, const lib::error_code & ec) {
|
||||
void handle_proxy_timeout(init_handler callback, lib::error_code const & ec)
|
||||
{
|
||||
if (ec == transport::error::operation_aborted) {
|
||||
m_alog.write(log::alevel::devel,
|
||||
"asio handle_proxy_write timer cancelled");
|
||||
@@ -539,11 +617,12 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
void handle_proxy_write(init_handler callback, const
|
||||
boost::system::error_code& ec)
|
||||
void handle_proxy_write(init_handler callback,
|
||||
boost::system::error_code const & ec)
|
||||
{
|
||||
if (m_alog.static_test(log::alevel::devel)) {
|
||||
m_alog.write(log::alevel::devel,"asio connection handle_proxy_write");
|
||||
m_alog.write(log::alevel::devel,
|
||||
"asio connection handle_proxy_write");
|
||||
}
|
||||
|
||||
m_bufs.clear();
|
||||
@@ -581,25 +660,37 @@ protected:
|
||||
return;
|
||||
}
|
||||
|
||||
boost::asio::async_read_until(
|
||||
socket_con_type::get_next_layer(),
|
||||
m_proxy_data->read_buf,
|
||||
"\r\n\r\n",
|
||||
m_strand->wrap(lib::bind(
|
||||
&type::handle_proxy_read,
|
||||
get_shared(),
|
||||
callback,
|
||||
lib::placeholders::_1,
|
||||
lib::placeholders::_2
|
||||
))
|
||||
);
|
||||
if (config::enable_multithreading) {
|
||||
boost::asio::async_read_until(
|
||||
socket_con_type::get_next_layer(),
|
||||
m_proxy_data->read_buf,
|
||||
"\r\n\r\n",
|
||||
m_strand->wrap(lib::bind(
|
||||
&type::handle_proxy_read, get_shared(),
|
||||
callback,
|
||||
lib::placeholders::_1, lib::placeholders::_2
|
||||
))
|
||||
);
|
||||
} else {
|
||||
boost::asio::async_read_until(
|
||||
socket_con_type::get_next_layer(),
|
||||
m_proxy_data->read_buf,
|
||||
"\r\n\r\n",
|
||||
lib::bind(
|
||||
&type::handle_proxy_read, get_shared(),
|
||||
callback,
|
||||
lib::placeholders::_1, lib::placeholders::_2
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void handle_proxy_read(init_handler callback, const
|
||||
boost::system::error_code& ec, size_t bytes_transferred)
|
||||
void handle_proxy_read(init_handler callback,
|
||||
boost::system::error_code const & ec, size_t bytes_transferred)
|
||||
{
|
||||
if (m_alog.static_test(log::alevel::devel)) {
|
||||
m_alog.write(log::alevel::devel,"asio connection handle_proxy_read");
|
||||
m_alog.write(log::alevel::devel,
|
||||
"asio connection handle_proxy_read");
|
||||
}
|
||||
|
||||
// Timer expired or the operation was aborted for some reason.
|
||||
@@ -667,7 +758,7 @@ protected:
|
||||
m_proxy_data.reset();
|
||||
|
||||
// Continue with post proxy initialization
|
||||
post_init(callback);
|
||||
post_init();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -685,93 +776,114 @@ protected:
|
||||
m_alog.write(log::alevel::devel,s.str());
|
||||
}
|
||||
|
||||
if (num_bytes > len) {
|
||||
if (!m_async_read_handler) {
|
||||
m_alog.write(log::alevel::devel,
|
||||
"async_read_at_least called after async_shutdown");
|
||||
handler(make_error_code(transport::error::action_after_shutdown), 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: safety vs speed ?
|
||||
// maybe move into an if devel block
|
||||
/*if (num_bytes > len) {
|
||||
m_elog.write(log::elevel::devel,
|
||||
"asio async_read_at_least error::invalid_num_bytes");
|
||||
handler(make_error_code(transport::error::invalid_num_bytes),
|
||||
size_t(0));
|
||||
return;
|
||||
}
|
||||
}*/
|
||||
|
||||
m_read_handler = handler;
|
||||
|
||||
boost::asio::async_read(
|
||||
socket_con_type::get_socket(),
|
||||
boost::asio::buffer(buf,len),
|
||||
boost::asio::transfer_at_least(num_bytes),
|
||||
m_strand->wrap(lib::bind(
|
||||
&type::handle_async_read,
|
||||
get_shared(),
|
||||
handler,
|
||||
lib::placeholders::_1,
|
||||
lib::placeholders::_2
|
||||
))
|
||||
make_custom_alloc_handler(
|
||||
m_read_handler_allocator,
|
||||
m_async_read_handler
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void handle_async_read(read_handler handler, const
|
||||
boost::system::error_code& ec, size_t bytes_transferred)
|
||||
void handle_async_read(const boost::system::error_code& ec,
|
||||
size_t bytes_transferred)
|
||||
{
|
||||
if (!ec) {
|
||||
handler(lib::error_code(), bytes_transferred);
|
||||
m_read_handler(lib::error_code(), bytes_transferred);
|
||||
return;
|
||||
}
|
||||
|
||||
// translate boost error codes into more lib::error_codes
|
||||
if (ec == boost::asio::error::eof) {
|
||||
handler(make_error_code(transport::error::eof),
|
||||
m_read_handler(make_error_code(transport::error::eof),
|
||||
bytes_transferred);
|
||||
} else if (ec.value() == 335544539) {
|
||||
handler(make_error_code(transport::error::tls_short_read),
|
||||
m_read_handler(make_error_code(transport::error::tls_short_read),
|
||||
bytes_transferred);
|
||||
} else {
|
||||
log_err(log::elevel::info,"asio async_read_at_least",ec);
|
||||
handler(make_error_code(transport::error::pass_through),
|
||||
m_read_handler(make_error_code(transport::error::pass_through),
|
||||
bytes_transferred);
|
||||
}
|
||||
}
|
||||
|
||||
void async_write(const char* buf, size_t len, write_handler handler) {
|
||||
m_bufs.push_back(boost::asio::buffer(buf,len));
|
||||
if (!m_async_write_handler) {
|
||||
m_alog.write(log::alevel::devel,
|
||||
"async_write (single) called after async_shutdown");
|
||||
handler(make_error_code(transport::error::action_after_shutdown));
|
||||
return;
|
||||
}
|
||||
|
||||
m_bufs.push_back(boost::asio::buffer(buf,len));
|
||||
|
||||
m_write_handler = handler;
|
||||
|
||||
boost::asio::async_write(
|
||||
socket_con_type::get_socket(),
|
||||
m_bufs,
|
||||
m_strand->wrap(lib::bind(
|
||||
&type::handle_async_write,
|
||||
get_shared(),
|
||||
handler,
|
||||
lib::placeholders::_1
|
||||
))
|
||||
make_custom_alloc_handler(
|
||||
m_write_handler_allocator,
|
||||
m_async_write_handler
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void async_write(const std::vector<buffer>& bufs, write_handler handler) {
|
||||
if (!m_async_write_handler) {
|
||||
m_alog.write(log::alevel::devel,
|
||||
"async_write (vector) called after async_shutdown");
|
||||
handler(make_error_code(transport::error::action_after_shutdown));
|
||||
return;
|
||||
}
|
||||
std::vector<buffer>::const_iterator it;
|
||||
|
||||
for (it = bufs.begin(); it != bufs.end(); ++it) {
|
||||
m_bufs.push_back(boost::asio::buffer((*it).buf,(*it).len));
|
||||
}
|
||||
|
||||
m_write_handler = handler;
|
||||
|
||||
boost::asio::async_write(
|
||||
socket_con_type::get_socket(),
|
||||
m_bufs,
|
||||
m_strand->wrap(lib::bind(
|
||||
&type::handle_async_write,
|
||||
get_shared(),
|
||||
handler,
|
||||
lib::placeholders::_1
|
||||
))
|
||||
make_custom_alloc_handler(
|
||||
m_write_handler_allocator,
|
||||
m_async_write_handler
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void handle_async_write(write_handler handler, const
|
||||
boost::system::error_code& ec)
|
||||
void handle_async_write(boost::system::error_code const & ec,
|
||||
size_t bytes_transferred)
|
||||
{
|
||||
m_bufs.clear();
|
||||
if (ec) {
|
||||
log_err(log::elevel::info,"asio async_write",ec);
|
||||
handler(make_error_code(transport::error::pass_through));
|
||||
m_write_handler(make_error_code(transport::error::pass_through));
|
||||
} else {
|
||||
handler(lib::error_code());
|
||||
m_write_handler(lib::error_code());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -792,12 +904,20 @@ protected:
|
||||
* This needs to be thread safe
|
||||
*/
|
||||
lib::error_code interrupt(interrupt_handler handler) {
|
||||
m_io_service->post(m_strand->wrap(handler));
|
||||
if (config::enable_multithreading) {
|
||||
m_io_service->post(m_strand->wrap(handler));
|
||||
} else {
|
||||
m_io_service->post(handler);
|
||||
}
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
lib::error_code dispatch(dispatch_handler handler) {
|
||||
m_io_service->post(m_strand->wrap(handler));
|
||||
if (config::enable_multithreading) {
|
||||
m_io_service->post(m_strand->wrap(handler));
|
||||
} else {
|
||||
m_io_service->post(handler);
|
||||
}
|
||||
return lib::error_code();
|
||||
}
|
||||
|
||||
@@ -811,6 +931,13 @@ protected:
|
||||
m_alog.write(log::alevel::devel,"asio connection async_shutdown");
|
||||
}
|
||||
|
||||
// Reset cached handlers now that we won't be reading or writing anymore
|
||||
// These cached handlers store shared pointers to this connection and will leak
|
||||
// the connection if not destroyed.
|
||||
m_async_read_handler = 0;
|
||||
m_async_write_handler = 0;
|
||||
m_init_handler = 0;
|
||||
|
||||
timer_ptr shutdown_timer;
|
||||
shutdown_timer = set_timer(
|
||||
config::timeout_socket_shutdown,
|
||||
@@ -926,7 +1053,18 @@ private:
|
||||
std::vector<boost::asio::const_buffer> m_bufs;
|
||||
|
||||
// Handlers
|
||||
tcp_init_handler m_tcp_init_handler;
|
||||
tcp_init_handler m_tcp_pre_init_handler;
|
||||
tcp_init_handler m_tcp_post_init_handler;
|
||||
|
||||
handler_allocator m_read_handler_allocator;
|
||||
handler_allocator m_write_handler_allocator;
|
||||
|
||||
read_handler m_read_handler;
|
||||
write_handler m_write_handler;
|
||||
init_handler m_init_handler;
|
||||
|
||||
async_read_handler m_async_read_handler;
|
||||
async_write_handler m_async_write_handler;
|
||||
};
|
||||
|
||||
|
||||
|
||||
+188
-50
@@ -84,10 +84,13 @@ public:
|
||||
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;
|
||||
/// Type of a shared pointer to an io_service work object
|
||||
typedef lib::shared_ptr<boost::asio::io_service::work> work_ptr;
|
||||
|
||||
// generate and manage our own io_service
|
||||
explicit endpoint()
|
||||
: m_external_io_service(false)
|
||||
, m_listen_backlog(0)
|
||||
, m_state(UNINITIALIZED)
|
||||
{
|
||||
//std::cout << "transport::asio::endpoint constructor" << std::endl;
|
||||
@@ -119,6 +122,7 @@ public:
|
||||
: m_io_service(src.m_io_service)
|
||||
, m_external_io_service(src.m_external_io_service)
|
||||
, m_acceptor(src.m_acceptor)
|
||||
, m_listen_backlog(0)
|
||||
, m_state(src.m_state)
|
||||
{
|
||||
src.m_io_service = NULL;
|
||||
@@ -132,11 +136,13 @@ public:
|
||||
m_io_service = rhs.m_io_service;
|
||||
m_external_io_service = rhs.m_external_io_service;
|
||||
m_acceptor = rhs.m_acceptor;
|
||||
m_listen_backlog = rhs.m_listen_backlog
|
||||
m_state = rhs.m_state;
|
||||
|
||||
rhs.m_io_service = NULL;
|
||||
rhs.m_external_io_service = false;
|
||||
rhs.m_acceptor = NULL;
|
||||
rhs.m_listen_backlog = 0;
|
||||
rhs.m_state = UNINITIALIZED;
|
||||
}
|
||||
return *this;
|
||||
@@ -216,6 +222,72 @@ public:
|
||||
m_external_io_service = false;
|
||||
}
|
||||
|
||||
/// Sets the tcp pre init handler
|
||||
/**
|
||||
* The tcp pre init handler is called after the raw tcp connection has been
|
||||
* established but before any additional wrappers (proxy connects, TLS
|
||||
* handshakes, etc) have been performed.
|
||||
*
|
||||
* @since 0.4.0-alpha1
|
||||
*
|
||||
* @param h The handler to call on tcp pre init.
|
||||
*/
|
||||
void set_tcp_pre_init_handler(tcp_init_handler h) {
|
||||
m_tcp_pre_init_handler = h;
|
||||
}
|
||||
|
||||
/// Sets the tcp pre init handler (deprecated)
|
||||
/**
|
||||
* The tcp pre init handler is called after the raw tcp connection has been
|
||||
* established but before any additional wrappers (proxy connects, TLS
|
||||
* handshakes, etc) have been performed.
|
||||
*
|
||||
* @deprecated Use set_tcp_pre_init_handler instead
|
||||
*
|
||||
* @param h The handler to call on tcp pre init.
|
||||
*/
|
||||
void set_tcp_init_handler(tcp_init_handler h) {
|
||||
set_tcp_pre_init_handler(h);
|
||||
}
|
||||
|
||||
/// Sets the tcp post init handler
|
||||
/**
|
||||
* The tcp post init handler is called after the tcp connection has been
|
||||
* established and all additional wrappers (proxy connects, TLS handshakes,
|
||||
* etc have been performed. This is fired before any bytes are read or any
|
||||
* WebSocket specific handshake logic has been performed.
|
||||
*
|
||||
* @since 0.4.0-alpha1
|
||||
*
|
||||
* @param h The handler to call on tcp post init.
|
||||
*/
|
||||
void set_tcp_post_init_handler(tcp_init_handler h) {
|
||||
m_tcp_post_init_handler = h;
|
||||
}
|
||||
|
||||
/// Sets the maximum length of the queue of pending connections.
|
||||
/**
|
||||
* Sets the maximum length of the queue of pending connections. Increasing
|
||||
* this will allow WebSocket++ to queue additional incoming connections.
|
||||
* Setting it higher may prevent failed connections at high connection rates
|
||||
* but may cause additional latency.
|
||||
*
|
||||
* For this value to take effect you may need to adjust operating system
|
||||
* settings.
|
||||
*
|
||||
* New values affect future calls to listen only.
|
||||
*
|
||||
* A value of zero will use the operating system default. This is the
|
||||
* default value.
|
||||
*
|
||||
* @since 0.4.0-alpha1
|
||||
*
|
||||
* @param backlog The maximum length of the queue of pending connections
|
||||
*/
|
||||
void set_listen_backlog(int backlog) {
|
||||
m_listen_backlog = backlog;
|
||||
}
|
||||
|
||||
/// Retrieve a reference to the endpoint's io_service
|
||||
/**
|
||||
* The io_service may be an internal or external one. This may be used to
|
||||
@@ -231,20 +303,6 @@ public:
|
||||
return *m_io_service;
|
||||
}
|
||||
|
||||
/// Sets the tcp init handler
|
||||
/**
|
||||
* The tcp init handler is called after the tcp connection has been
|
||||
* established.
|
||||
*
|
||||
* @see WebSocket++ handler documentation for more information about
|
||||
* handlers.
|
||||
*
|
||||
* @param h The handler to call on tcp init.
|
||||
*/
|
||||
void set_tcp_init_handler(tcp_init_handler h) {
|
||||
m_tcp_init_handler = h;
|
||||
}
|
||||
|
||||
/// Set up endpoint for listening manually (exception free)
|
||||
/**
|
||||
* Bind the internal acceptor using the specified settings. The endpoint
|
||||
@@ -268,7 +326,11 @@ public:
|
||||
m_acceptor->open(ep.protocol());
|
||||
m_acceptor->set_option(boost::asio::socket_base::reuse_address(true));
|
||||
m_acceptor->bind(ep);
|
||||
m_acceptor->listen();
|
||||
if (m_listen_backlog == 0) {
|
||||
m_acceptor->listen();
|
||||
} else {
|
||||
m_acceptor->listen(m_listen_backlog);
|
||||
}
|
||||
m_state = LISTENING;
|
||||
ec = lib::error_code();
|
||||
}
|
||||
@@ -494,6 +556,34 @@ public:
|
||||
return m_io_service->stopped();
|
||||
}
|
||||
|
||||
/// Marks the endpoint as perpetual, stopping it from exiting when empty
|
||||
/**
|
||||
* Marks the endpoint as perpetual. Perpetual endpoints will not
|
||||
* automatically exit when they run out of connections to process. To stop
|
||||
* a perpetual endpoint call `end_perpetual`.
|
||||
*
|
||||
* An endpoint may be marked perpetual at any time by any thread. It must be
|
||||
* called either before the endpoint has run out of work or before it was
|
||||
* started
|
||||
*
|
||||
* @since 0.4.0-alpha1
|
||||
*/
|
||||
void start_perpetual() {
|
||||
m_work.reset(new boost::asio::io_service::work(*m_io_service));
|
||||
}
|
||||
|
||||
/// Clears the endpoint's perpetual flag, allowing it to exit when empty
|
||||
/**
|
||||
* Clears the endpoint's perpetual flag. This will cause the endpoint's run
|
||||
* method to exit normally when it runs out of connections. If there are
|
||||
* currently active connections it will not end until they are complete.
|
||||
*
|
||||
* @since 0.4.0-alpha1
|
||||
*/
|
||||
void stop_perpetual() {
|
||||
m_work.reset();
|
||||
}
|
||||
|
||||
/// Call back a function after a period of time.
|
||||
/**
|
||||
* Sets a timer that calls back a function after the specified period of
|
||||
@@ -572,15 +662,27 @@ public:
|
||||
|
||||
m_alog->write(log::alevel::devel, "asio::async_accept");
|
||||
|
||||
m_acceptor->async_accept(
|
||||
tcon->get_raw_socket(),
|
||||
tcon->get_strand()->wrap(lib::bind(
|
||||
&type::handle_accept,
|
||||
this,
|
||||
callback,
|
||||
lib::placeholders::_1
|
||||
))
|
||||
);
|
||||
if (config::enable_multithreading) {
|
||||
m_acceptor->async_accept(
|
||||
tcon->get_raw_socket(),
|
||||
tcon->get_strand()->wrap(lib::bind(
|
||||
&type::handle_accept,
|
||||
this,
|
||||
callback,
|
||||
lib::placeholders::_1
|
||||
))
|
||||
);
|
||||
} else {
|
||||
m_acceptor->async_accept(
|
||||
tcon->get_raw_socket(),
|
||||
lib::bind(
|
||||
&type::handle_accept,
|
||||
this,
|
||||
callback,
|
||||
lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Accept the next connection attempt and assign it to con.
|
||||
@@ -683,18 +785,33 @@ protected:
|
||||
)
|
||||
);
|
||||
|
||||
m_resolver->async_resolve(
|
||||
query,
|
||||
tcon->get_strand()->wrap(lib::bind(
|
||||
&type::handle_resolve,
|
||||
this,
|
||||
tcon,
|
||||
dns_timer,
|
||||
cb,
|
||||
lib::placeholders::_1,
|
||||
lib::placeholders::_2
|
||||
))
|
||||
);
|
||||
if (config::enable_multithreading) {
|
||||
m_resolver->async_resolve(
|
||||
query,
|
||||
tcon->get_strand()->wrap(lib::bind(
|
||||
&type::handle_resolve,
|
||||
this,
|
||||
tcon,
|
||||
dns_timer,
|
||||
cb,
|
||||
lib::placeholders::_1,
|
||||
lib::placeholders::_2
|
||||
))
|
||||
);
|
||||
} else {
|
||||
m_resolver->async_resolve(
|
||||
query,
|
||||
lib::bind(
|
||||
&type::handle_resolve,
|
||||
this,
|
||||
tcon,
|
||||
dns_timer,
|
||||
cb,
|
||||
lib::placeholders::_1,
|
||||
lib::placeholders::_2
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void handle_resolve_timeout(timer_ptr dns_timer, connect_handler callback,
|
||||
@@ -767,18 +884,33 @@ protected:
|
||||
)
|
||||
);
|
||||
|
||||
boost::asio::async_connect(
|
||||
tcon->get_raw_socket(),
|
||||
iterator,
|
||||
tcon->get_strand()->wrap(lib::bind(
|
||||
&type::handle_connect,
|
||||
this,
|
||||
tcon,
|
||||
con_timer,
|
||||
callback,
|
||||
lib::placeholders::_1
|
||||
))
|
||||
);
|
||||
if (config::enable_multithreading) {
|
||||
boost::asio::async_connect(
|
||||
tcon->get_raw_socket(),
|
||||
iterator,
|
||||
tcon->get_strand()->wrap(lib::bind(
|
||||
&type::handle_connect,
|
||||
this,
|
||||
tcon,
|
||||
con_timer,
|
||||
callback,
|
||||
lib::placeholders::_1
|
||||
))
|
||||
);
|
||||
} else {
|
||||
boost::asio::async_connect(
|
||||
tcon->get_raw_socket(),
|
||||
iterator,
|
||||
lib::bind(
|
||||
&type::handle_connect,
|
||||
this,
|
||||
tcon,
|
||||
con_timer,
|
||||
callback,
|
||||
lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void handle_connect_timeout(transport_con_ptr tcon, timer_ptr con_timer,
|
||||
@@ -857,7 +989,8 @@ protected:
|
||||
ec = tcon->init_asio(m_io_service);
|
||||
if (ec) {return ec;}
|
||||
|
||||
tcon->set_tcp_init_handler(m_tcp_init_handler);
|
||||
tcon->set_tcp_pre_init_handler(m_tcp_pre_init_handler);
|
||||
tcon->set_tcp_post_init_handler(m_tcp_post_init_handler);
|
||||
|
||||
return lib::error_code();
|
||||
}
|
||||
@@ -877,13 +1010,18 @@ private:
|
||||
};
|
||||
|
||||
// Handlers
|
||||
tcp_init_handler m_tcp_init_handler;
|
||||
tcp_init_handler m_tcp_pre_init_handler;
|
||||
tcp_init_handler m_tcp_post_init_handler;
|
||||
|
||||
// Network Resources
|
||||
io_service_ptr m_io_service;
|
||||
bool m_external_io_service;
|
||||
acceptor_ptr m_acceptor;
|
||||
resolver_ptr m_resolver;
|
||||
work_ptr m_work;
|
||||
|
||||
// Network constants
|
||||
int m_listen_backlog;
|
||||
|
||||
elog_type* m_elog;
|
||||
alog_type* m_alog;
|
||||
|
||||
@@ -228,15 +228,25 @@ protected:
|
||||
m_ec = socket::make_error_code(socket::error::tls_handshake_timeout);
|
||||
|
||||
// TLS handshake
|
||||
m_socket->async_handshake(
|
||||
get_handshake_type(),
|
||||
m_strand->wrap(lib::bind(
|
||||
&type::handle_init,
|
||||
get_shared(),
|
||||
callback,
|
||||
lib::placeholders::_1
|
||||
))
|
||||
);
|
||||
if (m_strand) {
|
||||
m_socket->async_handshake(
|
||||
get_handshake_type(),
|
||||
m_strand->wrap(lib::bind(
|
||||
&type::handle_init, get_shared(),
|
||||
callback,
|
||||
lib::placeholders::_1
|
||||
))
|
||||
);
|
||||
} else {
|
||||
m_socket->async_handshake(
|
||||
get_handshake_type(),
|
||||
lib::bind(
|
||||
&type::handle_init, get_shared(),
|
||||
callback,
|
||||
lib::placeholders::_1
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the connection handle
|
||||
|
||||
@@ -169,7 +169,10 @@ enum value {
|
||||
tls_short_read,
|
||||
|
||||
/// Timer expired
|
||||
timeout
|
||||
timeout,
|
||||
|
||||
/// read or write after shutdown
|
||||
action_after_shutdown
|
||||
};
|
||||
|
||||
class category : public lib::error_category {
|
||||
@@ -198,6 +201,8 @@ class category : public lib::error_category {
|
||||
return "TLS Short Read";
|
||||
case timeout:
|
||||
return "Timer Expired";
|
||||
case action_after_shutdown:
|
||||
return "A transport action was requested after shutdown";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
+16
-1
@@ -282,7 +282,22 @@ public:
|
||||
return s.str();
|
||||
}
|
||||
|
||||
// get query?
|
||||
/// Return the query portion
|
||||
/**
|
||||
* Returns the query portion (after the ?) of the URI or an empty string if
|
||||
* there is none.
|
||||
*
|
||||
* @return query portion of the URI.
|
||||
*/
|
||||
std::string get_query() const {
|
||||
std::size_t found = m_resource.find('?');
|
||||
if (found != std::string::npos) {
|
||||
return m_resource.substr(found + 1);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
// get fragment
|
||||
|
||||
// hi <3
|
||||
|
||||
Reference in New Issue
Block a user