From 3817fb4c94c1a664ee9b3a02f8254d8b3aa82889 Mon Sep 17 00:00:00 2001 From: Damian Jarek Date: Sun, 14 Jul 2019 20:19:58 +0200 Subject: [PATCH] Fix data race in http server examples When using `beast::tcp_stream`, the user must make sure that async operations are initiated from within the strand associated with the stream. Signed-off-by: Damian Jarek --- .../async-ssl/http_server_async_ssl.cpp | 18 +++++++++- .../http/server/async/http_server_async.cpp | 10 +++++- example/http/server/flex/http_server_flex.cpp | 36 +++++++++++++------ .../http_server_stackless_ssl.cpp | 12 ++++++- .../stackless/http_server_stackless.cpp | 12 ++++++- 5 files changed, 73 insertions(+), 15 deletions(-) diff --git a/example/http/server/async-ssl/http_server_async_ssl.cpp b/example/http/server/async-ssl/http_server_async_ssl.cpp index f51d445c..f6c66c90 100644 --- a/example/http/server/async-ssl/http_server_async_ssl.cpp +++ b/example/http/server/async-ssl/http_server_async_ssl.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -298,9 +299,24 @@ public: // Start the asynchronous operation void run() + { + // We need to be executing within a strand to perform async operations + // on the I/O objects in this session. Although not strictly necessary + // for single-threaded contexts, this example code is written to be + // thread-safe by default. + net::dispatch( + stream_.get_executor(), + beast::bind_front_handler( + &session::on_run, + shared_from_this())); + } + + void + on_run() { // Set the timeout. - beast::get_lowest_layer(stream_).expires_after(std::chrono::seconds(30)); + beast::get_lowest_layer(stream_).expires_after( + std::chrono::seconds(30)); // Perform the SSL handshake stream_.async_handshake( diff --git a/example/http/server/async/http_server_async.cpp b/example/http/server/async/http_server_async.cpp index e02ec231..55fd234b 100644 --- a/example/http/server/async/http_server_async.cpp +++ b/example/http/server/async/http_server_async.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -273,7 +274,14 @@ public: void run() { - do_read(); + // We need to be executing within a strand to perform async operations + // on the I/O objects in this session. Although not strictly necessary + // for single-threaded contexts, this example code is written to be + // thread-safe by default. + net::dispatch(stream_.get_executor(), + beast::bind_front_handler( + &session::do_read, + shared_from_this())); } void diff --git a/example/http/server/flex/http_server_flex.cpp b/example/http/server/flex/http_server_flex.cpp index 1c1b7551..dd4b4ccd 100644 --- a/example/http/server/flex/http_server_flex.cpp +++ b/example/http/server/flex/http_server_flex.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -396,7 +397,14 @@ public: void run() { - do_read(); + // We need to be executing within a strand to perform async operations + // on the I/O objects in this session. Although not strictly necessary + // for single-threaded contexts, this example code is written to be + // thread-safe by default. + net::dispatch(stream_.get_executor(), + beast::bind_front_handler( + &session::do_read, + shared_from_this())); } void @@ -442,17 +450,23 @@ public: void run() { - // Set the timeout. - beast::get_lowest_layer(stream_).expires_after(std::chrono::seconds(30)); + auto self = shared_from_this(); + // We need to be executing within a strand to perform async operations + // on the I/O objects in this session. + net::dispatch(stream_.get_executor(), [self]() { + // Set the timeout. + beast::get_lowest_layer(self->stream_).expires_after( + std::chrono::seconds(30)); - // Perform the SSL handshake - // Note, this is the buffered version of the handshake. - stream_.async_handshake( - ssl::stream_base::server, - buffer_.data(), - beast::bind_front_handler( - &ssl_session::on_handshake, - shared_from_this())); + // Perform the SSL handshake + // Note, this is the buffered version of the handshake. + self->stream_.async_handshake( + ssl::stream_base::server, + self->buffer_.data(), + beast::bind_front_handler( + &ssl_session::on_handshake, + self)); + }); } void diff --git a/example/http/server/stackless-ssl/http_server_stackless_ssl.cpp b/example/http/server/stackless-ssl/http_server_stackless_ssl.cpp index 06c0e361..7786cbb4 100644 --- a/example/http/server/stackless-ssl/http_server_stackless_ssl.cpp +++ b/example/http/server/stackless-ssl/http_server_stackless_ssl.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -304,7 +305,16 @@ public: void run() { - loop({}, 0, false); + // We need to be executing within a strand to perform async operations + // on the I/O objects in this session.Although not strictly necessary + // for single-threaded contexts, this example code is written to be + // thread-safe by default. + net::dispatch(stream_.get_executor(), + beast::bind_front_handler(&session::loop, + shared_from_this(), + beast::error_code{}, + 0, + false)); } #include diff --git a/example/http/server/stackless/http_server_stackless.cpp b/example/http/server/stackless/http_server_stackless.cpp index f0c78160..2439c689 100644 --- a/example/http/server/stackless/http_server_stackless.cpp +++ b/example/http/server/stackless/http_server_stackless.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -278,7 +279,16 @@ public: void run() { - loop(false, {}, 0); + // We need to be executing within a strand to perform async operations + // on the I/O objects in this session. Although not strictly necessary + // for single-threaded contexts, this example code is written to be + // thread-safe by default. + net::dispatch(stream_.get_executor(), + beast::bind_front_handler(&session::loop, + shared_from_this(), + false, + beast::error_code{}, + 0)); } #include