Compare commits

..

37 Commits

Author SHA1 Message Date
Peter Thorson c5510d6de0 Merge branch 'develop'
Conflicts:
	CMakeLists.txt
	Doxyfile
	changelog.md
	readme.md
	websocketpp/version.hpp
2015-06-02 08:55:24 -04:00
Peter Thorson f931734369 prep for release 2015-06-02 07:19:59 -04:00
Peter Thorson af792aeaba Update changelog 2015-06-02 07:02:48 -04:00
Peter Thorson 2af2135d82 Merge pull request #432 from rec/develop
Fix dangling pointer and message in error.hpp.
2015-06-02 06:59:04 -04:00
Tom Ritchford f2b38d5634 Fix dangling pointer and message in error.hpp. 2015-05-27 19:18:24 -04:00
Peter Thorson 1b9e40040c update readme 2015-05-10 21:36:19 -04:00
Peter Thorson 8893faff53 Removes an unnecessary mutex lock in get_con_from_hdl 2015-05-10 21:36:19 -04:00
Peter Thorson 430fb82e76 Fix typo in cmake files 2015-05-10 21:36:19 -04:00
Peter Thorson 01d4109ae8 Merge pull request #428 from timrau/develop
Fix grammar
2015-05-07 09:02:24 -04:00
timrau 4cc678ee93 Fix grammar 2015-05-07 21:00:09 +08:00
Peter Thorson acb53a379c Refactor deferred http handler support to better match the library conventions 2015-04-29 20:00:20 -04:00
Peter Thorson c18f210ea3 Allow deferring the sending of an HTTP response. references #425
This allows processing of long running http handlers to defer their
response until it is ready without blocking the network thread.
2015-04-29 19:28:36 -04:00
Peter Thorson f469b90bfc update changelog credit 2015-04-29 19:24:04 -04:00
Peter Thorson 9d95501536 changelog update 2015-04-25 13:32:33 -04:00
Peter Thorson 9351e73e90 initial sketch of TLS tutorial 2015-04-25 12:41:14 -04:00
Peter Thorson b817c4499e Updates echo_server_tls reference TLS settings 2015-04-25 12:28:28 -04:00
Peter Thorson 7829de34a3 Update changelog 2015-04-25 12:26:16 -04:00
Peter Thorson 6973f02d1c make sure boost version is loaded before using it 2015-04-25 12:25:17 -04:00
Peter Thorson 31b75714bd Update common/chrono.hpp to latest spec 2015-04-25 12:24:53 -04:00
Peter Thorson 257b5ac8e5 add boost chrono to travis dependencies 2015-04-25 07:33:26 -04:00
Peter Thorson 769fe89533 Major refactor to support standalone Asio and remove Boost dependencies
It is now possible to use WebSocket++’s asio transport using only
standalone asio by defining ASIO_STANDALONE before including any
WebSocket++ headers.
2015-04-25 07:17:28 -04:00
Peter Thorson d670d69c6e Refactor boost dependencies
Introduces a common type_traits header that supplies aligned_storage
using either boost or C++11.

removes unused boost header boost/array.hpp

