Compare commits

...

30 Commits

Author SHA1 Message Date
Peter Thorson abf927bb24 Fix some bugs, normalize code style, update documentation, add tests
Method needs to be public to be useful, updated return type to const
reference for efficiency
2016-10-14 08:27:06 -05:00
Jupp Müller e1f75756d1 Expose HTTP request headers
This change allows users to get a full list of HTTP request headers
allowing libraries that build on top of websocketpp to pass those on
to their users without exposing access to the already existing getter
methods.
2016-10-14 13:17:28 +02:00
Peter Thorson 322e3bafbf Update telemetry_client to use Sleep on windows references #574 2016-10-04 07:41:02 -05:00
Peter Thorson 9019af0070 Add FAQ entry 2016-10-03 19:04:27 -05:00
Peter Thorson e65b277017 Remove catching websocketpp::lib::error_code in examples, fixes #584
A few versions ago the library was standardized to only throw
websocketpp::exception. Not all example code was updated.
2016-10-03 19:04:12 -05:00
Peter Thorson 8434139b67 Add first draft of print_client and print_client_tls 2016-06-10 07:24:36 -04:00
Peter Thorson d4a4b79684 update changelog for recent PR 2016-06-09 09:22:17 -04:00
Peter Thorson 6b09310479 Merge pull request #553 from yeswalrus/fix-tls-crash
Fix server_endpoint crash on connection failure
2016-06-09 09:08:12 -04:00
Peter Thorson 2b310fa80b Merge branch 'develop' of https://github.com/zaphoyd/websocketpp into develop 2016-05-25 08:11:20 -04:00
Peter Thorson 0bb33e4bca Change default listen backlog to socket_base::max_connections from 0, fixes #549
After a change in Linux Kernel 4.4 the value of 0 causes all
connections to be rejected rather than the default value being used.
The default is now the asio::socket_base::max_connections value instead
(which is the default asio uses when no value is provided).
Documentation has been updated accordingly.
2016-05-25 08:10:47 -04:00
Walter Gray ebd0afd67d Check the return of get_connection, raise an appropriate error if it failed. 2016-05-19 16:00:20 -07:00
Walter Gray 5f42305bbd remove trailing whitespaces 2016-05-19 13:47:20 -07:00
Peter Thorson a2f182733a Merge pull request #550 from wal-rus/fix-cmake
Fix CMake config files
2016-05-18 08:38:11 -04:00
Walter Gray 59fb9ece5d Added interface target to config file for cmake versions > 3.0 2016-05-11 16:54:41 -07:00
Walter Gray 73c3b81411 Added include directories to targets (How was this ever working?) 2016-05-11 16:54:40 -07:00
Walter Gray cc851aa167 remove whitespace at end of lines in CMakeHelpers.cmake 2016-05-11 16:54:39 -07:00
Walter Gray 0f2df92ae4 Use CMakePackageConfigHelpers, make websocketpp-config.cmake.in relocatable 2016-05-11 16:54:39 -07:00
Walter Gray 6b702cc050 Updated minimum required version to 2.8.8, Added VERSION argument to project if supported. 2016-05-11 16:54:38 -07:00
Walter Gray 92c1f0c415 Fix default CMAKE_INSTALL_PREFIX setting on windows 2016-05-10 13:44:25 -07:00
Peter Thorson 9e5163364f Add logging reference documentation 2016-04-27 09:00:30 -04:00
Peter Thorson 8f0fab3e77 Update docs & FAQ 2016-04-23 08:05:01 -04:00
Peter Thorson 94fe989840 Store loggers in shared pointers references #501 #537
adds related changelog entry and fix one overzealous find and replace
operation.
2016-04-06 09:38:45 -04:00
Peter Thorson 9da5ac93ec Merge pull request #539 from jupp0r/feature/shutdown-fix-for-shared-ioservice
Fix shutdown bugs by holding loggers in shared_ptrs
2016-04-06 09:27:35 -04:00
Peter Thorson 891a7a5ed5 documentation 2016-04-03 11:39:46 -04:00
Jupp Müller 1013aa89bc Fix shutdown bugs by holding loggers in shared_ptrs
This change fixes a shutdown crash occuring when using an
external io_service to drive a websocketpp server. The crash
itself is reproduced by the following code:

```

int main(int argc, const char * argv[])
{
    boost::asio::io_service ioService;
        std::unique_ptr<boost::asio::io_service::work> ioServiceWork(new boost::asio::io_service::work(ioService));
            std::thread ioServiceThread(boost::bind(&boost::asio::io_service::run, &ioService));

    {
        auto server = std::unique_ptr<websocketpp::server<websocketpp::config::asio>>(new websocketpp::server<websocketpp::config::asio>());
        server->init_asio(&ioService);
        server->listen(0);
        server->start_accept();

        server->stop();
    }

    ioServiceWork.reset();
    ioService.stop();
    ioServiceThread.join();

    return 0;
}
```

The cause of the crash is a dangling pointer to alog or elog objects in endpoints.
This is mitigated by storing logging objects as shared_ptrs. This ensures that
they are kept alive and able to log even if their owning structures have already
been deallocated.
2016-03-31 16:49:16 +02:00
Peter Thorson 366679b50a Update docs and changelog 2016-03-31 09:57:45 -04:00
Peter Thorson 94cc1ec5cb Fix an issue detecting which version of the chrono library to use references #512
If we are using Boost for Asio, the
websocketpp::lib::asio::milliseconds function should return a chrono
milliseconds object using whatever chrono library boost is using.

