Skip to content

Compatibility fixes for Boost 1.87 #1164

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
############ Setup project and cmake
# 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.8.8)
cmake_minimum_required (VERSION 3.10)

############ Paths

Expand Down Expand Up @@ -77,6 +77,7 @@ include (CMakeHelpers)
option (ENABLE_CPP11 "Build websocketpp with CPP11 features enabled." TRUE)
option (BUILD_EXAMPLES "Build websocketpp examples." FALSE)
option (BUILD_TESTS "Build websocketpp tests." FALSE)
option (USE_ASIO_STANDALONE "Build websocketpp examples and tests using the standalone ASIO library." FALSE)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love that you added the ability to test against Asio standalone as well. I didn't think of doing that!


if (BUILD_TESTS OR BUILD_EXAMPLES)

Expand Down Expand Up @@ -221,9 +222,8 @@ if (BUILD_TESTS OR BUILD_EXAMPLES)
set (Boost_FIND_QUIETLY TRUE)
set (Boost_DEBUG FALSE)
set (Boost_USE_MULTITHREADED TRUE)
set (Boost_ADDITIONAL_VERSIONS "1.39.0" "1.40.0" "1.41.0" "1.42.0" "1.43.0" "1.44.0" "1.46.1") # todo: someone who knows better spesify these!

find_package (Boost 1.39.0 COMPONENTS ${WEBSOCKETPP_BOOST_LIBS})
find_package (Boost 1.66.0 NO_MODULE COMPONENTS ${WEBSOCKETPP_BOOST_LIBS})

if (Boost_FOUND)
# Boost is a project wide global dependency.
Expand Down Expand Up @@ -254,6 +254,10 @@ endif()

############ Add projects

if (USE_ASIO_STANDALONE)
add_definitions("-DASIO_STANDALONE -DASIO_HAS_BOOST_DATE_TIME")
endif ()

# Add main library
add_subdirectory (websocketpp)