removes usage of boost::noncopyable in favor of C++11 deleted copy
constructor/operators
2015-04-24 09:40:59 -04:00
Peter Thorson 2c843b9343 echo_server now checks for a special command to stop listening for new connections 2015-04-14 08:14:47 -04:00
Peter Thorson d076e38e00 properly set opcode on outgoing close frames 2015-04-14 07:58:34 -04:00
Peter Thorson 4331de8a29 Add missing header references #418 2015-04-14 06:56:30 -04:00
Peter Thorson 6dde40d96e Merge pull request #413 from rec/public-accessor
Make transport::asio::connection::get_strand() public.
2015-04-14 06:50:09 -04:00
Tom Ritchford dc313effa5 Make transport::asio::connection::get_strand() public. 2015-03-27 00:06:01 -04:00
Peter Thorson 6300e090ad disable emplace test
emplace requires move assignability which the class in question doesn’t
support.
2015-03-05 07:55:03 -06:00
Peter Thorson 45dfcbec3c changelog update 2015-03-04 18:43:49 -06:00
Peter Thorson 39dbe3a4e0 adds a vectored write handler for iostream transport 2015-03-04 18:42:55 -06:00
Peter Thorson 13f6da6f81 fix typo in changelog entry about typos 2015-02-27 09:54:21 -05:00
Peter Thorson bcd82bd6f4 asio transport clients will now connect properly to servers using TLS SNI 2015-02-23 09:10:23 -05:00
Peter Thorson 8f042d95ec don't test for std::move on non-c++11 systems 2015-02-06 08:07:42 -05:00
Peter Thorson 0278ba7895 temporary disable of a unit test 2015-02-06 08:00:36 -05:00
Peter Thorson 41c37cfd93 make sure key is always initialized
some compilers complain without this. Its probably a safer sane default
anyways.
2015-02-06 07:58:00 -05:00
Peter Thorson 4bea90f555 preliminary support for move semantics for endpoints 2015-02-06 07:51:24 -05:00
Peter Thorson ce0300e6dc prepare develop branch for next version 2015-01-22 10:00:51 -05:00
46 changed files with 1355 additions and 392 deletions
+1 -1
View File
@@ -2,7 +2,7 @@ language: cpp
compiler:
- gcc
before_install:
- sudo apt-get install libboost-regex1.48-dev libboost-system1.48-dev libboost-thread1.48-dev libboost-test1.48-dev libboost-random1.48-dev -y
- sudo apt-get install libboost-chrono1.48-dev libboost-regex1.48-dev libboost-system1.48-dev libboost-thread1.48-dev libboost-test1.48-dev libboost-random1.48-dev -y
env:
global:
- BOOST_INCLUDES=/usr/include
+5 -5
View File
@@ -9,8 +9,8 @@ project (websocketpp)
cmake_minimum_required (VERSION 2.6)
set (WEBSOCKETPP_MAJOR_VERSION 0)
set (WEBSOCKETPP_MINOR_VERSION 5)
set (WEBSOCKETPP_PATCH_VERSION 1)
set (WEBSOCKETPP_MINOR_VERSION 6)
set (WEBSOCKETPP_PATCH_VERSION 0)
set (WEBSOCKETPP_VERSION ${WEBSOCKETPP_MAJOR_VERSION}.${WEBSOCKETPP_MINOR_VERSION}.${WEBSOCKETPP_PATCH_VERSION})
set(INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for header files")
@@ -70,7 +70,7 @@ if (BUILD_TESTS OR BUILD_EXAMPLES)
############ Compiler specific setup
set (WEBSOCKETPP_PLATFORM_LIBS "")
set (WEBSOCKETPP_PLATFORM_TSL_LIBS "")
set (WEBSOCKETPP_PLATFORM_TLS_LIBS "")
set (WEBSOCKETPP_BOOST_LIBS "")
# VC9 and C++11 reasoning
@@ -111,7 +111,7 @@ if (BUILD_TESTS OR BUILD_EXAMPLES)
# g++
if (CMAKE_COMPILER_IS_GNUCXX)
set (WEBSOCKETPP_PLATFORM_LIBS pthread rt)
set (WEBSOCKETPP_PLATFORM_TSL_LIBS ssl crypto)
set (WEBSOCKETPP_PLATFORM_TLS_LIBS ssl crypto)
set (WEBSOCKETPP_BOOST_LIBS system thread)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
if (NOT APPLE)
@@ -133,7 +133,7 @@ if (BUILD_TESTS OR BUILD_EXAMPLES)
else()
set (WEBSOCKETPP_PLATFORM_LIBS pthread)
endif()
set (WEBSOCKETPP_PLATFORM_TSL_LIBS ssl crypto)
set (WEBSOCKETPP_PLATFORM_TLS_LIBS ssl crypto)
set (WEBSOCKETPP_BOOST_LIBS system thread)
set (CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-std=c++0x -stdlib=libc++") # todo: is libc++ really needed here?
if (NOT APPLE)
+1 -3
View File
@@ -32,9 +32,7 @@ PROJECT_NAME = "websocketpp"
# This could be handy for archiving the generated documentation or
# if some version control system is used.
PROJECT_NUMBER = "0.5.1"
PROJECT_NUMBER = "0.6.0"
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer
+46 -1
View File
@@ -1,10 +1,55 @@
HEAD
0.6.0
- MINOR BREAKING TRANSPORT POLICY CHANGE: Custom transport policies will now be
required to include a new method `void set_uri(uri_ptr u)`. An implementation
is not required. The stub transport policy includes an example stub method
that can be added to any existing custom transport policy to fulfill this
requirement. This does not affect anyone using the bundled transports or
configs.
- MINOR BREAKING SOCKET POLICY CHANGE: Custom asio transport socket policies
will now be required to include a new method `void set_uri(uri_ptr u)`. Like
with the transport layer, an implementation is not required. This does not
affect anyone using the bundled socket policies.
- MINOR BREAKING DEPENDENCY CHANGE: When using Boost versions greater than or
equal to 1.49 in C++03 mode, `libboost-chrono` is needed now instead of
`libboost-date_time`. Users with C++11 compilers or using Boost versions 1.48
and earlier are not affected. Note: This change affects the bundled unit test
suite.
- Feature: WebSocket++ Asio transport policy can now be used with the standalone
version of Asio (1.8.0+) when a C++11 compiler and standard library are
present. This means that it is possible now to use WebSocket++'s Asio
transport entirely without Boost. Thank you Robert Seiler for proof of concept
code that was used as a guide for this implementation. Fixes #324
- Feature: Adds a vectored/scatter-gather write handler to the iostream
transport.
- Feature: Adds the ability to defer sending an HTTP response until sometime
after the `http_handler` is run. This allows processing of long running http
handlers to defer their response until it is ready without blocking the
network thread. references #425
- Improvement: `echo_server_tls` has been update to demonstrate how to configure
it for Mozilla's recommended intermediate and modern TLS security profiles.
- Improvement: `endpoint::set_timer` now uses a steady clock provided by
`boost::chrono` or `std::chrono` where available instead of the non-monotonic
system clock. Thank you breyed for reporting. fixes #241
- Improvement: Outgoing TLS connections to servers using the SNI extension to
choose a certificate will now work. Thank you moozzyk for reporting.
Fixes #400
- Improvement: Removes an unnecessary mutex lock in `get_con_from_hdl`.
- Cleanup: Asio transport policy has been refactored to remove many Boost
dependencies. On C++03 compilers the `boost::noncopyable` dependency has been
removed and the `boost::date_time` dependency has been replaced with the newer
`boost::chrono` when possible. On C++11 compilers the `boost::aligned_storage`
and `boost::date_time` dependencies are gone, replaced with equivalent C++11
standard library features.
- Bug: Fixes a potential dangling pointer and inconsistent error message
handling in `websocketpp::exception`. #432 Thank you Tom Swirly for the fix.
0.5.1 - 2015-02-27
- Bug: Fixes an issue where some frame data was counted against the max header
size limit, resulting in connections that included a lot of frame data
immediately after the opening handshake to fail.
- Bug: Fix a type in the name of the set method for `max_http_body_size`. #406
- Bug: Fix a typo in the name of the set method for `max_http_body_size`. #406
Thank you jplatte for reporting.
0.5.0 - 2015-01-22
+7
View File
@@ -19,6 +19,13 @@ void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {
<< " and message: " << msg->get_payload()
<< std::endl;
// check for a special command to instruct the server to stop listening so
// it can be cleanly exited.
if (msg->get_payload() == "stop-listening") {
s->stop_listening();
return;
}
try {
s->send(hdl, msg->get_payload(), msg->get_opcode());
} catch (const websocketpp::lib::error_code& e) {
+8
View File
@@ -0,0 +1,8 @@
-----BEGIN DH PARAMETERS-----
MIIBCAKCAQEAqxMGKZB8YNV8WQnbJWwwwmifc+PfVRtd1FN5v5aQSsf6dpjX3Zlh
N1NmgecsQyg4u2EWe4Umta10QzCgYaxf6QdTCg7iprLzFNw7IvWYbQ6du12NMGDr
hmwA6KQKwbTgPL6mSlSlcK2wTP2FzxDTNffFu10cB/6Fj4kdQjPG0c1Koz/z7OOq
BuDElJLClS8rjp3z1xvrc7gX95dFa2KaKgOAYDkpe8tfHRhHfJeIVS/whH9hzx6r
OBg+E5K9JyvayrUoKgPeptRKCqo8A4YevtMLpRxMup0nMUgAIv6+BGTwPAFpwgl/
8UIVcvjh1v95PwGDM/Q8yvIBJznBYk/e2wIBAg==
-----END DH PARAMETERS-----
+51 -9
View File
@@ -27,24 +27,66 @@ void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {
}
}
void on_http(server* s, websocketpp::connection_hdl hdl) {
server::connection_ptr con = s->get_con_from_hdl(hdl);
con->set_body("Hello World!");
con->set_status(websocketpp::http::status_code::ok);
}
std::string get_password() {
return "test";
}
context_ptr on_tls_init(websocketpp::connection_hdl hdl) {
// See https://wiki.mozilla.org/Security/Server_Side_TLS for more details about
// the TLS modes. The code below demonstrates how to implement both the modern
enum tls_mode {
MOZILLA_INTERMEDIATE = 1,
MOZILLA_MODERN = 2
};
context_ptr on_tls_init(tls_mode mode, websocketpp::connection_hdl hdl) {
std::cout << "on_tls_init called with hdl: " << hdl.lock().get() << std::endl;
context_ptr ctx = websocketpp::lib::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::tlsv1);
std::cout << "using TLS mode: " << (mode == MOZILLA_MODERN ? "Mozilla Modern" : "Mozilla Intermediate") << std::endl;
context_ptr ctx = websocketpp::lib::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::sslv23);
try {
ctx->set_options(boost::asio::ssl::context::default_workarounds |
boost::asio::ssl::context::no_sslv2 |
boost::asio::ssl::context::no_sslv3 |
boost::asio::ssl::context::single_dh_use);
if (mode == MOZILLA_MODERN) {
// Modern disables TLSv1
ctx->set_options(boost::asio::ssl::context::default_workarounds |
boost::asio::ssl::context::no_sslv2 |
boost::asio::ssl::context::no_sslv3 |
boost::asio::ssl::context::no_tlsv1 |
boost::asio::ssl::context::single_dh_use);
} else {
ctx->set_options(boost::asio::ssl::context::default_workarounds |
boost::asio::ssl::context::no_sslv2 |
boost::asio::ssl::context::no_sslv3 |
boost::asio::ssl::context::single_dh_use);
}
ctx->set_password_callback(bind(&get_password));
ctx->use_certificate_chain_file("server.pem");
ctx->use_private_key_file("server.pem", boost::asio::ssl::context::pem);
// Example method of generating this file:
// `openssl dhparam -out dh.pem 2048`
// Mozilla Intermediate suggests 1024 as the minimum size to use
// Mozilla Modern suggests 2048 as the minimum size to use.
ctx->use_tmp_dh_file("dh.pem");
std::string ciphers;
if (mode == MOZILLA_MODERN) {
ciphers = "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK";
} else {
ciphers = "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA";
}
if (SSL_CTX_set_cipher_list(ctx->native_handle() , ciphers.c_str()) != 1) {
std::cout << "Error setting cipher list" << std::endl;
}
} catch (std::exception& e) {
std::cout << e.what() << std::endl;
std::cout << "Exception: " << e.what() << std::endl;
}
return ctx;
}
@@ -58,8 +100,8 @@ int main() {
// Register our message handler
echo_server.set_message_handler(bind(&on_message,&echo_server,::_1,::_2));
echo_server.set_tls_init_handler(bind(&on_tls_init,::_1));
echo_server.set_http_handler(bind(&on_http,&echo_server,::_1));
echo_server.set_tls_init_handler(bind(&on_tls_init,MOZILLA_INTERMEDIATE,::_1));
// Listen on port 9002
echo_server.listen(9002);
+51 -54
View File
@@ -1,58 +1,55 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,A0ED66EF872A48A9
gXuvKojXzApVhhPVNdRliiajbC4PtwQG5c8TA7JADLgwOR7o9t6KtXEr37bDRpvB
9aO9P+SJaK5OOp3XKPGthOdqv+tvCRTlmzmC8GjPLBX389DWT2xoGu7JkGwDtdSm
rnF49Rlp5bfjpACk5xKNiKeDo1CWfeEJzw9Kto0g+5eMaEdors64oPzjXs3geA2g
TxCJSHv9qSX6++pCLKKCUTbyzidAxV/Zb0AAubt5V40QKqX4HhSwwstFnTaX3tlb
3QOdY+y04VIkM6d7qN5W8M7NzRkMpZ1qBpQcUMpkhQcRzWP2wub5AAff9D2GntRd
4Dz1vn3u41U3Okdr0CNj+iH7byCzuokoAhk6ZQEN6WB+GTpGgfBXdtUZrfpb0MKm
UNYP5AF2AmUqJRXhViTDVtu/V2tHF3LGuNT+W2Dz+spFZEq0byEO0N858eR0dikc
6jOASvNQbSwD0+mkgBC1gXKKU3ngj2gpJUwljeACdWFd8N2egrZfyI05CmX7vPNC
NXbs7k2buWNdjP4/D8IM+HDVidWzQa/kG/qokXKqllem9Egg37lUucwnP3cX2/Hw
U2mfaBWzeZtqc+GqRp08rYIql+Reai3sUYlQMnNk01prVY47UQb+dxuqjaxGV5Xx
Xkx0s2mfQnNRjL4S7Hjhqelufi6GpkCQ2EGsPpA+6K1ztZ0ame9Q2BE1SXeM/6vU
rxT5nRrCxueyXAyQSGcqMX9//gSeK8WWBqG/c1IAMVDa0NWrJeOJhSziE+ta3B0m
bHAPBY6vh0iB3lLdRlbUOPbC6R1TpxMOs+6Vbs2+OTifFpvOVymEoZq/nroyg68P
vn5uCKogwWA7o8EArf/UTlIwWJmH9bgILdZKld4wMel2HQg16RDzm+mEXAJi52a/
FC+fgfphdxltmUJ+rqOyR4AHULjaTWUQqTIB6sdlzgmES1nXAiE71zX//KFqomar
O60SPPk3C1bs0x5DsvmGJa8SIfDhyd+D7NPyqwEKqrZsaotYGklNkfqxa6pa8mrc
ejxquW1PK4FvBk26+osu5a90Jih0PcQM7DUMMr2WHdTiMSXWAiK2ToYF8Itt25Qv
Cd0CsSYw9CJkXNr1u1+mObheaY9QYOmztnSJLy4ZO2JsMhqNwuAueIcwmhXOREq7
kzlnGMgJcuSeAS/OBNj8Zgx0c7QQ0kzc+YmnOCsqoMtPsu/CsXJ4iJiM3Tki/2jT
bywrTiQwE6R3a/87GREOREX+WLicZBWX3k9/4tBL5XSe1p5wPpuIRQUDvAGNfNHP
JN7kujDF4SehilF1qtvCygAwvxHFDj+EwhXKNDKJzoZZIM15rAk3k92n2j6nz1qH
a3xOU05yydOlO6F6w51I1QoDddmkzCRNB0TeO3D6rekHsCK1aDWmC+qRcm2ZFtVz
sY6fdZN2NEmMQokIh9Opi1f8CSYSizPESMzdu2SF0xVO9n/IGIkn1ksK04O2BZo0
X3LBPHLfCRsQNY1eF17bj07fYU2oPZKs/XzJiwxkqK6LFvpeAVaYrtg9fqRO/UVe
QhUIj3BL550ocEpa15xLehLrmwzYiW5zwGjSHQ4EgZluGLCwyKGTh4QswEJRA9Rt
MIIEowIBAAKCAQEA77v5VbFaq+geVd/RCLXoKTWj/LgXGjiOXBpJZca3o5edi7N1
Ej41/13jfZ4OxgFIRFAALd+fU4NsObXzskth3rJLmJjUtGajRIPqF2IUVjFMmybQ
9dUDSqPzd/bG+ul0DP7DNuiBcLC8XNC3/kchPUzVq9gNDk56jXn87kMoIkVXBWQS
Rwk0yCtELSfwxxRCrGKgQDfXnRdwmkPe42DmKtdGksXJlUhP1UVTAXaSw1Nz64LV
9bJje/eoDsSe4OxifVVToE6ZxIW+r1jVgrcupeYXQrSHIztl2U/rx2JkGMN0eS+P
qrsJmkmRBN1cpgmvSV7WoM3hj6Eq71z4Dfv6EwIDAQABAoIBAEXAL19bZsI1mv3p
TOx34MB8tuXEuhQK+ICbtVdDZhLW/iOzZxCTwSo3qwTVg/7gSKJ3lFXEhprJ1idE
ZU8u157vyUbw0JJceoxoxSdghgI9/cf2lz2vaHHDGgeBaYt/eSB+z1WeeGrNQUDQ
CXiWQXmQbWq+Ra4v70BSieDY8UhmzCTRhvfZV80vaY/4SnHxJ9C8Nu8/An7U3pwq
ccfTaWMp3Q5ztmEnExF6/b1SUsnI8rzFovw/4C50AU09N/Z6zZVFsXgJAT2Kd1Tx
HfP1vUkWZ/TJ6kcmVIV9U3uMcedBD8Rb/3M0Qdp+eymQ+1oYQ3K3/a2RlUQIeXzf
hRbE4wECgYEA/WyULrwBsvSMPqK0K9pZpv921Yl6d4bGnpxKze7ltc9o5/LsU35q
8u29Es7cPyhyUDOsPW8v2CNjw54t+eFGsu59bBvXZNz5gB7hTUEyLntB24cO5PmN
kVExcMDFC6NgPaauBtUhODievKJ2C8P7sRJDAVKE9KkavDddU7nSEjMCgYEA8ivG
AqwNXYsiIFjAo4uj3kuBFt8LU/q4m6GXI+9qyxfiJjuF1dROx5qaQGiE85VaBFUu
gpbnjZH7s+BBgoaQhrB4i6mztljdN1KKuAlnjhB+Fywg8m8N9lAi3wIaxnIEqDkU
vFiIFPTBCk0U7IZ/OyCrKPQTE9ApWHfBwA/vWKECgYBQixrJg61SkBCms5Vpvprx
zY2aLniC1o33yRqpOr09PG9OENH1c19QWCjYenBbjmJOhS2/1L+zBQRnHrXkDion
Ik8wdeTORMDzbF0U7ZyiU0BKIjGkqn/I6LI68LlvinxC+9+hgkltkek5cLTt5lrv
Gyu6ltx02e4KVdpOiuduKwKBgQC3U0PWigCkK8ttyUIrjG5Evcu/UKH2tPpDdpQ/
8+JYVIAyiSTLtqjcmcDjuTvMWeeHGCTZXvtzRGvSw5VUBiIqlDTtJU6SX7s3QhkZ
MKVf+kQ5roJShJeBOzDquWEjkPTNlEiKPErn8lCgR7HrS/XNAPIRUpOOkCp8ekwF
5Qo/gQKBgAue3TeCeIzxh4PxSAk39Uaj+AaLvlYg8C+ucEodCNQZnJ7jOO0hHkfT
NvZBes0VukCGlBLOGRQtC3kgtyrerscnDiZOhdnJrhPIdNPC0k/p/uAfh7+C5Sxm
rCEL0S7kORdEjlIGd5j6ZEN/HZe8FyOYSjbFAoJSlAId9WMSxycQ
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIE0DCCA7igAwIBAgIJAM5MuKJezXq0MA0GCSqGSIb3DQEBBQUAMIGgMQswCQYD
VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xGDAW
BgNVBAoTD1phcGhveWQgU3R1ZGlvczEUMBIGA1UECxMLV2ViU29ja2V0KysxFjAU
BgNVBAMTDVBldGVyIFRob3Jzb24xJDAiBgkqhkiG9w0BCQEWFXdlYm1hc3RlckB6
YXBob3lkLmNvbTAeFw0xMTExMTUyMTIwMDZaFw0xMjExMTQyMTIwMDZaMIGgMQsw
CQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28x
GDAWBgNVBAoTD1phcGhveWQgU3R1ZGlvczEUMBIGA1UECxMLV2ViU29ja2V0Kysx
FjAUBgNVBAMTDVBldGVyIFRob3Jzb24xJDAiBgkqhkiG9w0BCQEWFXdlYm1hc3Rl
ckB6YXBob3lkLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANR0
tdwAnIB8I9qRZ7QbzEWY95RpM7GIn0u/9oH90PzdHiE0rXSkKT+yw3XUzH0iw5t0
5dEwSC+srSP5Vm4cA6kXc94agVVaPW89tGcdP4fHptCruSrzQsDXELCPl5UUvMpA
YUcGisdXYPN/EeOoqb9wKWxoW5mREsyyeWWS89fYN5qU/d0QpbSvEWghqLbL/ZS2
hOlXT9LufOeA+vHiV1/T/h5xC7ecIH02YDQw1EnqxbPmkLPcWThztLS9FiufNDRM
Rhcoaj2b9VDHvDwdbeA0T5v5qNdG34LaapYOelxzQMOtM0f9Dgqehodyxl2qm9mR
lq432dlOEzDnVCPNHwECAwEAAaOCAQkwggEFMB0GA1UdDgQWBBTTPKfNMnKOykhv
+vKS7vql5JsMyzCB1QYDVR0jBIHNMIHKgBTTPKfNMnKOykhv+vKS7vql5JsMy6GB
pqSBozCBoDELMAkGA1UEBhMCVVMxETAPBgNVBAgTCElsbGlub2lzMRAwDgYDVQQH
EwdDaGljYWdvMRgwFgYDVQQKEw9aYXBob3lkIFN0dWRpb3MxFDASBgNVBAsTC1dl
YlNvY2tldCsrMRYwFAYDVQQDEw1QZXRlciBUaG9yc29uMSQwIgYJKoZIhvcNAQkB
FhV3ZWJtYXN0ZXJAemFwaG95ZC5jb22CCQDOTLiiXs16tDAMBgNVHRMEBTADAQH/
MA0GCSqGSIb3DQEBBQUAA4IBAQB+SH0s/hrv5VYqgX6SNLzxdSLvCVsUkCdTpxwY
wOJ84XmYcXDMhKDtZqLtOtN6pfEwVusFlC9mkieuunztCnWNmsSG83RuljJPjFSi
1d4Id4bKEQkQ4cfnjoHKivRrViWLnxuNnLzC6tpyGH/35kKWhhr6T58AXerFgVw3
mHvLPTr1DuhdAZA0ZuvuseVAFFAjI3RetSySwHJE3ak8KswDVfLi6E3XxMVsIWTS
/iFsC2WwoZQlljya2V/kRYIhu+uCdqJ01wunn2BvmURPSgr4GTBF0FQ9JGpNbXxM
TAU7oQJgyFc5sCcuEgPTO0dWVQTvdZVgay4tkmduKDRkmJBF
MIIEpzCCA4+gAwIBAgIJAMlCHvwnJ+F/MA0GCSqGSIb3DQEBCwUAMIGTMQswCQYD
VQQGEwJVUzELMAkGA1UECBMCSUwxEDAOBgNVBAcTB0NoaWNhZ28xGTAXBgNVBAoT
EFdlYlNvY2tldCsrIERlbW8xIjAgBgNVBAMTGXV0aWxpdGllcy53ZWJzb2NrZXRw
cC5vcmcxJjAkBgkqhkiG9w0BCQEWF3dlYnNvY2tldHBwQHphcGhveWQuY29tMB4X
DTE1MDQyNTE1NTk1M1oXDTE4MDMyODE1NTk1M1owgZMxCzAJBgNVBAYTAlVTMQsw
CQYDVQQIEwJJTDEQMA4GA1UEBxMHQ2hpY2FnbzEZMBcGA1UEChMQV2ViU29ja2V0
KysgRGVtbzEiMCAGA1UEAxMZdXRpbGl0aWVzLndlYnNvY2tldHBwLm9yZzEmMCQG
CSqGSIb3DQEJARYXd2Vic29ja2V0cHBAemFwaG95ZC5jb20wggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQDvu/lVsVqr6B5V39EItegpNaP8uBcaOI5cGkll
xrejl52Ls3USPjX/XeN9ng7GAUhEUAAt359Tg2w5tfOyS2HeskuYmNS0ZqNEg+oX
YhRWMUybJtD11QNKo/N39sb66XQM/sM26IFwsLxc0Lf+RyE9TNWr2A0OTnqNefzu
QygiRVcFZBJHCTTIK0QtJ/DHFEKsYqBAN9edF3CaQ97jYOYq10aSxcmVSE/VRVMB
dpLDU3PrgtX1smN796gOxJ7g7GJ9VVOgTpnEhb6vWNWCty6l5hdCtIcjO2XZT+vH
YmQYw3R5L4+quwmaSZEE3VymCa9JXtagzeGPoSrvXPgN+/oTAgMBAAGjgfswgfgw
HQYDVR0OBBYEFAWNBET93ZzSukXGkuGb93CfmUkDMIHIBgNVHSMEgcAwgb2AFAWN
BET93ZzSukXGkuGb93CfmUkDoYGZpIGWMIGTMQswCQYDVQQGEwJVUzELMAkGA1UE
CBMCSUwxEDAOBgNVBAcTB0NoaWNhZ28xGTAXBgNVBAoTEFdlYlNvY2tldCsrIERl
bW8xIjAgBgNVBAMTGXV0aWxpdGllcy53ZWJzb2NrZXRwcC5vcmcxJjAkBgkqhkiG
9w0BCQEWF3dlYnNvY2tldHBwQHphcGhveWQuY29tggkAyUIe/Ccn4X8wDAYDVR0T
BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEA2DRQSDmo2Q5t8MEjp6jddRIFts5t
BDBWPSwJ0qvmheFt53MuLds2hhvMn42WGrKtVJiLiDyOWuUZ41REJZb1uaissUuY
r9pLuP5QLdibx7+/30iDEY0OGTgtSTfgwNx8bIApBSHoZEN3/HaikqplBng2+6u/
kTe6UnRrBJ+8JOGl+duhCXNPeSyLa2NcrxE9XpWC/k1kC9MTUF+2NuqCtK3zO8ci
p0mqARWDSrEBYISh3dAOgDFrcX6zj+0MK+iswu3ijEdItGAjxjlQ2t4XT1T/CDbc
ysHg04TJw7v682+v124GrnrAPYUK34OK8kFVJ60SNYRUi7euOCdTM4Lwkw==
-----END CERTIFICATE-----
@@ -30,9 +30,9 @@ public:
// Bind the handlers we are using
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::bind;
m_client.set_open_handler(bind(&telemetry_client::on_open,this,::_1));
m_client.set_close_handler(bind(&telemetry_client::on_close,this,::_1));
m_client.set_fail_handler(bind(&telemetry_client::on_fail,this,::_1));
m_client.set_open_handler(bind(&telemetry_client::on_open,this,_1));
m_client.set_close_handler(bind(&telemetry_client::on_close,this,_1));
m_client.set_fail_handler(bind(&telemetry_client::on_fail,this,_1));
}
// This method will block until the connection is complete
@@ -46,9 +46,9 @@ public:
// Bind the handlers we are using
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::bind;
m_endpoint.set_open_handler(bind(&telemetry_server::on_open,this,::_1));
m_endpoint.set_close_handler(bind(&telemetry_server::on_close,this,::_1));
m_endpoint.set_http_handler(bind(&telemetry_server::on_http,this,::_1));
m_endpoint.set_open_handler(bind(&telemetry_server::on_open,this,_1));
m_endpoint.set_close_handler(bind(&telemetry_server::on_close,this,_1));
m_endpoint.set_http_handler(bind(&telemetry_server::on_http,this,_1));
}
void run(std::string docroot, uint16_t port) {
+7 -3
View File
@@ -1,10 +1,12 @@
WebSocket++ (0.5.1)
WebSocket++ (0.6.0)
==========================
WebSocket++ is a header only C++ library that implements RFC6455 The WebSocket
Protocol. It allows integrating WebSocket client and server functionality into
C++ programs. It uses interchangeable network transport modules including one
based on C++ iostreams and one based on Boost Asio.
based on raw char buffers, one based on C++ iostreams, and one based on Asio
(either via Boost or standalone). End users can write additional transport
policies to support other networking or event libraries as needed.
Major Features
==============
@@ -13,7 +15,7 @@ Major Features
* Message/event based interface
* Supports secure WebSockets (TLS), IPv6, and explicit proxies.
* Flexible dependency management (C++11 Standard Library or Boost)
* Interchangeable network transport modules (iostream and Boost Asio)
* Interchangeable network transport modules (raw, iostream, Asio, or custom)
* Portable/cross platform (Posix/Windows, 32/64bit, Intel/ARM/PPC)
* Thread-safe
@@ -31,6 +33,8 @@ http://www.zaphoyd.com/websocketpp/manual/
**GitHub Repository**
https://github.com/zaphoyd/websocketpp/
GitHub pull requests should be submitted to the `develop` branch.
**Announcements Mailing List**
http://groups.google.com/group/websocketpp-announcements/
+47
View File
@@ -167,6 +167,15 @@ void http_func(server* s, websocketpp::connection_hdl hdl) {
con->set_status(websocketpp::http::status_code::ok);
}
void defer_http_func(server* s, bool * deferred, websocketpp::connection_hdl hdl) {
*deferred = true;
server::connection_ptr con = s->get_con_from_hdl(hdl);
websocketpp::lib::error_code ec = con->defer_http_response();
BOOST_CHECK_EQUAL(ec, websocketpp::lib::error_code());
}
void check_on_fail(server* s, websocketpp::lib::error_code ec, bool & called,
websocketpp::connection_hdl hdl)
{
@@ -223,6 +232,44 @@ BOOST_AUTO_TEST_CASE( http_request ) {
BOOST_CHECK_EQUAL(run_server_test(s,input), output);
}
BOOST_AUTO_TEST_CASE( deferred_http_request ) {
std::string input = "GET /foo/bar HTTP/1.1\r\nHost: www.example.com\r\nOrigin: http://www.example.com\r\n\r\n";
std::string output = "HTTP/1.1 200 OK\r\nContent-Length: 8\r\nServer: ";
output+=websocketpp::user_agent;
output+="\r\n\r\n/foo/bar";
server s;
server::connection_ptr con;
bool deferred = false;
s.set_http_handler(bind(&defer_http_func,&s, &deferred,::_1));
s.clear_access_channels(websocketpp::log::alevel::all);
s.clear_error_channels(websocketpp::log::elevel::all);
std::stringstream ostream;
s.register_ostream(&ostream);
con = s.get_connection();
con->start();
BOOST_CHECK(!deferred);
BOOST_CHECK_EQUAL(ostream.str(), "");
con->read_some(input.data(),input.size());
BOOST_CHECK(deferred);
BOOST_CHECK_EQUAL(ostream.str(), "");
con->set_body(con->get_resource());
con->set_status(websocketpp::http::status_code::ok);
websocketpp::lib::error_code ec;
s.send_http_response(con->get_handle(),ec);
BOOST_CHECK_EQUAL(ec, websocketpp::lib::error_code());
BOOST_CHECK_EQUAL(ostream.str(), output);
con->send_http_response(ec);
BOOST_CHECK_EQUAL(ec, make_error_code(websocketpp::error::invalid_state));
}
BOOST_AUTO_TEST_CASE( request_no_server_header ) {
std::string input = "GET / HTTP/1.1\r\nHost: www.example.com\r\nConnection: upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nOrigin: http://www.example.com\r\n\r\n";
std::string output = "HTTP/1.1 101 Switching Protocols\r\nConnection: upgrade\r\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\nUpgrade: websocket\r\n\r\n";
+29
View File
@@ -57,6 +57,35 @@ BOOST_AUTO_TEST_CASE( initialize_server_asio_external ) {
s.init_asio(&ios);
}
#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_
BOOST_AUTO_TEST_CASE( move_construct_server_core ) {
websocketpp::server<websocketpp::config::core> s1;
websocketpp::server<websocketpp::config::core> s2(std::move(s1));
}
/*
// temporary disable because library doesn't pass
BOOST_AUTO_TEST_CASE( emplace ) {
std::stringstream out1;
std::stringstream out2;
std::vector<websocketpp::server<websocketpp::config::asio_tls>> v;
v.emplace_back();
v.emplace_back();
v[0].get_alog().set_ostream(&out1);
v[0].get_alog().set_ostream(&out2);
v[0].get_alog().write(websocketpp::log::alevel::app,"devel0");
v[1].get_alog().write(websocketpp::log::alevel::app,"devel1");
BOOST_CHECK( out1.str().size() > 0 );
BOOST_CHECK( out2.str().size() > 0 );
}*/
#endif // _WEBSOCKETPP_MOVE_SEMANTICS_
struct endpoint_extension {
endpoint_extension() : extension_value(5) {}
+64
View File
@@ -34,6 +34,8 @@
#include <websocketpp/concurrency/none.hpp>
#include <websocketpp/concurrency/basic.hpp>
typedef websocketpp::log::basic<websocketpp::concurrency::basic,websocketpp::log::alevel> basic_access_log_type;
BOOST_AUTO_TEST_CASE( is_token_char ) {
typedef websocketpp::log::basic<websocketpp::concurrency::none,websocketpp::log::elevel> error_log;
@@ -79,3 +81,65 @@ BOOST_AUTO_TEST_CASE( basic_concurrency ) {
//std::cout << "|" << out.str() << "|" << std::endl;
BOOST_CHECK( out.str().size() > 0 );
}
BOOST_AUTO_TEST_CASE( copy_constructor ) {
std::stringstream out;
basic_access_log_type logger1(0xffffffff,&out);
basic_access_log_type logger2(logger1);
logger2.set_channels(0xffffffff);
logger2.write(websocketpp::log::alevel::devel,"devel");
BOOST_CHECK( out.str().size() > 0 );
}
#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_
BOOST_AUTO_TEST_CASE( move_constructor ) {
std::stringstream out;
basic_access_log_type logger1(0xffffffff,&out);
basic_access_log_type logger2(std::move(logger1));
logger2.set_channels(0xffffffff);
logger2.write(websocketpp::log::alevel::devel,"devel");
BOOST_CHECK( out.str().size() > 0 );
}
// Emplace requires move assignment, which logger doesn't support right now
// due to const members. This is pretty irritating and will probably result in
// the const members being removed. For now though this test will fail to
// compile
/*BOOST_AUTO_TEST_CASE( emplace ) {
std::stringstream out1;
std::stringstream out2;
std::vector<basic_access_log_type> v;
v.emplace_back(websocketpp::log::level(0xffffffff),&out1);
v.emplace_back(websocketpp::log::level(0xffffffff),&out2);
v[0].set_channels(0xffffffff);
v[1].set_channels(0xffffffff);
v[0].write(websocketpp::log::alevel::devel,"devel");
v[1].write(websocketpp::log::alevel::devel,"devel");
BOOST_CHECK( out1.str().size() > 0 );
BOOST_CHECK( out2.str().size() > 0 );
}*/
#endif // #ifdef _WEBSOCKETPP_MOVE_SEMANTICS_
// As long as there are const member variables these can't exist
// These remain commented as they are useful for testing the deleted operators
/*BOOST_AUTO_TEST_CASE( copy_assign ) {
basic_access_log_type logger1;
basic_access_log_type logger2;
logger2 = logger1;
}
BOOST_AUTO_TEST_CASE( move_assign ) {
basic_access_log_type logger1;
basic_access_log_type logger2;
logger2 = std::move(logger1);
}*/
+1 -1
View File
@@ -11,7 +11,7 @@ Import('tls_libs')
env = env.Clone ()
env_cpp11 = env_cpp11.Clone ()
BOOST_LIBS = boostlibs(['unit_test_framework','system','thread','random'],env) + [platform_libs] + [tls_libs]
BOOST_LIBS = boostlibs(['unit_test_framework','system','thread','random','chrono'],env) + [platform_libs] + [tls_libs]
objs = env.Object('boost_integration.o', ["integration.cpp"], LIBS = BOOST_LIBS)
prgs = env.Program('test_boost_integration', ["boost_integration.o"], LIBS = BOOST_LIBS)
+1 -1
View File
@@ -11,7 +11,7 @@ Import('tls_libs')
env = env.Clone ()
env_cpp11 = env_cpp11.Clone ()
BOOST_LIBS = boostlibs(['unit_test_framework','system','thread'],env) + [platform_libs] + [tls_libs]
BOOST_LIBS = boostlibs(['unit_test_framework','system','thread','chrono'],env) + [platform_libs] + [tls_libs]
objs = env.Object('base_boost.o', ["base.cpp"], LIBS = BOOST_LIBS)
objs += env.Object('timers_boost.o', ["timers.cpp"], LIBS = BOOST_LIBS)
+8
View File
@@ -607,3 +607,11 @@ BOOST_AUTO_TEST_CASE( pause_reading ) {
BOOST_AUTO_TEST_CASE( server_connection_cleanup ) {
server_tls s;
}
#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_
BOOST_AUTO_TEST_CASE( move_construct_transport ) {
server s1;
server s2(std::move(s1));
}
#endif // _WEBSOCKETPP_MOVE_SEMANTICS_
+39 -5
View File
@@ -117,7 +117,7 @@ struct stub_con : public iostream_con {
indef_read_size = num_bytes;
indef_read_buf = buf;
indef_read_len = len;
indef_read();
}
@@ -138,7 +138,7 @@ struct stub_con : public iostream_con {
void handle_indef(websocketpp::lib::error_code const & e, size_t amt_read) {
ec = e;
indef_read_total += amt_read;
indef_read();
}
@@ -203,6 +203,15 @@ websocketpp::lib::error_code write_handler(std::string & o, websocketpp::connect
return websocketpp::lib::error_code();
}
websocketpp::lib::error_code vector_write_handler(std::string & o, websocketpp::connection_hdl, std::vector<websocketpp::transport::buffer> const & bufs) {
std::vector<websocketpp::transport::buffer>::const_iterator it;
for (it = bufs.begin(); it != bufs.end(); it++) {
o += std::string((*it).buf, (*it).len);
}
return websocketpp::lib::error_code();
}
websocketpp::lib::error_code write_handler_error(websocketpp::connection_hdl, char const *, size_t) {
return make_error_code(websocketpp::transport::error::general);
}
@@ -249,7 +258,7 @@ BOOST_AUTO_TEST_CASE( async_write_vector_0_write_handler ) {
std::string output;
stub_con::ptr con(new stub_con(true,alogger,elogger));
con->set_write_handler(websocketpp::lib::bind(
&write_handler,
websocketpp::lib::ref(output),
@@ -354,6 +363,31 @@ BOOST_AUTO_TEST_CASE( async_write_vector_2_write_handler ) {
BOOST_CHECK_EQUAL( output, "foobar" );
}
BOOST_AUTO_TEST_CASE( async_write_vector_2_vector_write_handler ) {
std::string output;
stub_con::ptr con(new stub_con(true,alogger,elogger));
con->set_vector_write_handler(websocketpp::lib::bind(
&vector_write_handler,
websocketpp::lib::ref(output),
websocketpp::lib::placeholders::_1,
websocketpp::lib::placeholders::_2
));
std::vector<websocketpp::transport::buffer> bufs;
std::string foo = "foo";
std::string bar = "bar";
bufs.push_back(websocketpp::transport::buffer(foo.data(),foo.size()));
bufs.push_back(websocketpp::transport::buffer(bar.data(),bar.size()));
con->write(bufs);
BOOST_CHECK( !con->ec );
BOOST_CHECK_EQUAL( output, "foobar" );
}
BOOST_AUTO_TEST_CASE( async_read_at_least_too_much ) {
stub_con::ptr con(new stub_con(true,alogger,elogger));
@@ -483,7 +517,7 @@ BOOST_AUTO_TEST_CASE( async_read_at_least_read_some_indef ) {
BOOST_CHECK( !con->ec );
BOOST_CHECK_EQUAL( std::string(buf,10), "aaaaaxxxxx" );
BOOST_CHECK_EQUAL( con->indef_read_total, 5 );
// A subsequent read should read 5 more because the indef read refreshes
// itself. The new read will start again at the beginning of the buffer.
BOOST_CHECK_EQUAL(con->read_some(input+5,5), 5);
@@ -539,7 +573,7 @@ websocketpp::lib::error_code sd_handler(websocketpp::connection_hdl) {
BOOST_AUTO_TEST_CASE( shutdown_handler ) {
stub_con::ptr con(new stub_con(true,alogger,elogger));
con->set_shutdown_handler(&sd_handler);
BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );
con->shutdown();
+8 -1
View File
@@ -235,7 +235,7 @@ The `websocket_endpoint` object has gained some new data members and methods. It
A new WebSocket connection is initiated via a three step process. First, a connection request is created by `endpoint::get_connection(uri)`. Next, the connection request is configured. Lastly, the connection request is submitted back to the endpoint via `endpoint::connect()` which adds it to the queue of new connections to make.
> ###### Terminology `connection_ptr`
> WebSocket++ keeps track of connection related resources using a reference counted shared pointer. The type of this pointer is `endpoint::connection_ptr`. A `connection_ptr` allows direct access to information about the connection and allows changing connection settings. Because of this direct access and their internal resource management role within the library it is not safe to for end applications to use `connection_ptr` except in the specific circumstances detailed below.
> WebSocket++ keeps track of connection related resources using a reference counted shared pointer. The type of this pointer is `endpoint::connection_ptr`. A `connection_ptr` allows direct access to information about the connection and allows changing connection settings. Because of this direct access and their internal resource management role within the library it is not safe for end applications to use `connection_ptr` except in the specific circumstances detailed below.
>
> **When is it safe to use `connection_ptr`?**
> - After `endpoint::get_connection(...)` and before `endpoint::connect()`: `get_connection` returns a `connection_ptr`. It is safe to use this pointer to configure your new connection. Once you submit the connection to `connect` you may no longer use the `connection_ptr` and should discard it immediately for optimal memory management.
@@ -813,6 +813,13 @@ Enter Command: show 0
_Using TLS / Secure WebSockets_
- Change the includes
- link to the new library dependencies
- Switch the config
- add the `tls_init_handler`
- configure the SSL context for desired security level
- mixing secure and non-secure connections in one application.
Chapter 2: Intermediate Features
--------------------------------
+131
View File
@@ -0,0 +1,131 @@
/*
* Copyright (c) 2015, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef WEBSOCKETPP_COMMON_ASIO_HPP
#define WEBSOCKETPP_COMMON_ASIO_HPP
// This file goes to some length to preserve compatibility with versions of
// boost older than 1.49 (where the first modern steady_timer timer based on
// boost/std chrono was introduced.
//
// For the versions older than 1.49, the deadline_timer is used instead. this
// brings in dependencies on boost date_time and it has a different interface
// that is normalized by the `lib::asio::is_neg` and `lib::asio::milliseconds`
// wrappers provided by this file.
//
// The primary reason for this continued support is that boost 1.48 is the
// default and not easily changeable version of boost supplied by the package
// manager of popular Linux distributions like Ubuntu 12.04 LTS. Once the need
// for this has passed this should be cleaned up and simplified.
#ifdef ASIO_STANDALONE
#include <asio/version.hpp>
#if (ASIO_VERSION/100000) == 1 && ((ASIO_VERSION/100)%1000) < 8
static_assert(false, "The minimum version of standalone Asio is 1.8.0");
#endif
#include <asio.hpp>
#include <asio/steady_timer.hpp>
#include <websocketpp/common/chrono.hpp>
#else
#include <boost/version.hpp>
// See note above about boost <1.49 compatibility. If we are running on
// boost > 1.48 pull in the steady timer and chrono library
#if (BOOST_VERSION/100000) == 1 && ((BOOST_VERSION/100)%1000) > 48
#include <boost/asio/steady_timer.hpp>
#include <websocketpp/common/chrono.hpp>
#endif
#include <boost/asio.hpp>
#include <boost/system/error_code.hpp>
#endif
namespace websocketpp {
namespace lib {
#ifdef ASIO_STANDALONE
namespace asio {
using namespace ::asio;
// Here we assume that we will be using std::error_code with standalone
// Asio. This is probably a good assumption, but it is possible in rare
// cases that local Asio versions would be used.
using std::errc;
// See note above about boost <1.49 compatibility. Because we require
// a standalone Asio version of 1.8+ we are guaranteed to have
// steady_timer available. By convention we require the chrono library
// (either boost or std) for use with standalone Asio.
template <typename T>
bool is_neg(T duration) {
return duration.count() < 0;
}
inline lib::chrono::milliseconds milliseconds(long duration) {
return lib::chrono::milliseconds(duration);
}
} // namespace asio
#else
namespace asio {
using namespace boost::asio;
// See note above about boost <1.49 compatibility
#if (BOOST_VERSION/100000) == 1 && ((BOOST_VERSION/100)%1000) > 48
// Using boost::asio >=1.49 so we use chrono and steady_timer
template <typename T>
bool is_neg(T duration) {
return duration.count() < 0;
}
inline lib::chrono::milliseconds milliseconds(long duration) {
return lib::chrono::milliseconds(duration);
}
#else
// Using boost::asio <1.49 we pretend a deadline timer is a steady
// timer and wrap the negative detection and duration conversion
// appropriately.
typedef boost::asio::deadline_timer steady_timer;
template <typename T>
bool is_neg(T duration) {
return duration.is_negative();
}
inline boost::posix_time::time_duration milliseconds(long duration) {
return boost::posix_time::milliseconds(duration);
}
#endif
using boost::system::error_code;
namespace errc = boost::system::errc;
} // namespace asio
#endif
} // namespace lib
} // namespace websocketpp
#endif // WEBSOCKETPP_COMMON_ASIO_HPP
+37
View File
@@ -0,0 +1,37 @@
/*
* Copyright (c) 2015, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef WEBSOCKETPP_COMMON_ASIO_SSL_HPP
#define WEBSOCKETPP_COMMON_ASIO_SSL_HPP
#ifdef ASIO_STANDALONE
#include <asio/asio/ssl.hpp>
#else
#include <boost/asio/ssl.hpp>
#endif
#endif // WEBSOCKETPP_COMMON_ASIO_SSL_HPP
+8 -3
View File
@@ -28,7 +28,12 @@
#ifndef WEBSOCKETPP_COMMON_CHRONO_HPP
#define WEBSOCKETPP_COMMON_CHRONO_HPP
#if defined _WEBSOCKETPP_CPP11_STL_ && !defined _WEBSOCKETPP_NO_CPP11_CHRONO_
#include <websocketpp/common/cpp11.hpp>
// If we've determined that we're in full C++11 mode and the user hasn't
// explicitly disabled the use of C++11 functional header, then prefer it to
// boost.
#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_CHRONO_
#ifndef _WEBSOCKETPP_CPP11_CHRONO_
#define _WEBSOCKETPP_CPP11_CHRONO_
#endif
@@ -44,9 +49,9 @@ namespace websocketpp {
namespace lib {
#ifdef _WEBSOCKETPP_CPP11_CHRONO_
using std::chrono::system_clock;
namespace chrono = std::chrono;
#else
using boost::chrono::system_clock;
namespace chrono = boost::chrono;
#endif
} // namespace lib
+6
View File
@@ -80,6 +80,12 @@
#ifndef _WEBSOCKETPP_NULLPTR_TOKEN_
#define _WEBSOCKETPP_NULLPTR_TOKEN_ nullptr
#endif
#ifndef _WEBSOCKETPP_MOVE_SEMANTICS_
#define _WEBSOCKETPP_MOVE_SEMANTICS_
#endif
#ifndef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
#define _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
#endif
#ifndef __GNUC__
// GCC as of version 4.9 (latest) does not support std::put_time yet.
+2
View File
@@ -36,6 +36,8 @@
#include <netinet/in.h>
#endif
#include <websocketpp/common/stdint.hpp>
namespace websocketpp {
namespace lib {
namespace net {
+2
View File
@@ -61,6 +61,7 @@ namespace websocketpp {
namespace lib {
#ifdef _WEBSOCKETPP_CPP11_SYSTEM_ERROR_
using std::errc;
using std::error_code;
using std::error_category;
using std::error_condition;
@@ -68,6 +69,7 @@ namespace lib {
#define _WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_ namespace std {
#define _WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_ }
#else
namespace errc = boost::system::errc;
using boost::system::error_code;
using boost::system::error_category;
using boost::system::error_condition;
+63
View File
@@ -0,0 +1,63 @@
/*
* Copyright (c) 2015, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef WEBSOCKETPP_COMMON_TYPE_TRAITS_HPP
#define WEBSOCKETPP_COMMON_TYPE_TRAITS_HPP
#include <websocketpp/common/cpp11.hpp>
// If we've determined that we're in full C++11 mode and the user hasn't
// explicitly disabled the use of C++11 functional header, then prefer it to
// boost.
#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_TYPE_TRAITS_
#ifndef _WEBSOCKETPP_CPP11_TYPE_TRAITS_
#define _WEBSOCKETPP_CPP11_TYPE_TRAITS_
#endif
#endif
#ifdef _WEBSOCKETPP_CPP11_TYPE_TRAITS_
#include <type_traits>
#else
#include <boost/aligned_storage.hpp>
#endif
namespace websocketpp {
namespace lib {
#ifdef _WEBSOCKETPP_CPP11_TYPE_TRAITS_
using std::aligned_storage;
#else
using boost::aligned_storage;
#endif
} // namespace lib
} // namespace websocketpp
#endif // WEBSOCKETPP_COMMON_TYPE_TRAITS_HPP
+70 -4
View File
@@ -214,6 +214,20 @@ namespace internal_state {
PROCESS_CONNECTION = 7
};
} // namespace internal_state
namespace http_state {
// states to keep track of the progress of http connections
enum value {
init = 0,
deferred = 1,
headers_written = 2,
body_written = 3,
closed = 4
};
} // namespace http_state
} // namespace session
/// Represents an individual WebSocket connection
@@ -312,6 +326,7 @@ public:
, m_local_close_code(close::status::abnormal_close)
, m_remote_close_code(close::status::abnormal_close)
, m_is_http(false)
, m_http_state(session::http_state::init)
, m_was_clean(false)
{
m_alog.write(log::alevel::devel,"connection constructor");
@@ -1060,6 +1075,52 @@ public:
request_type const & get_request() const {
return m_request;
}
/// Defer HTTP Response until later (Exception free)
/**
* Used in the http handler to defer the HTTP response for this connection
* until later. Handshake timers will be canceled and the connection will be
* left open until `send_http_response` or an equivalent is called.
*
* Warning: deferred connections won't time out and as a result can tie up
* resources.
*
* @since 0.6.0
*
* @return A status code, zero on success, non-zero otherwise
*/
lib::error_code defer_http_response();
/// Send deferred HTTP Response (exception free)
/**
* Sends an http response to an HTTP connection that was deferred. This will
* send a complete response including all headers, status line, and body
* text. The connection will be closed afterwards.
*
* @since 0.6.0
*
* @param ec A status code, zero on success, non-zero otherwise
*/
void send_http_response(lib::error_code & ec);
/// Send deferred HTTP Response
void send_http_response();
// TODO HTTPNBIO: write_headers
// function that processes headers + status so far and writes it to the wire
// beginning the HTTP response body state. This method will ignore anything
// in the response body.
// TODO HTTPNBIO: write_body_message
// queues the specified message_buffer for async writing
// TODO HTTPNBIO: finish connection
//
// TODO HTTPNBIO: write_response
// Writes the whole response, headers + body and closes the connection
/////////////////////////////////////////////////////////////
// Pass-through access to the other connection information //
@@ -1202,7 +1263,8 @@ public:
void handle_read_http_response(lib::error_code const & ec,
size_t bytes_transferred);
void handle_send_http_response(lib::error_code const & ec);
void handle_write_http_response(lib::error_code const & ec);
void handle_send_http_request(lib::error_code const & ec);
void handle_open_handshake_timeout(lib::error_code const & ec);
@@ -1254,13 +1316,13 @@ protected:
lib::error_code process_handshake_request();
private:
/// Completes m_response, serializes it, and sends it out on the wire.
void send_http_response(lib::error_code const & ec);
void write_http_response(lib::error_code const & ec);
/// Sends an opening WebSocket connect request
void send_http_request();
/// Alternate path for send_http_response in error conditions
void send_http_response_error(lib::error_code const & ec);
/// Alternate path for write_http_response in error conditions
void write_http_response_error(lib::error_code const & ec);
/// Process control message
/**
@@ -1510,6 +1572,10 @@ private:
/// A flag that gets set once it is determined that the connection is an
/// HTTP connection and not a WebSocket one.
bool m_is_http;
/// A flag that gets set when the completion of an http connection is
/// deferred until later.
session::http_state::value m_http_state;
bool m_was_clean;
+79 -1
View File
@@ -104,6 +104,56 @@ public:
transport_type::init_logging(&m_alog, &m_elog);
}
/// Destructor
~endpoint<connection,config>() {}
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
// no copy constructor because endpoints are not copyable
endpoint(endpoint &) = delete;
// no copy assignment operator because endpoints are not copyable
endpoint & operator=(endpoint const &) = delete;
#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_
/// Move constructor
endpoint(endpoint && o)
: config::transport_type(std::move(o))
, config::endpoint_base(std::move(o))
, m_alog(std::move(o.m_alog))
, m_elog(std::move(o.m_elog))
, m_user_agent(std::move(o.m_user_agent))
, m_open_handler(std::move(o.m_open_handler))
, m_close_handler(std::move(o.m_close_handler))
, m_fail_handler(std::move(o.m_fail_handler))
, m_ping_handler(std::move(o.m_ping_handler))
, m_pong_handler(std::move(o.m_pong_handler))
, m_pong_timeout_handler(std::move(o.m_pong_timeout_handler))
, m_interrupt_handler(std::move(o.m_interrupt_handler))
, m_http_handler(std::move(o.m_http_handler))
, m_validate_handler(std::move(o.m_validate_handler))
, m_message_handler(std::move(o.m_message_handler))
, m_open_handshake_timeout_dur(o.m_open_handshake_timeout_dur)
, m_close_handshake_timeout_dur(o.m_close_handshake_timeout_dur)
, m_pong_timeout_dur(o.m_pong_timeout_dur)
, m_max_message_size(o.m_max_message_size)
, m_max_http_body_size(o.m_max_http_body_size)
, m_rng(std::move(o.m_rng))
, m_is_server(o.m_is_server)
{}
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
// no move assignment operator because of const member variables
endpoint & operator=(endpoint &&) = delete;
#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
#endif // _WEBSOCKETPP_MOVE_SEMANTICS_
/// Returns the user agent string that this endpoint will use
/**
* Returns the user agent string that this endpoint will use when creating
@@ -466,6 +516,35 @@ public:
/// Resume reading of new data
void resume_reading(connection_hdl hdl);
/// Send deferred HTTP Response
/**
* Sends an http response to an HTTP connection that was deferred. This will
* send a complete response including all headers, status line, and body
* text. The connection will be closed afterwards.
*
* Exception free variant
*
* @since 0.6.0
*
* @param hdl The connection to send the response on
* @param ec A status code, zero on success, non-zero otherwise
*/
void send_http_response(connection_hdl hdl, lib::error_code & ec);
/// Send deferred HTTP Response (exception free)
/**
* Sends an http response to an HTTP connection that was deferred. This will
* send a complete response including all headers, status line, and body
* text. The connection will be closed afterwards.
*
* Exception variant
*
* @since 0.6.0
*
* @param hdl The connection to send the response on
*/
void send_http_response(connection_hdl hdl);
/// Create a message and add it to the outgoing send queue (exception free)
/**
* Convenience method to send a message given a payload string and an opcode
@@ -559,7 +638,6 @@ public:
* @return the connection_ptr. May be NULL if the handle was invalid.
*/
connection_ptr get_con_from_hdl(connection_hdl hdl, lib::error_code & ec) {
scoped_lock_type lock(m_mutex);
connection_ptr con = lib::static_pointer_cast<connection_type>(
hdl.lock());
if (!con) {
+2 -2
View File
@@ -250,7 +250,7 @@ public:
{}
explicit exception(lib::error_code ec)
: m_code(ec)
: m_msg(ec.message()), m_code(ec)
{}
~exception() throw() {}
@@ -263,7 +263,7 @@ public:
return m_code;
}
std::string m_msg;
const std::string m_msg;
lib::error_code m_code;
};
+84 -19
View File
@@ -635,7 +635,66 @@ void connection<config>::remove_header(std::string const & key)
}
}
/// Defer HTTP Response until later
/**
* Used in the http handler to defer the HTTP response for this connection
* until later. Handshake timers will be canceled and the connection will be
* left open until `send_http_response` or an equivalent is called.
*
* Warning: deferred connections won't time out and as a result can tie up
* resources.
*
* @return A status code, zero on success, non-zero otherwise
*/
template <typename config>
lib::error_code connection<config>::defer_http_response() {
// Cancel handshake timer, otherwise the connection will time out and we'll
// close the connection before the app has a chance to send a response.
if (m_handshake_timer) {
m_handshake_timer->cancel();
m_handshake_timer.reset();
}
// Do something to signal deferral
m_http_state = session::http_state::deferred;
return lib::error_code();
}
/// Send deferred HTTP Response (exception free)
/**
* Sends an http response to an HTTP connection that was deferred. This will
* send a complete response including all headers, status line, and body
* text. The connection will be closed afterwards.
*
* @since 0.6.0
*
* @param ec A status code, zero on success, non-zero otherwise
*/
template <typename config>
void connection<config>::send_http_response(lib::error_code & ec) {
{
scoped_lock_type lock(m_connection_state_lock);
if (m_http_state != session::http_state::deferred) {
ec = error::make_error_code(error::invalid_state);
return;
}
m_http_state = session::http_state::body_written;
}
this->write_http_response(lib::error_code());
ec = lib::error_code();
}
template <typename config>
void connection<config>::send_http_response() {
lib::error_code ec;
this->send_http_response(ec);
if (ec) {
throw exception(ec);
}
}
@@ -728,7 +787,7 @@ void connection<config>::read_handshake(size_t num_bytes) {
);
}
// All exit paths for this function need to call send_http_response() or submit
// All exit paths for this function need to call write_http_response() or submit
// a new read request with this function as the handler.
template <typename config>
void connection<config>::handle_read_handshake(lib::error_code const & ec,
@@ -784,7 +843,7 @@ void connection<config>::handle_read_handshake(lib::error_code const & ec,
// All HTTP exceptions will result in this request failing and an error
// response being returned. No more bytes will be read in this con.
m_response.set_status(e.m_error_code,e.m_error_msg);
this->send_http_response_error(error::make_error_code(error::http_parse_error));
this->write_http_response_error(error::make_error_code(error::http_parse_error));
return;
}
@@ -806,7 +865,7 @@ void connection<config>::handle_read_handshake(lib::error_code const & ec,
if (m_request.ready()) {
lib::error_code processor_ec = this->initialize_processor();
if (processor_ec) {
this->send_http_response_error(processor_ec);
this->write_http_response_error(processor_ec);
return;
}
@@ -823,7 +882,7 @@ void connection<config>::handle_read_handshake(lib::error_code const & ec,
// TODO: need more bytes
m_alog.write(log::alevel::devel,"short key3 read");
m_response.set_status(http::status_code::internal_server_error);
this->send_http_response_error(processor::error::make_error_code(processor::error::short_key3));
this->write_http_response_error(processor::error::make_error_code(processor::error::short_key3));
return;
}
}
@@ -847,7 +906,9 @@ void connection<config>::handle_read_handshake(lib::error_code const & ec,
// We have the complete request. Process it.
lib::error_code handshake_ec = this->process_handshake_request();
this->send_http_response(handshake_ec);
if (!m_is_http || m_http_state != session::http_state::deferred) {
this->write_http_response(handshake_ec);
}
} else {
// read at least 1 more byte
transport_con_type::async_read_at_least(
@@ -864,26 +925,26 @@ void connection<config>::handle_read_handshake(lib::error_code const & ec,
}
}
// send_http_response requires the request to be fully read and the connection
// write_http_response requires the request to be fully read and the connection
// to be in the PROCESS_HTTP_REQUEST state. In some cases we can detect errors
// before the request is fully read (specifically at a point where we aren't
// sure if the hybi00 key3 bytes need to be read). This method sets the correct
// state and calls send_http_response
// state and calls write_http_response
template <typename config>
void connection<config>::send_http_response_error(lib::error_code const & ec) {
void connection<config>::write_http_response_error(lib::error_code const & ec) {
if (m_internal_state != istate::READ_HTTP_REQUEST) {
m_alog.write(log::alevel::devel,
"send_http_response_error called in invalid state");
"write_http_response_error called in invalid state");
this->terminate(error::make_error_code(error::invalid_state));
return;
}
m_internal_state = istate::PROCESS_HTTP_REQUEST;
this->send_http_response(ec);
this->write_http_response(ec);
}
// All exit paths for this function need to call send_http_response() or submit
// All exit paths for this function need to call write_http_response() or submit
// a new read request with this function as the handler.
template <typename config>
void connection<config>::handle_read_frame(lib::error_code const & ec,
@@ -1113,6 +1174,7 @@ lib::error_code connection<config>::process_handshake_request() {
if (m_http_handler) {
m_is_http = true;
m_http_handler(m_connection_hdl);
if (m_state == session::state::closed) {
return error::make_error_code(error::http_connection_ended);
}
@@ -1207,8 +1269,8 @@ lib::error_code connection<config>::process_handshake_request() {
}
template <typename config>
void connection<config>::send_http_response(lib::error_code const & ec) {
m_alog.write(log::alevel::devel,"connection send_http_response");
void connection<config>::write_http_response(lib::error_code const & ec) {
m_alog.write(log::alevel::devel,"connection write_http_response");
if (ec == error::make_error_code(error::http_connection_ended)) {
m_alog.write(log::alevel::http,"An HTTP handler took over the connection.");
@@ -1254,7 +1316,7 @@ void connection<config>::send_http_response(lib::error_code const & ec) {
m_handshake_buffer.data(),
m_handshake_buffer.size(),
lib::bind(
&type::handle_send_http_response,
&type::handle_write_http_response,
type::get_shared(),
lib::placeholders::_1
)
@@ -1262,8 +1324,8 @@ void connection<config>::send_http_response(lib::error_code const & ec) {
}
template <typename config>
void connection<config>::handle_send_http_response(lib::error_code const & ec) {
m_alog.write(log::alevel::devel,"handle_send_http_response");
void connection<config>::handle_write_http_response(lib::error_code const & ec) {
m_alog.write(log::alevel::devel,"handle_write_http_response");
lib::error_code ecm = ec;
@@ -1279,7 +1341,7 @@ void connection<config>::handle_send_http_response(lib::error_code const & ec) {
// usually by the handshake timer. This is basically expected
// (though hopefully rare) and there is nothing we can do so ignore.
m_alog.write(log::alevel::devel,
"handle_send_http_response invoked after connection was closed");
"handle_write_http_response invoked after connection was closed");
return;
} else {
ecm = error::make_error_code(error::invalid_state);
@@ -1294,7 +1356,7 @@ void connection<config>::handle_send_http_response(lib::error_code const & ec) {
return;
}
log_err(log::elevel::rerror,"handle_send_http_response",ecm);
log_err(log::elevel::rerror,"handle_write_http_response",ecm);
this->terminate(ecm);
return;
}
@@ -1608,7 +1670,10 @@ void connection<config>::terminate(lib::error_code const & ec) {
m_local_close_reason = ec.message();
}
// TODO: does this need a mutex?
// TODO: does any of this need a mutex?
if (m_is_http) {
m_http_state = session::http_state::closed;
}
if (m_state == session::state::connecting) {
m_state = session::state::closed;
tstat = failed;
+14
View File
@@ -142,7 +142,21 @@ void endpoint<connection,config>::resume_reading(connection_hdl hdl) {
if (ec) { throw exception(ec); }
}
template <typename connection, typename config>
void endpoint<connection,config>::send_http_response(connection_hdl hdl,
lib::error_code & ec)
{
connection_ptr con = get_con_from_hdl(hdl,ec);
if (ec) {return;}
con->send_http_response(ec);
}
template <typename connection, typename config>
void endpoint<connection,config>::send_http_response(connection_hdl hdl) {
lib::error_code ec;
send_http_response(hdl,ec);
if (ec) { throw exception(ec); }
}
template <typename connection, typename config>
void endpoint<connection,config>::send(connection_hdl hdl, std::string const & payload,
+30
View File
@@ -80,6 +80,36 @@ public:
, m_dynamic_channels(0)
, m_out(out) {}
/// Destructor
~basic<concurrency,names>() {}
/// Copy constructor
basic<concurrency,names>(basic<concurrency,names> const & other)
: m_static_channels(other.m_static_channels)
, m_dynamic_channels(other.m_dynamic_channels)
, m_out(other.m_out)
{}
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
// no copy assignment operator because of const member variables
basic<concurrency,names> & operator=(basic<concurrency,names> const &) = delete;
#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_
/// Move constructor
basic<concurrency,names>(basic<concurrency,names> && other)
: m_static_channels(other.m_static_channels)
, m_dynamic_channels(other.m_dynamic_channels)
, m_out(other.m_out)
{}
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
// no move assignment operator because of const member variables
basic<concurrency,names> & operator=(basic<concurrency,names> &&) = delete;
#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
#endif // _WEBSOCKETPP_MOVE_SEMANTICS_
void set_ostream(std::ostream * out = &std::cout) {
m_out = out;
}
+3 -1
View File
@@ -563,6 +563,7 @@ public:
} else {
frame::extended_header e(i.size());
out->set_header(frame::prepare_header(h,e));
key.i = 0;
}
// prepare payload
@@ -937,7 +938,8 @@ protected:
out->set_header(frame::prepare_header(h,e));
std::copy(payload.begin(),payload.end(),o.begin());
}
out->set_opcode(op);
out->set_prepared(true);
return lib::error_code();
+1
View File
@@ -29,6 +29,7 @@
#define WEBSOCKETPP_CLIENT_ENDPOINT_HPP
#include <websocketpp/endpoint.hpp>
#include <websocketpp/uri.hpp>
#include <websocketpp/logger/levels.hpp>
+22
View File
@@ -69,6 +69,28 @@ public:
endpoint_type::m_alog.write(log::alevel::devel, "server constructor");
}
/// Destructor
~server<config>() {}
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
// no copy constructor because endpoints are not copyable
server<config>(server<config> &) = delete;
// no copy assignment operator because endpoints are not copyable
server<config> & operator=(server<config> const &) = delete;
#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_
/// Move constructor
server<config>(server<config> && o) : endpoint<connection<config>,config>(std::move(o)) {}
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
// no move assignment operator because of const member variables
server<config> & operator=(server<config> &&) = delete;
#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
#endif // _WEBSOCKETPP_MOVE_SEMANTICS_
/// Create and initialize a new connection
/**
* The connection will be initialized and ready to begin. Call its start()
+61 -77
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Peter Thorson. All rights reserved.
* Copyright (c) 2015, 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:
@@ -28,123 +28,107 @@
#ifndef WEBSOCKETPP_TRANSPORT_ASIO_BASE_HPP
#define WEBSOCKETPP_TRANSPORT_ASIO_BASE_HPP
#include <websocketpp/common/asio.hpp>
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/common/functional.hpp>
#include <websocketpp/common/system_error.hpp>
#include <boost/system/error_code.hpp>
#include <boost/aligned_storage.hpp>
#include <boost/noncopyable.hpp>
#include <boost/array.hpp>
#include <websocketpp/common/type_traits.hpp>
#include <string>
namespace websocketpp {
namespace transport {
/// Transport policy that uses boost::asio
/// Transport policy that uses asio
/**
* This policy uses a single boost::asio io_service to provide transport
* This policy uses a single asio io_service to provide transport
* services to a WebSocket++ endpoint.
*/
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
{
class handler_allocator {
public:
handler_allocator()
: in_use_(false)
{
}
static const size_t size = 1024;
handler_allocator() : m_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);
}
}
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
handler_allocator(handler_allocator const & cpy) = delete;
handler_allocator & operator =(handler_allocator const &) = delete;
#endif
void deallocate(void* pointer)
{
if (pointer == storage_.address())
{
in_use_ = false;
void * allocate(std::size_t memsize) {
if (!m_in_use && memsize < size) {
m_in_use = true;
return static_cast<void*>(&m_storage);
} else {
return ::operator new(memsize);
}
}
else
{
::operator delete(pointer);
void deallocate(void * pointer) {
if (pointer == &m_storage) {
m_in_use = false;
} else {
::operator delete(pointer);
}
}
}
private:
// Storage space used for handler-based custom memory allocation.
boost::aligned_storage<1024> storage_;
// Storage space used for handler-based custom memory allocation.
lib::aligned_storage<size>::type m_storage;
// Whether the handler-based custom allocation storage has been used.
bool in_use_;
// Whether the handler-based custom allocation storage has been used.
bool m_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
{
class custom_alloc_handler {
public:
custom_alloc_handler(handler_allocator& a, Handler h)
: allocator_(a),
handler_(h)
{
}
custom_alloc_handler(handler_allocator& a, Handler h)
: allocator_(a),
handler_(h)
{}
template <typename Arg1>
void operator()(Arg1 arg1)
{
handler_(arg1);
}
template <typename Arg1>
void operator()(Arg1 arg1) {
handler_(arg1);
}
template <typename Arg1, typename Arg2>
void operator()(Arg1 arg1, Arg2 arg2)
{
handler_(arg1, arg2);
}
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_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);
}
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_;
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)
handler_allocator & a, Handler h)
{
return custom_alloc_handler<Handler>(a, h);
return custom_alloc_handler<Handler>(a, h);
}
@@ -158,13 +142,13 @@ inline custom_alloc_handler<Handler> make_custom_alloc_handler(
template <typename config>
class endpoint;
typedef lib::function<void(boost::system::error_code const &)>
typedef lib::function<void(lib::asio::error_code const &)>
socket_shutdown_handler;
typedef lib::function<void (boost::system::error_code const & ec,
typedef lib::function<void (lib::asio::error_code const & ec,
size_t bytes_transferred)> async_read_handler;
typedef lib::function<void (boost::system::error_code const & ec,
typedef lib::function<void (lib::asio::error_code const & ec,
size_t bytes_transferred)> async_write_handler;
typedef lib::function<void (lib::error_code const & ec)> pre_init_handler;
+68 -51
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Peter Thorson. All rights reserved.
* Copyright (c) 2015, 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:
@@ -37,15 +37,15 @@
#include <websocketpp/base64/base64.hpp>
#include <websocketpp/error.hpp>
#include <websocketpp/uri.hpp>
#include <websocketpp/common/asio.hpp>
#include <websocketpp/common/chrono.hpp>
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/common/memory.hpp>
#include <websocketpp/common/functional.hpp>
#include <websocketpp/common/connection_hdl.hpp>
#include <boost/asio.hpp>
#include <boost/system/error_code.hpp>
#include <istream>
#include <sstream>
#include <string>
@@ -57,10 +57,10 @@ namespace asio {
typedef lib::function<void(connection_hdl)> tcp_init_handler;
/// Boost Asio based connection transport component
/// Asio based connection transport component
/**
* transport::asio::connection implements a connection transport component using
* Boost ASIO that works with the transport::asio::endpoint endpoint transport
* Asio that works with the transport::asio::endpoint endpoint transport
* component.
*/
template <typename config>
@@ -85,12 +85,12 @@ public:
typedef typename config::response_type response_type;
typedef typename response_type::ptr response_ptr;
/// 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 io_service::strand being used
typedef lib::shared_ptr<boost::asio::io_service::strand> strand_ptr;
/// Type of a pointer to the ASIO timer class
typedef lib::shared_ptr<boost::asio::deadline_timer> timer_ptr;
/// Type of a pointer to the Asio io_service being used
typedef lib::asio::io_service * io_service_ptr;
/// Type of a pointer to the Asio io_service::strand being used
typedef lib::shared_ptr<lib::asio::io_service::strand> strand_ptr;
/// Type of a pointer to the Asio timer class
typedef lib::shared_ptr<lib::asio::steady_timer> timer_ptr;
// connection is friends with its associated endpoint to allow the endpoint
// to call private/protected utility methods that we don't want to expose
@@ -98,7 +98,7 @@ public:
friend class endpoint<config>;
// generate and manage our own io_service
explicit connection(bool is_server, alog_type& alog, elog_type& elog)
explicit connection(bool is_server, alog_type & alog, elog_type & elog)
: m_is_server(is_server)
, m_alog(alog)
, m_elog(elog)
@@ -115,6 +115,22 @@ public:
return socket_con_type::is_secure();
}
/// Set uri hook
/**
* Called by the endpoint as a connection is being established to provide
* the uri being connected to to the transport layer.
*
* This transport policy doesn't use the uri except to forward it to the
* socket layer.
*
* @since 0.6.0
*
* @param u The uri to set
*/
void set_uri(uri_ptr u) {
socket_con_type::set_uri(u);
}
/// Sets the tcp pre init handler
/**
* The tcp pre init handler is called after the raw tcp connection has been
@@ -295,9 +311,9 @@ public:
* needed.
*/
timer_ptr set_timer(long duration, timer_handler callback) {
timer_ptr new_timer = lib::make_shared<boost::asio::deadline_timer>(
timer_ptr new_timer = lib::make_shared<lib::asio::steady_timer>(
lib::ref(*m_io_service),
boost::posix_time::milliseconds(duration)
lib::asio::milliseconds(duration)
);
if (config::enable_multithreading) {
@@ -331,10 +347,10 @@ public:
* @param ec The status code
*/
void handle_timer(timer_ptr, timer_handler callback,
boost::system::error_code const & ec)
lib::asio::error_code const & ec)
{
if (ec) {
if (ec == boost::asio::error::operation_aborted) {
if (ec == lib::asio::error::operation_aborted) {
callback(make_error_code(transport::error::operation_aborted));
} else {
log_err(log::elevel::info,"asio handle_timer",ec);
@@ -344,7 +360,7 @@ public:
callback(lib::error_code());
}
}
protected:
/// Get a pointer to this connection's strand
strand_ptr get_strand() {
return m_strand;
@@ -353,7 +369,7 @@ protected:
/// Initialize transport for reading
/**
* init_asio is called once immediately after construction to initialize
* boost::asio components to the io_service
* Asio components to the io_service
*
* The transport initialization sequence consists of the following steps:
* - Pre-init: the underlying socket is initialized to the point where
@@ -367,6 +383,7 @@ protected:
* read or write the WebSocket handshakes. At this point the original
* callback function is called.
*/
protected:
void init(init_handler callback) {
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"asio connection init");
@@ -411,7 +428,7 @@ protected:
/// Finish constructing the transport
/**
* init_asio is called once immediately after construction to initialize
* boost::asio components to the io_service.
* Asio components to the io_service.
*
* @param io_service A pointer to the io_service to register with this
* connection
@@ -422,7 +439,7 @@ protected:
m_io_service = io_service;
if (config::enable_multithreading) {
m_strand = lib::make_shared<boost::asio::strand>(
m_strand = lib::make_shared<lib::asio::strand>(
lib::ref(*io_service));
m_async_read_handler = m_strand->wrap(lib::bind(
@@ -555,7 +572,7 @@ protected:
lib::error_code const & ec)
{
if (ec == transport::error::operation_aborted ||
(post_timer && post_timer->expires_from_now().is_negative()))
(post_timer && lib::asio::is_neg(post_timer->expires_from_now())))
{
m_alog.write(log::alevel::devel,"post_init cancelled");
return;
@@ -590,8 +607,8 @@ protected:
m_proxy_data->write_buf = m_proxy_data->req.raw();
m_bufs.push_back(boost::asio::buffer(m_proxy_data->write_buf.data(),
m_proxy_data->write_buf.size()));
m_bufs.push_back(lib::asio::buffer(m_proxy_data->write_buf.data(),
m_proxy_data->write_buf.size()));
m_alog.write(log::alevel::devel,m_proxy_data->write_buf);
@@ -608,7 +625,7 @@ protected:
// Send proxy request
if (config::enable_multithreading) {
boost::asio::async_write(
lib::asio::async_write(
socket_con_type::get_next_layer(),
m_bufs,
m_strand->wrap(lib::bind(
@@ -618,7 +635,7 @@ protected:
))
);
} else {
boost::asio::async_write(
lib::asio::async_write(
socket_con_type::get_next_layer(),
m_bufs,
lib::bind(
@@ -648,7 +665,7 @@ protected:
}
void handle_proxy_write(init_handler callback,
boost::system::error_code const & ec)
lib::asio::error_code const & ec)
{
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,
@@ -660,8 +677,8 @@ protected:
// Timer expired or the operation was aborted for some reason.
// Whatever aborted it will be issuing the callback so we are safe to
// return
if (ec == boost::asio::error::operation_aborted ||
m_proxy_data->timer->expires_from_now().is_negative())
if (ec == lib::asio::error::operation_aborted ||
lib::asio::is_neg(m_proxy_data->timer->expires_from_now()))
{
m_elog.write(log::elevel::devel,"write operation aborted");
return;
@@ -691,7 +708,7 @@ protected:
}
if (config::enable_multithreading) {
boost::asio::async_read_until(
lib::asio::async_read_until(
socket_con_type::get_next_layer(),
m_proxy_data->read_buf,
"\r\n\r\n",
@@ -702,7 +719,7 @@ protected:
))
);
} else {
boost::asio::async_read_until(
lib::asio::async_read_until(
socket_con_type::get_next_layer(),
m_proxy_data->read_buf,
"\r\n\r\n",
@@ -722,7 +739,7 @@ protected:
* @param bytes_transferred The number of bytes read
*/
void handle_proxy_read(init_handler callback,
boost::system::error_code const & ec, size_t)
lib::asio::error_code const & ec, size_t)
{
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,
@@ -732,8 +749,8 @@ protected:
// Timer expired or the operation was aborted for some reason.
// Whatever aborted it will be issuing the callback so we are safe to
// return
if (ec == boost::asio::error::operation_aborted ||
m_proxy_data->timer->expires_from_now().is_negative())
if (ec == lib::asio::error::operation_aborted ||
lib::asio::is_neg(m_proxy_data->timer->expires_from_now()))
{
m_elog.write(log::elevel::devel,"read operation aborted");
return;
@@ -836,10 +853,10 @@ protected:
"asio con async_read_at_least called with bad handler");
}
boost::asio::async_read(
lib::asio::async_read(
socket_con_type::get_socket(),
boost::asio::buffer(buf,len),
boost::asio::transfer_at_least(num_bytes),
lib::asio::buffer(buf,len),
lib::asio::transfer_at_least(num_bytes),
make_custom_alloc_handler(
m_read_handler_allocator,
m_async_read_handler
@@ -847,14 +864,14 @@ protected:
);
}
void handle_async_read(boost::system::error_code const & ec,
void handle_async_read(lib::asio::error_code const & ec,
size_t bytes_transferred)
{
m_alog.write(log::alevel::devel, "asio con handle_async_read");
// translate boost error codes into more lib::error_codes
// translate asio error codes into more lib::error_codes
lib::error_code tec;
if (ec == boost::asio::error::eof) {
if (ec == lib::asio::error::eof) {
tec = make_error_code(transport::error::eof);
} else if (ec) {
// We don't know much more about the error at this point. As our
@@ -890,11 +907,11 @@ protected:
return;
}
m_bufs.push_back(boost::asio::buffer(buf,len));
m_bufs.push_back(lib::asio::buffer(buf,len));
m_write_handler = handler;
boost::asio::async_write(
lib::asio::async_write(
socket_con_type::get_socket(),
m_bufs,
make_custom_alloc_handler(
@@ -914,12 +931,12 @@ protected:
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_bufs.push_back(lib::asio::buffer((*it).buf,(*it).len));
}
m_write_handler = handler;
boost::asio::async_write(
lib::asio::async_write(
socket_con_type::get_socket(),
m_bufs,
make_custom_alloc_handler(
@@ -934,7 +951,7 @@ protected:
* @param ec The status code
* @param bytes_transferred The number of bytes read
*/
void handle_async_write(boost::system::error_code const & ec, size_t) {
void handle_async_write(lib::asio::error_code const & ec, size_t) {
m_bufs.clear();
lib::error_code tec;
if (ec) {
@@ -1061,10 +1078,10 @@ protected:
}
void handle_async_shutdown(timer_ptr shutdown_timer, shutdown_handler
callback, boost::system::error_code const & ec)
callback, lib::asio::error_code const & ec)
{
if (ec == boost::asio::error::operation_aborted ||
shutdown_timer->expires_from_now().is_negative())
if (ec == lib::asio::error::operation_aborted ||
lib::asio::is_neg(shutdown_timer->expires_from_now()))
{
m_alog.write(log::alevel::devel,"async_shutdown cancelled");
return;
@@ -1074,7 +1091,7 @@ protected:
lib::error_code tec;
if (ec) {
if (ec == boost::asio::error::not_connected) {
if (ec == lib::asio::error::not_connected) {
// The socket was already closed when we tried to close it. This
// happens periodically (usually if a read or write fails
// earlier and if it is a real error will be caught at another
@@ -1124,7 +1141,7 @@ private:
request_type req;
response_type res;
std::string write_buf;
boost::asio::streambuf read_buf;
lib::asio::streambuf read_buf;
long timeout_proxy;
timer_ptr timer;
};
@@ -1137,7 +1154,7 @@ private:
strand_ptr m_strand;
connection_hdl m_connection_hdl;
std::vector<boost::asio::const_buffer> m_bufs;
std::vector<lib::asio::const_buffer> m_bufs;
// Handlers
tcp_init_handler m_tcp_pre_init_handler;
+72 -66
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Peter Thorson. All rights reserved.
* Copyright (c) 2015, 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:
@@ -37,10 +37,6 @@
#include <websocketpp/common/functional.hpp>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/system/error_code.hpp>
#include <sstream>
#include <string>
@@ -48,10 +44,10 @@ namespace websocketpp {
namespace transport {
namespace asio {
/// Boost Asio based endpoint transport component
/// Asio based endpoint transport component
/**
* transport::asio::endpoint implements an endpoint transport component using
* Boost ASIO.
* Asio.
*/
template <typename config>
class endpoint : public config::socket_type {
@@ -81,15 +77,15 @@ public:
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;
typedef lib::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;
typedef lib::shared_ptr<lib::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;
typedef lib::shared_ptr<lib::asio::ip::tcp::resolver> resolver_ptr;
/// Type of timer handle
typedef lib::shared_ptr<boost::asio::deadline_timer> timer_ptr;
typedef lib::shared_ptr<lib::asio::steady_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;
typedef lib::shared_ptr<lib::asio::io_service::work> work_ptr;
// generate and manage our own io_service
explicit endpoint()
@@ -113,23 +109,28 @@ public:
/// transport::asio objects are moveable but not copyable or assignable.
/// The following code sets this situation up based on whether or not we
/// have C++11 support or not
#ifdef _WEBSOCKETPP_DELETED_FUNCTIONS_
endpoint(const endpoint& src) = delete;
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
endpoint(const endpoint & src) = delete;
endpoint& operator= (const endpoint & rhs) = delete;
#else
private:
endpoint(const endpoint& src);
endpoint& operator= (const endpoint & rhs);
endpoint(const endpoint & src);
endpoint & operator= (const endpoint & rhs);
public:
#endif
#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
#ifdef _WEBSOCKETPP_RVALUE_REFERENCES_
endpoint (endpoint&& src)
: m_io_service(src.m_io_service)
#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_
endpoint (endpoint && src)
: config::socket_type(std::move(src))
, m_tcp_pre_init_handler(src.m_tcp_pre_init_handler)
, m_tcp_post_init_handler(src.m_tcp_post_init_handler)
, m_io_service(src.m_io_service)
, m_external_io_service(src.m_external_io_service)
, m_acceptor(src.m_acceptor)
, m_listen_backlog(boost::asio::socket_base::max_connections)
, m_listen_backlog(lib::asio::socket_base::max_connections)
, m_reuse_addr(src.m_reuse_addr)
, m_elog(src.m_elog)
, m_alog(src.m_alog)
, m_state(src.m_state)
{
src.m_io_service = NULL;
@@ -138,7 +139,7 @@ public:
src.m_state = UNINITIALIZED;
}
endpoint& operator= (const endpoint && rhs) {
/*endpoint & operator= (const endpoint && rhs) {
if (this != &rhs) {
m_io_service = rhs.m_io_service;
m_external_io_service = rhs.m_external_io_service;
@@ -150,12 +151,15 @@ public:
rhs.m_io_service = NULL;
rhs.m_external_io_service = false;
rhs.m_acceptor = NULL;
rhs.m_listen_backlog = boost::asio::socket_base::max_connections;
rhs.m_listen_backlog = lib::asio::socket_base::max_connections;
rhs.m_state = UNINITIALIZED;
// TODO: this needs to be updated
}
return *this;
}
#endif
}*/
#endif // _WEBSOCKETPP_MOVE_SEMANTICS_
/// Return whether or not the endpoint produces secure connections.
bool is_secure() const {
return socket_type::is_secure();
@@ -183,7 +187,7 @@ public:
m_io_service = ptr;
m_external_io_service = true;
m_acceptor = lib::make_shared<boost::asio::ip::tcp::acceptor>(
m_acceptor = lib::make_shared<lib::asio::ip::tcp::acceptor>(
lib::ref(*m_io_service));
m_state = READY;
@@ -214,7 +218,7 @@ public:
* @param ec Set to indicate what error occurred, if any.
*/
void init_asio(lib::error_code & ec) {
init_asio(new boost::asio::io_service(), ec);
init_asio(new lib::asio::io_service(), ec);
m_external_io_service = false;
}
@@ -226,7 +230,7 @@ public:
* @see init_asio(io_service_ptr ptr)
*/
void init_asio() {
init_asio(new boost::asio::io_service());
init_asio(new lib::asio::io_service());
m_external_io_service = false;
}
@@ -325,7 +329,7 @@ public:
*
* @return A reference to the endpoint's io_service
*/
boost::asio::io_service & get_io_service() {
lib::asio::io_service & get_io_service() {
return *m_io_service;
}
@@ -337,7 +341,7 @@ public:
* @param ep An endpoint to read settings from
* @param ec Set to indicate what error occurred, if any.
*/
void listen(boost::asio::ip::tcp::endpoint const & ep, lib::error_code & ec)
void listen(lib::asio::ip::tcp::endpoint const & ep, lib::error_code & ec)
{
if (m_state != READY) {
m_elog->write(log::elevel::library,
@@ -349,11 +353,11 @@ public:
m_alog->write(log::alevel::devel,"asio::listen");
boost::system::error_code bec;
lib::asio::error_code bec;
m_acceptor->open(ep.protocol(),bec);
if (!bec) {
m_acceptor->set_option(boost::asio::socket_base::reuse_address(m_reuse_addr),bec);
m_acceptor->set_option(lib::asio::socket_base::reuse_address(m_reuse_addr),bec);
}
if (!bec) {
m_acceptor->bind(ep,bec);
@@ -379,7 +383,7 @@ public:
*
* @param ep An endpoint to read settings from
*/
void listen(boost::asio::ip::tcp::endpoint const & ep) {
void listen(lib::asio::ip::tcp::endpoint const & ep) {
lib::error_code ec;
listen(ep,ec);
if (ec) { throw exception(ec); }
@@ -392,8 +396,8 @@ public:
* listening.
*
* Common options include:
* - IPv6 with mapped IPv4 for dual stack hosts boost::asio::ip::tcp::v6()
* - IPv4 only: boost::asio::ip::tcp::v4()
* - IPv6 with mapped IPv4 for dual stack hosts lib::asio::ip::tcp::v6()
* - IPv4 only: lib::asio::ip::tcp::v4()
*
* @param internet_protocol The internet protocol to use.
* @param port The port to listen on.
@@ -403,7 +407,7 @@ public:
void listen(InternetProtocol const & internet_protocol, uint16_t port,
lib::error_code & ec)
{
boost::asio::ip::tcp::endpoint ep(internet_protocol, port);
lib::asio::ip::tcp::endpoint ep(internet_protocol, port);
listen(ep,ec);
}
@@ -414,8 +418,8 @@ public:
* listening.
*
* Common options include:
* - IPv6 with mapped IPv4 for dual stack hosts boost::asio::ip::tcp::v6()
* - IPv4 only: boost::asio::ip::tcp::v4()
* - IPv6 with mapped IPv4 for dual stack hosts lib::asio::ip::tcp::v6()
* - IPv4 only: lib::asio::ip::tcp::v4()
*
* @param internet_protocol The internet protocol to use.
* @param port The port to listen on.
@@ -423,7 +427,7 @@ public:
template <typename InternetProtocol>
void listen(InternetProtocol const & internet_protocol, uint16_t port)
{
boost::asio::ip::tcp::endpoint ep(internet_protocol, port);
lib::asio::ip::tcp::endpoint ep(internet_protocol, port);
listen(ep);
}
@@ -440,7 +444,7 @@ public:
* @param ec Set to indicate what error occurred, if any.
*/
void listen(uint16_t port, lib::error_code & ec) {
listen(boost::asio::ip::tcp::v6(), port, ec);
listen(lib::asio::ip::tcp::v6(), port, ec);
}
/// Set up endpoint for listening on a port
@@ -456,13 +460,13 @@ public:
* @param ec Set to indicate what error occurred, if any.
*/
void listen(uint16_t port) {
listen(boost::asio::ip::tcp::v6(), port);
listen(lib::asio::ip::tcp::v6(), port);
}
/// Set up endpoint for listening on a host and service (exception free)
/**
* Bind the internal acceptor using the given host and service. More details
* about what host and service can be are available in the boost asio
* about what host and service can be are available in the Asio
* documentation for ip::basic_resolver_query::basic_resolver_query's
* constructors.
*
@@ -478,7 +482,7 @@ public:
void listen(std::string const & host, std::string const & service,
lib::error_code & ec)
{
using boost::asio::ip::tcp;
using lib::asio::ip::tcp;
tcp::resolver r(*m_io_service);
tcp::resolver::query query(host, service);
tcp::resolver::iterator endpoint_iterator = r.resolve(query);
@@ -495,7 +499,7 @@ public:
/// Set up endpoint for listening on a host and service
/**
* Bind the internal acceptor using the given host and service. More details
* about what host and service can be are available in the boost asio
* about what host and service can be are available in the Asio
* documentation for ip::basic_resolver_query::basic_resolver_query's
* constructors.
*
@@ -609,7 +613,7 @@ public:
* @since 0.3.0
*/
void start_perpetual() {
m_work = lib::make_shared<boost::asio::io_service::work>(
m_work = lib::make_shared<lib::asio::io_service::work>(
lib::ref(*m_io_service)
);
}
@@ -639,9 +643,9 @@ public:
* needed.
*/
timer_ptr set_timer(long duration, timer_handler callback) {
timer_ptr new_timer = lib::make_shared<boost::asio::deadline_timer>(
timer_ptr new_timer = lib::make_shared<lib::asio::steady_timer>(
*m_io_service,
boost::posix_time::milliseconds(duration)
lib::asio::milliseconds(duration)
);
new_timer->async_wait(
@@ -667,10 +671,10 @@ public:
* @param ec A status code indicating an error, if any.
*/
void handle_timer(timer_ptr, timer_handler callback,
boost::system::error_code const & ec)
lib::asio::error_code const & ec)
{
if (ec) {
if (ec == boost::asio::error::operation_aborted) {
if (ec == lib::asio::error::operation_aborted) {
callback(make_error_code(transport::error::operation_aborted));
} else {
m_elog->write(log::elevel::info,
@@ -749,18 +753,18 @@ protected:
m_elog = e;
}
void handle_accept(accept_handler callback, boost::system::error_code const
& boost_ec)
void handle_accept(accept_handler callback, lib::asio::error_code const &
asio_ec)
{
lib::error_code ret_ec;
m_alog->write(log::alevel::devel, "asio::handle_accept");
if (boost_ec) {
if (boost_ec == boost::system::errc::operation_canceled) {
if (asio_ec) {
if (asio_ec == lib::asio::errc::operation_canceled) {
ret_ec = make_error_code(websocketpp::error::operation_canceled);
} else {
log_err(log::elevel::info,"asio handle_accept",boost_ec);
log_err(log::elevel::info,"asio handle_accept",asio_ec);
ret_ec = make_error_code(error::pass_through);
}
}
@@ -771,14 +775,16 @@ protected:
/// Initiate a new connection
// TODO: there have to be some more failure conditions here
void async_connect(transport_con_ptr tcon, uri_ptr u, connect_handler cb) {
using namespace boost::asio::ip;
using namespace lib::asio::ip;
// Create a resolver
if (!m_resolver) {
m_resolver = lib::make_shared<boost::asio::ip::tcp::resolver>(
m_resolver = lib::make_shared<lib::asio::ip::tcp::resolver>(
lib::ref(*m_io_service));
}
tcon->set_uri(u);
std::string proxy = tcon->get_proxy();
std::string host;
std::string port;
@@ -888,11 +894,11 @@ protected:
}
void handle_resolve(transport_con_ptr tcon, timer_ptr dns_timer,
connect_handler callback, boost::system::error_code const & ec,
boost::asio::ip::tcp::resolver::iterator iterator)
connect_handler callback, lib::asio::error_code const & ec,
lib::asio::ip::tcp::resolver::iterator iterator)
{
if (ec == boost::asio::error::operation_aborted ||
dns_timer->expires_from_now().is_negative())
if (ec == lib::asio::error::operation_aborted ||
lib::asio::is_neg(dns_timer->expires_from_now()))
{
m_alog->write(log::alevel::devel,"async_resolve cancelled");
return;
@@ -910,7 +916,7 @@ protected:
std::stringstream s;
s << "Async DNS resolve successful. Results: ";
boost::asio::ip::tcp::resolver::iterator it, end;
lib::asio::ip::tcp::resolver::iterator it, end;
for (it = iterator; it != end; ++it) {
s << (*it).endpoint() << " ";
}
@@ -935,7 +941,7 @@ protected:
);
if (config::enable_multithreading) {
boost::asio::async_connect(
lib::asio::async_connect(
tcon->get_raw_socket(),
iterator,
tcon->get_strand()->wrap(lib::bind(
@@ -948,7 +954,7 @@ protected:
))
);
} else {
boost::asio::async_connect(
lib::asio::async_connect(
tcon->get_raw_socket(),
iterator,
lib::bind(
@@ -997,10 +1003,10 @@ protected:
}
void handle_connect(transport_con_ptr tcon, timer_ptr con_timer,
connect_handler callback, boost::system::error_code const & ec)
connect_handler callback, lib::asio::error_code const & ec)
{
if (ec == boost::asio::error::operation_aborted ||
con_timer->expires_from_now().is_negative())
if (ec == lib::asio::error::operation_aborted ||
lib::asio::is_neg(con_timer->expires_from_now()))
{
m_alog->write(log::alevel::devel,"async_connect cancelled");
return;
+7 -3
View File
@@ -34,8 +34,6 @@
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/common/connection_hdl.hpp>
#include <boost/asio.hpp>
#include <string>
// Interface that sockets/security policies must implement
@@ -56,6 +54,7 @@
// Connection
// TODO
// set_hostname(std::string hostname)
// pre_init(init_handler);
// post_init(init_handler);
@@ -97,7 +96,10 @@ namespace error {
missing_tls_init_handler,
/// TLS Handshake Failed
tls_handshake_failed
tls_handshake_failed,
/// Failed to set TLS SNI hostname
tls_failed_sni_hostname
};
} // namespace error
@@ -126,6 +128,8 @@ public:
return "Required tls_init handler not present.";
case error::tls_handshake_failed:
return "TLS handshake failed";
case error::tls_failed_sni_hostname:
return "Failed to set TLS SNI hostname";
default:
return "Unknown";
}
+40 -26
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Peter Thorson. All rights reserved.
* Copyright (c) 2015, 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:
@@ -28,12 +28,13 @@
#ifndef WEBSOCKETPP_TRANSPORT_SECURITY_NONE_HPP
#define WEBSOCKETPP_TRANSPORT_SECURITY_NONE_HPP
#include <websocketpp/uri.hpp>
#include <websocketpp/transport/asio/security/base.hpp>
#include <websocketpp/common/asio.hpp>
#include <websocketpp/common/memory.hpp>
#include <boost/asio.hpp>
#include <sstream>
#include <string>
@@ -45,13 +46,13 @@ namespace asio {
namespace basic_socket {
/// The signature of the socket init handler for this socket policy
typedef lib::function<void(connection_hdl,boost::asio::ip::tcp::socket&)>
typedef lib::function<void(connection_hdl,lib::asio::ip::tcp::socket&)>
socket_init_handler;
/// Basic Boost ASIO connection socket component
/// Basic Asio connection socket component
/**
* transport::asio::basic_socket::connection implements a connection socket
* component using Boost ASIO ip::tcp::socket.
* component using Asio ip::tcp::socket.
*/
class connection : public lib::enable_shared_from_this<connection> {
public:
@@ -60,12 +61,12 @@ public:
/// Type of a shared pointer to this connection socket component
typedef lib::shared_ptr<type> ptr;
/// 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 io_service strand being used
typedef lib::shared_ptr<boost::asio::io_service::strand> strand_ptr;
/// Type of a pointer to the Asio io_service being used
typedef lib::asio::io_service* io_service_ptr;
/// Type of a pointer to the Asio io_service strand being used
typedef lib::shared_ptr<lib::asio::io_service::strand> strand_ptr;
/// Type of the ASIO socket being used
typedef boost::asio::ip::tcp::socket socket_type;
typedef lib::asio::ip::tcp::socket socket_type;
/// Type of a shared pointer to the socket being used.
typedef lib::shared_ptr<socket_type> socket_ptr;
@@ -91,7 +92,7 @@ public:
/**
* The socket initialization handler is called after the socket object is
* created but before it is used. This gives the application a chance to
* set any ASIO socket options it needs.
* set any Asio socket options it needs.
*
* @param h The new socket_init_handler
*/
@@ -103,7 +104,7 @@ public:
/**
* This is used internally. It can also be used to set socket options, etc
*/
boost::asio::ip::tcp::socket& get_socket() {
lib::asio::ip::tcp::socket & get_socket() {
return *m_socket;
}
@@ -111,7 +112,7 @@ public:
/**
* This is used internally.
*/
boost::asio::ip::tcp::socket& get_next_layer() {
lib::asio::ip::tcp::socket & get_next_layer() {
return *m_socket;
}
@@ -119,7 +120,7 @@ public:
/**
* This is used internally. It can also be used to set socket options, etc
*/
boost::asio::ip::tcp::socket& get_raw_socket() {
lib::asio::ip::tcp::socket & get_raw_socket() {
return *m_socket;
}
@@ -133,16 +134,16 @@ public:
*
* @return A string identifying the address of the remote endpoint
*/
std::string get_remote_endpoint(lib::error_code &ec) const {
std::string get_remote_endpoint(lib::error_code & ec) const {
std::stringstream s;
boost::system::error_code bec;
boost::asio::ip::tcp::endpoint ep = m_socket->remote_endpoint(bec);
lib::asio::error_code aec;
lib::asio::ip::tcp::endpoint ep = m_socket->remote_endpoint(aec);
if (bec) {
if (aec) {
ec = error::make_error_code(error::pass_through);
s << "Error getting remote endpoint: " << bec
<< " (" << bec.message() << ")";
s << "Error getting remote endpoint: " << aec
<< " (" << aec.message() << ")";
return s.str();
} else {
ec = lib::error_code();
@@ -154,7 +155,7 @@ protected:
/// Perform one time initializations
/**
* init_asio is called once immediately after construction to initialize
* boost::asio components to the io_service
* Asio components to the io_service
*
* @param service A pointer to the endpoint's io_service
* @param strand A shared pointer to the connection's asio strand
@@ -166,7 +167,7 @@ protected:
return socket::make_error_code(socket::error::invalid_state);
}
m_socket = lib::make_shared<boost::asio::ip::tcp::socket>(
m_socket = lib::make_shared<lib::asio::ip::tcp::socket>(
lib::ref(*service));
m_state = READY;
@@ -174,6 +175,19 @@ protected:
return lib::error_code();
}
/// Set uri hook
/**
* Called by the transport as a connection is being established to provide
* the uri being connected to to the security/socket layer.
*
* This socket policy doesn't use the uri so it is ignored.
*
* @since 0.6.0
*
* @param u The uri to set
*/
void set_uri(uri_ptr) {}
/// Pre-initialize security policy
/**
* Called by the transport after a new connection is created to initialize
@@ -227,8 +241,8 @@ protected:
}
void async_shutdown(socket_shutdown_handler h) {
boost::system::error_code ec;
m_socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both,ec);
lib::asio::error_code ec;
m_socket->shutdown(lib::asio::ip::tcp::socket::shutdown_both, ec);
h(ec);
}
@@ -248,7 +262,7 @@ protected:
* @param ec The error code to translate_ec
* @return The translated error code
*/
lib::error_code translate_ec(boost::system::error_code) {
lib::error_code translate_ec(lib::asio::error_code) {
// We don't know any more information about this error so pass through
return make_error_code(transport::error::pass_through);
}
+62 -32
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Peter Thorson. All rights reserved.
* Copyright (c) 2015, 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:
@@ -30,14 +30,14 @@
#include <websocketpp/transport/asio/security/base.hpp>
#include <websocketpp/uri.hpp>
#include <websocketpp/common/asio.hpp>
#include <websocketpp/common/asio_ssl.hpp>
#include <websocketpp/common/connection_hdl.hpp>
#include <websocketpp/common/functional.hpp>
#include <websocketpp/common/memory.hpp>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/system/error_code.hpp>
#include <sstream>
#include <string>
@@ -49,16 +49,16 @@ namespace asio {
namespace tls_socket {
/// The signature of the socket_init_handler for this socket policy
typedef lib::function<void(connection_hdl,boost::asio::ssl::stream<
boost::asio::ip::tcp::socket>&)> socket_init_handler;
typedef lib::function<void(connection_hdl,lib::asio::ssl::stream<
lib::asio::ip::tcp::socket>&)> socket_init_handler;
/// The signature of the tls_init_handler for this socket policy
typedef lib::function<lib::shared_ptr<boost::asio::ssl::context>(connection_hdl)>
typedef lib::function<lib::shared_ptr<lib::asio::ssl::context>(connection_hdl)>
tls_init_handler;
/// TLS enabled Boost ASIO connection socket component
/**
* transport::asio::tls_socket::connection implements a secure connection socket
* component that uses Boost ASIO's ssl::stream to wrap an ip::tcp::socket.
* component that uses Asio's ssl::stream to wrap an ip::tcp::socket.
*/
class connection : public lib::enable_shared_from_this<connection> {
public:
@@ -68,17 +68,15 @@ public:
typedef lib::shared_ptr<type> ptr;
/// Type of the ASIO socket being used
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_type;
typedef lib::asio::ssl::stream<lib::asio::ip::tcp::socket> socket_type;
/// Type of a shared pointer to the ASIO socket being used
typedef lib::shared_ptr<socket_type> socket_ptr;
/// Type of a pointer to the ASIO io_service being used
typedef boost::asio::io_service* io_service_ptr;
typedef lib::asio::io_service * io_service_ptr;
/// Type of a pointer to the ASIO io_service strand being used
typedef lib::shared_ptr<boost::asio::io_service::strand> strand_ptr;
typedef lib::shared_ptr<lib::asio::io_service::strand> strand_ptr;
/// Type of a shared pointer to the ASIO TLS context being used
typedef lib::shared_ptr<boost::asio::ssl::context> context_ptr;
typedef boost::system::error_code boost_error;
typedef lib::shared_ptr<lib::asio::ssl::context> context_ptr;
explicit connection() {
//std::cout << "transport::asio::tls_socket::connection constructor"
@@ -102,7 +100,7 @@ public:
/**
* This is used internally. It can also be used to set socket options, etc
*/
socket_type::lowest_layer_type& get_raw_socket() {
socket_type::lowest_layer_type & get_raw_socket() {
return m_socket->lowest_layer();
}
@@ -110,7 +108,7 @@ public:
/**
* This is used internally.
*/
socket_type::next_layer_type& get_next_layer() {
socket_type::next_layer_type & get_next_layer() {
return m_socket->next_layer();
}
@@ -118,7 +116,7 @@ public:
/**
* This is used internally.
*/
socket_type& get_socket() {
socket_type & get_socket() {
return *m_socket;
}
@@ -157,16 +155,16 @@ public:
*
* @return A string identifying the address of the remote endpoint
*/
std::string get_remote_endpoint(lib::error_code &ec) const {
std::string get_remote_endpoint(lib::error_code & ec) const {
std::stringstream s;
boost::system::error_code bec;
boost::asio::ip::tcp::endpoint ep = m_socket->lowest_layer().remote_endpoint(bec);
lib::asio::error_code aec;
lib::asio::ip::tcp::endpoint ep = m_socket->lowest_layer().remote_endpoint(aec);
if (bec) {
if (aec) {
ec = error::make_error_code(error::pass_through);
s << "Error getting remote endpoint: " << bec
<< " (" << bec.message() << ")";
s << "Error getting remote endpoint: " << aec
<< " (" << aec.message() << ")";
return s.str();
} else {
ec = lib::error_code();
@@ -178,7 +176,7 @@ protected:
/// Perform one time initializations
/**
* init_asio is called once immediately after construction to initialize
* boost::asio components to the io_service
* Asio components to the io_service
*
* @param service A pointer to the endpoint's io_service
* @param strand A pointer to the connection's strand
@@ -205,6 +203,22 @@ protected:
return lib::error_code();
}
/// Set hostname hook
/**
* Called by the transport as a connection is being established to provide
* the hostname being connected to to the security/socket layer.
*
* This socket policy uses the hostname to set the appropriate TLS SNI
* header.
*
* @since 0.6.0
*
* @param u The uri to set
*/
void set_uri(uri_ptr u) {
m_uri = u;
}
/// Pre-initialize security policy
/**
* Called by the transport after a new connection is created to initialize
@@ -215,6 +229,22 @@ protected:
* @param callback Handler to call back with completion information
*/
void pre_init(init_handler callback) {
// TODO: is this the best way to check whether this function is
// available in the version of OpenSSL being used?
// TODO: consider case where host is an IP address
#if OPENSSL_VERSION_NUMBER >= 0x90812f
if (!m_is_server) {
// For clients on systems with a suitable OpenSSL version, set the
// TLS SNI hostname header so connecting to TLS servers using SNI
// will work.
long res = SSL_set_tlsext_host_name(
get_socket().native_handle(), m_uri->get_host().c_str());
if (!(1 == res)) {
callback(socket::make_error_code(socket::error::tls_failed_sni_hostname));
}
}
#endif
if (m_socket_init_handler) {
m_socket_init_handler(m_hdl,get_socket());
}
@@ -266,8 +296,7 @@ protected:
m_hdl = hdl;
}
void handle_init(init_handler callback,boost::system::error_code const & ec)
{
void handle_init(init_handler callback,lib::asio::error_code const & ec) {
if (ec) {
m_ec = socket::make_error_code(socket::error::tls_handshake_failed);
} else {
@@ -306,7 +335,7 @@ protected:
* @return The translated error code
*/
lib::error_code translate_ec(boost::system::error_code ec) {
if (ec.category() == boost::asio::error::get_ssl_category()) {
if (ec.category() == lib::asio::error::get_ssl_category()) {
if (ERR_GET_REASON(ec.value()) == SSL_R_SHORT_READ) {
return make_error_code(transport::error::tls_short_read);
} else {
@@ -323,9 +352,9 @@ protected:
private:
socket_type::handshake_type get_handshake_type() {
if (m_is_server) {
return boost::asio::ssl::stream_base::server;
return lib::asio::ssl::stream_base::server;
} else {
return boost::asio::ssl::stream_base::client;
return lib::asio::ssl::stream_base::client;
}
}
@@ -333,6 +362,7 @@ private:
strand_ptr m_strand;
context_ptr m_context;
socket_ptr m_socket;
uri_ptr m_uri;
bool m_is_server;
lib::error_code m_ec;
@@ -342,10 +372,10 @@ private:
tls_init_handler m_tls_init_handler;
};
/// TLS enabled Boost ASIO endpoint socket component
/// TLS enabled Asio endpoint socket component
/**
* transport::asio::tls_socket::endpoint implements a secure endpoint socket
* component that uses Boost ASIO's ssl::stream to wrap an ip::tcp::socket.
* component that uses Asio's ssl::stream to wrap an ip::tcp::socket.
*/
class endpoint {
public:
@@ -32,6 +32,7 @@
#include <websocketpp/transport/base/connection.hpp>
#include <websocketpp/uri.hpp>
#include <websocketpp/logger/levels.hpp>
#include <websocketpp/common/connection_hdl.hpp>
@@ -103,6 +104,20 @@ public:
return false;
}
/// Set uri hook
/**
* Called by the endpoint as a connection is being established to provide
* the uri being connected to to the transport layer.
*
* Implementation is optional and can be ignored if the transport has no
* need for this information.
*
* @since 0.6.0
*
* @param u The uri to set
*/
void set_uri(uri_ptr) {}
/// Set human readable remote endpoint address
/**
* Sets the remote endpoint address returned by `get_remote_endpoint`. This
+14 -2
View File
@@ -33,7 +33,10 @@
#include <websocketpp/common/functional.hpp>
#include <websocketpp/common/connection_hdl.hpp>
#include <websocketpp/transport/base/connection.hpp>
#include <string>
#include <vector>
namespace websocketpp {
namespace transport {
@@ -41,10 +44,19 @@ namespace transport {
namespace iostream {
/// The type and signature of the callback used by iostream transport to write
typedef lib::function<lib::error_code(connection_hdl, char const *, size_t)>
typedef lib::function<lib::error_code(connection_hdl, char const *, size_t)>
write_handler;
/// The type and signature of the callback used by iostream transport to signal
/// The type and signature of the callback used by iostream transport to perform
/// vectored writes.
/**
* If a vectored write handler is not set the standard write handler will be
* called multiple times.
*/
typedef lib::function<lib::error_code(connection_hdl, std::vector<transport::buffer> const
& bufs)> vector_write_handler;
/// The type and signature of the callback used by iostream transport to signal
/// a transport shutdown.
typedef lib::function<lib::error_code(connection_hdl)> shutdown_handler;
+65 -12
View File
@@ -32,6 +32,8 @@
#include <websocketpp/transport/base/connection.hpp>
#include <websocketpp/uri.hpp>
#include <websocketpp/logger/levels.hpp>
#include <websocketpp/common/connection_hdl.hpp>
@@ -105,6 +107,19 @@ public:
m_output_stream = o;
}
/// Set uri hook
/**
* Called by the endpoint as a connection is being established to provide
* the uri being connected to to the transport layer.
*
* This transport policy doesn't use the uri so it is ignored.
*
* @since 0.6.0
*
* @param u The uri to set
*/
void set_uri(uri_ptr) {}
/// Overloaded stream input operator
/**
* Attempts to read input from the given stream into the transport. Bytes
@@ -153,7 +168,7 @@ public:
return this->read_some_impl(buf,len);
}
/// Manual input supply (read all)
/**
* Similar to read_some, but continues to read until all bytes in the
@@ -173,7 +188,7 @@ public:
size_t read_all(char const * buf, size_t len) {
// this serializes calls to external read.
scoped_lock_type lock(m_read_mutex);
size_t total_read = 0;
size_t temp_read = 0;
@@ -312,25 +327,60 @@ public:
timer_ptr set_timer(long, timer_handler) {
return timer_ptr();
}
/// Sets the write handler
/**
* The write handler is called when the iostream transport receives data
* that needs to be written to the appropriate output location. This handler
* can be used in place of registering an ostream for output.
*
* The signature of the handler is
* The signature of the handler is
* `lib::error_code (connection_hdl, char const *, size_t)` The
* code returned will be reported and logged by the core library.
*
* See also, set_vector_write_handler, for an optional write handler that
* allows more efficient handling of multiple writes at once.
*
* @see set_vector_write_handler
*
* @since 0.5.0
*
* @param h The handler to call on connection shutdown.
* @param h The handler to call when data is to be written.
*/
void set_write_handler(write_handler h) {
m_write_handler = h;
}
/// Sets the vectored write handler
/**
* The vectored write handler is called when the iostream transport receives
* multiple chunks of data that need to be written to the appropriate output
* location. This handler can be used in conjunction with the write_handler
* in place of registering an ostream for output.
*
* The sequence of buffers represents bytes that should be written
* consecutively and it is suggested to group the buffers into as few next
* layer packets as possible. Vector write is used to allow implementations
* that support it to coalesce writes into a single TCP packet or TLS
* segment for improved efficiency.
*
* This is an optional handler. If it is not defined then multiple calls
* will be made to the standard write handler.
*
* The signature of the handler is
* `lib::error_code (connection_hdl, std::vector<websocketpp::transport::buffer>
* const & bufs)`. The code returned will be reported and logged by the core
* library. The `websocketpp::transport::buffer` type is a struct with two
* data members. buf (char const *) and len (size_t).
*
* @since 0.6.0
*
* @param h The handler to call when vectored data is to be written.
*/
void set_vector_write_handler(vector_write_handler h) {
m_vector_write_handler = h;
}
/// Sets the shutdown handler
/**
* The shutdown handler is called when the iostream transport receives a
@@ -434,7 +484,7 @@ protected:
* @param len number of bytes to write
* @param handler Callback to invoke with operation status.
*/
void async_write(char const * buf, size_t len, transport::write_handler
void async_write(char const * buf, size_t len, transport::write_handler
handler)
{
m_alog.write(log::alevel::devel,"iostream_con async_write");
@@ -444,7 +494,7 @@ protected:
if (m_output_stream) {
m_output_stream->write(buf,len);
if (m_output_stream->bad()) {
ec = make_error_code(error::bad_stream);
}
@@ -492,17 +542,19 @@ protected:
break;
}
}
} else if (m_vector_write_handler) {
ec = m_vector_write_handler(m_connection_hdl, bufs);
} else if (m_write_handler) {
std::vector<buffer>::const_iterator it;
for (it = bufs.begin(); it != bufs.end(); it++) {
ec = m_write_handler(m_connection_hdl, (*it).buf, (*it).len);
if (ec) {break;}
}
} else {
ec = make_error_code(error::output_stream_required);
}
handler(ec);
}
@@ -540,11 +592,11 @@ protected:
*/
void async_shutdown(transport::shutdown_handler handler) {
lib::error_code ec;
if (m_shutdown_handler) {
ec = m_shutdown_handler(m_connection_hdl);
}
handler(ec);
}
private:
@@ -636,6 +688,7 @@ private:
std::ostream * m_output_stream;
connection_hdl m_connection_hdl;
write_handler m_write_handler;
vector_write_handler m_vector_write_handler;
shutdown_handler m_shutdown_handler;
bool m_reading;
+14
View File
@@ -103,6 +103,20 @@ public:
return false;
}
/// Set uri hook
/**
* Called by the endpoint as a connection is being established to provide
* the uri being connected to to the transport layer.
*
* Implementation is optional and can be ignored if the transport has no
* need for this information.
*
* @since 0.6.0
*
* @param u The uri to set
*/
void set_uri(uri_ptr) {}
/// Set human readable remote endpoint address
/**
* Sets the remote endpoint address returned by `get_remote_endpoint`. This
+3 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Peter Thorson. All rights reserved.
* Copyright (c) 2015, 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:
@@ -42,7 +42,7 @@ namespace websocketpp {
/// Library major version number
static int const major_version = 0;
/// Library minor version number
static int const minor_version = 5;
static int const minor_version = 6;
/// Library patch version number
static int const patch_version = 1;
/// Library pre-release flag
@@ -53,7 +53,7 @@ static int const patch_version = 1;
static char const prerelease_flag[] = "";
/// Default user agent string
static char const user_agent[] = "WebSocket++/0.5.1";
static char const user_agent[] = "WebSocket++/0.6.0";
} // namespace websocketpp