Fix data race in websocket examples

When using `websocket::stream`, the user has to take care to initiate
async operations within the associated strand.

Signed-off-by: Damian Jarek <damian.jarek93@gmail.com>
This commit is contained in:
Damian Jarek
2019-07-15 21:27:29 +02:00
committed by Vinnie Falco
parent 3817fb4c94
commit 0f5d1edcd8
4 changed files with 53 additions and 6 deletions

View File

@ -20,6 +20,7 @@
#include <boost/beast/websocket.hpp> #include <boost/beast/websocket.hpp>
#include <boost/beast/websocket/ssl.hpp> #include <boost/beast/websocket/ssl.hpp>
#include <boost/asio/strand.hpp> #include <boost/asio/strand.hpp>
#include <boost/asio/dispatch.hpp>
#include <algorithm> #include <algorithm>
#include <cstdlib> #include <cstdlib>
#include <functional> #include <functional>
@ -59,14 +60,28 @@ public:
{ {
} }
// Start the asynchronous operation // Get on the correct executor
void void
run() 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(ws_.get_executor(),
beast::bind_front_handler(
&session::on_run,
shared_from_this()));
}
// Start the asynchronous operation
void
on_run()
{ {
// Set the timeout. // Set the timeout.
beast::get_lowest_layer(ws_).expires_after(std::chrono::seconds(30)); beast::get_lowest_layer(ws_).expires_after(std::chrono::seconds(30));
// Perform the SSL handshake // Perform the SSL handshake
ws_.next_layer().async_handshake( ws_.next_layer().async_handshake(
ssl::stream_base::server, ssl::stream_base::server,
beast::bind_front_handler( beast::bind_front_handler(

View File

@ -15,6 +15,7 @@
#include <boost/beast/core.hpp> #include <boost/beast/core.hpp>
#include <boost/beast/websocket.hpp> #include <boost/beast/websocket.hpp>
#include <boost/asio/dispatch.hpp>
#include <boost/asio/strand.hpp> #include <boost/asio/strand.hpp>
#include <algorithm> #include <algorithm>
#include <cstdlib> #include <cstdlib>
@ -54,9 +55,23 @@ public:
{ {
} }
// Start the asynchronous operation // Get on the correct executor
void void
run() 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(ws_.get_executor(),
beast::bind_front_handler(
&session::on_run,
shared_from_this()));
}
// Start the asynchronous operation
void
on_run()
{ {
// Set suggested timeout settings for the websocket // Set suggested timeout settings for the websocket
ws_.set_option( ws_.set_option(
@ -71,7 +86,6 @@ public:
std::string(BOOST_BEAST_VERSION_STRING) + std::string(BOOST_BEAST_VERSION_STRING) +
" websocket-server-async"); " websocket-server-async");
})); }));
// Accept the websocket handshake // Accept the websocket handshake
ws_.async_accept( ws_.async_accept(
beast::bind_front_handler( beast::bind_front_handler(

View File

@ -21,6 +21,7 @@
#include <boost/beast/websocket/ssl.hpp> #include <boost/beast/websocket/ssl.hpp>
#include <boost/asio/coroutine.hpp> #include <boost/asio/coroutine.hpp>
#include <boost/asio/strand.hpp> #include <boost/asio/strand.hpp>
#include <boost/asio/dispatch.hpp>
#include <algorithm> #include <algorithm>
#include <cstdlib> #include <cstdlib>
#include <functional> #include <functional>
@ -65,7 +66,15 @@ public:
void void
run() run()
{ {
loop({}, 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(ws_.get_executor(),
beast::bind_front_handler(&session::loop,
shared_from_this(),
beast::error_code{},
0));
} }
#include <boost/asio/yield.hpp> #include <boost/asio/yield.hpp>

View File

@ -17,6 +17,7 @@
#include <boost/beast/websocket.hpp> #include <boost/beast/websocket.hpp>
#include <boost/asio/coroutine.hpp> #include <boost/asio/coroutine.hpp>
#include <boost/asio/strand.hpp> #include <boost/asio/strand.hpp>
#include <boost/asio/dispatch.hpp>
#include <algorithm> #include <algorithm>
#include <cstdlib> #include <cstdlib>
#include <functional> #include <functional>
@ -61,7 +62,15 @@ public:
void void
run() run()
{ {
loop({}, 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(ws_.get_executor(),
beast::bind_front_handler(&session::loop,
shared_from_this(),
beast::error_code{},
0));
} }
#include <boost/asio/yield.hpp> #include <boost/asio/yield.hpp>