Boost does its own autodetection of the std::chrono library and prefers
it over boost::chrono when available. This change checks which chrono
library boost is using and uses that. Otherwise it falls back to the
websocketpp default.
2016-03-31 09:55:07 -04:00
Peter Thorson 6f128a5499 Move socket_init_handler from pre_init to init_asio #530
pre_init happens after bind/listen/accept, preventing socket options
that affect those system calls from being set in time.
2016-02-26 06:37:34 -05:00
Peter Thorson f5d14f3ad3 Bump develop branch version 2016-02-26 06:30:44 -05:00
Peter Thorson 918745a7ea Add test case for un-setting a handler (with NULL) 2016-02-26 06:20:53 -05:00
54 changed files with 1356 additions and 437 deletions
+40 -23
View File
@@ -1,18 +1,42 @@
############ Setup project and cmake
# Project name
project (websocketpp)
# Minimum cmake requirement. We should require a quite recent
# cmake for the dependency find macros etc. to be up to date.
cmake_minimum_required (VERSION 2.6)
cmake_minimum_required (VERSION 2.8.8)
############ Paths
set (WEBSOCKETPP_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
set (WEBSOCKETPP_INCLUDE ${WEBSOCKETPP_ROOT}/websocketpp)
set (WEBSOCKETPP_BUILD_ROOT ${CMAKE_CURRENT_BINARY_DIR})
set (WEBSOCKETPP_BIN ${WEBSOCKETPP_BUILD_ROOT}/bin)
set (WEBSOCKETPP_LIB ${WEBSOCKETPP_BUILD_ROOT}/lib)
# CMake install step prefix. I assume linux users want the prefix to
# be the default /usr or /usr/local so this is only adjusted on Windows.
# This must be set prior to any call to project or it will not be read correctly.
# - Windows: Build the INSTALL project in your solution file.
# - Linux/OSX: make install.
if (WIN32)
set (CMAKE_INSTALL_PREFIX "${WEBSOCKETPP_ROOT}/install" CACHE PATH "")
endif ()
############ Project name and version
set (WEBSOCKETPP_MAJOR_VERSION 0)
set (WEBSOCKETPP_MINOR_VERSION 7)
set (WEBSOCKETPP_MINOR_VERSION 8)
set (WEBSOCKETPP_PATCH_VERSION 0)
set (WEBSOCKETPP_VERSION ${WEBSOCKETPP_MAJOR_VERSION}.${WEBSOCKETPP_MINOR_VERSION}.${WEBSOCKETPP_PATCH_VERSION})
if(POLICY CMP0048)
cmake_policy(GET CMP0048 _version_policy)
endif()
if(_version_allowed STREQUAL NEW)
project (websocketpp VERSION ${WEBSOCKETPP_VERSION})
else()
project (websocketpp)
endif()
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set(INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for header files")
@@ -44,21 +68,6 @@ set (CMAKE_CONFIGURATION_TYPES "Release;RelWithDebInfo;Debug" CACHE STRING "Conf
set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
include (CMakeHelpers)
############ Paths
set (WEBSOCKETPP_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
set (WEBSOCKETPP_INCLUDE ${WEBSOCKETPP_ROOT}/websocketpp)
set (WEBSOCKETPP_BUILD_ROOT ${CMAKE_CURRENT_BINARY_DIR})
set (WEBSOCKETPP_BIN ${WEBSOCKETPP_BUILD_ROOT}/bin)
set (WEBSOCKETPP_LIB ${WEBSOCKETPP_BUILD_ROOT}/lib)
# CMake install step prefix. I assume linux users want the prefix to
# be the default /usr or /usr/local so this is only adjusted on Windows.
# - Windows: Build the INSTALL project in your solution file.
# - Linux/OSX: make install.
if (MSVC)
set (CMAKE_INSTALL_PREFIX "${WEBSOCKETPP_ROOT}/install")
endif ()
############ Build customization
@@ -250,8 +259,16 @@ print_used_build_config()
export (PACKAGE websocketpp)
configure_file (websocketpp-config.cmake.in "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/websocketpp-config.cmake" @ONLY)
configure_file (websocketpp-configVersion.cmake.in "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/websocketpp-configVersion.cmake" @ONLY)
include(CMakePackageConfigHelpers)
configure_package_config_file(websocketpp-config.cmake.in
"${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/websocketpp-config.cmake"
PATH_VARS INSTALL_INCLUDE_DIR
INSTALL_DESTINATION "${INSTALL_CMAKE_DIR}"
NO_CHECK_REQUIRED_COMPONENTS_MACRO
)
write_basic_package_version_file("${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/websocketpp-configVersion.cmake"
VERSION ${WEBSOCKETPP_VERSION}
COMPATIBILITY ExactVersion)
# Install the websocketpp-config.cmake and websocketpp-configVersion.cmake
install (FILES
+1 -1
View File
@@ -38,7 +38,7 @@ PROJECT_NAME = WebSocket++
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = 0.7.0
PROJECT_NUMBER = 0.8.0-dev
# 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 a
+4
View File
@@ -234,10 +234,14 @@ echo_server = SConscript('#/examples/echo_server/SConscript',variant_dir = build
# echo_client
echo_client = SConscript('#/examples/echo_client/SConscript',variant_dir = builddir + 'echo_client',duplicate = 0)
# print_client
print_client = SConscript('#/examples/print_client/SConscript',variant_dir = builddir + 'print_client',duplicate = 0)
# echo_server_tls
if tls_build:
echo_server_tls = SConscript('#/examples/echo_server_tls/SConscript',variant_dir = builddir + 'echo_server_tls',duplicate = 0)
echo_server_both = SConscript('#/examples/echo_server_both/SConscript',variant_dir = builddir + 'echo_server_both',duplicate = 0)
print_client_tls = SConscript('#/examples/print_client_tls/SConscript',variant_dir = builddir + 'print_client_tls',duplicate = 0)
# broadcast_server
broadcast_server = SConscript('#/examples/broadcast_server/SConscript',variant_dir = builddir + 'broadcast_server',duplicate = 0)
+35 -5
View File
@@ -1,4 +1,34 @@
HEAD
- Examples: Add `print_client` example. This demonstrates a minimal non-TLS
client that connects to a server and prints out the messages it receives.
- Examples: Add `print_client_tls` example. This demonstrates a minimal TLS
client, including basic support via Asio+OpenSSL for certificate chain
and hostname verification.
- Feature: Add getter for all headers to the HTTP parsers. This allows a
wrapping library to enumerate all headers to send upstream. Thank you Jupp
Müller for reporting and an initial pull request.
- Improvement: Move the `socket_init_handler` to execute as a part of `init_asio`
rather than connection `pre_init`. This allows setting of socket options prior
to the bind/listen/accept system calls. Thank you ChristianRobl3D for
reporting #530.
- Compatibility: Make sure the chrono library used by Boost/Asio is in sync
with what the websocketpp is using. Thank you Flow86 for reporting and a
patch.
- Compatibility: Update `telemetry_client` to use a slightly more cross platform
method of sleeping. Should work on windows now. Thank you Meir Yanovich for
reporting.
- Bug: Store loggers in shared pointers to avoid crashes related to connections
trying to write logs entries after their respective endpoint has been
deallocated. Thank you Thalhammer for reporting and Jupp Müller for the
patch. #539 #501
- Bug: Change default listen backlog from 0 to `socket_base::max_connections`.
#549. Thank you derwassi and zwelab for reporting and na1pir for providing
access to hardware to debug the issue.
- Bug: Fix a crash in the accept loop when `get_connection` fails. #551 Thank you
Walter Gray for a patch.
- Bug/Documentation: Fix incorrect example code that used
`websocketpp::lib::error_code` instead of `websocketpp::exception`. Thank you
heretic13 for reporting
0.7.0 - 2016-02-22
- MINOR BREAKING SOCKET POLICY CHANGE: Asio transport socket policy method
@@ -31,9 +61,9 @@ HEAD
and `string::empty()`. This avoids generating unnecessary temporary objects.
#468 Thank you Vladislav Yaroslavlev for reporting and a patch.
- Documentation: Adds an example demonstrating the use of external `io_service`
- Documentation: Adds a simple echo_client example.
- Documentation: Adds a simple `echo_client` example.
- Documentation: Begins migration of the web based user manual into Doxygen.
- Bug: Fix memory leak when init_asio produces an error. #454 Thank you Mark
- Bug: Fix memory leak when `init_asio` produces an error. #454 Thank you Mark
Grimes for reporting and fixing.
- Bug: Fix crash when processing a specially crafted HTTP header. Thank you Eli
Fidler for reporting, test cases, and a patch. #456
@@ -51,7 +81,7 @@ HEAD
- Bug: Fix an issue where TLS includes were broken for Asio Standalone builds.
Thank you giachi and Bastien Brunnenstein for reporting. #491
- Bug: Remove the use of cached read and write handlers in the Asio transport.
This feature caused memory leaks when the io_service the connection was
This feature caused memory leaks when the `io_service` the connection was
running on was abruptly stopped. There isn't a clean and safe way of using
this optimization without global state and the associated locks. The locks
perform worse. Thank you Xavier Gibert for reporting, test cases, and code.
@@ -60,8 +90,8 @@ HEAD
Xavier Gibert for reporting and a patch #524
- Compatibility: Fixes a number of build & config issues on Visual Studio 2015
- Compatibility: Removes non-standards compliant masking behavior. #395, #469
- Compatibility: Replace deprecated use of auto_ptr on systems where unique_ptr
is available.
- Compatibility: Replace deprecated use of `auto_ptr` on systems where
`unique_ptr` is available.
0.6.0 - 2015-06-02
- MINOR BREAKING TRANSPORT POLICY CHANGE: Custom transport policies will now be
+9 -6
View File
@@ -14,15 +14,15 @@ macro (print_used_build_config)
message (STATUS "WEBSOCKETPP_BOOST_LIBS = ${WEBSOCKETPP_BOOST_LIBS}")
message (STATUS "WEBSOCKETPP_PLATFORM_LIBS = ${WEBSOCKETPP_PLATFORM_LIBS}")
message (STATUS "WEBSOCKETPP_PLATFORM_TLS_LIBS = ${WEBSOCKETPP_PLATFORM_TLS_LIBS}")
message ("")
message ("")
message (STATUS "OPENSSL_FOUND = ${OPENSSL_FOUND}")
message (STATUS "OPENSSL_INCLUDE_DIR = ${OPENSSL_INCLUDE_DIR}")
message (STATUS "OPENSSL_LIBRARIES = ${OPENSSL_LIBRARIES}")
message (STATUS "OPENSSL_VERSION = ${OPENSSL_VERSION}")
message ("")
message ("")
endmacro ()
# Adds the given folder_name into the source files of the current project.
# Adds the given folder_name into the source files of the current project.
# Use this macro when your module contains .cpp and .h files in several subdirectories.
# Your sources variable needs to be WSPP_SOURCE_FILES and headers variable WSPP_HEADER_FILES.
macro(add_source_folder folder_name)
@@ -39,7 +39,7 @@ macro (init_target NAME)
set (TARGET_NAME ${NAME})
message ("** " ${TARGET_NAME})
# Include our own module path. This makes #include "x.h"
# Include our own module path. This makes #include "x.h"
# work in project subfolders to include the main directory headers.
include_directories (${CMAKE_CURRENT_SOURCE_DIR})
endmacro ()
@@ -74,8 +74,8 @@ endmacro ()
# Finalize target for all types
macro (final_target)
if ("${TARGET_LIB_TYPE}" STREQUAL "EXECUTABLE")
install (TARGETS ${TARGET_NAME}
RUNTIME DESTINATION "bin"
install (TARGETS ${TARGET_NAME}
RUNTIME DESTINATION "bin"
CONFIGURATIONS ${CMAKE_CONFIGURATION_TYPES})
endif ()
@@ -89,14 +89,17 @@ endmacro ()
macro (link_boost)
target_link_libraries (${TARGET_NAME} ${Boost_LIBRARIES})
set_property(TARGET ${TARGET_NAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${Boost_INCLUDE_DIR})
endmacro ()
macro (link_openssl)
target_link_libraries (${TARGET_NAME} ${OPENSSL_SSL_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY})
set_property(TARGET ${TARGET_NAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${OPENSSL_INCLUDE_DIR})
endmacro ()
macro (link_zlib)
target_link_libraries (${TARGET_NAME} ${ZLIB_LIBRARIES})
set_property(TARGET ${TARGET_NAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${ZLIB_INCLUDE_DIR})
endmacro ()
macro (include_subdirs PARENT)
+138
View File
@@ -0,0 +1,138 @@
/** \page reference.config Config Reference
WebSocket++ uses a config template parameter to supply a number of compile type policy types and default numerical values for buffer sizes, timeouts, security behavior, etc. Swapping policies allows changing certain core library behavior designed to be pluggable.
A custom config can be made standalone or can subclass one of the bundled configs and just override a few things.
__Example__
```
// some config options may require additional includes or dependencies.
// syslog logging policy, for example, requires <syslog.h>,
// the permessage deflate settings require zlib.
#include <websocketpp/logger/syslog.hpp>
#include <websocketpp/extensions/permessage_deflate/enabled.hpp>
// Custom server config based on bundled asio config
struct custom_server_config : public websocketpp::config::asio {
// Replace default stream logger with a syslog logger
typedef websocketpp::log::syslog<concurrency_type, websocketpp::log::elevel> elog_type;
typedef websocketpp::log::syslog<concurrency_type, websocketpp::log::alevel> alog_type;
// Reduce read buffer size to optimize for small messages
static const size_t connection_read_buffer_size = 1024;
// enable permessage_compress extension
struct permessage_deflate_config {};
typedef websocketpp::extensions::permessage_deflate::enabled
<permessage_deflate_config> permessage_deflate_type;
};
typedef websocketpp::server<custom_server_config> server_endpoint_type;
```
Core Config Options
-------------------
### Policies
Policies are classes used to allow clean swapping of behavior without changing the core library
| Typedef Name | Effect |
| ------------------------- | -------------------------------------- |
| concurrency_type | Concurrency policy |
| elog_type | Error logger type |
| alog_type | Access logger type |
| request_type | HTTP request type |
| response_type | HTTP response type |
| message_type | Type to deliver recieved messages |
| con_msg_manager_type | Connection level message manager |
| endpoint_msg_manager_type | Endpoint level message manager |
| rng_type | Random Number Generation policy |
| transport_type | Transport policy to use |
| endpoint_base | User overridable Endpoint base class |
| connection_base | User overridable Connection base class |
### Timeouts Values
These represent the length of time (in ms) before the given operation is aborted
| Field | Type | Default | Operation |
| ----------------------- | ---- | ------- | --------------------------- |
| timeout_open_handshake | long | 5000 | Opening handshake |
| timeout_close_handshake | long | 5000 | Closing handshake |
| timeout_pong | long | 5000 | No pong recieved after ping |
### Performance tuning
| Field | Type | Default | Meaning |
| --------------------------- | ------ | -------- | ------------------------------------------------------------------ |
| connection_read_buffer_size | size_t | 16384 | Size of the per-connection read buffer |
| enable_multithreading | bool | true | Disabling may reduce locking overhead for single threaded programs |
#### Connection Read Buffer
Each connection has an internal buffer of this size. A larger value will result in fewer trips through the library and less CPU overhead at the expense of increased memory usage per connection.
If your application primarily deals in very large messages you may want to try setting this value higher.
If your application has a lot of connections or primarily deals in small messages you may want to try setting this smaller.
### Security settings
| Field | Type | Default | Effect |
| ---------------------- | ------ | ------- | -------------------------------------- |
| drop_on_protocol_error | bool | false | Omit close handshake on protocol error |
| silent_close | bool | false | Don't return close codes or reasons |
| max_message_size | size_t | 32MB | WebSocket max message size limit |
| max_http_body_size | size_t | 32MB | HTTP Parser's max body size limit |
#### Drop on protocol error
Drop connections on protocol error rather than sending a close frame. Off by default. This may result in legitimate messages near the error being dropped as well. It may free up resources otherwise spent dealing with misbehaving clients.
#### Silent Close
Silence close suppresses the return of detailed connection close information during the closing handshake. This information is useful for debugging and presenting useful errors to end users but may be undesirable for security reasons in some production environments. Close reasons could be used by an attacker to confirm that the endpoint is out of resources or be used to identify the WebSocket implementation in use.
Note: this will suppress *all* close codes, including those explicitly sent by local applications.
#### Max message size
Default value for the processor's maximum message size. Maximum message size determines the point at which the library will drop a connection with the message_too_big protocol error.
#### Max HTTP header size
Maximum body size determines the point at which the library will abort reading an HTTP message body and return the 413/request entity too large error.
Transport Config Options
------------------------
### Policies
Policies are classes used to allow clean swapping of behavior without changing the core library
| Typedef Name | Effect |
| ---------------- | ------------------ |
| concurrency_type | Concurrency Policy |
| elog_type | Error logger type |
| alog_type | Access logger type |
| request_type | HTTP request type |
| response_type | HTTP response type |
### Timeouts Values
These represent the length of time (in ms) before the given operation is aborted
| Field | Type | Default | Operation |
| ------------------------ | ---- | ------- | --------------------------------------------- |
| timeout_socket_pre_init | long | 5000 | Transport dependent |
| timeout_proxy | long | 5000 | Proxy handshake |
| timeout_socket_post_init | long | 5000 | Transport dependent (commonly: TLS handshake) |
| timeout_dns_resolve | long | 5000 | DNS resolution |
| timeout_connect | long | 5000 | TCP Connect |
| timeout_socket_shutdown | long | 5000 | Socket shutdown |
### Performance tuning
| Field | Type | Default | Meaning |
| --------------------------- | ------ | -------- | ------------------------------------------------------------------ |
| enable_multithreading | bool | true | Disabling may reduce locking overhead for single threaded programs |
*/
+71
View File
@@ -1,5 +1,74 @@
/** \page faq FAQ
## General Library Usage
### Can a handler be changed after a connection is established? Can one be removed?
Yes, but not globally.
Handlers assigned to endpoints will be automatically copied to the connections created by that endpoint. Changing a handler on an endpoint will only affect future connections.
Once a particular connection is created, it's handlers can be changed individually by calling the `set_*_handler` methods. Once changed, all future events of that type for that connection will use the new handler.
To remove a handler that was previously set, call the set method with `nullptr` or `NULL`.
### Can I reject or conditionally accept a connection
Yes. The `validate` handler is called after the initial handshake has been recieved but before WebSocket++ has responded. This gives you the opportunity to inspect the incoming connection request, its headers, origin, subprotocols, and the remote endpoint IP. Return `true` from the validate handler to accept the connection and `false` to reject it.
To set a custom HTTP error message for your rejection, use `websocketpp::connection::set_status` and (optionally) `websocketpp::connection::set_body()` to set the HTTP status code and error message body text. If you do not set body text a message will be generated automatically based on the status code.
### How do I negotiate subprotocols?
WebSocket connections may offer a particular subprotocol they want to use. The WebSocket protocol does not define the meaning or interpretation of the subprotocol. This interpretation is left up to the individual application endpoints.
WebSocket++ servers can read the requested subprotocols during the `validate` handler by calling `websocketpp::connection::get_requested_subprotocols`. The list is ordered by client priority. You may optionally choose one of these subprotocols with `websocketpp::connection::select_subprotocol`. The handshake will then complete and let the client know which one was chosen. If you do not choose any, the "blank"/empty/none subprotocol will be used.
WebSocket++ clients can add a subprotocol to an outgoing connection by calling `websocketpp::connection::add_subprotocol` before calling `websocketpp::client::connect`. The order of adding will be interpreted as the order of preference.
In both caases, after the connection has been established, the selected subprotocol is available via the `websocketpp::connection::get_subprotocol` method.
Note: some browsers will allow the connection to continue if they requested a subprotocol and your server doesn't select one. Others will reject the connection.
### How do I cleanly exit an Asio transport based program
The Asio transport based clients and servers use the Asio library's underlying `io_service` to handle asyncronous networking operations. The standard behavior of the io_service is to run until there are no async operations left and then return. WebSocket++, when using the Asio transport, behaves like a standard Asio application. If you want your WebSocket++/Asio based program to stop network operations and cleanly close all sockets you will want to do the following:
- For servers, call `websocketpp::transport::asio::endpoint::stop_listening` to initiate the closing of the server listening socket.
- For clients, if you have engaged perpetual mode with `websocketpp::transport::asio::endpoint::start_perpetual`, disable it with `websocketpp::transport::asio::endpoint::stop_perpetual`.
- For both, run `websocketpp::endpoint::close` or `websocketpp::connection::close` on all currently outstanding connections. This will initiate the WebSocket closing handshake for these connections
- Wait. Asio is asyncronous. When the calls to the above methods (stop_listening, close, etc) complete the server *will still be listening*, the connections *will still be active* until the io_service gets around to asyncronously processing the socket and WebSocket protocol closing handshakes. The `io_service::run` method will exit cleanly and automatically when all operations are complete.
__WARNING__: Asio's `io_service` has a method called `stop`. WebSocket++ wraps this method as `websocketpp::transport::asio::endpoint::stop`. While this operation has a benign sounding name, it is a powerful and destructive operation that should only be used in special cases. If you are using `io_service::stop` or `endpoint::stop` without a very good reason your program is likely broken and may exhibit erratic behavior. Specifically, `io_service::stop` stops the processing of events entirely. This does not give current operations (such as socket closing handshakes) the opportunity to finish. It will leave your sockets in a dangling state that may invoke operating system level timeouts or other errors.
__Special cases__:
- If your client uses the `start_perpetual` method it will prevent the io_service from exiting even if it has nothing to do. This is useful if you want a client endpoint to idle in the background to allow new connections to be formed on demand rather than generating a new endpoint for each.
- If you are using an external io_service and/or are placing non-WebSocket++ operations on the `io_service` those operations may keep the `io_service` open even after all WebSocket++ operations have completed.
- If you are using `poll`/`poll_one`/`run_one` or otherwise manually driving the `io_service` event loop you may need to adjust usage to make sure you are correctly recognizing the "done with work" and "not done but idling / `io_service::work`" cases.
### Is there a way to check the validity of a `connection_hdl`?
Sometimes, not generally though, because there isnt a way to check if a TCP connection is valid.
You can try upgrading your hdl to a full connection_ptr using `websocketpp::endpoint::get_con_from_hdl`. If this fails, the hdl is definitely invalid. If it succeeds it may or may not be. The only way to tell definitively is to try and send something (either a message or a ping).
If you handle errors from methods like send, ping, close, etc correctly then you shouldnt have to worry about accidentally sending to dead connections. The send/ping/pong/close methods will set or throw a specific error in the case that you tried to send something but the connection was closed/gone/etc.
### How do I fix the "address is in use" error when trying to restart my server?
Normally, for security purposes, operating systems prevent programs from listening on sockets created by other programs. When your program crashes and restarts, the new instance is a different program from the perspective of the operating system. As such it cant listen on the socket address/port that the previous program was using until after a timeout occurs to make sure the old program was done with it.
The the first step for handling this is to make sure that you provide a method (signal handler, admin websocket message, etc) to perform a clean server shutdown. There is a question elsewhere in this FAQ that describes the steps necessary for this.
The clean close strategy won't help in the case of crashes or other abnormal closures. An option to consider for these cases is the use of the SO_REUSEADDR socket option. This instructs the OS to not request an exclusive lock on the socket. This means that after your program crashes the replacement you start can immediately listen on that address/port combo again.
__Please note__: how this works exactly depends on your operating system. Additionally, not exclusively locking your listening socket could allow hijacking by other programs if you are running in a shared resource environment. For development this is generally no problem. For a production environment, think carefully about the security model. `websocketpp::transport::asio::endpoint::set_reuse_addr` is the method to do this. You must specify this setting before calling `websocketpp::transport::asio::endpoint::listen`.
### How do I send and recieve binary messages?
When supported by the remote endpoint, WebSocket++ allows reading and sending messages in the two formats specified in RFC6455, UTF8 text and binary. WebSocket++ performs UTF8 validation on all outgoing text messages to ensure that they meet the specification. Binary messages do not have any additional processing and their interpretation is left entirely to the library user.
To determine the type of an incoming message, use `websocketpp::message_buffer::message::get_opcode`. The relevant return values are `websocketpp::frame::opcode::text` and `websocketpp::frame::opcode::binary`. There is no difference in how payloads are retrieved between these modes, only in how WebSocket++ validated the contents and how the library user is to interpret the data.
To specify the type of an outgoing message, use the frame opcode values listed above as the second op parameter for `websocketpp::connection::send`. There are two relevant overloads of send. One that takes a `std::string` and defaults to op=text. The other that takes a `void const *` and a `size_t` length and defaults to op=binary. Note: You can send binary messages via the string overload and text messages via the void * overload. In the case that you are manually building a message buffer rather than using the automatic send member functions, you can pass the opcode in as a parameter to the message buffer constructor or user the `websocketpp::message_buffer::message::set_opcode` member function to set or re-set it later.
## Dependency Management
### Can WebSocket++ be used without Boost?
@@ -19,6 +88,8 @@ Whether an Asio endpoint uses TLS or not is determined by its config template pa
The `<websocketpp/config/asio.hpp>` and `<websocketpp/config/asio_client.hpp>` headers will include both the TLS and non-TLS varients of their respective configs and require the presence of OpenSSL. The `<websocketpp/config/asio_no_tls.hpp>` and `<websocketpp/config/asio_no_tls_client.hpp>` headers will include only the non-TLS configs and do not require OpenSSL.
### Build issues with TLS on recent versions of OS X
Mac OS X ships a severely outdated version of the OpenSSL library. To securely use TLS with WebSocket++ on OS X you will need to install a modern version of OpenSSL via homebrew or compiling from source.
## Compression
+102
View File
@@ -0,0 +1,102 @@
/** \page reference.logging Logging Reference
WebSocket++ has the capability of logging events during the lifetime of the connections that it processes. Each endpoint has two independent logging interfaces that are used by all connections created by that endpoint. The first is an access interface that allows logging routine events in the life of a connection (such as connect/disconnect and receipt of messages). The other is an error interface that allows logging non-routine problems or errors. Each interface has a number of different named channels that can be toggled on and off independently.
Exactly how these logs are processed and where they are written to depends on which logging policy is in use. Several logging policies are included by default and you can write your own policy if you need something more specialized. Selecting a policy is done via the \subpage reference.config "endpoint config".
Common functionality (all policies)
-----------------------------------
### Logging Channels
Each logging interface is divided into 32 named channels. Log messages are written to a specific interface on a specific channel. Which log messages are actually printed is determined by which channels are enabled or not. Channels can be enabled or disabled either at compile time or at runtime.
### Enabling and Disabling Channels
Channels disabled at compile time are removed from the code entirely (assuming correct compiler optimization settings) and are not available for runtime enabling or disabling. To disable channels at compile time, use the `alog_level` and `elog_level` values within your \subpage reference.config "endpoint config". Channels not disabled at compile time can be enabled or disabled at runtime using the `websocketpp::endpoint::set_access_channels()`, `websocketpp::endpoint::clear_access_channels()`, `websocketpp::endpoint::set_error_channels()`, and `websocketpp::endpoint::clear_error_channels()` methods.
The set and clear functions act only on the channels specified. `set_access_channels(log::alevel::connect)` will enable logging of new connections. Following this with `set_access_channels(log::alevel::disconnect)` will enable logging of disconnections in addition to connections. Use `clear*` functions to disable a specific channel. Channels may be combined using bitwise operations to create aggregate packages of channels that may be set or cleared at once. Default packages include `websocketpp::log::alevel::all`, `websocketpp::log::elevel::all`, `websocketpp::log::alevel::none`, `websocketpp::log::elevel::none`. These represent all possible access/error channels and no access/error channels respectively. For convenience, setting none is aliased to clearing all.
### Examples
__Disable all__
`clear_access_channels(log::alevel::all)`
__Disable all (alternative method)__
`set_access_channels(log::alevel::none)`
__Multiple channels at once__
`log::alevel::message_payload | log::alevel::message_payload`
__All except one__
`log::alevel::all ^ log::alevel::message_payload`
__Default settings__
By default, only debug/development logging is disabled.
### Access to underlying loggers
Logging interfaces may be directly accessed via their associated endpoint or connection using get_alog() and get_elog(). This allows access to methods specific to the chosen logging policy.
Basic Logging (Default Policy)
------------------------------
The basic logging policy (`websocketpp::log::basic`) writes logs to a std::ostream. By default, access logs are written to stdout and error logs are written to stderr. Each logging interface may be optionally redirected to an arbitrary C++ stream (including file streams) using the `websocketpp::log::basic::set_ostream()` method.
Syslog Logging
--------------
The syslog logging policy (`websocketpp::log::syslog`) logs to POSIX syslog. It is included in the header `<websocketpp/logger/syslog.hpp>`. It requires a system with `<syslog.h>`.
Stub Logging
------------
The stub logging policy (`websocketpp::log::stub`) implements the logging policy interface but ignores all input and provides no output. It can be used to stub out the logging system in tests or to completely disable and remove nearly all logging related code.
The stub logger also provides documentation for the minimal required interface to build a custom logging policy.
Log level reference
-------------------
### Error Logging Levels
Each of these channels is in the namespace `websocketpp::log::elevel`
| Level | Description |
| ------- | -------------------------------------------------------------------------------------------------------------------------- |
| none | Special aggregate value representing "no levels" |
| devel | Low level debugging information (warning: very chatty). Requires debug or custom config. |
| library | Information about unusual system states or other minor internal library problems, less chatty than devel. |
| info | Information about minor configuration problems or additional information about other warnings. |
| warn | Information about important problems not severe enough to terminate connections. |
| rerror | Recoverable error. Recovery may mean cleanly closing the connection with an appropriate error code to the remote endpoint. |
| fatal | Unrecoverable error. This error will trigger immediate unclean termination of the connection or endpoint. |
| all | Special aggregate value representing "all levels" |
### Access Logging Levels
Each of these channels is in the namespace `websocketpp::log::alevel`
| Level | Description |
| --------------- | -------------------------------------------------------------------------------------------------- |
| none | Special aggregate value representing "no levels" |
| connect | One line for each new connection that includes a host of information including: the remote address, websocket version, requested resource, http code, remote user agent |
| disconnect | One line for each connection that is closed. Includes closing codes and reasons |
| control | One line per control message |
| frame_header | One line per frame, includes the full frame header |
| frame_payload | One line per frame, includes the full message payload (warning: lots of output for large messages) |
| message_header | Reserved |
| message_payload | Reserved |
| endpoint | Reserved |
| debug_handshake | Extra information about opening handshakes |
| debug_close | Extra information about closing handshakes |
| devel | Development messages (warning: very chatty). Requires debug or custom config. |
| app | Special channel for application specific logs. Not used by the library. |
| all | Special aggregate value representing "all levels" |
*/
+2
View File
@@ -16,6 +16,8 @@ In order to accommodate the wide variety of use cases WebSocket++ has collected,
- \subpage md_changelog "Change Log / Version History"
- Reference
- \subpage reference.handlers "Handler Reference"
- \subpage reference.config "Config Reference"
- \subpage reference.logging "Logging Reference"
*/
+3 -3
View File
@@ -157,10 +157,10 @@ int main(int argc, char* argv[]) {
try {
perftest endpoint;
endpoint.start(uri);
} catch (const std::exception & e) {
} catch (websocketpp::exception const & e) {
std::cout << e.what() << std::endl;
} catch (std::exception const & e) {
std::cout << e.what() << std::endl;
} catch (websocketpp::lib::error_code e) {
std::cout << e.message() << std::endl;
} catch (...) {
std::cout << "other exception" << std::endl;
}
+5 -5
View File
@@ -128,9 +128,9 @@ void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {
try {
s->send(hdl, msg->get_payload(), msg->get_opcode());
} catch (const websocketpp::lib::error_code& e) {
std::cout << "Echo failed because: " << e
<< "(" << e.message() << ")" << std::endl;
} catch (websocketpp::exception const & e) {
std::cout << "Echo failed because: "
<< "(" << e.what() << ")" << std::endl;
}
}
@@ -164,10 +164,10 @@ int main() {
// Start the ASIO io_service run loop
echo_server.run();
} catch (websocketpp::exception const & e) {
std::cout << e.what() << std::endl;
} catch (const std::exception & e) {
std::cout << e.what() << std::endl;
} catch (websocketpp::lib::error_code e) {
std::cout << e.message() << std::endl;
} catch (...) {
std::cout << "other exception" << std::endl;
}
+3 -3
View File
@@ -28,9 +28,9 @@ void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {
try {
s->send(hdl, msg->get_payload(), msg->get_opcode());
} catch (const websocketpp::lib::error_code& e) {
std::cout << "Echo failed because: " << e
<< "(" << e.message() << ")" << std::endl;
} catch (websocketpp::exception const & e) {
std::cout << "Echo failed because: "
<< "(" << e.what() << ")" << std::endl;
}
}
@@ -28,9 +28,9 @@ void on_message(EndpointType* s, websocketpp::connection_hdl hdl,
try {
s->send(hdl, msg->get_payload(), msg->get_opcode());
} catch (const websocketpp::lib::error_code& e) {
std::cout << "Echo failed because: " << e
<< "(" << e.message() << ")" << std::endl;
} catch (websocketpp::exception const & e) {
std::cout << "Echo failed because: "
<< "(" << e.what() << ")" << std::endl;
}
}
+3 -3
View File
@@ -57,9 +57,9 @@ void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {
try {
s->send(hdl, msg->get_payload(), msg->get_opcode());
} catch (const websocketpp::lib::error_code& e) {
std::cout << "Echo failed because: " << e
<< "(" << e.message() << ")" << std::endl;
} catch (websocketpp::exception const & e) {
std::cout << "Echo failed because: "
<< "(" << e.what() << ")" << std::endl;
}
}
+55 -53
View File
@@ -1,55 +1,57 @@
-----BEGIN RSA PRIVATE KEY-----
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 PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDMYjHlTUeUGSys
Fz5PZcvgS3gojBlEAOu2gXFQDcJ7kq6dJ4jKsPaH1Q5jAtEDkU/el8otzfacOgyp
2ZxioRimpmcORWGU0bKJcenh4ZQ1oK1CQObjeYk1YgE7H8/sBetSdtL4n1rB8LIz
AV/k6kwSZFu3/lSmc6g09H4efSKGKVBcVOjBamcvFGVH4KhM2NyL+ffeV5H2Ucxk
ipyhpr4uxEoC3EV60sQxloqZb+upBM0LS4kVvaYMcn39XkUx3Z8FwN5+hFGwsWda
tU8zDxEuRMrZxG7mwDXLBGehtQvoJIVMQbOuwBQcgAbsVyy1dxV3aczbLX0iGEuG
eBhdFE+BAgMBAAECggEAQaPn0nUXYAEVz89HO8i9ybNzS9Jy6txA18SK1+MTawyY
9/AShsZ+5vEORc5JwpOQyzSEwmE7qsEaABLbnvGOMTeQMY0m4dzXMj1bmCgSqYaJ
HpYpkTUfU/2913dIF81u3nU7HI5RX6gmEyuF2MdG10FUE6ujFDJg+2DqgHA//kYD
hkXFinVS2PuZs8d5xdzpF0aCIWTuOc+Fgsyhdm/lZRIzFdID45YUVuPIN2uh+GkM
ENp/r1x7dPlDRqiL1ufP0mTQGs26S5kQSF8W0BClkOIOgmrhSON4+Vqhqx+ki/7w
RY+7mmgdvt0uzYT+Lk2cDw4f89Rsh7rR1EieBpQ2YQKBgQDq6zAHWfweJmkugT0w
HzI0UKfcOdzlJBwMu6tSgSHU99dnXlTwQY8sG7vtfRekokoo7XY4JsSk1n6E9OVy
4UKuEvU1+llDGxtvHxEEGOAgwB8wxMuY4uNYgDVhTlUzr2ERcet7FOIGzxEWzSsg
5vgnTQfyMzAh5/6k8CsHVI4u2wKBgQDeuYVCgg555lcc5rvTFxfU15d3fweSd78+
akgIBaXAlFbxI+5znGPmKG/ii4N2XObC8B568fA2nIxw6M1xgbKyvvmN3ECYiqWv
bx8x6Vg5Slg0vJr+DrPgvIKbOWEEKF/cfpTeeVLP0gUBT63mA3qezuRx1r0JJr7A
k9a4Td9j0wKBgDmRQMfMaVgKGaRnz1LHkkn3qerx0wvj+Wu1YZpqQpwp0ANovm/R
4P/yG+9qxCx4CKxW5K2F8pJibcavLLsmMGzwAF8l5lHnhqWIe2cBoYrlCb+tuibR
Et1RLcOWqpJr2+GmhQo4Z9s7SvjHdlYtw4n9+oCDwrvMWj6ZDDJTqjQZAoGAEhRt
RODZ2/texvHT/Wa6gISfvwuIydL+q0plXoFW2zMve5O3H5tqYJyXuIQqv8j60og7
cS+CmGxM2j2Lr9MfdnMaPvHKLJfUq1ER7zNJ/hyS3HUS/9yhrXSgBYm63mOIpJWB
8C1ZE5Ww4lJdg3Z01b9lu/f6kGucwHU/0OZBZBECgYAQ+dl2kKKd+lQ9O/LVz7oD
goQMPYF+QZcEhY4vlYKkWVtR2A0CiY6XeTi6vO/qVUt/ht+UO3XIJFOjGV1VyORQ
Bhibfstxl5s59jGlns5y5QqcRKzCiX74BKG0xQUtHgga7Od6L+GJKbJAPBfncYwW
U7Tfwwi0WbbgQoy5Xr/5gg==
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
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==
MIIFBTCCAu2gAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNVBAYTAlVT
MQswCQYDVQQIDAJJTDEUMBIGA1UECgwLV2ViU29ja2V0KysxKjAoBgNVBAsMIVdl
YlNvY2tldCsrIENlcnRpZmljYXRlIEF1dGhvcml0eTEkMCIGA1UEAwwbV2ViU29j
a2V0KysgSW50ZXJtZWRpYXRlIENBMB4XDTE2MDYwODEyNDUxMloXDTI2MDYwNjEy
NDUxMlowfjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAklMMRAwDgYDVQQHDAdDaGlj
YWdvMRQwEgYDVQQKDAtXZWJTb2NrZXQrKzEgMB4GA1UECwwXV2ViU29ja2V0Kysg
VExTIEV4YW1wbGUxGDAWBgNVBAMMD3dlYnNvY2tldHBwLm9yZzCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBAMxiMeVNR5QZLKwXPk9ly+BLeCiMGUQA67aB
cVANwnuSrp0niMqw9ofVDmMC0QORT96Xyi3N9pw6DKnZnGKhGKamZw5FYZTRsolx
6eHhlDWgrUJA5uN5iTViATsfz+wF61J20vifWsHwsjMBX+TqTBJkW7f+VKZzqDT0
fh59IoYpUFxU6MFqZy8UZUfgqEzY3Iv5995XkfZRzGSKnKGmvi7ESgLcRXrSxDGW
iplv66kEzQtLiRW9pgxyff1eRTHdnwXA3n6EUbCxZ1q1TzMPES5EytnEbubANcsE
Z6G1C+gkhUxBs67AFByABuxXLLV3FXdpzNstfSIYS4Z4GF0UT4ECAwEAAaOBhzCB
hDALBgNVHQ8EBAMCBDAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwYAYDVR0RBFkwV4IP
d2Vic29ja2V0cHAub3JnghN3d3cud2Vic29ja2V0cHAub3Jnghl1dGlsaXRpZXMu
d2Vic29ja2V0cHAub3JnghRkb2NzLndlYnNvY2tldHBwLm9yZzANBgkqhkiG9w0B
AQsFAAOCAgEAelJvIWFikBU3HVoP0icuoezTHGqABPLCeooTC/GELq7lHCFEjiqW
p96Zc3vrk+0Z0tkYy3E0fpuzPtlTUhBzO3fMF41FpB5ix3W/tH9YJvrozlIuDD1I
IEusxomeeiMRbyYpX/gkSOO74ylCzMEQVzleMNdpzpeXOg0Kp5z2JNShdEoT7eMR
qkJQJjMdL6QeXUqWNvX1Zqb8v6VeWGWjuu/cl374P8D8bjn89VwZQ5HFqoLOhI5v
XEYsMViZWwLSMcfWTU2Rdi0RxUZQVciLP/3GQROR1/0/e1J1kd7GsRWQMZcU20Vy
jXBVAiWhW1bgd0XOrrFILsAmnBtinEJiE+h5UC4ksZtwWf9x1IhXGlpb9bmD4+Ud
93wmqytPXBFL6wwlj4IYjjy0gU6xP6h7nwhHXnBlwFWGDpe8Cco9qgyJxJxBTtj9
MbBv+BSLXJoniDASdk6RIqCjPWZtWbQ7j5mIKV0bdJQZpBX553QOy8AoIpJE32An
FzR0SSCHOCgSAbqtM8CvLO6mquEJunmwKQx6xfos5N6ee+D+JtUFTw04TrjZUzFs
Z7v3SN/N4Hd13iTBDSu4XY/tJYICvTRLYNrzQRh/XEVbEEVxXhL8rxNn5aL1pqrV
yEnvHXrnSXWxTif1K+hS2HfTkQ6d1GjglvmwkoBqBHuRH0OJ1VguTqM=
-----END CERTIFICATE-----
@@ -52,9 +52,9 @@ void on_message(ws_echo_server* s, websocketpp::connection_hdl hdl, ws_echo_serv
try {
s->send(hdl, msg->get_payload(), msg->get_opcode());
} catch (websocketpp::lib::error_code const & e) {
std::cout << "Echo failed because: " << e
<< "(" << e.message() << ")" << std::endl;
} catch (websocketpp::exception const & e) {
std::cout << "Echo failed because: "
<< "(" << e.what() << ")" << std::endl;
}
}
+2 -2
View File
@@ -26,9 +26,9 @@ void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {
try {
s->send(hdl, msg->get_payload(), msg->get_opcode());
} catch (const websocketpp::lib::error_code& e) {
} catch (websocketpp::exception const & e) {
s->get_alog().write(websocketpp::log::alevel::app,
"Echo Failed: "+e.message());
std::string("Echo Failed: ")+e.what());
}
}
+12
View File
@@ -0,0 +1,12 @@
file (GLOB SOURCE_FILES *.cpp)
file (GLOB HEADER_FILES *.hpp)
init_target (print_client)
build_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})
link_boost ()
final_target ()
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "examples")
+23
View File
@@ -0,0 +1,23 @@
## Print client example
##
Import('env')
Import('env_cpp11')
Import('boostlibs')
Import('platform_libs')
Import('polyfill_libs')
env = env.Clone ()
env_cpp11 = env_cpp11.Clone ()
prgs = []
# if a C++11 environment is available build using that, otherwise use boost
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
prgs += env_cpp11.Program('print_client', ["print_client.cpp"], LIBS = ALL_LIBS)
else:
ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs]
prgs += env.Program('print_client', ["print_client.cpp"], LIBS = ALL_LIBS)
Return('prgs')
+78
View File
@@ -0,0 +1,78 @@
/*
* Copyright (c) 2016, 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.
*
*/
#include <websocketpp/config/asio_no_tls_client.hpp>
#include <websocketpp/client.hpp>
#include <iostream>
typedef websocketpp::client<websocketpp::config::asio_client> client;
void on_message(websocketpp::connection_hdl, client::message_ptr msg) {
std::cout << msg->get_payload() << std::endl;
}
int main(int argc, char* argv[]) {
client c;
std::string uri = "ws://localhost:9002";
if (argc == 2) {
uri = argv[1];
}
try {
// Set logging to be pretty verbose (everything except message payloads)
c.set_access_channels(websocketpp::log::alevel::all);
c.clear_access_channels(websocketpp::log::alevel::frame_payload);
c.set_error_channels(websocketpp::log::elevel::all);
// Initialize ASIO
c.init_asio();
// Register our message handler
c.set_message_handler(&on_message);
websocketpp::lib::error_code ec;
client::connection_ptr con = c.get_connection(uri, ec);
if (ec) {
std::cout << "could not create connection because: " << ec.message() << std::endl;
return 0;
}
// Note that connect here only requests a connection. No network messages are
// exchanged until the event loop starts running in the next line.
c.connect(con);
// Start the ASIO io_service run loop
// this will cause a single connection to be made to the server. c.run()
// will exit when this connection is closed.
c.run();
} catch (websocketpp::exception const & e) {
std::cout << e.what() << std::endl;
}
}
+17
View File
@@ -0,0 +1,17 @@
file (GLOB SOURCE_FILES *.cpp)
file (GLOB HEADER_FILES *.hpp)
if (OPENSSL_FOUND)
init_target (print_client_tls)
build_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})
link_boost ()
link_openssl()
final_target ()
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "examples")
endif()
+24
View File
@@ -0,0 +1,24 @@
## Print client tls example
##
Import('env')
Import('env_cpp11')
Import('boostlibs')
Import('platform_libs')
Import('polyfill_libs')
Import('tls_libs')
env = env.Clone ()
env_cpp11 = env_cpp11.Clone ()
prgs = []
# if a C++11 environment is available build using that, otherwise use boost
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + [tls_libs]
prgs += env_cpp11.Program('print_client_tls', ["print_client_tls.cpp"], LIBS = ALL_LIBS)
else:
ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs] + [tls_libs]
prgs += env.Program('print_client_tls', ["print_client_tls.cpp"], LIBS = ALL_LIBS)
Return('prgs')
@@ -0,0 +1,66 @@
-----BEGIN CERTIFICATE-----
MIIFxTCCA62gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwYDELMAkGA1UEBhMCVVMx
CzAJBgNVBAgMAklMMRAwDgYDVQQHDAdDaGljYWdvMRQwEgYDVQQKDAtXZWJTb2Nr
ZXQrKzEcMBoGA1UEAwwTV2ViU29ja2V0KysgUm9vdCBDQTAeFw0xNjA1MjUxMzU4
MjdaFw0yNjA1MjMxMzU4MjdaMIGCMQswCQYDVQQGEwJVUzELMAkGA1UECAwCSUwx
FDASBgNVBAoMC1dlYlNvY2tldCsrMSowKAYDVQQLDCFXZWJTb2NrZXQrKyBDZXJ0
aWZpY2F0ZSBBdXRob3JpdHkxJDAiBgNVBAMMG1dlYlNvY2tldCsrIEludGVybWVk
aWF0ZSBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMNaFAzlx0KJ
gG15yRHI3xn9+B1woHG4uuOr124Sk1JllPcO3enusgIYTMl0FiYYW9CsyPoe4L0P
wflbz20vDDjxmXG+NPgjuYmnPaq7q2JXYz+cShv9+o60EIwEIe+EWk1ZQs9YSdQ0
r4UOxGVq6eEuWJi8Wh02cbnxdjwvrk7lTMFVY+z5EX8cCj6Tbrd0lyIf/0X8OkOb
q2HOqqzTgT2apBCWCEW6grW6rtMOoDx93BOZDBEGz39sJ5i8AQ8XIdYCdUcOMdJU
SCAw/MMyFTHXhv8hJdG5GcDSfc7woB9xRUf8UHuCH0nYkTb260TWvyDCYJy001ko
SWoRbh2hVgPqQ9FTDMzMTY8T8C5u3BRfGN5PHuSPhwfHv/p1g4uPnltDBe4CNtOs
wu8w1wbrr3uI7qETnqOzbXlcT7o4rCrrRQqLbNOssf2mMH+Phq6dINjXpZjiAhO0
SURtBMmQdAZcQkGStzFitEkb2Py5LEIxQ068i8RCowTyD9+/jbO1fZyxJ4X8TDUe
Xx48xWnu0i4f8/9ldnWLwX9h3ilaZVsr7buNYJoMlz+v73TQoWKSybJ2SMe/Cddj
OZCy5r1UakuZhX6n1ScD/hbO8FEfmQRpAywYajyU4dZ9XMbf5bo6OAUqlJ2f4yYh
VAy5mi1JHfD5PiJN90j79GXXvtBTJc4hAgMBAAGjZjBkMB0GA1UdDgQWBBTKMn5O
3NUPpztL1bAz8UCsOBLpkjAfBgNVHSMEGDAWgBTNBBKZQN694xplMGyMruXFv27o
eTASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0B
AQsFAAOCAgEAyNkZUEAdP73th4/RLu0d2foMiIqKlcvw3JsW0tto3MT5lvQ5UugH
OwluhWhnMLE0KsknQd7/p4ZwyZugWAYjGcDydp0GDIDfNBBEOQkOAL23KkYiRFqt
VPBTZi9S7P2MJLY0j94liIg94nikhz/0q7JxxWFlvSHUjwZxXrbFjfZRPOS1vIq/
/VK2QjUsdIXE3NOPYfQwd9FpG2YS8ZcMeipwNYVAs2FBEeWzGH1j6i2hP8FFBDYP
0LTvJYOJvlCeyIvPBjKk9461/Z4CPJcKtKC59onQmiqSK/Juak/bpPoY7jJ228KG
bEBzClIEHgbDiBewFTHbyOWhW2ySRLOGsPeqKDSbm4J1N5rfKnrSQB9PfOmWoRfJ
vqPlXFSlpdgD4j/WnEumpvt78fT+cn+AkRG8tE5DQrCWZTK47TSWn902Fm0A19Rl
pSbE9qsulXurOqEuOOayrzcUmbZ/jkU+wj+/tN4Gl8K98WbjcXvwz0sRL3SgRRrI
awUdaGWKQHrTJNEOTisepUAuHVDmvuQz0j/Ru+PbB9K3GcKY6X6+o1c2JBC1V6KX
aHHZQ+xPm+VEa1pG/QVHGpt2AbGUQlXwDYtOIRwEhO27tFbH8Q68s2cMLYjsF5gd
MWuMYCPkFv10/V2f2lAIPSEzw2pldIGERcb4VG4xuD0qU+HH/aAID7k=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFpjCCA46gAwIBAgIJAL42eqbfw976MA0GCSqGSIb3DQEBCwUAMGAxCzAJBgNV
BAYTAlVTMQswCQYDVQQIDAJJTDEQMA4GA1UEBwwHQ2hpY2FnbzEUMBIGA1UECgwL
V2ViU29ja2V0KysxHDAaBgNVBAMME1dlYlNvY2tldCsrIFJvb3QgQ0EwHhcNMTYw
NTI1MTM1MTUzWhcNMzYwNTIwMTM1MTUzWjBgMQswCQYDVQQGEwJVUzELMAkGA1UE
CAwCSUwxEDAOBgNVBAcMB0NoaWNhZ28xFDASBgNVBAoMC1dlYlNvY2tldCsrMRww
GgYDVQQDDBNXZWJTb2NrZXQrKyBSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOC
Ag8AMIICCgKCAgEA4QjJ0v5yri+pAN67I/XPz88D8oIczCW96CIuwc44aDC9Kptb
9iY8xwbGCyQsFZ/1IQ74QfnXZSwq8EwedcBIdcyHdBu6qtNkCVKeDIZAMBef6Hx+
tWSe1op3sDbUlT8NHiTxZCZWk/2/yIi8yPzQTi4y1vF04vvrQS5RFomCz17kdyOa
NdxO5p+I4afdoVKtzA1aHoBqdTe7vzM3eww4AxKfgIEDdIuOGDiglI/b/frlwiOi
SfTOsPzu52TOPW2d1Ad5BG4GuMpnTUOVnc8j18w9LdeXO0J10oVyCmwiPuzFCcDB
g1xvVr5TXzIZ5J+qlso7+mUfZGH+nxOT7Tc78o1EvX6JbfQAI2PrpcksmJfFnN4l
4XnXDW/eKl8AlLUr/cW5axAfql4QHJoBCZcfYldQpMoL5R1ikLtY53cOJpycFoWm
1IEfkLBZ4C1old+KoaErG0+Aur8/kwAJGMnmMvZqGZ5pgXtVipOLy5TKuS6ZKO8g
MRzalaF/naiu3pF+/sctaqkAPvOr65WrANNGxTQ93ePdyuT6sOEUKXxaXcTtAOOM
5FCgX8dPxkOACxTrxppvb+bYmYL9GIuYDGYxSRu3Fm+04eXIh+uCqcuWPQuRPc5t
VXvk/M0fPaJvKfP6lRAoE5Dp4qPRvL6tRVtOXfP6d+O+yGnxRoLKAW7ejoMCAwEA
AaNjMGEwHQYDVR0OBBYEFM0EEplA3r3jGmUwbIyu5cW/buh5MB8GA1UdIwQYMBaA
FM0EEplA3r3jGmUwbIyu5cW/buh5MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/
BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQAQ4eY4LhW795wl9XuDVg2vOFTYmIS0
OxrunFX4f3RjddbIbXzYmQ0cJ8pJ5l7eGYcg/DYQRY4Tk6LjXMs9VhIU10akqLS4
qGE+Bmp3Jhu5NxZbKkY+k+kTAA1LYxFCjGjSV0v5QNLFULDAmGer2zWwU5DcDwwq
8yWyBuI974UyE/49/TeckfqwBrb90LL2lFEwoL86XZK2IZMPyMBC/S1X5P/Kc15Q
d8lwOPS5AirFkkrzs/px+mRia5U1uWKIPRLq9Medvjf8HR8SFWq9eRtkxiLaWyRv
HBVyVRKCubCZR8psVLK/zrF+Bc+Hr9aAi3TuqTKjIOI7hrq5oJcJpebZDNoBIqoj
kab13WcRwG+BQvuK1CEkd1aq8Nh2GX6Reb2Zv82/WntgP1a0sztbIGgrUBYQryb5
HF79v4e2byY613SiQ3lz+g/AWxaZsYH80/Zl+hEwEtU4fFz34Jcv9Kvda1JpknBT
Fi63ugfoNeNriO02AReMmDvuBG3X8RF1UQyBoTU3uZuW7X26MizEjiVCK9qaOLED
WDSEoyKLe4JKd387CVlsCY8K/6fBlFTI/hJhggDz8pZFj3n2irUI44kjgOmoxOrW
JY2jgY89AEMN9yOKkyQGara8pF9IJxTQ7jurYnWcUbompWeybJRwvWN0h+tGV+bd
l/aq/5LwL3fVpg==
-----END CERTIFICATE-----
@@ -0,0 +1,249 @@
/*
* Copyright (c) 2016, 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.
*
*/
#include <websocketpp/config/asio_client.hpp>
#include <websocketpp/client.hpp>
#include <iostream>
typedef websocketpp::client<websocketpp::config::asio_tls_client> client;
typedef websocketpp::lib::shared_ptr<websocketpp::lib::asio::ssl::context> context_ptr;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;
void on_message(websocketpp::connection_hdl, client::message_ptr msg) {
std::cout << msg->get_payload() << std::endl;
}
/// Verify that one of the subject alternative names matches the given hostname
bool verify_subject_alternative_name(const char * hostname, X509 * cert) {
STACK_OF(GENERAL_NAME) * san_names = NULL;
san_names = (STACK_OF(GENERAL_NAME) *) X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
if (san_names == NULL) {
return false;
}
int san_names_count = sk_GENERAL_NAME_num(san_names);
bool result = false;
for (int i = 0; i < san_names_count; i++) {
const GENERAL_NAME * current_name = sk_GENERAL_NAME_value(san_names, i);
if (current_name->type != GEN_DNS) {
continue;
}
char * dns_name = (char *) ASN1_STRING_data(current_name->d.dNSName);
// Make sure there isn't an embedded NUL character in the DNS name
if (ASN1_STRING_length(current_name->d.dNSName) != strlen(dns_name)) {
break;
}
// Compare expected hostname with the CN
result = (strcasecmp(hostname, dns_name) == 0);
}
sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
return result;
}
/// Verify that the certificate common name matches the given hostname
bool verify_common_name(const char * hostname, X509 * cert) {
// Find the position of the CN field in the Subject field of the certificate
int common_name_loc = X509_NAME_get_index_by_NID(X509_get_subject_name(cert), NID_commonName, -1);
if (common_name_loc < 0) {
return false;
}
// Extract the CN field
X509_NAME_ENTRY * common_name_entry = X509_NAME_get_entry(X509_get_subject_name(cert), common_name_loc);
if (common_name_entry == NULL) {
return false;
}
// Convert the CN field to a C string
ASN1_STRING * common_name_asn1 = X509_NAME_ENTRY_get_data(common_name_entry);
if (common_name_asn1 == NULL) {
return false;
}
char * common_name_str = (char *) ASN1_STRING_data(common_name_asn1);
// Make sure there isn't an embedded NUL character in the CN
if (ASN1_STRING_length(common_name_asn1) != strlen(common_name_str)) {
return false;
}
// Compare expected hostname with the CN
return (strcasecmp(hostname, common_name_str) == 0);
}
/**
* This code is derived from examples and documentation found ato00po
* http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/example/cpp03/ssl/client.cpp
* and
* https://github.com/iSECPartners/ssl-conservatory
*/
bool verify_certificate(const char * hostname, bool preverified, boost::asio::ssl::verify_context& ctx) {
// The verify callback can be used to check whether the certificate that is
// being presented is valid for the peer. For example, RFC 2818 describes
// the steps involved in doing this for HTTPS. Consult the OpenSSL
// documentation for more details. Note that the callback is called once
// for each certificate in the certificate chain, starting from the root
// certificate authority.
// Retrieve the depth of the current cert in the chain. 0 indicates the
// actual server cert, upon which we will perform extra validation
// (specifically, ensuring that the hostname matches. For other certs we
// will use the 'preverified' flag from Asio, which incorporates a number of
// non-implementation specific OpenSSL checking, such as the formatting of
// certs and the trusted status based on the CA certs we imported earlier.
int depth = X509_STORE_CTX_get_error_depth(ctx.native_handle());
// if we are on the final cert and everything else checks out, ensure that
// the hostname is present on the list of SANs or the common name (CN).
if (depth == 0 && preverified) {
X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
if (verify_subject_alternative_name(hostname, cert)) {
return true;
} else if (verify_common_name(hostname, cert)) {
return true;
} else {
return false;
}
}
return preverified;
}
/// TLS Initialization handler
/**
* WebSocket++ core and the Asio Transport do not handle TLS context creation
* and setup. This callback is provided so that the end user can set up their
* TLS context using whatever settings make sense for their application.
*
* As Asio and OpenSSL do not provide great documentation for the very common
* case of connect and actually perform basic verification of server certs this
* example includes a basic implementation (using Asio and OpenSSL) of the
* following reasonable default settings and verification steps:
*
* - Disable SSLv2 and SSLv3
* - Load trusted CA certificates and verify the server cert is trusted.
* - Verify that the hostname matches either the common name or one of the
* subject alternative names on the certificate.
*
* This is not meant to be an exhaustive reference implimentation of a perfect
* TLS client, but rather a reasonable starting point for building a secure
* TLS encrypted WebSocket client.
*
* If any TLS, Asio, or OpenSSL experts feel that these settings are poor
* defaults or there are critically missing steps please open a GitHub issue
* or drop a line on the project mailing list.
*
* Note the bundled CA cert ca-chain.cert.pem is the CA cert that signed the
* cert bundled with echo_server_tls. You can use print_client_tls with this
* CA cert to connect to echo_server_tls as long as you use /etc/hosts or
* something equivilent to spoof one of the names on that cert
* (websocketpp.org, for example).
*/
context_ptr on_tls_init(const char * hostname, websocketpp::connection_hdl) {
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);
ctx->set_verify_mode(boost::asio::ssl::verify_peer);
ctx->set_verify_callback(bind(&verify_certificate, hostname, ::_1, ::_2));
// Here we load the CA certificates of all CA's that this client trusts.
ctx->load_verify_file("ca-chain.cert.pem");
} catch (std::exception& e) {
std::cout << e.what() << std::endl;
}
return ctx;
}
int main(int argc, char* argv[]) {
client c;
std::string hostname = "localhost";
std::string port = "9002";
if (argc == 3) {
hostname = argv[1];
port = argv[2];
} else {
std::cout << "Usage: print_server_tls <hostname> <port>" << std::endl;
return 1;
}
std::string uri = "wss://" + hostname + ":" + port;
try {
// Set logging to be pretty verbose (everything except message payloads)
c.set_access_channels(websocketpp::log::alevel::all);
c.clear_access_channels(websocketpp::log::alevel::frame_payload);
c.set_error_channels(websocketpp::log::elevel::all);
// Initialize ASIO
c.init_asio();
// Register our message handler
c.set_message_handler(&on_message);
c.set_tls_init_handler(bind(&on_tls_init, hostname.c_str(), ::_1));
websocketpp::lib::error_code ec;
client::connection_ptr con = c.get_connection(uri, ec);
if (ec) {
std::cout << "could not create connection because: " << ec.message() << std::endl;
return 0;
}
// Note that connect here only requests a connection. No network messages are
// exchanged until the event loop starts running in the next line.
c.connect(con);
c.get_alog().write(websocketpp::log::alevel::app, "Connecting to " + uri);
// Start the ASIO io_service run loop
// this will cause a single connection to be made to the server. c.run()
// will exit when this connection is closed.
c.run();
} catch (websocketpp::exception const & e) {
std::cout << e.what() << std::endl;
}
}
+5 -5
View File
@@ -60,9 +60,9 @@ void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {
*/
try {
s->send(hdl, msg->get_payload(), msg->get_opcode());
} catch (const websocketpp::lib::error_code& e) {
std::cout << "Echo failed because: " << e
<< "(" << e.message() << ")" << std::endl;
} catch (websocketpp::exception const & e) {
std::cout << "Echo failed because: "
<< "(" << e.what() << ")" << std::endl;
}
}
@@ -96,10 +96,10 @@ int main(int argc, char * argv[]) {
// Start the ASIO io_service run loop
echo_server.run();
} catch (websocketpp::exception const & e) {
std::cout << e.what() << std::endl;
} catch (const std::exception & e) {
std::cout << e.what() << std::endl;
} catch (websocketpp::lib::error_code e) {
std::cout << e.message() << std::endl;
} catch (...) {
std::cout << "other exception" << std::endl;
}
+13 -2
View File
@@ -6,6 +6,17 @@
// is configured.
#include <websocketpp/common/thread.hpp>
/**
* Define a semi-cross platform helper method that waits/sleeps for a bit.
*/
void wait_a_bit() {
#ifdef WIN32
Sleep(1000);
#else
sleep(1);
#endif
}
/**
* The telemetry client connects to a WebSocket server and sends a message every
* second containing an integer count. This example can be used as the basis for
@@ -111,7 +122,7 @@ public:
}
if (wait) {
sleep(1);
wait_a_bit();
continue;
}
@@ -132,7 +143,7 @@ public:
break;
}
sleep(1);
wait_a_bit();
}
}
private:
+2 -2
View File
@@ -1,4 +1,4 @@
WebSocket++ (0.7.0)
WebSocket++ (0.8.0-dev)
==========================
WebSocket++ is a header only C++ library that implements RFC6455 The WebSocket
@@ -28,7 +28,7 @@ Get Involved
http://www.zaphoyd.com/websocketpp/
**User Manual**
http://www.zaphoyd.com/websocketpp/manual/
http://docs.websocketpp.org/
**GitHub Repository**
https://github.com/zaphoyd/websocketpp/
+6 -3
View File
@@ -132,11 +132,14 @@ struct debug_config_client : public websocketpp::config::core {
};
struct connection_setup {
connection_setup(bool p_is_server) : c(p_is_server, "", alog, elog, rng) {}
connection_setup(bool p_is_server)
: alog(websocketpp::lib::make_shared<stub_config::alog_type>())
, elog(websocketpp::lib::make_shared<stub_config::elog_type>())
, c(p_is_server, "", alog, elog, rng) {}
websocketpp::lib::error_code ec;
stub_config::alog_type alog;
stub_config::elog_type elog;
websocketpp::lib::shared_ptr<stub_config::alog_type> alog;
websocketpp::lib::shared_ptr<stub_config::elog_type> elog;
stub_config::rng_type rng;
websocketpp::connection<stub_config> c;
};
+12
View File
@@ -506,6 +506,18 @@ BOOST_AUTO_TEST_CASE( basic_request_with_body ) {
BOOST_CHECK_EQUAL( r.get_header("Host"), "www.example.com" );
BOOST_CHECK_EQUAL( r.get_header("Content-Length"), "5" );
BOOST_CHECK_EQUAL( r.get_body(), "abcde" );
BOOST_CHECK_EQUAL( r.get_headers().size(), 2);
websocketpp::http::parser::header_list::const_iterator it = r.get_headers().begin();
BOOST_CHECK_EQUAL( it->first, "Content-Length");
BOOST_CHECK_EQUAL( it->second, "5");
it++;
BOOST_CHECK_EQUAL( it->first, "Host");
BOOST_CHECK_EQUAL( it->second, "www.example.com");
}
BOOST_AUTO_TEST_CASE( basic_request_with_body_split ) {
+7 -5
View File
@@ -115,7 +115,9 @@ context_ptr on_tls_init(websocketpp::connection_hdl) {
struct mock_con: public websocketpp::transport::asio::connection<config> {
typedef websocketpp::transport::asio::connection<config> base;
mock_con(bool a, config::alog_type& b, config::elog_type& c) : base(a,b,c) {}
mock_con(bool a, const websocketpp::lib::shared_ptr<config::alog_type>& b,
const websocketpp::lib::shared_ptr<config::elog_type>& c)
: base(a,b,c) {}
void start() {
base::init(websocketpp::lib::bind(&mock_con::handle_start,this,
@@ -139,8 +141,8 @@ struct mock_endpoint : public websocketpp::transport::asio::endpoint<config> {
typedef websocketpp::transport::asio::endpoint<config> base;
mock_endpoint() {
alog.set_channels(websocketpp::log::alevel::all);
base::init_logging(&alog,&elog);
alog->set_channels(websocketpp::log::alevel::all);
base::init_logging(alog,elog);
init_asio();
}
@@ -170,8 +172,8 @@ struct mock_endpoint : public websocketpp::transport::asio::endpoint<config> {
}
connection_ptr m_con;
config::alog_type alog;
config::elog_type elog;
websocketpp::lib::shared_ptr<config::alog_type> alog;
websocketpp::lib::shared_ptr<config::elog_type> elog;
};
BOOST_AUTO_TEST_CASE( tls_handshake_timeout ) {
+13 -3
View File
@@ -58,7 +58,7 @@ struct stub_con : public iostream_con {
typedef websocketpp::lib::shared_ptr<type> ptr;
typedef iostream_con::timer_ptr timer_ptr;
stub_con(bool is_server, config::alog_type & a, config::elog_type & e)
stub_con(bool is_server, const websocketpp::lib::shared_ptr<config::alog_type>& a, const websocketpp::lib::shared_ptr<config::elog_type>& e)
: iostream_con(is_server,a,e)
// Set the error to a known code that is unused by the library
// This way we can easily confirm that the handler was run at all.
@@ -164,8 +164,8 @@ struct stub_con : public iostream_con {
};
// Stubs
config::alog_type alogger;
config::elog_type elogger;
websocketpp::lib::shared_ptr<config::alog_type> alogger = websocketpp::lib::make_shared<config::alog_type>();
websocketpp::lib::shared_ptr<config::elog_type> elogger = websocketpp::lib::make_shared<config::elog_type>();
BOOST_AUTO_TEST_CASE( const_methods ) {
iostream_con::ptr con(new iostream_con(true,alogger,elogger));
@@ -580,6 +580,16 @@ BOOST_AUTO_TEST_CASE( shutdown_handler ) {
BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::transport::error::general) );
}
BOOST_AUTO_TEST_CASE( clear_handler ) {
stub_con::ptr con(new stub_con(true,alogger,elogger));
con->set_shutdown_handler(&sd_handler);
con->set_shutdown_handler(NULL);
BOOST_CHECK_EQUAL( con->ec, make_error_code(websocketpp::error::test) );
con->shutdown();
BOOST_CHECK_EQUAL( con->ec, websocketpp::lib::error_code() );
}
BOOST_AUTO_TEST_CASE( shared_pointer_memory_cleanup ) {
stub_con::ptr con(new stub_con(true,alogger,elogger));
+8 -1
View File
@@ -3,5 +3,12 @@
# WEBSOCKETPP_FOUND - indicates that the module was found
# WEBSOCKETPP_INCLUDE_DIR - include directories
@PACKAGE_INIT@
set_and_check(WEBSOCKETPP_INCLUDE_DIR "@PACKAGE_INSTALL_INCLUDE_DIR@")
set(WEBSOCKETPP_FOUND TRUE)
set(WEBSOCKETPP_INCLUDE_DIR "@INSTALL_INCLUDE_DIR@")
#This is a bit of a hack, but it works well. It also allows continued support of CMake 2.8
if(${CMAKE_VERSION} VERSION_GREATER 3.0.0 OR ${CMAKE_VERSION} VERSION_EQUAL 3.0.0)
add_library(websocketpp::websocketpp INTERFACE IMPORTED)
set_target_properties(websocketpp::websocketpp PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${WEBSOCKETPP_INCLUDE_DIR}")
endif()
-11
View File
@@ -1,11 +0,0 @@
set(PACKAGE_VERSION "@WEBSOCKETPP_VERSION@")
# Check whether the requested PACKAGE_FIND_VERSION is compatible
if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
set(PACKAGE_VERSION_COMPATIBLE FALSE)
else()
set(PACKAGE_VERSION_COMPATIBLE TRUE)
if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
set(PACKAGE_VERSION_EXACT TRUE)
endif()
endif()
+13 -3
View File
@@ -101,9 +101,19 @@ namespace lib {
bool is_neg(T duration) {
return duration.count() < 0;
}
inline lib::chrono::milliseconds milliseconds(long duration) {
return lib::chrono::milliseconds(duration);
}
// If boost believes it has std::chrono available it will use it
// so we should also use it for things that relate to boost, even
// if the library would otherwise use boost::chrono.
#if defined(BOOST_ASIO_HAS_STD_CHRONO)
inline std::chrono::milliseconds milliseconds(long duration) {
return std::chrono::milliseconds(duration);
}
#else
inline lib::chrono::milliseconds milliseconds(long duration) {
return lib::chrono::milliseconds(duration);
}
#endif
#else
// Using boost::asio <1.49 we pretend a deadline timer is a steady
// timer and wrap the negative detection and duration conversion
+13 -1
View File
@@ -49,6 +49,7 @@
// Loggers
#include <websocketpp/logger/basic.hpp>
#include <websocketpp/logger/levels.hpp>
// RNG
#include <websocketpp/random/none.hpp>
@@ -188,7 +189,18 @@ struct core {
static const websocketpp::log::level alog_level =
websocketpp::log::alevel::all ^ websocketpp::log::alevel::devel;
///
/// Size of the per-connection read buffer
/**
* Each connection has an internal buffer of this size. A larger value will
* result in fewer trips through the library and less CPU overhead at the
* expense of increased memory usage per connection.
*
* If your application primarily deals in very large messages you may want
* to try setting this value higher.
*
* If your application has a lot of connections or primarily deals in small
* messages you may want to try setting this smaller.
*/
static const size_t connection_read_buffer_size = 16384;
/// Drop connections immediately on protocol error.
+6 -6
View File
@@ -294,8 +294,8 @@ private:
};
public:
explicit connection(bool p_is_server, std::string const & ua, alog_type& alog,
elog_type& elog, rng_type & rng)
explicit connection(bool p_is_server, std::string const & ua, const lib::shared_ptr<alog_type>& alog,
const lib::shared_ptr<elog_type>& elog, rng_type & rng)
: transport_con_type(p_is_server, alog, elog)
, m_handle_read_frame(lib::bind(
&type::handle_read_frame,
@@ -329,7 +329,7 @@ public:
, m_http_state(session::http_state::init)
, m_was_clean(false)
{
m_alog.write(log::alevel::devel,"connection constructor");
m_alog->write(log::alevel::devel,"connection constructor");
}
/// Get a shared pointer to this component
@@ -1486,7 +1486,7 @@ private:
void log_err(log::level l, char const * msg, error_type const & ec) {
std::stringstream s;
s << msg << " error: " << ec << " (" << ec.message() << ")";
m_elog.write(l, s.str());
m_elog->write(l, s.str());
}
// internal handler functions
@@ -1603,8 +1603,8 @@ private:
std::vector<std::string> m_requested_subprotocols;
bool const m_is_server;
alog_type& m_alog;
elog_type& m_elog;
const lib::shared_ptr<alog_type> m_alog;
const lib::shared_ptr<elog_type> m_elog;
rng_type & m_rng;
+24 -24
View File
@@ -89,8 +89,8 @@ public:
//friend connection;
explicit endpoint(bool p_is_server)
: m_alog(config::alog_level, log::channel_type_hint::access)
, m_elog(config::elog_level, log::channel_type_hint::error)
: m_alog(new alog_type(config::alog_level, log::channel_type_hint::access))
, m_elog(new elog_type(config::elog_level, log::channel_type_hint::error))
, m_user_agent(::websocketpp::user_agent)
, m_open_handshake_timeout_dur(config::timeout_open_handshake)
, m_close_handshake_timeout_dur(config::timeout_close_handshake)
@@ -99,12 +99,12 @@ public:
, m_max_http_body_size(config::max_http_body_size)
, m_is_server(p_is_server)
{
m_alog.set_channels(config::alog_level);
m_elog.set_channels(config::elog_level);
m_alog->set_channels(config::alog_level);
m_elog->set_channels(config::elog_level);
m_alog.write(log::alevel::devel, "endpoint constructor");
m_alog->write(log::alevel::devel, "endpoint constructor");
transport_type::init_logging(&m_alog, &m_elog);
transport_type::init_logging(m_alog, m_elog);
}
@@ -218,7 +218,7 @@ public:
* @param channels The channel value(s) to set
*/
void set_access_channels(log::level channels) {
m_alog.set_channels(channels);
m_alog->set_channels(channels);
}
/// Clear Access logging channels
@@ -229,7 +229,7 @@ public:
* @param channels The channel value(s) to clear
*/
void clear_access_channels(log::level channels) {
m_alog.clear_channels(channels);
m_alog->clear_channels(channels);
}
/// Set Error logging channel
@@ -240,7 +240,7 @@ public:
* @param channels The channel value(s) to set
*/
void set_error_channels(log::level channels) {
m_elog.set_channels(channels);
m_elog->set_channels(channels);
}
/// Clear Error logging channels
@@ -251,7 +251,7 @@ public:
* @param channels The channel value(s) to clear
*/
void clear_error_channels(log::level channels) {
m_elog.clear_channels(channels);
m_elog->clear_channels(channels);
}
/// Get reference to access logger
@@ -259,7 +259,7 @@ public:
* @return A reference to the access logger
*/
alog_type & get_alog() {
return m_alog;
return *m_alog;
}
/// Get reference to error logger
@@ -267,7 +267,7 @@ public:
* @return A reference to the error logger
*/
elog_type & get_elog() {
return m_elog;
return *m_elog;
}
/*************************/
@@ -275,52 +275,52 @@ public:
/*************************/
void set_open_handler(open_handler h) {
m_alog.write(log::alevel::devel,"set_open_handler");
m_alog->write(log::alevel::devel,"set_open_handler");
scoped_lock_type guard(m_mutex);
m_open_handler = h;
}
void set_close_handler(close_handler h) {
m_alog.write(log::alevel::devel,"set_close_handler");
m_alog->write(log::alevel::devel,"set_close_handler");
scoped_lock_type guard(m_mutex);
m_close_handler = h;
}
void set_fail_handler(fail_handler h) {
m_alog.write(log::alevel::devel,"set_fail_handler");
m_alog->write(log::alevel::devel,"set_fail_handler");
scoped_lock_type guard(m_mutex);
m_fail_handler = h;
}
void set_ping_handler(ping_handler h) {
m_alog.write(log::alevel::devel,"set_ping_handler");
m_alog->write(log::alevel::devel,"set_ping_handler");
scoped_lock_type guard(m_mutex);
m_ping_handler = h;
}
void set_pong_handler(pong_handler h) {
m_alog.write(log::alevel::devel,"set_pong_handler");
m_alog->write(log::alevel::devel,"set_pong_handler");
scoped_lock_type guard(m_mutex);
m_pong_handler = h;
}
void set_pong_timeout_handler(pong_timeout_handler h) {
m_alog.write(log::alevel::devel,"set_pong_timeout_handler");
m_alog->write(log::alevel::devel,"set_pong_timeout_handler");
scoped_lock_type guard(m_mutex);
m_pong_timeout_handler = h;
}
void set_interrupt_handler(interrupt_handler h) {
m_alog.write(log::alevel::devel,"set_interrupt_handler");
m_alog->write(log::alevel::devel,"set_interrupt_handler");
scoped_lock_type guard(m_mutex);
m_interrupt_handler = h;
}
void set_http_handler(http_handler h) {
m_alog.write(log::alevel::devel,"set_http_handler");
m_alog->write(log::alevel::devel,"set_http_handler");
scoped_lock_type guard(m_mutex);
m_http_handler = h;
}
void set_validate_handler(validate_handler h) {
m_alog.write(log::alevel::devel,"set_validate_handler");
m_alog->write(log::alevel::devel,"set_validate_handler");
scoped_lock_type guard(m_mutex);
m_validate_handler = h;
}
void set_message_handler(message_handler h) {
m_alog.write(log::alevel::devel,"set_message_handler");
m_alog->write(log::alevel::devel,"set_message_handler");
scoped_lock_type guard(m_mutex);
m_message_handler = h;
}
@@ -661,8 +661,8 @@ public:
protected:
connection_ptr create_connection();
alog_type m_alog;
elog_type m_elog;
lib::shared_ptr<alog_type> m_alog;
lib::shared_ptr<elog_type> m_elog;
private:
// dynamic settings
std::string m_user_agent;
+4
View File
@@ -176,6 +176,10 @@ inline void parser::process_header(std::string::iterator begin,
strip_lws(std::string(cursor+sizeof(header_separator)-1,end)));
}
inline header_list const & parser::get_headers() const {
return m_headers;
}
inline std::string parser::raw_headers() const {
std::stringstream raw;
+10
View File
@@ -441,6 +441,16 @@ public:
bool get_header_as_plist(std::string const & key, parameter_list & out)
const;
/// Return a list of all HTTP headers
/**
* Return a list of all HTTP headers
*
* @since 0.8.0
*
* @return A list of all HTTP headers
*/
header_list const & get_headers() const;
/// Append a value to an existing HTTP header
/**
* This method will set the value of the HTTP header `key` with the
+137 -137
View File
@@ -53,7 +53,7 @@ template <typename config>
void connection<config>::set_termination_handler(
termination_handler new_handler)
{
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
"connection set_termination_handler");
//scoped_lock_type lock(m_connection_state_lock);
@@ -103,8 +103,8 @@ lib::error_code connection<config>::send(void const * payload, size_t len,
template <typename config>
lib::error_code connection<config>::send(typename config::message_type::ptr msg)
{
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"connection send");
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"connection send");
}
{
@@ -153,8 +153,8 @@ lib::error_code connection<config>::send(typename config::message_type::ptr msg)
template <typename config>
void connection<config>::ping(std::string const& payload, lib::error_code& ec) {
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"connection ping");
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"connection ping");
}
{
@@ -162,7 +162,7 @@ void connection<config>::ping(std::string const& payload, lib::error_code& ec) {
if (m_state != session::state::open) {
std::stringstream ss;
ss << "connection::ping called from invalid state " << m_state;
m_alog.write(log::alevel::devel,ss.str());
m_alog->write(log::alevel::devel,ss.str());
ec = error::make_error_code(error::invalid_state);
return;
}
@@ -198,7 +198,7 @@ void connection<config>::ping(std::string const& payload, lib::error_code& ec) {
if (!m_ping_timer) {
// Our transport doesn't support timers
m_elog.write(log::elevel::warn,"Warning: a pong_timeout_handler is \
m_elog->write(log::elevel::warn,"Warning: a pong_timeout_handler is \
set but the transport in use does not support timeouts.");
}
}
@@ -239,7 +239,7 @@ void connection<config>::handle_pong_timeout(std::string payload,
return;
}
m_elog.write(log::elevel::devel,"pong_timeout error: "+ec.message());
m_elog->write(log::elevel::devel,"pong_timeout error: "+ec.message());
return;
}
@@ -250,8 +250,8 @@ void connection<config>::handle_pong_timeout(std::string payload,
template <typename config>
void connection<config>::pong(std::string const& payload, lib::error_code& ec) {
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"connection pong");
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"connection pong");
}
{
@@ -259,7 +259,7 @@ void connection<config>::pong(std::string const& payload, lib::error_code& ec) {
if (m_state != session::state::open) {
std::stringstream ss;
ss << "connection::pong called from invalid state " << m_state;
m_alog.write(log::alevel::devel,ss.str());
m_alog->write(log::alevel::devel,ss.str());
ec = error::make_error_code(error::invalid_state);
return;
}
@@ -304,8 +304,8 @@ template <typename config>
void connection<config>::close(close::status::value const code,
std::string const & reason, lib::error_code & ec)
{
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"connection close");
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"connection close");
}
// Truncate reason to maximum size allowable in a close frame.
@@ -339,7 +339,7 @@ void connection<config>::close(close::status::value const code,
*/
template <typename config>
lib::error_code connection<config>::interrupt() {
m_alog.write(log::alevel::devel,"connection connection::interrupt");
m_alog->write(log::alevel::devel,"connection connection::interrupt");
return transport_con_type::interrupt(
lib::bind(
&type::handle_interrupt,
@@ -358,7 +358,7 @@ void connection<config>::handle_interrupt() {
template <typename config>
lib::error_code connection<config>::pause_reading() {
m_alog.write(log::alevel::devel,"connection connection::pause_reading");
m_alog->write(log::alevel::devel,"connection connection::pause_reading");
return transport_con_type::dispatch(
lib::bind(
&type::handle_pause_reading,
@@ -370,13 +370,13 @@ lib::error_code connection<config>::pause_reading() {
/// Pause reading handler. Not safe to call directly
template <typename config>
void connection<config>::handle_pause_reading() {
m_alog.write(log::alevel::devel,"connection connection::handle_pause_reading");
m_alog->write(log::alevel::devel,"connection connection::handle_pause_reading");
m_read_flag = false;
}
template <typename config>
lib::error_code connection<config>::resume_reading() {
m_alog.write(log::alevel::devel,"connection connection::resume_reading");
m_alog->write(log::alevel::devel,"connection connection::resume_reading");
return transport_con_type::dispatch(
lib::bind(
&type::handle_resume_reading,
@@ -714,10 +714,10 @@ void connection<config>::send_http_response() {
template <typename config>
void connection<config>::start() {
m_alog.write(log::alevel::devel,"connection start");
m_alog->write(log::alevel::devel,"connection start");
if (m_internal_state != istate::USER_INIT) {
m_alog.write(log::alevel::devel,"Start called in invalid state");
m_alog->write(log::alevel::devel,"Start called in invalid state");
this->terminate(error::make_error_code(error::invalid_state));
return;
}
@@ -738,12 +738,12 @@ void connection<config>::start() {
template <typename config>
void connection<config>::handle_transport_init(lib::error_code const & ec) {
m_alog.write(log::alevel::devel,"connection handle_transport_init");
m_alog->write(log::alevel::devel,"connection handle_transport_init");
lib::error_code ecm = ec;
if (m_internal_state != istate::TRANSPORT_INIT) {
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
"handle_transport_init must be called from transport init state");
ecm = error::make_error_code(error::invalid_state);
}
@@ -751,7 +751,7 @@ void connection<config>::handle_transport_init(lib::error_code const & ec) {
if (ecm) {
std::stringstream s;
s << "handle_transport_init received error: "<< ecm.message();
m_elog.write(log::elevel::rerror,s.str());
m_elog->write(log::elevel::rerror,s.str());
this->terminate(ecm);
return;
@@ -772,7 +772,7 @@ void connection<config>::handle_transport_init(lib::error_code const & ec) {
template <typename config>
void connection<config>::read_handshake(size_t num_bytes) {
m_alog.write(log::alevel::devel,"connection read_handshake");
m_alog->write(log::alevel::devel,"connection read_handshake");
if (m_open_handshake_timeout_dur > 0) {
m_handshake_timer = transport_con_type::set_timer(
@@ -804,7 +804,7 @@ template <typename config>
void connection<config>::handle_read_handshake(lib::error_code const & ec,
size_t bytes_transferred)
{
m_alog.write(log::alevel::devel,"connection handle_read_handshake");
m_alog->write(log::alevel::devel,"connection handle_read_handshake");
lib::error_code ecm = ec;
@@ -819,7 +819,7 @@ void connection<config>::handle_read_handshake(lib::error_code const & ec,
// The connection was canceled while the response was being sent,
// 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,
m_alog->write(log::alevel::devel,
"handle_read_handshake invoked after connection was closed");
return;
} else {
@@ -830,7 +830,7 @@ void connection<config>::handle_read_handshake(lib::error_code const & ec,
if (ecm) {
if (ecm == transport::error::eof && m_state == session::state::closed) {
// we expect to get eof if the connection is closed already
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
"got (expected) eof/state error from closed con");
return;
}
@@ -842,7 +842,7 @@ void connection<config>::handle_read_handshake(lib::error_code const & ec,
// Boundaries checking. TODO: How much of this should be done?
if (bytes_transferred > config::connection_read_buffer_size) {
m_elog.write(log::elevel::fatal,"Fatal boundaries checking error.");
m_elog->write(log::elevel::fatal,"Fatal boundaries checking error.");
this->terminate(make_error_code(error::general));
return;
}
@@ -861,16 +861,16 @@ void connection<config>::handle_read_handshake(lib::error_code const & ec,
// More paranoid boundaries checking.
// TODO: Is this overkill?
if (bytes_processed > bytes_transferred) {
m_elog.write(log::elevel::fatal,"Fatal boundaries checking error.");
m_elog->write(log::elevel::fatal,"Fatal boundaries checking error.");
this->terminate(make_error_code(error::general));
return;
}
if (m_alog.static_test(log::alevel::devel)) {
if (m_alog->static_test(log::alevel::devel)) {
std::stringstream s;
s << "bytes_transferred: " << bytes_transferred
<< " bytes, bytes processed: " << bytes_processed << " bytes";
m_alog.write(log::alevel::devel,s.str());
m_alog->write(log::alevel::devel,s.str());
}
if (m_request.ready()) {
@@ -891,17 +891,17 @@ void connection<config>::handle_read_handshake(lib::error_code const & ec,
bytes_processed += 8;
} else {
// TODO: need more bytes
m_alog.write(log::alevel::devel,"short key3 read");
m_alog->write(log::alevel::devel,"short key3 read");
m_response.set_status(http::status_code::internal_server_error);
this->write_http_response_error(processor::error::make_error_code(processor::error::short_key3));
return;
}
}
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,m_request.raw());
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,m_request.raw());
if (!m_request.get_header("Sec-WebSocket-Key3").empty()) {
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
utility::to_hex(m_request.get_header("Sec-WebSocket-Key3")));
}
}
@@ -948,7 +948,7 @@ void connection<config>::handle_read_handshake(lib::error_code const & ec,
template <typename config>
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,
m_alog->write(log::alevel::devel,
"write_http_response_error called in invalid state");
this->terminate(error::make_error_code(error::invalid_state));
return;
@@ -965,7 +965,7 @@ template <typename config>
void connection<config>::handle_read_frame(lib::error_code const & ec,
size_t bytes_transferred)
{
//m_alog.write(log::alevel::devel,"connection handle_read_frame");
//m_alog->write(log::alevel::devel,"connection handle_read_frame");
lib::error_code ecm = ec;
@@ -980,7 +980,7 @@ void connection<config>::handle_read_frame(lib::error_code const & ec,
if (m_state == session::state::closed) {
// we expect to get eof if the connection is closed already
// just ignore it
m_alog.write(log::alevel::devel,"got eof from closed con");
m_alog->write(log::alevel::devel,"got eof from closed con");
return;
} else if (m_state == session::state::closing && !m_is_server) {
// If we are a client we expect to get eof in the closing state,
@@ -995,7 +995,7 @@ void connection<config>::handle_read_frame(lib::error_code const & ec,
// changed and should be ignored as they pose no problems and there
// is nothing useful that we can do about them.
if (m_state == session::state::closed) {
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
"handle_read_frame: got invalid istate in closed state");
return;
}
@@ -1019,32 +1019,32 @@ void connection<config>::handle_read_frame(lib::error_code const & ec,
// Boundaries checking. TODO: How much of this should be done?
/*if (bytes_transferred > config::connection_read_buffer_size) {
m_elog.write(log::elevel::fatal,"Fatal boundaries checking error");
m_elog->write(log::elevel::fatal,"Fatal boundaries checking error");
this->terminate(make_error_code(error::general));
return;
}*/
size_t p = 0;
if (m_alog.static_test(log::alevel::devel)) {
if (m_alog->static_test(log::alevel::devel)) {
std::stringstream s;
s << "p = " << p << " bytes transferred = " << bytes_transferred;
m_alog.write(log::alevel::devel,s.str());
m_alog->write(log::alevel::devel,s.str());
}
while (p < bytes_transferred) {
if (m_alog.static_test(log::alevel::devel)) {
if (m_alog->static_test(log::alevel::devel)) {
std::stringstream s;
s << "calling consume with " << bytes_transferred-p << " bytes";
m_alog.write(log::alevel::devel,s.str());
m_alog->write(log::alevel::devel,s.str());
}
lib::error_code consume_ec;
if (m_alog.static_test(log::alevel::devel)) {
if (m_alog->static_test(log::alevel::devel)) {
std::stringstream s;
s << "Processing Bytes: " << utility::to_hex(reinterpret_cast<uint8_t*>(m_buf)+p,bytes_transferred-p);
m_alog.write(log::alevel::devel,s.str());
m_alog->write(log::alevel::devel,s.str());
}
p += m_processor->consume(
@@ -1053,10 +1053,10 @@ void connection<config>::handle_read_frame(lib::error_code const & ec,
consume_ec
);
if (m_alog.static_test(log::alevel::devel)) {
if (m_alog->static_test(log::alevel::devel)) {
std::stringstream s;
s << "bytes left after consume: " << bytes_transferred-p;
m_alog.write(log::alevel::devel,s.str());
m_alog->write(log::alevel::devel,s.str());
}
if (consume_ec) {
log_err(log::elevel::rerror, "consume", consume_ec);
@@ -1082,20 +1082,20 @@ void connection<config>::handle_read_frame(lib::error_code const & ec,
}
if (m_processor->ready()) {
if (m_alog.static_test(log::alevel::devel)) {
if (m_alog->static_test(log::alevel::devel)) {
std::stringstream s;
s << "Complete message received. Dispatching";
m_alog.write(log::alevel::devel,s.str());
m_alog->write(log::alevel::devel,s.str());
}
message_ptr msg = m_processor->get_message();
if (!msg) {
m_alog.write(log::alevel::devel, "null message from m_processor");
m_alog->write(log::alevel::devel, "null message from m_processor");
} else if (!is_control(msg->get_opcode())) {
// data message, dispatch to user
if (m_state != session::state::open) {
m_elog.write(log::elevel::warn, "got non-close frame while closing");
m_elog->write(log::elevel::warn, "got non-close frame while closing");
} else if (m_message_handler) {
m_message_handler(m_connection_hdl, msg);
}
@@ -1132,7 +1132,7 @@ void connection<config>::read_frame() {
template <typename config>
lib::error_code connection<config>::initialize_processor() {
m_alog.write(log::alevel::devel,"initialize_processor");
m_alog->write(log::alevel::devel,"initialize_processor");
// if it isn't a websocket handshake nothing to do.
if (!processor::is_websocket_handshake(m_request)) {
@@ -1142,7 +1142,7 @@ lib::error_code connection<config>::initialize_processor() {
int version = processor::get_websocket_version(m_request);
if (version < 0) {
m_alog.write(log::alevel::devel, "BAD REQUEST: can't determine version");
m_alog->write(log::alevel::devel, "BAD REQUEST: can't determine version");
m_response.set_status(http::status_code::bad_request);
return error::make_error_code(error::invalid_version);
}
@@ -1156,7 +1156,7 @@ lib::error_code connection<config>::initialize_processor() {
// We don't have a processor for this version. Return bad request
// with Sec-WebSocket-Version header filled with values we do accept
m_alog.write(log::alevel::devel, "BAD REQUEST: no processor for version");
m_alog->write(log::alevel::devel, "BAD REQUEST: no processor for version");
m_response.set_status(http::status_code::bad_request);
std::stringstream ss;
@@ -1174,11 +1174,11 @@ lib::error_code connection<config>::initialize_processor() {
template <typename config>
lib::error_code connection<config>::process_handshake_request() {
m_alog.write(log::alevel::devel,"process handshake request");
m_alog->write(log::alevel::devel,"process handshake request");
if (!processor::is_websocket_handshake(m_request)) {
// this is not a websocket handshake. Process as plain HTTP
m_alog.write(log::alevel::devel,"HTTP REQUEST");
m_alog->write(log::alevel::devel,"HTTP REQUEST");
// extract URI from request
m_uri = processor::get_uri_from_host(
@@ -1187,7 +1187,7 @@ lib::error_code connection<config>::process_handshake_request() {
);
if (!m_uri->get_valid()) {
m_alog.write(log::alevel::devel, "Bad request: failed to parse uri");
m_alog->write(log::alevel::devel, "Bad request: failed to parse uri");
m_response.set_status(http::status_code::bad_request);
return error::make_error_code(error::invalid_uri);
}
@@ -1212,7 +1212,7 @@ lib::error_code connection<config>::process_handshake_request() {
// Validate: make sure all required elements are present.
if (ec){
// Not a valid handshake request
m_alog.write(log::alevel::devel, "Bad request " + ec.message());
m_alog->write(log::alevel::devel, "Bad request " + ec.message());
m_response.set_status(http::status_code::bad_request);
return ec;
}
@@ -1225,7 +1225,7 @@ lib::error_code connection<config>::process_handshake_request() {
if (neg_results.first) {
// There was a fatal error in extension parsing that should result in
// a failed connection attempt.
m_alog.write(log::alevel::devel, "Bad request: " + neg_results.first.message());
m_alog->write(log::alevel::devel, "Bad request: " + neg_results.first.message());
m_response.set_status(http::status_code::bad_request);
return neg_results.first;
} else {
@@ -1243,7 +1243,7 @@ lib::error_code connection<config>::process_handshake_request() {
if (!m_uri->get_valid()) {
m_alog.write(log::alevel::devel, "Bad request: failed to parse uri");
m_alog->write(log::alevel::devel, "Bad request: failed to parse uri");
m_response.set_status(http::status_code::bad_request);
return error::make_error_code(error::invalid_uri);
}
@@ -1267,14 +1267,14 @@ lib::error_code connection<config>::process_handshake_request() {
if (ec) {
std::stringstream s;
s << "Processing error: " << ec << "(" << ec.message() << ")";
m_alog.write(log::alevel::devel, s.str());
m_alog->write(log::alevel::devel, s.str());
m_response.set_status(http::status_code::internal_server_error);
return ec;
}
} else {
// User application has rejected the handshake
m_alog.write(log::alevel::devel, "USER REJECT");
m_alog->write(log::alevel::devel, "USER REJECT");
// Use Bad Request if the user handler did not provide a more
// specific http response error code.
@@ -1291,10 +1291,10 @@ lib::error_code connection<config>::process_handshake_request() {
template <typename config>
void connection<config>::write_http_response(lib::error_code const & ec) {
m_alog.write(log::alevel::devel,"connection write_http_response");
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.");
m_alog->write(log::alevel::http,"An HTTP handler took over the connection.");
return;
}
@@ -1324,10 +1324,10 @@ void connection<config>::write_http_response(lib::error_code const & ec) {
m_handshake_buffer = m_response.raw();
}
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"Raw Handshake response:\n"+m_handshake_buffer);
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"Raw Handshake response:\n"+m_handshake_buffer);
if (!m_response.get_header("Sec-WebSocket-Key3").empty()) {
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
utility::to_hex(m_response.get_header("Sec-WebSocket-Key3")));
}
}
@@ -1346,7 +1346,7 @@ void connection<config>::write_http_response(lib::error_code const & ec) {
template <typename config>
void connection<config>::handle_write_http_response(lib::error_code const & ec) {
m_alog.write(log::alevel::devel,"handle_write_http_response");
m_alog->write(log::alevel::devel,"handle_write_http_response");
lib::error_code ecm = ec;
@@ -1361,7 +1361,7 @@ void connection<config>::handle_write_http_response(lib::error_code const & ec)
// The connection was canceled while the response was being sent,
// 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,
m_alog->write(log::alevel::devel,
"handle_write_http_response invoked after connection was closed");
return;
} else {
@@ -1372,7 +1372,7 @@ void connection<config>::handle_write_http_response(lib::error_code const & ec)
if (ecm) {
if (ecm == transport::error::eof && m_state == session::state::closed) {
// we expect to get eof if the connection is closed already
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
"got (expected) eof/state error from closed con");
return;
}
@@ -1397,7 +1397,7 @@ void connection<config>::handle_write_http_response(lib::error_code const & ec)
std::stringstream s;
s << "Handshake ended with HTTP error: "
<< m_response.get_status_code();
m_elog.write(log::elevel::rerror,s.str());
m_elog->write(log::elevel::rerror,s.str());
} else {
// if this was not a websocket connection, we have written
// the expected response and the connection can be closed.
@@ -1405,7 +1405,7 @@ void connection<config>::handle_write_http_response(lib::error_code const & ec)
this->log_http_result();
if (m_ec) {
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
"got to writing HTTP results with m_ec set: "+m_ec.message());
}
m_ec = make_error_code(error::http_connection_ended);
@@ -1429,7 +1429,7 @@ void connection<config>::handle_write_http_response(lib::error_code const & ec)
template <typename config>
void connection<config>::send_http_request() {
m_alog.write(log::alevel::devel,"connection send_http_request");
m_alog->write(log::alevel::devel,"connection send_http_request");
// TODO: origin header?
@@ -1445,7 +1445,7 @@ void connection<config>::send_http_request() {
return;
}
} else {
m_elog.write(log::elevel::fatal,"Internal library error: missing processor");
m_elog->write(log::elevel::fatal,"Internal library error: missing processor");
return;
}
@@ -1460,8 +1460,8 @@ void connection<config>::send_http_request() {
m_handshake_buffer = m_request.raw();
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"Raw Handshake request:\n"+m_handshake_buffer);
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"Raw Handshake request:\n"+m_handshake_buffer);
}
if (m_open_handshake_timeout_dur > 0) {
@@ -1488,7 +1488,7 @@ void connection<config>::send_http_request() {
template <typename config>
void connection<config>::handle_send_http_request(lib::error_code const & ec) {
m_alog.write(log::alevel::devel,"handle_send_http_request");
m_alog->write(log::alevel::devel,"handle_send_http_request");
lib::error_code ecm = ec;
@@ -1505,7 +1505,7 @@ void connection<config>::handle_send_http_request(lib::error_code const & ec) {
// The connection was canceled while the response was being sent,
// 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,
m_alog->write(log::alevel::devel,
"handle_send_http_request invoked after connection was closed");
return;
} else {
@@ -1516,7 +1516,7 @@ void connection<config>::handle_send_http_request(lib::error_code const & ec) {
if (ecm) {
if (ecm == transport::error::eof && m_state == session::state::closed) {
// we expect to get eof if the connection is closed already
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
"got (expected) eof/state error from closed con");
return;
}
@@ -1543,7 +1543,7 @@ template <typename config>
void connection<config>::handle_read_http_response(lib::error_code const & ec,
size_t bytes_transferred)
{
m_alog.write(log::alevel::devel,"handle_read_http_response");
m_alog->write(log::alevel::devel,"handle_read_http_response");
lib::error_code ecm = ec;
@@ -1558,7 +1558,7 @@ void connection<config>::handle_read_http_response(lib::error_code const & ec,
// The connection was canceled while the response was being sent,
// 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,
m_alog->write(log::alevel::devel,
"handle_read_http_response invoked after connection was closed");
return;
} else {
@@ -1569,7 +1569,7 @@ void connection<config>::handle_read_http_response(lib::error_code const & ec,
if (ecm) {
if (ecm == transport::error::eof && m_state == session::state::closed) {
// we expect to get eof if the connection is closed already
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
"got (expected) eof/state error from closed con");
return;
}
@@ -1584,13 +1584,13 @@ void connection<config>::handle_read_http_response(lib::error_code const & ec,
try {
bytes_processed = m_response.consume(m_buf,bytes_transferred);
} catch (http::exception & e) {
m_elog.write(log::elevel::rerror,
m_elog->write(log::elevel::rerror,
std::string("error in handle_read_http_response: ")+e.what());
this->terminate(make_error_code(error::general));
return;
}
m_alog.write(log::alevel::devel,std::string("Raw response: ")+m_response.raw());
m_alog->write(log::alevel::devel,std::string("Raw response: ")+m_response.raw());
if (m_response.headers_ready()) {
if (m_handshake_timer) {
@@ -1621,7 +1621,7 @@ void connection<config>::handle_read_http_response(lib::error_code const & ec,
// doesn't match the options requested by the client. Its possible
// that the best behavior in this cases is to log and continue with
// an unextended connection.
m_alog.write(log::alevel::devel, "Extension negotiation failed: "
m_alog->write(log::alevel::devel, "Extension negotiation failed: "
+ neg_results.first.message());
this->terminate(make_error_code(error::extension_neg_failed));
// TODO: close connection with reason 1010 (and list extensions)
@@ -1664,13 +1664,13 @@ void connection<config>::handle_open_handshake_timeout(
lib::error_code const & ec)
{
if (ec == transport::error::operation_aborted) {
m_alog.write(log::alevel::devel,"open handshake timer cancelled");
m_alog->write(log::alevel::devel,"open handshake timer cancelled");
} else if (ec) {
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
"open handle_open_handshake_timeout error: "+ec.message());
// TODO: ignore or fail here?
} else {
m_alog.write(log::alevel::devel,"open handshake timer expired");
m_alog->write(log::alevel::devel,"open handshake timer expired");
terminate(make_error_code(error::open_handshake_timeout));
}
}
@@ -1680,21 +1680,21 @@ void connection<config>::handle_close_handshake_timeout(
lib::error_code const & ec)
{
if (ec == transport::error::operation_aborted) {
m_alog.write(log::alevel::devel,"asio close handshake timer cancelled");
m_alog->write(log::alevel::devel,"asio close handshake timer cancelled");
} else if (ec) {
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
"asio open handle_close_handshake_timeout error: "+ec.message());
// TODO: ignore or fail here?
} else {
m_alog.write(log::alevel::devel, "asio close handshake timer expired");
m_alog->write(log::alevel::devel, "asio close handshake timer expired");
terminate(make_error_code(error::close_handshake_timeout));
}
}
template <typename config>
void connection<config>::terminate(lib::error_code const & ec) {
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"connection terminate");
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"connection terminate");
}
// Cancel close handshake timer
@@ -1727,7 +1727,7 @@ void connection<config>::terminate(lib::error_code const & ec) {
m_state = session::state::closed;
tstat = closed;
} else {
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
"terminate called on connection that was already terminated");
return;
}
@@ -1748,8 +1748,8 @@ template <typename config>
void connection<config>::handle_terminate(terminate_status tstat,
lib::error_code const & ec)
{
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"connection handle_terminate");
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"connection handle_terminate");
}
if (ec) {
@@ -1770,7 +1770,7 @@ void connection<config>::handle_terminate(terminate_status tstat,
}
log_close_result();
} else {
m_elog.write(log::elevel::rerror,"Unknown terminate_status");
m_elog->write(log::elevel::rerror,"Unknown terminate_status");
}
// call the termination handler if it exists
@@ -1780,7 +1780,7 @@ void connection<config>::handle_terminate(terminate_status tstat,
try {
m_termination_handler(type::get_shared());
} catch (std::exception const & e) {
m_elog.write(log::elevel::warn,
m_elog->write(log::elevel::warn,
std::string("termination_handler call failed. Reason was: ")+e.what());
}
}
@@ -1788,7 +1788,7 @@ void connection<config>::handle_terminate(terminate_status tstat,
template <typename config>
void connection<config>::write_frame() {
//m_alog.write(log::alevel::devel,"connection write_frame");
//m_alog->write(log::alevel::devel,"connection write_frame");
{
scoped_lock_type lock(m_write_lock);
@@ -1834,8 +1834,8 @@ void connection<config>::write_frame() {
}
// Print detailed send stats if those log levels are enabled
if (m_alog.static_test(log::alevel::frame_header)) {
if (m_alog.dynamic_test(log::alevel::frame_header)) {
if (m_alog->static_test(log::alevel::frame_header)) {
if (m_alog->dynamic_test(log::alevel::frame_header)) {
std::stringstream general,header,payload;
general << "Dispatching write containing " << m_current_msgs.size()
@@ -1855,8 +1855,8 @@ void connection<config>::write_frame() {
<< m_current_msgs[i]->get_header().size() << ") "
<< utility::to_hex(m_current_msgs[i]->get_header()) << "\n";
if (m_alog.static_test(log::alevel::frame_payload)) {
if (m_alog.dynamic_test(log::alevel::frame_payload)) {
if (m_alog->static_test(log::alevel::frame_payload)) {
if (m_alog->dynamic_test(log::alevel::frame_payload)) {
payload << "[" << i << "] ("
<< m_current_msgs[i]->get_payload().size() << ") ["<<m_current_msgs[i]->get_opcode()<<"] "
<< (m_current_msgs[i]->get_opcode() == frame::opcode::text ?
@@ -1870,9 +1870,9 @@ void connection<config>::write_frame() {
general << hbytes << " header bytes and " << pbytes << " payload bytes";
m_alog.write(log::alevel::frame_header,general.str());
m_alog.write(log::alevel::frame_header,header.str());
m_alog.write(log::alevel::frame_payload,payload.str());
m_alog->write(log::alevel::frame_header,general.str());
m_alog->write(log::alevel::frame_header,header.str());
m_alog->write(log::alevel::frame_payload,payload.str());
}
}
@@ -1885,8 +1885,8 @@ void connection<config>::write_frame() {
template <typename config>
void connection<config>::handle_write_frame(lib::error_code const & ec)
{
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"connection handle_write_frame");
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"connection handle_write_frame");
}
bool terminal = m_current_msgs.back()->get_terminal();
@@ -1933,21 +1933,21 @@ std::vector<int> const & connection<config>::get_supported_versions() const
template <typename config>
void connection<config>::process_control_frame(typename config::message_type::ptr msg)
{
m_alog.write(log::alevel::devel,"process_control_frame");
m_alog->write(log::alevel::devel,"process_control_frame");
frame::opcode::value op = msg->get_opcode();
lib::error_code ec;
std::stringstream s;
s << "Control frame received with opcode " << op;
m_alog.write(log::alevel::control,s.str());
m_alog->write(log::alevel::control,s.str());
if (m_state == session::state::closed) {
m_elog.write(log::elevel::warn,"got frame in state closed");
m_elog->write(log::elevel::warn,"got frame in state closed");
return;
}
if (op != frame::opcode::CLOSE && m_state != session::state::open) {
m_elog.write(log::elevel::warn,"got non-close frame in state closing");
m_elog->write(log::elevel::warn,"got non-close frame in state closing");
return;
}
@@ -1972,7 +1972,7 @@ void connection<config>::process_control_frame(typename config::message_type::pt
m_ping_timer->cancel();
}
} else if (op == frame::opcode::CLOSE) {
m_alog.write(log::alevel::devel,"got close frame");
m_alog->write(log::alevel::devel,"got close frame");
// record close code and reason somewhere
m_remote_close_code = close::extract_code(msg->get_payload(),ec);
@@ -1981,12 +1981,12 @@ void connection<config>::process_control_frame(typename config::message_type::pt
if (config::drop_on_protocol_error) {
s << "Received invalid close code " << m_remote_close_code
<< " dropping connection per config.";
m_elog.write(log::elevel::devel,s.str());
m_elog->write(log::elevel::devel,s.str());
this->terminate(ec);
} else {
s << "Received invalid close code " << m_remote_close_code
<< " sending acknowledgement and closing";
m_elog.write(log::elevel::devel,s.str());
m_elog->write(log::elevel::devel,s.str());
ec = send_close_ack(close::status::protocol_error,
"Invalid close code");
if (ec) {
@@ -1999,11 +1999,11 @@ void connection<config>::process_control_frame(typename config::message_type::pt
m_remote_close_reason = close::extract_reason(msg->get_payload(),ec);
if (ec) {
if (config::drop_on_protocol_error) {
m_elog.write(log::elevel::devel,
m_elog->write(log::elevel::devel,
"Received invalid close reason. Dropping connection per config");
this->terminate(ec);
} else {
m_elog.write(log::elevel::devel,
m_elog->write(log::elevel::devel,
"Received invalid close reason. Sending acknowledgement and closing");
ec = send_close_ack(close::status::protocol_error,
"Invalid close reason");
@@ -2018,7 +2018,7 @@ void connection<config>::process_control_frame(typename config::message_type::pt
s.str("");
s << "Received close frame with code " << m_remote_close_code
<< " and reason " << m_remote_close_reason;
m_alog.write(log::alevel::devel,s.str());
m_alog->write(log::alevel::devel,s.str());
ec = send_close_ack();
if (ec) {
@@ -2026,7 +2026,7 @@ void connection<config>::process_control_frame(typename config::message_type::pt
}
} else if (m_state == session::state::closing && !m_was_clean) {
// ack of our close
m_alog.write(log::alevel::devel, "Got acknowledgement of close");
m_alog->write(log::alevel::devel, "Got acknowledgement of close");
m_was_clean = true;
@@ -2042,11 +2042,11 @@ void connection<config>::process_control_frame(typename config::message_type::pt
}
} else {
// spurious, ignore
m_elog.write(log::elevel::devel, "Got close frame in wrong state");
m_elog->write(log::elevel::devel, "Got close frame in wrong state");
}
} else {
// got an invalid control opcode
m_elog.write(log::elevel::devel, "Got control frame with invalid opcode");
m_elog->write(log::elevel::devel, "Got control frame with invalid opcode");
// initiate protocol error shutdown
}
}
@@ -2062,7 +2062,7 @@ template <typename config>
lib::error_code connection<config>::send_close_frame(close::status::value code,
std::string const & reason, bool ack, bool terminal)
{
m_alog.write(log::alevel::devel,"send_close_frame");
m_alog->write(log::alevel::devel,"send_close_frame");
// check for special codes
@@ -2073,24 +2073,24 @@ lib::error_code connection<config>::send_close_frame(close::status::value code,
// send blank info. If it is an ack then echo the close information from
// the remote endpoint.
if (config::silent_close) {
m_alog.write(log::alevel::devel,"closing silently");
m_alog->write(log::alevel::devel,"closing silently");
m_local_close_code = close::status::no_status;
m_local_close_reason.clear();
} else if (code != close::status::blank) {
m_alog.write(log::alevel::devel,"closing with specified codes");
m_alog->write(log::alevel::devel,"closing with specified codes");
m_local_close_code = code;
m_local_close_reason = reason;
} else if (!ack) {
m_alog.write(log::alevel::devel,"closing with no status code");
m_alog->write(log::alevel::devel,"closing with no status code");
m_local_close_code = close::status::no_status;
m_local_close_reason.clear();
} else if (m_remote_close_code == close::status::no_status) {
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
"acknowledging a no-status close with normal code");
m_local_close_code = close::status::normal;
m_local_close_reason.clear();
} else {
m_alog.write(log::alevel::devel,"acknowledging with remote codes");
m_alog->write(log::alevel::devel,"acknowledging with remote codes");
m_local_close_code = m_remote_close_code;
m_local_close_reason = m_remote_close_reason;
}
@@ -2098,7 +2098,7 @@ lib::error_code connection<config>::send_close_frame(close::status::value code,
std::stringstream s;
s << "Closing with code: " << m_local_close_code << ", and reason: "
<< m_local_close_reason;
m_alog.write(log::alevel::devel,s.str());
m_alog->write(log::alevel::devel,s.str());
message_ptr msg = m_msg_manager->get_message();
if (!msg) {
@@ -2213,11 +2213,11 @@ void connection<config>::write_push(typename config::message_type::ptr msg)
m_send_buffer_size += msg->get_payload().size();
m_send_queue.push(msg);
if (m_alog.static_test(log::alevel::devel)) {
if (m_alog->static_test(log::alevel::devel)) {
std::stringstream s;
s << "write_push: message count: " << m_send_queue.size()
<< " buffer size: " << m_send_buffer_size;
m_alog.write(log::alevel::devel,s.str());
m_alog->write(log::alevel::devel,s.str());
}
}
@@ -2235,11 +2235,11 @@ typename config::message_type::ptr connection<config>::write_pop()
m_send_buffer_size -= msg->get_payload().size();
m_send_queue.pop();
if (m_alog.static_test(log::alevel::devel)) {
if (m_alog->static_test(log::alevel::devel)) {
std::stringstream s;
s << "write_pop: message count: " << m_send_queue.size()
<< " buffer size: " << m_send_buffer_size;
m_alog.write(log::alevel::devel,s.str());
m_alog->write(log::alevel::devel,s.str());
}
return msg;
}
@@ -2282,7 +2282,7 @@ void connection<config>::log_open_result()
// Status code
s << m_response.get_status_code();
m_alog.write(log::alevel::connect,s.str());
m_alog->write(log::alevel::connect,s.str());
}
template <typename config>
@@ -2296,7 +2296,7 @@ void connection<config>::log_close_result()
<< "] remote:[" << m_remote_close_code
<< (m_remote_close_reason.empty() ? "" : ","+m_remote_close_reason) << "]";
m_alog.write(log::alevel::disconnect,s.str());
m_alog->write(log::alevel::disconnect,s.str());
}
template <typename config>
@@ -2335,7 +2335,7 @@ void connection<config>::log_fail_result()
// WebSocket++ error code & reason
s << " " << m_ec << " " << m_ec.message();
m_alog.write(log::alevel::fail,s.str());
m_alog->write(log::alevel::fail,s.str());
}
template <typename config>
@@ -2343,7 +2343,7 @@ void connection<config>::log_http_result() {
std::stringstream s;
if (processor::is_websocket_handshake(m_request)) {
m_alog.write(log::alevel::devel,"Call to log_http_result for WebSocket");
m_alog->write(log::alevel::devel,"Call to log_http_result for WebSocket");
return;
}
@@ -2364,7 +2364,7 @@ void connection<config>::log_http_result() {
s << " \"" << utility::string_replace_all(ua,"\"","\\\"") << "\" ";
}
m_alog.write(log::alevel::http,s.str());
m_alog->write(log::alevel::http,s.str());
}
} // namespace websocketpp
+4 -4
View File
@@ -35,7 +35,7 @@ namespace websocketpp {
template <typename connection, typename config>
typename endpoint<connection,config>::connection_ptr
endpoint<connection,config>::create_connection() {
m_alog.write(log::alevel::devel,"create_connection");
m_alog->write(log::alevel::devel,"create_connection");
//scoped_lock_type lock(m_state_lock);
/*if (m_state == STOPPING || m_state == STOPPED) {
@@ -45,7 +45,7 @@ endpoint<connection,config>::create_connection() {
//scoped_lock_type guard(m_mutex);
// Create a connection on the heap and manage it using a shared pointer
connection_ptr con = lib::make_shared<connection_type>(m_is_server,
m_user_agent, lib::ref(m_alog), lib::ref(m_elog), lib::ref(m_rng));
m_user_agent, m_alog, m_elog, lib::ref(m_rng));
connection_weak_ptr w(con);
@@ -85,7 +85,7 @@ endpoint<connection,config>::create_connection() {
ec = transport_type::init(con);
if (ec) {
m_elog.write(log::elevel::fatal,ec.message());
m_elog->write(log::elevel::fatal,ec.message());
return connection_ptr();
}
@@ -98,7 +98,7 @@ void endpoint<connection,config>::interrupt(connection_hdl hdl, lib::error_code
connection_ptr con = get_con_from_hdl(hdl,ec);
if (ec) {return;}
m_alog.write(log::alevel::devel,"Interrupting connection");
m_alog->write(log::alevel::devel,"Interrupting connection");
ec = con->interrupt();
}
+3 -3
View File
@@ -71,7 +71,7 @@ public:
explicit client() : endpoint_type(false)
{
endpoint_type::m_alog.write(log::alevel::devel, "client constructor");
endpoint_type::m_alog->write(log::alevel::devel, "client constructor");
}
/// Get a new connection
@@ -157,10 +157,10 @@ private:
if (ec) {
con->terminate(ec);
endpoint_type::m_elog.write(log::elevel::rerror,
endpoint_type::m_elog->write(log::elevel::rerror,
"handle_connect error: "+ec.message());
} else {
endpoint_type::m_alog.write(log::alevel::connect,
endpoint_type::m_alog->write(log::alevel::connect,
"Successful connection");
con->start();
+14 -9
View File
@@ -68,7 +68,7 @@ public:
explicit server() : endpoint_type(true)
{
endpoint_type::m_alog.write(log::alevel::devel, "server constructor");
endpoint_type::m_alog->write(log::alevel::devel, "server constructor");
}
/// Destructor
@@ -77,7 +77,7 @@ public:
#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_
@@ -115,7 +115,7 @@ public:
*
* Refer to documentation for the transport policy you are using for
* instructions on how to stop this acceptance loop.
*
*
* @param [out] ec A status code indicating an error, if any.
*/
void start_accept(lib::error_code & ec) {
@@ -126,13 +126,18 @@ public:
ec = lib::error_code();
connection_ptr con = get_connection();
if (!con) {
ec = error::make_error_code(error::con_creation_failed);
return;
}
transport_type::async_accept(
lib::static_pointer_cast<transport_con_type>(con),
lib::bind(&type::handle_accept,this,con,lib::placeholders::_1),
ec
);
if (ec && con) {
// If the connection was constructed but the accept failed,
// terminate the connection to prevent memory leaks
@@ -163,10 +168,10 @@ public:
con->terminate(ec);
if (ec == error::operation_canceled) {
endpoint_type::m_elog.write(log::elevel::info,
endpoint_type::m_elog->write(log::elevel::info,
"handle_accept error: "+ec.message());
} else {
endpoint_type::m_elog.write(log::elevel::rerror,
endpoint_type::m_elog->write(log::elevel::rerror,
"handle_accept error: "+ec.message());
}
} else {
@@ -176,10 +181,10 @@ public:
lib::error_code start_ec;
start_accept(start_ec);
if (start_ec == error::async_accept_not_listening) {
endpoint_type::m_elog.write(log::elevel::info,
endpoint_type::m_elog->write(log::elevel::info,
"Stopping acceptance of new connections because the underlying transport is no longer listening.");
} else if (start_ec) {
endpoint_type::m_elog.write(log::elevel::rerror,
endpoint_type::m_elog->write(log::elevel::rerror,
"Restarting async_accept loop failed: "+ec.message());
}
}
+50 -50
View File
@@ -98,12 +98,12 @@ 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, const lib::shared_ptr<alog_type> & alog, const lib::shared_ptr<elog_type> & elog)
: m_is_server(is_server)
, m_alog(alog)
, m_elog(elog)
{
m_alog.write(log::alevel::devel,"asio con transport constructor");
m_alog->write(log::alevel::devel,"asio con transport constructor");
}
/// Get a shared pointer to this component
@@ -284,7 +284,7 @@ public:
std::string ret = socket_con_type::get_remote_endpoint(ec);
if (ec) {
m_elog.write(log::elevel::info,ret);
m_elog->write(log::elevel::info,ret);
return "Unknown";
} else {
return ret;
@@ -408,8 +408,8 @@ public:
*/
protected:
void init(init_handler callback) {
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"asio connection init");
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"asio connection init");
}
// TODO: pre-init timeout. Right now no implemented socket policies
@@ -472,8 +472,8 @@ protected:
}
void handle_pre_init(init_handler callback, lib::error_code const & ec) {
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"asio connection handle pre_init");
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"asio connection handle pre_init");
}
if (m_tcp_pre_init_handler) {
@@ -494,8 +494,8 @@ protected:
}
void post_init(init_handler callback) {
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"asio connection post_init");
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"asio connection post_init");
}
timer_ptr post_timer;
@@ -540,7 +540,7 @@ protected:
if (ec) {
if (ec == transport::error::operation_aborted) {
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
"asio post init timer cancelled");
return;
}
@@ -555,7 +555,7 @@ protected:
}
}
m_alog.write(log::alevel::devel, "Asio transport post-init timed out");
m_alog->write(log::alevel::devel, "Asio transport post-init timed out");
cancel_socket_checked();
callback(ret_ec);
}
@@ -575,7 +575,7 @@ protected:
if (ec == transport::error::operation_aborted ||
(post_timer && lib::asio::is_neg(post_timer->expires_from_now())))
{
m_alog.write(log::alevel::devel,"post_init cancelled");
m_alog->write(log::alevel::devel,"post_init cancelled");
return;
}
@@ -583,8 +583,8 @@ protected:
post_timer->cancel();
}
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"asio connection handle_post_init");
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"asio connection handle_post_init");
}
if (m_tcp_post_init_handler) {
@@ -595,12 +595,12 @@ protected:
}
void proxy_write(init_handler callback) {
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"asio connection proxy_write");
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"asio connection proxy_write");
}
if (!m_proxy_data) {
m_elog.write(log::elevel::library,
m_elog->write(log::elevel::library,
"assertion failed: !m_proxy_data in asio::connection::proxy_write");
callback(make_error_code(error::general));
return;
@@ -611,7 +611,7 @@ protected:
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);
m_alog->write(log::alevel::devel,m_proxy_data->write_buf);
// Set a timer so we don't wait forever for the proxy to respond
m_proxy_data->timer = this->set_timer(
@@ -651,14 +651,14 @@ protected:
void handle_proxy_timeout(init_handler callback, lib::error_code const & ec)
{
if (ec == transport::error::operation_aborted) {
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
"asio handle_proxy_write timer cancelled");
return;
} else if (ec) {
log_err(log::elevel::devel,"asio handle_proxy_write",ec);
callback(ec);
} else {
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
"asio handle_proxy_write timer expired");
cancel_socket_checked();
callback(make_error_code(transport::error::timeout));
@@ -668,8 +668,8 @@ protected:
void handle_proxy_write(init_handler callback,
lib::asio::error_code const & ec)
{
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,
"asio connection handle_proxy_write");
}
@@ -681,7 +681,7 @@ protected:
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");
m_elog->write(log::elevel::devel,"write operation aborted");
return;
}
@@ -696,12 +696,12 @@ protected:
}
void proxy_read(init_handler callback) {
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"asio connection proxy_read");
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"asio connection proxy_read");
}
if (!m_proxy_data) {
m_elog.write(log::elevel::library,
m_elog->write(log::elevel::library,
"assertion failed: !m_proxy_data in asio::connection::proxy_read");
m_proxy_data->timer->cancel();
callback(make_error_code(error::general));
@@ -742,8 +742,8 @@ protected:
void handle_proxy_read(init_handler callback,
lib::asio::error_code const & ec, size_t)
{
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,
"asio connection handle_proxy_read");
}
@@ -753,7 +753,7 @@ protected:
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");
m_elog->write(log::elevel::devel,"read operation aborted");
return;
}
@@ -761,12 +761,12 @@ protected:
m_proxy_data->timer->cancel();
if (ec) {
m_elog.write(log::elevel::info,
m_elog->write(log::elevel::info,
"asio handle_proxy_read error: "+ec.message());
callback(make_error_code(error::pass_through));
} else {
if (!m_proxy_data) {
m_elog.write(log::elevel::library,
m_elog->write(log::elevel::library,
"assertion failed: !m_proxy_data in asio::connection::handle_proxy_read");
callback(make_error_code(error::general));
return;
@@ -783,7 +783,7 @@ protected:
return;
}
m_alog.write(log::alevel::devel,m_proxy_data->res.raw());
m_alog->write(log::alevel::devel,m_proxy_data->res.raw());
if (m_proxy_data->res.get_status_code() != http::status_code::ok) {
// got an error response back
@@ -795,7 +795,7 @@ protected:
<< " ("
<< m_proxy_data->res.get_status_msg()
<< ")";
m_elog.write(log::elevel::info,s.str());
m_elog->write(log::elevel::info,s.str());
callback(make_error_code(error::proxy_failed));
return;
}
@@ -820,16 +820,16 @@ protected:
void async_read_at_least(size_t num_bytes, char *buf, size_t len,
read_handler handler)
{
if (m_alog.static_test(log::alevel::devel)) {
if (m_alog->static_test(log::alevel::devel)) {
std::stringstream s;
s << "asio async_read_at_least: " << num_bytes;
m_alog.write(log::alevel::devel,s.str());
m_alog->write(log::alevel::devel,s.str());
}
// TODO: safety vs speed ?
// maybe move into an if devel block
/*if (num_bytes > len) {
m_elog.write(log::elevel::devel,
m_elog->write(log::elevel::devel,
"asio async_read_at_least error::invalid_num_bytes");
handler(make_error_code(transport::error::invalid_num_bytes),
size_t(0));
@@ -871,7 +871,7 @@ protected:
void handle_async_read(read_handler handler, lib::asio::error_code const & ec,
size_t bytes_transferred)
{
m_alog.write(log::alevel::devel, "asio con handle_async_read");
m_alog->write(log::alevel::devel, "asio con handle_async_read");
// translate asio error codes into more lib::error_codes
lib::error_code tec;
@@ -897,7 +897,7 @@ protected:
} else {
// This can happen in cases where the connection is terminated while
// the transport is waiting on a read.
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
"handle_async_read called with null read handler");
}
}
@@ -989,7 +989,7 @@ protected:
} else {
// This can happen in cases where the connection is terminated while
// the transport is waiting on a read.
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
"handle_async_write called with null write handler");
}
}
@@ -1034,8 +1034,8 @@ protected:
/// close and clean up the underlying socket
void async_shutdown(shutdown_handler callback) {
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"asio connection async_shutdown");
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,"asio connection async_shutdown");
}
timer_ptr shutdown_timer;
@@ -1074,7 +1074,7 @@ protected:
if (ec) {
if (ec == transport::error::operation_aborted) {
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
"asio socket shutdown timer cancelled");
return;
}
@@ -1085,7 +1085,7 @@ protected:
ret_ec = make_error_code(transport::error::timeout);
}
m_alog.write(log::alevel::devel,
m_alog->write(log::alevel::devel,
"Asio transport socket shutdown timed out");
cancel_socket_checked();
callback(ret_ec);
@@ -1097,7 +1097,7 @@ protected:
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");
m_alog->write(log::alevel::devel,"async_shutdown cancelled");
return;
}
@@ -1129,8 +1129,8 @@ protected:
}
}
} else {
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,
if (m_alog->static_test(log::alevel::devel)) {
m_alog->write(log::alevel::devel,
"asio con handle_async_shutdown");
}
}
@@ -1143,7 +1143,7 @@ protected:
if (cec) {
if (cec == lib::asio::error::operation_not_supported) {
// cancel not supported on this OS, ignore and log at dev level
m_alog.write(log::alevel::devel, "socket cancel not supported");
m_alog->write(log::alevel::devel, "socket cancel not supported");
} else {
log_err(log::elevel::warn, "socket cancel failed", cec);
}
@@ -1156,13 +1156,13 @@ private:
void log_err(log::level l, const char * msg, const error_type & ec) {
std::stringstream s;
s << msg << " error: " << ec << " (" << ec.message() << ")";
m_elog.write(l,s.str());
m_elog->write(l,s.str());
}
// static settings
const bool m_is_server;
alog_type& m_alog;
elog_type& m_elog;
lib::shared_ptr<alog_type> m_alog;
lib::shared_ptr<elog_type> m_elog;
struct proxy_data {
proxy_data() : timeout_proxy(config::timeout_proxy) {}
+16 -10
View File
@@ -35,6 +35,7 @@
#include <websocketpp/uri.hpp>
#include <websocketpp/logger/levels.hpp>
#include <websocketpp/common/asio.hpp>
#include <websocketpp/common/functional.hpp>
#include <sstream>
@@ -91,7 +92,7 @@ public:
explicit endpoint()
: m_io_service(NULL)
, m_external_io_service(false)
, m_listen_backlog(0)
, m_listen_backlog(lib::asio::socket_base::max_connections)
, m_reuse_addr(false)
, m_state(UNINITIALIZED)
{
@@ -314,8 +315,10 @@ public:
*
* New values affect future calls to listen only.
*
* A value of zero will use the operating system default. This is the
* default value.
* The default value is specified as *::asio::socket_base::max_connections
* which uses the operating system defined maximum queue length. Your OS
* may restrict or silently lower this value. A value of zero may cause
* all connections to be rejected.
*
* @since 0.3.0
*
@@ -328,10 +331,13 @@ public:
/// Sets whether to use the SO_REUSEADDR flag when opening listening sockets
/**
* Specifies whether or not to use the SO_REUSEADDR TCP socket option. What
* this flag does depends on your operating system. Please consult operating
* system documentation for more details.
* this flag does depends on your operating system.
*
* New values affect future calls to listen only.
* Please consult operating system documentation for more details. There
* may be security consequences to enabling this option.
*
* New values affect future calls to listen only so set this value prior to
* calling listen.
*
* The default is false.
*
@@ -743,7 +749,7 @@ public:
void async_accept(transport_con_ptr tcon, accept_handler callback,
lib::error_code & ec)
{
if (m_state != LISTENING) {
if (m_state != LISTENING || !m_acceptor) {
using websocketpp::error::make_error_code;
ec = make_error_code(websocketpp::error::async_accept_not_listening);
return;
@@ -795,7 +801,7 @@ protected:
* haven't been constructed yet, and cannot be used in the transport
* destructor as they will have been destroyed by then.
*/
void init_logging(alog_type* a, elog_type* e) {
void init_logging(const lib::shared_ptr<alog_type>& a, const lib::shared_ptr<elog_type>& e) {
m_alog = a;
m_elog = e;
}
@@ -1133,8 +1139,8 @@ private:
int m_listen_backlog;
bool m_reuse_addr;
elog_type* m_elog;
alog_type* m_alog;
lib::shared_ptr<elog_type> m_elog;
lib::shared_ptr<alog_type> m_alog;
// Transport state
state m_state;
+4 -4
View File
@@ -171,6 +171,10 @@ protected:
m_socket = lib::make_shared<lib::asio::ip::tcp::socket>(
lib::ref(*service));
if (m_socket_init_handler) {
m_socket_init_handler(m_hdl, *m_socket);
}
m_state = READY;
return lib::error_code();
@@ -204,10 +208,6 @@ protected:
return;
}
if (m_socket_init_handler) {
m_socket_init_handler(m_hdl,*m_socket);
}
m_state = READING;
callback(lib::error_code());
+4 -4
View File
@@ -196,6 +196,10 @@ protected:
m_socket = lib::make_shared<socket_type>(
_WEBSOCKETPP_REF(*service),lib::ref(*m_context));
if (m_socket_init_handler) {
m_socket_init_handler(m_hdl, get_socket());
}
m_io_service = service;
m_strand = strand;
m_is_server = is_server;
@@ -245,10 +249,6 @@ protected:
}
#endif
if (m_socket_init_handler) {
m_socket_init_handler(m_hdl,get_socket());
}
callback(lib::error_code());
}
+1 -1
View File
@@ -59,7 +59,7 @@ namespace websocketpp {
* `connection_hdl` and any error that occurred.
*
* **init_logging**
* `void init_logging(alog_type * a, elog_type * e)`\n
* `void init_logging(const lib::shared_ptr<alog_type>& a, const lib::shared_ptr<elog_type>& e)`\n
* Called once after construction to provide pointers to the endpoint's access
* and error loggers. These may be stored and used to log messages or ignored.
*/
+11 -11
View File
@@ -73,10 +73,10 @@ public:
typedef lib::shared_ptr<timer> timer_ptr;
explicit connection(bool is_server, alog_type & alog, elog_type & elog)
explicit connection(bool is_server, const lib::shared_ptr<alog_type> & alog, const lib::shared_ptr<elog_type> & elog)
: m_reading(false), m_is_server(is_server), m_alog(alog), m_elog(elog)
{
m_alog.write(log::alevel::devel,"debug con transport constructor");
m_alog->write(log::alevel::devel,"debug con transport constructor");
}
/// Get a shared pointer to this component
@@ -166,7 +166,7 @@ public:
* needed.
*/
timer_ptr set_timer(long, timer_handler handler) {
m_alog.write(log::alevel::devel,"debug connection set timer");
m_alog->write(log::alevel::devel,"debug connection set timer");
m_timer_handler = handler;
return timer_ptr();
}
@@ -215,7 +215,7 @@ protected:
* @param handler The `init_handler` to call when initialization is done
*/
void init(init_handler handler) {
m_alog.write(log::alevel::devel,"debug connection init");
m_alog->write(log::alevel::devel,"debug connection init");
handler(lib::error_code());
}
@@ -248,7 +248,7 @@ protected:
{
std::stringstream s;
s << "debug_con async_read_at_least: " << num_bytes;
m_alog.write(log::alevel::devel,s.str());
m_alog->write(log::alevel::devel,s.str());
if (num_bytes > len) {
handler(make_error_code(error::invalid_num_bytes),size_t(0));
@@ -286,7 +286,7 @@ protected:
* @param handler Callback to invoke with operation status.
*/
void async_write(char const *, size_t, write_handler handler) {
m_alog.write(log::alevel::devel,"debug_con async_write");
m_alog->write(log::alevel::devel,"debug_con async_write");
m_write_handler = handler;
}
@@ -302,7 +302,7 @@ protected:
* @param handler Callback to invoke with operation status.
*/
void async_write(std::vector<buffer> const &, write_handler handler) {
m_alog.write(log::alevel::devel,"debug_con async_write buffer list");
m_alog->write(log::alevel::devel,"debug_con async_write buffer list");
m_write_handler = handler;
}
@@ -337,10 +337,10 @@ protected:
}
size_t read_some_impl(char const * buf, size_t len) {
m_alog.write(log::alevel::devel,"debug_con read_some");
m_alog->write(log::alevel::devel,"debug_con read_some");
if (!m_reading) {
m_elog.write(log::elevel::devel,"write while not reading");
m_elog->write(log::elevel::devel,"write while not reading");
return 0;
}
@@ -399,8 +399,8 @@ private:
bool m_reading;
bool const m_is_server;
bool m_is_secure;
alog_type & m_alog;
elog_type & m_elog;
lib::shared_ptr<alog_type> m_alog;
lib::shared_ptr<elog_type> m_elog;
std::string m_remote_endpoint;
};
+1 -1
View File
@@ -103,7 +103,7 @@ protected:
* @param a A pointer to the access logger to use.
* @param e A pointer to the error logger to use.
*/
void init_logging(alog_type *, elog_type *) {}
void init_logging(lib::shared_ptr<alog_type>, lib::shared_ptr<elog_type>) {}
/// Initiate a new connection
/**
+13 -13
View File
@@ -77,7 +77,7 @@ public:
typedef lib::shared_ptr<timer> timer_ptr;
explicit connection(bool is_server, alog_type & alog, elog_type & elog)
explicit connection(bool is_server, const lib::shared_ptr<alog_type> & alog, const lib::shared_ptr<elog_type> & elog)
: m_output_stream(NULL)
, m_reading(false)
, m_is_server(is_server)
@@ -86,7 +86,7 @@ public:
, m_elog(elog)
, m_remote_endpoint("iostream transport")
{
m_alog.write(log::alevel::devel,"iostream con transport constructor");
m_alog->write(log::alevel::devel,"iostream con transport constructor");
}
/// Get a shared pointer to this component
@@ -408,7 +408,7 @@ protected:
* @param handler The `init_handler` to call when initialization is done
*/
void init(init_handler handler) {
m_alog.write(log::alevel::devel,"iostream connection init");
m_alog->write(log::alevel::devel,"iostream connection init");
handler(lib::error_code());
}
@@ -441,7 +441,7 @@ protected:
{
std::stringstream s;
s << "iostream_con async_read_at_least: " << num_bytes;
m_alog.write(log::alevel::devel,s.str());
m_alog->write(log::alevel::devel,s.str());
if (num_bytes > len) {
handler(make_error_code(error::invalid_num_bytes),size_t(0));
@@ -487,7 +487,7 @@ protected:
void async_write(char const * buf, size_t len, transport::write_handler
handler)
{
m_alog.write(log::alevel::devel,"iostream_con async_write");
m_alog->write(log::alevel::devel,"iostream_con async_write");
// TODO: lock transport state?
lib::error_code ec;
@@ -527,7 +527,7 @@ protected:
void async_write(std::vector<buffer> const & bufs, transport::write_handler
handler)
{
m_alog.write(log::alevel::devel,"iostream_con async_write buffer list");
m_alog->write(log::alevel::devel,"iostream_con async_write buffer list");
// TODO: lock transport state?
lib::error_code ec;
@@ -601,18 +601,18 @@ protected:
}
private:
void read(std::istream &in) {
m_alog.write(log::alevel::devel,"iostream_con read");
m_alog->write(log::alevel::devel,"iostream_con read");
while (in.good()) {
if (!m_reading) {
m_elog.write(log::elevel::devel,"write while not reading");
m_elog->write(log::elevel::devel,"write while not reading");
break;
}
in.read(m_buf+m_cursor,static_cast<std::streamsize>(m_len-m_cursor));
if (in.gcount() == 0) {
m_elog.write(log::elevel::devel,"read zero bytes");
m_elog->write(log::elevel::devel,"read zero bytes");
break;
}
@@ -632,10 +632,10 @@ private:
}
size_t read_some_impl(char const * buf, size_t len) {
m_alog.write(log::alevel::devel,"iostream_con read_some");
m_alog->write(log::alevel::devel,"iostream_con read_some");
if (!m_reading) {
m_elog.write(log::elevel::devel,"write while not reading");
m_elog->write(log::elevel::devel,"write while not reading");
return 0;
}
@@ -694,8 +694,8 @@ private:
bool m_reading;
bool const m_is_server;
bool m_is_secure;
alog_type & m_alog;
elog_type & m_elog;
lib::shared_ptr<alog_type> m_alog;
lib::shared_ptr<elog_type> m_elog;
std::string m_remote_endpoint;
// This lock ensures that only one thread can edit read data for this
+3 -3
View File
@@ -168,7 +168,7 @@ protected:
* @param a A pointer to the access logger to use.
* @param e A pointer to the error logger to use.
*/
void init_logging(alog_type * a, elog_type * e) {
void init_logging(lib::shared_ptr<alog_type> a, lib::shared_ptr<elog_type> e) {
m_elog = e;
m_alog = a;
}
@@ -209,8 +209,8 @@ private:
shutdown_handler m_shutdown_handler;
write_handler m_write_handler;
elog_type * m_elog;
alog_type * m_alog;
lib::shared_ptr<elog_type> m_elog;
lib::shared_ptr<alog_type> m_alog;
bool m_is_secure;
};
+8 -8
View File
@@ -72,10 +72,10 @@ public:
typedef lib::shared_ptr<timer> timer_ptr;
explicit connection(bool is_server, alog_type & alog, elog_type & elog)
explicit connection(bool is_server, const lib::shared_ptr<alog_type> & alog, const lib::shared_ptr<elog_type> & elog)
: m_alog(alog), m_elog(elog)
{
m_alog.write(log::alevel::devel,"stub con transport constructor");
m_alog->write(log::alevel::devel,"stub con transport constructor");
}
/// Get a shared pointer to this component
@@ -175,7 +175,7 @@ protected:
* @param handler The `init_handler` to call when initialization is done
*/
void init(init_handler handler) {
m_alog.write(log::alevel::devel,"stub connection init");
m_alog->write(log::alevel::devel,"stub connection init");
handler(make_error_code(error::not_implemented));
}
@@ -206,7 +206,7 @@ protected:
void async_read_at_least(size_t num_bytes, char * buf, size_t len,
read_handler handler)
{
m_alog.write(log::alevel::devel, "stub_con async_read_at_least");
m_alog->write(log::alevel::devel, "stub_con async_read_at_least");
handler(make_error_code(error::not_implemented), 0);
}
@@ -223,7 +223,7 @@ protected:
* @param handler Callback to invoke with operation status.
*/
void async_write(char const * buf, size_t len, write_handler handler) {
m_alog.write(log::alevel::devel,"stub_con async_write");
m_alog->write(log::alevel::devel,"stub_con async_write");
handler(make_error_code(error::not_implemented));
}
@@ -239,7 +239,7 @@ protected:
* @param handler Callback to invoke with operation status.
*/
void async_write(std::vector<buffer> const & bufs, write_handler handler) {
m_alog.write(log::alevel::devel,"stub_con async_write buffer list");
m_alog->write(log::alevel::devel,"stub_con async_write buffer list");
handler(make_error_code(error::not_implemented));
}
@@ -274,8 +274,8 @@ protected:
}
private:
// member variables!
alog_type & m_alog;
elog_type & m_elog;
lib::shared_ptr<alog_type> m_alog;
lib::shared_ptr<elog_type> m_elog;
};
+3 -3
View File
@@ -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 = 7;
static int const minor_version = 8;
/// Library patch version number
static int const patch_version = 0;
/// Library pre-release flag
@@ -51,10 +51,10 @@ static int const patch_version = 0;
* versions (dev, alpha, beta, rc). This will be blank for release versions.
*/
static char const prerelease_flag[] = "";
static char const prerelease_flag[] = "dev";
/// Default user agent string
static char const user_agent[] = "WebSocket++/0.7.0";
static char const user_agent[] = "WebSocket++/0.8.0-dev";
} // namespace websocketpp