Expand Down
4 changes: 2 additions & 2 deletions SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -273,8 +273,8 @@ subprotocol_server = SConscript('#/examples/subprotocol_server/SConscript',varia
# telemetry_server
telemetry_server = SConscript('#/examples/telemetry_server/SConscript',variant_dir = builddir + 'telemetry_server',duplicate = 0)

# external_io_service
external_io_service = SConscript('#/examples/external_io_service/SConscript',variant_dir = builddir + 'external_io_service',duplicate = 0)
# external_io_context
external_io_context = SConscript('#/examples/external_io_context/SConscript',variant_dir = builddir + 'external_io_context',duplicate = 0)

if not env['PLATFORM'].startswith('win'):
# iostream_server
Expand Down
12 changes: 6 additions & 6 deletions docs/faq.dox
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,19 @@ Note: some browsers will allow the connection to continue if they requested a su

### 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:
The Asio transport based clients and servers use the Asio library's underlying `io_context` to handle asyncronous networking operations. The standard behavior of the io_context 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.
- 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_context gets around to asyncronously processing the socket and WebSocket protocol closing handshakes. The `io_context::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.
__WARNING__: Asio's `io_context` 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_context::stop` or `endpoint::stop` without a very good reason your program is likely broken and may exhibit erratic behavior. Specifically, `io_context::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.
- If your client uses the `start_perpetual` method it will prevent the io_context 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_context and/or are placing non-WebSocket++ operations on the `io_context` those operations may keep the `io_context` open even after all WebSocket++ operations have completed.
- If you are using `poll`/`poll_one`/`run_one` or otherwise manually driving the `io_context` 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_context::work`" cases.

### Is there a way to check the validity of a `connection_hdl`?

Expand Down
2 changes: 1 addition & 1 deletion examples/broadcast_server/broadcast_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class broadcast_server {
return;
}

// Start the ASIO io_service run loop
// Start the ASIO io_context run loop
//try {
m_server.run();
//} catch (const std::exception & e) {
Expand Down
14 changes: 7 additions & 7 deletions examples/debug_client/debug_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ using websocketpp::lib::bind;

// pull out the type of messages sent by our config
typedef websocketpp::config::asio_tls_client::message_type::ptr message_ptr;
typedef websocketpp::lib::shared_ptr<boost::asio::ssl::context> context_ptr;
typedef websocketpp::lib::shared_ptr<websocketpp::lib::asio::ssl::context> context_ptr;
typedef client::connection_ptr connection_ptr;


Expand Down Expand Up @@ -82,7 +82,7 @@ class perftest {

m_endpoint.connect(con);

// Start the ASIO io_service run loop
// Start the ASIO io_context run loop
m_start = std::chrono::high_resolution_clock::now();
m_endpoint.run();
}
Expand All @@ -93,13 +93,13 @@ class perftest {

context_ptr on_tls_init(websocketpp::connection_hdl) {
m_tls_init = std::chrono::high_resolution_clock::now();
context_ptr ctx = websocketpp::lib::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::tlsv1);
context_ptr ctx = websocketpp::lib::make_shared<websocketpp::lib::asio::ssl::context>(websocketpp::lib::asio::ssl::context::tlsv1);

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_options(websocketpp::lib::asio::ssl::context::default_workarounds |
websocketpp::lib::asio::ssl::context::no_sslv2 |
websocketpp::lib::asio::ssl::context::no_sslv3 |
websocketpp::lib::asio::ssl::context::single_dh_use);
} catch (std::exception& e) {
std::cout << e.what() << std::endl;
}
Expand Down
2 changes: 1 addition & 1 deletion examples/debug_server/debug_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ int main() {
// Start the server accept loop
echo_server.start_accept();

// Start the ASIO io_service run loop
// Start the ASIO io_context run loop
echo_server.run();
} catch (websocketpp::exception const & e) {
std::cout << e.what() << std::endl;
Expand Down
2 changes: 1 addition & 1 deletion examples/echo_client/echo_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ int main(int argc, char* argv[]) {
// exchanged until the event loop starts running in the next line.
c.connect(con);

// Start the ASIO io_service run loop
// Start the ASIO io_context 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();
Expand Down
2 changes: 1 addition & 1 deletion examples/echo_server/echo_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ int main() {
// Start the server accept loop
echo_server.start_accept(&on_end_accept);

// Start the ASIO io_service run loop
// Start the ASIO io_context run loop
echo_server.run();
} catch (websocketpp::exception const & e) {
std::cout << e.what() << std::endl;
Expand Down
28 changes: 14 additions & 14 deletions examples/echo_server_both/echo_server_both.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ using websocketpp::lib::bind;
using websocketpp::lib::error_code;

// type of the ssl context pointer is long so alias it
typedef websocketpp::lib::shared_ptr<boost::asio::ssl::context> context_ptr;
typedef websocketpp::lib::shared_ptr<websocketpp::lib::asio::ssl::context> context_ptr;

// The shared on_message handler takes a template parameter so the function can
// resolve any endpoint dependent types like message_ptr or connection_ptr
Expand Down Expand Up @@ -48,39 +48,39 @@ std::string get_password() {

context_ptr on_tls_init(websocketpp::connection_hdl hdl) {
std::cout << "on_tls_init called with hdl: " << hdl.lock().get() << std::endl;
context_ptr ctx(new boost::asio::ssl::context(boost::asio::ssl::context::tlsv1));
context_ptr ctx(new websocketpp::lib::asio::ssl::context(websocketpp::lib::asio::ssl::context::tlsv1));

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_options(websocketpp::lib::asio::ssl::context::default_workarounds |
websocketpp::lib::asio::ssl::context::no_sslv2 |
websocketpp::lib::asio::ssl::context::no_sslv3 |
websocketpp::lib::asio::ssl::context::single_dh_use);
ctx->set_password_callback(bind(&get_password));
ctx->use_certificate_chain_file("server.pem");
ctx->use_private_key_file("server.pem", boost::asio::ssl::context::pem);
ctx->use_private_key_file("server.pem", websocketpp::lib::asio::ssl::context::pem);
} catch (std::exception& e) {
std::cout << e.what() << std::endl;
}
return ctx;
}

int main() {
// set up an external io_service to run both endpoints on. This is not
// set up an external io_context to run both endpoints on. This is not
// strictly necessary, but simplifies thread management a bit.
boost::asio::io_service ios;
websocketpp::lib::asio::io_context ctx;

// set up plain endpoint
server_plain endpoint_plain;
// initialize asio with our external io_service rather than an internal one
endpoint_plain.init_asio(&ios);
// initialize asio with our external io_context rather than an internal one
endpoint_plain.init_asio(&ctx);
endpoint_plain.set_message_handler(
bind(&on_message<server_plain>,&endpoint_plain,::_1,::_2));
endpoint_plain.listen(80);
endpoint_plain.start_accept(&on_end_accept);

// set up tls endpoint
server_tls endpoint_tls;
endpoint_tls.init_asio(&ios);
endpoint_tls.init_asio(&ctx);
endpoint_tls.set_message_handler(
bind(&on_message<server_tls>,&endpoint_tls,::_1,::_2));
// TLS endpoint has an extra handler for the tls init
Expand All @@ -89,6 +89,6 @@ int main() {
endpoint_tls.listen(443);
endpoint_tls.start_accept(&on_end_accept);

// Start the ASIO io_service run loop running both endpoints
ios.run();
// Start the ASIO io_context run loop running both endpoints
ctx.run();
}
2 changes: 1 addition & 1 deletion examples/echo_server_tls/echo_server_tls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ int main() {
// Start the server accept loop
echo_server.start_accept(&on_end_accept);

// Start the ASIO io_service run loop
// Start the ASIO io_context run loop
echo_server.run();

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
file (GLOB SOURCE_FILES *.cpp)
file (GLOB HEADER_FILES *.hpp)

init_target (external_io_service)
init_target (external_io_context)

build_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ prgs = []
# if a C++11 environment is available build using that, otherwise use boost
if 'WSPP_CPP11_ENABLED' in env_cpp11:
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
prgs += env_cpp11.Program('external_io_service', ["external_io_service.cpp"], LIBS = ALL_LIBS)
prgs += env_cpp11.Program('external_io_context', ["external_io_context.cpp"], LIBS = ALL_LIBS)
else:
ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs]
prgs += env.Program('external_io_service', ["external_io_service.cpp"], LIBS = ALL_LIBS)
prgs += env.Program('external_io_context', ["external_io_context.cpp"], LIBS = ALL_LIBS)

Return('prgs')
Original file line number Diff line number Diff line change
Expand Up @@ -66,19 +66,19 @@ void on_end_accept(error_code lib_ec, error_code trans_ec) {
}

int main() {
asio::io_service service;
websocketpp::lib::asio::io_context context;

// Add a TCP echo server on port 9003
tcp_echo_server custom_http_server(service, 9003);
tcp_echo_server custom_http_server(context, 9003);

// Add a WebSocket echo server on port 9002
ws_echo_server ws_server;
ws_server.set_access_channels(websocketpp::log::alevel::all);
ws_server.clear_access_channels(websocketpp::log::alevel::frame_payload);

// The only difference in this code between an internal and external
// io_service is the different constructor to init_asio
ws_server.init_asio(&service);
// io_context is the different constructor to init_asio
ws_server.init_asio(&context);

// Register our message handler
ws_server.set_message_handler(bind(&on_message,&ws_server,::_1,::_2));
Expand All @@ -87,6 +87,6 @@ int main() {

// TODO: add a timer?

// Start the Asio io_service run loop for all
service.run();
}
// Start the Asio io_context run loop for all
context.run();
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,59 +39,57 @@ using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;

namespace asio = websocketpp::lib::asio;

struct tcp_echo_session : websocketpp::lib::enable_shared_from_this<tcp_echo_session> {
typedef websocketpp::lib::shared_ptr<tcp_echo_session> ptr;

tcp_echo_session(asio::io_service & service) : m_socket(service) {}
tcp_echo_session(websocketpp::lib::asio::io_context & context) : m_socket(context) {}

void start() {
m_socket.async_read_some(asio::buffer(m_buffer, sizeof(m_buffer)),
m_socket.async_read_some(websocketpp::lib::asio::buffer(m_buffer, sizeof(m_buffer)),
websocketpp::lib::bind(
&tcp_echo_session::handle_read, shared_from_this(), _1, _2));
}

void handle_read(const asio::error_code & ec, size_t transferred) {
void handle_read(const websocketpp::lib::asio::error_code & ec, size_t transferred) {
if (!ec) {
asio::async_write(m_socket,
asio::buffer(m_buffer, transferred),
websocketpp::lib::asio::async_write(m_socket,
websocketpp::lib::asio::buffer(m_buffer, transferred),
bind(&tcp_echo_session::handle_write, shared_from_this(), _1));
}
}

void handle_write(const asio::error_code & ec) {
void handle_write(const websocketpp::lib::asio::error_code & ec) {
if (!ec) {
m_socket.async_read_some(asio::buffer(m_buffer, sizeof(m_buffer)),
m_socket.async_read_some(websocketpp::lib::asio::buffer(m_buffer, sizeof(m_buffer)),
bind(&tcp_echo_session::handle_read, shared_from_this(), _1, _2));
}
}

asio::ip::tcp::socket m_socket;
websocketpp::lib::asio::ip::tcp::socket m_socket;
char m_buffer[1024];
};

struct tcp_echo_server {
tcp_echo_server(asio::io_service & service, short port)
: m_service(service)
, m_acceptor(service, asio::ip::tcp::endpoint(asio::ip::tcp::v6(), port))
tcp_echo_server(websocketpp::lib::asio::io_context & context, short port)
: m_context(context)
, m_acceptor(context, websocketpp::lib::asio::ip::tcp::endpoint(websocketpp::lib::asio::ip::tcp::v6(), port))
{
this->start_accept();
}

void start_accept() {
tcp_echo_session::ptr new_session(new tcp_echo_session(m_service));
tcp_echo_session::ptr new_session(new tcp_echo_session(m_context));
m_acceptor.async_accept(new_session->m_socket,
bind(&tcp_echo_server::handle_accept, this, new_session, _1));
}

void handle_accept(tcp_echo_session::ptr new_session, const asio::error_code & ec) {
void handle_accept(tcp_echo_session::ptr new_session, const websocketpp::lib::asio::error_code & ec) {
if (!ec) {
new_session->start();
}
start_accept();
}

asio::io_service & m_service;
asio::ip::tcp::acceptor m_acceptor;
websocketpp::lib::asio::io_context & m_context;
websocketpp::lib::asio::ip::tcp::acceptor m_acceptor;
};
2 changes: 1 addition & 1 deletion examples/print_client/print_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ int main(int argc, char* argv[]) {
// exchanged until the event loop starts running in the next line.
c.connect(con);

// Start the ASIO io_service run loop
// Start the ASIO io_context 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();
Expand Down
Loading