Fixes to support Asio changes (API Change):

This adjusts Beast's interfaces and implementation to match
the changes in Boost.Asio.
This commit is contained in:
Vinnie Falco
2019-02-18 12:42:24 -08:00
parent ac24e58fb3
commit 6baa607295
58 changed files with 762 additions and 723 deletions

View File

@ -84,6 +84,11 @@ add_definitions (-DBOOST_ASIO_DISABLE_BOOST_ARRAY=1)
add_definitions (-DBOOST_ASIO_DISABLE_BOOST_BIND=1)
add_definitions (-DBOOST_ASIO_DISABLE_BOOST_DATE_TIME=1)
add_definitions (-DBOOST_ASIO_DISABLE_BOOST_REGEX=1)
# workaround for asio defect
add_definitions (-DBOOST_ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE=1)
add_definitions (-DBOOST_ASIO_DISABLE_WINDOWS_STREAM_HANDLE=1)
add_definitions (-DBOOST_COROUTINES_NO_DEPRECATION_WARNING=1)
include_directories (${BOOST_ROOT})
@ -174,6 +179,9 @@ endif()
include_directories (.)
# VFALCO FIXME Need this for recent asio changes
add_definitions (-DBOOST_BEAST_NO_FILE_BODY_WIN32=1)
if (OPENSSL_FOUND)
include_directories (${OPENSSL_INCLUDE_DIR})
endif()

View File

@ -93,6 +93,14 @@ project /boost/beast
<define>BOOST_ASIO_DISABLE_BOOST_DATE_TIME=1
<define>BOOST_ASIO_DISABLE_BOOST_REGEX=1
<define>BOOST_COROUTINES_NO_DEPRECATION_WARNING=1
# workaround for asio defect
<define>BOOST_ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE=1
<define>BOOST_ASIO_DISABLE_WINDOWS_STREAM_HANDLE=1
# VFALCO FIXME Need this for recent asio changes
<define>BOOST_BEAST_NO_FILE_BODY_WIN32=1
<toolset>msvc:<cxxflags>"/bigobj"
<toolset>msvc-14.1:<cxxflags>"/permissive-"
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS=1

View File

@ -331,27 +331,26 @@ public:
}
};
//------------------------------------------------------------------------------
// Handles a plain WebSocket connection
class plain_websocket_session
: public websocket_session<plain_websocket_session>
, public std::enable_shared_from_this<plain_websocket_session>
{
websocket::stream<
beast::tcp_stream<net::io_context::strand>> ws_;
bool close_ = false;
websocket::stream<beast::tcp_stream> ws_;
public:
// Create the session
explicit
plain_websocket_session(
beast::tcp_stream<net::io_context::strand>&& stream)
beast::tcp_stream&& stream)
: ws_(std::move(stream))
{
}
// Called by the base class
websocket::stream<
beast::tcp_stream<net::io_context::strand>>&
websocket::stream<beast::tcp_stream>&
ws()
{
return ws_;
@ -365,48 +364,28 @@ public:
// Accept the WebSocket upgrade request
do_accept(std::move(req));
}
void
on_close(beast::error_code ec)
{
// Happens when close times out
if(ec == net::error::operation_aborted)
return;
if(ec)
return fail(ec, "close");
// At this point the connection is gracefully closed
}
};
//------------------------------------------------------------------------------
// Handles an SSL WebSocket connection
class ssl_websocket_session
: public websocket_session<ssl_websocket_session>
, public std::enable_shared_from_this<ssl_websocket_session>
{
websocket::stream<beast::ssl_stream<
beast::tcp_stream<net::io_context::strand>>> ws_;
bool eof_ = false;
websocket::stream<
beast::ssl_stream<beast::tcp_stream>> ws_;
public:
// Create the http_session
// Create the ssl_websocket_session
explicit
ssl_websocket_session(beast::ssl_stream<
beast::tcp_stream<net::io_context::strand>>&& stream)
ssl_websocket_session(
beast::ssl_stream<beast::tcp_stream>&& stream)
: ws_(std::move(stream))
{
}
// Called by the base class
websocket::stream<beast::ssl_stream<
beast::tcp_stream<net::io_context::strand>>>&
ws()
{
return ws_;
}
// Start the asynchronous operation
// Start the session
template<class Body, class Allocator>
void
run(http::request<Body, http::basic_fields<Allocator>> req)
@ -415,18 +394,15 @@ public:
do_accept(std::move(req));
}
void
do_eof()
// Called by the base class
websocket::stream<
beast::ssl_stream<beast::tcp_stream>>&
ws()
{
eof_ = true;
// Perform the SSL shutdown
ws_.next_layer().async_shutdown(
beast::bind_front_handler(
&ssl_websocket_session::on_shutdown,
shared_from_this()));
return ws_;
}
private:
void
on_shutdown(beast::error_code ec)
{
@ -437,10 +413,12 @@ public:
}
};
//------------------------------------------------------------------------------
template<class Body, class Allocator>
void
make_websocket_session(
beast::tcp_stream<net::io_context::strand> stream,
beast::tcp_stream stream,
http::request<Body, http::basic_fields<Allocator>> req)
{
std::make_shared<plain_websocket_session>(
@ -450,7 +428,7 @@ make_websocket_session(
template<class Body, class Allocator>
void
make_websocket_session(
beast::ssl_stream<beast::tcp_stream<net::io_context::strand>> stream,
beast::ssl_stream<beast::tcp_stream> stream,
http::request<Body, http::basic_fields<Allocator>> req)
{
std::make_shared<ssl_websocket_session>(
@ -568,19 +546,15 @@ class http_session
queue queue_;
protected:
net::steady_timer timer_;
beast::flat_buffer buffer_;
public:
// Construct the session
http_session(
net::io_context& ioc,
beast::flat_buffer buffer,
std::shared_ptr<std::string const> const& doc_root)
: doc_root_(doc_root)
, queue_(*this)
, timer_(ioc,
(std::chrono::steady_clock::time_point::max)())
, buffer_(std::move(buffer))
{
}
@ -621,7 +595,11 @@ public:
// See if it is a WebSocket Upgrade
if(websocket::is_upgrade(req_))
{
// Transfer the stream to a new WebSocket session
// Disable the timeout.
// The websocket::stream uses its own timeout settings.
beast::get_lowest_layer(derived().stream()).expires_never();
// Transfer the stream to a new WebSocket session.
return make_websocket_session(
derived().release_stream(),
std::move(req_));
@ -663,56 +641,50 @@ public:
}
};
//------------------------------------------------------------------------------
// Handles a plain HTTP connection
class plain_http_session
: public http_session<plain_http_session>
, public std::enable_shared_from_this<plain_http_session>
{
beast::tcp_stream<net::io_context::strand> stream_;
beast::tcp_stream stream_;
public:
// Create the http_session
// Create the session
plain_http_session(
beast::tcp_stream<net::io_context::strand>&& stream,
beast::tcp_stream&& stream,
beast::flat_buffer&& buffer,
std::shared_ptr<std::string const> const& doc_root)
: http_session<plain_http_session>(
stream.get_executor().context(),
std::move(buffer),
doc_root)
, stream_(std::move(stream))
{
}
// Start the session
void
run()
{
this->do_read();
}
// Called by the base class
beast::tcp_stream<net::io_context::strand>&
beast::tcp_stream&
stream()
{
return stream_;
}
// Called by the base class
beast::tcp_stream<net::io_context::strand>
beast::tcp_stream
release_stream()
{
return std::move(stream_);
}
// Start the asynchronous operation
void
run()
{
// Make sure we run on the strand
if(! stream_.get_executor().running_in_this_thread())
return net::post(
stream_.get_executor(),
beast::bind_front_handler(
&plain_http_session::run,
shared_from_this()));
do_read();
}
// Called by the base class
void
do_eof()
{
@ -722,70 +694,35 @@ public:
// At this point the connection is closed gracefully
}
void
do_timeout()
{
// Closing the socket cancels all outstanding operations. They
// will complete with net::error::operation_aborted
beast::error_code ec;
stream_.socket().shutdown(tcp::socket::shutdown_both, ec);
stream_.socket().close(ec);
}
};
//------------------------------------------------------------------------------
// Handles an SSL HTTP connection
class ssl_http_session
: public http_session<ssl_http_session>
, public std::enable_shared_from_this<ssl_http_session>
{
beast::ssl_stream<
beast::tcp_stream<net::io_context::strand>> stream_;
bool eof_ = false;
beast::ssl_stream<beast::tcp_stream> stream_;
public:
// Create the http_session
ssl_http_session(
beast::tcp_stream<net::io_context::strand>&& stream,
beast::tcp_stream&& stream,
ssl::context& ctx,
beast::flat_buffer&& buffer,
std::shared_ptr<std::string const> const& doc_root)
: http_session<ssl_http_session>(
stream.get_executor().context(),
std::move(buffer),
doc_root)
, stream_(std::move(stream), ctx)
{
}
// Called by the base class
beast::ssl_stream<
beast::tcp_stream<net::io_context::strand>>&
stream()
{
return stream_;
}
// Called by the base class
beast::ssl_stream<
beast::tcp_stream<net::io_context::strand>>
release_stream()
{
return std::move(stream_);
}
// Start the asynchronous operation
// Start the session
void
run()
{
// Make sure we run on the strand
if(! stream_.get_executor().running_in_this_thread())
return net::post(
stream_.get_executor(),
beast::bind_front_handler(
&ssl_http_session::run,
shared_from_this()));
// Set the timeout.
beast::get_lowest_layer(stream_).expires_after(std::chrono::seconds(30));
@ -798,6 +735,36 @@ public:
&ssl_http_session::on_handshake,
shared_from_this()));
}
// Called by the base class
beast::ssl_stream<beast::tcp_stream>&
stream()
{
return stream_;
}
// Called by the base class
beast::ssl_stream<beast::tcp_stream>
release_stream()
{
return std::move(stream_);
}
// Called by the base class
void
do_eof()
{
// Set the timeout.
beast::get_lowest_layer(stream_).expires_after(std::chrono::seconds(30));
// Perform the SSL shutdown
stream_.async_shutdown(
beast::bind_front_handler(
&ssl_http_session::on_shutdown,
shared_from_this()));
}
private:
void
on_handshake(
beast::error_code ec,
@ -812,21 +779,6 @@ public:
do_read();
}
void
do_eof()
{
eof_ = true;
// Set the timeout.
beast::get_lowest_layer(stream_).expires_after(std::chrono::seconds(30));
// Perform the SSL shutdown
stream_.async_shutdown(
beast::bind_front_handler(
&ssl_http_session::on_shutdown,
shared_from_this()));
}
void
on_shutdown(beast::error_code ec)
{
@ -846,7 +798,7 @@ public:
// Detects SSL handshakes
class detect_session : public std::enable_shared_from_this<detect_session>
{
beast::tcp_stream<net::io_context::strand> stream_;
beast::tcp_stream stream_;
ssl::context& ctx_;
std::shared_ptr<std::string const> doc_root_;
beast::flat_buffer buffer_;
@ -854,7 +806,7 @@ class detect_session : public std::enable_shared_from_this<detect_session>
public:
explicit
detect_session(
tcp::socket socket,
tcp::socket&& socket,
ssl::context& ctx,
std::shared_ptr<std::string const> const& doc_root)
: stream_(std::move(socket))
@ -906,8 +858,10 @@ public:
// Accepts incoming connections and launches the sessions
class listener : public std::enable_shared_from_this<listener>
{
net::io_context& ioc_;
ssl::context& ctx_;
tcp::acceptor acceptor_;
tcp::socket socket_;
std::shared_ptr<std::string const> doc_root_;
public:
@ -916,8 +870,10 @@ public:
ssl::context& ctx,
tcp::endpoint endpoint,
std::shared_ptr<std::string const> const& doc_root)
: ctx_(ctx)
, acceptor_(ioc)
: ioc_(ioc)
, ctx_(ctx)
, acceptor_(beast::make_strand(ioc))
, socket_(beast::make_strand(ioc))
, doc_root_(doc_root)
{
beast::error_code ec;
@ -969,13 +925,14 @@ public:
do_accept()
{
acceptor_.async_accept(
socket_,
beast::bind_front_handler(
&listener::on_accept,
shared_from_this()));
}
void
on_accept(beast::error_code ec, tcp::socket socket)
on_accept(beast::error_code ec)
{
if(ec)
{
@ -985,11 +942,14 @@ public:
{
// Create the detector http_session and run it
std::make_shared<detect_session>(
std::move(socket),
std::move(socket_),
ctx_,
doc_root_)->run();
}
// Make sure each session gets its own strand
socket_ = tcp::socket(beast::make_strand(ioc_));
// Accept another connection
do_accept();
}

View File

@ -219,14 +219,13 @@ fail(beast::error_code ec, char const* what)
// Echoes back all received WebSocket messages
class websocket_session : public std::enable_shared_from_this<websocket_session>
{
websocket::stream<beast::tcp_stream<net::io_context::strand>> ws_;
websocket::stream<beast::tcp_stream> ws_;
beast::flat_buffer buffer_;
char ping_state_ = 0;
public:
// Take ownership of the socket
explicit
websocket_session(tcp::socket socket)
websocket_session(tcp::socket&& socket)
: ws_(std::move(socket))
{
}
@ -258,6 +257,7 @@ public:
shared_from_this()));
}
private:
void
on_accept(beast::error_code ec)
{
@ -413,7 +413,7 @@ class http_session : public std::enable_shared_from_this<http_session>
}
};
beast::tcp_stream<net::io_context::strand> stream_;
beast::tcp_stream stream_;
beast::flat_buffer buffer_;
std::shared_ptr<std::string const> doc_root_;
http::request<http::string_body> req_;
@ -421,9 +421,8 @@ class http_session : public std::enable_shared_from_this<http_session>
public:
// Take ownership of the socket
explicit
http_session(
tcp::socket socket,
tcp::socket&& socket,
std::shared_ptr<std::string const> const& doc_root)
: stream_(std::move(socket))
, doc_root_(doc_root)
@ -431,21 +430,14 @@ public:
{
}
// Start the asynchronous operation
// Start the session
void
run()
{
// Make sure we run on the strand
if(! stream_.get_executor().running_in_this_thread())
return net::post(
stream_.get_executor(),
std::bind(
&http_session::run,
shared_from_this()));
do_read();
}
private:
void
do_read()
{
@ -532,6 +524,7 @@ public:
// Accepts incoming connections and launches the sessions
class listener : public std::enable_shared_from_this<listener>
{
net::io_context& ioc_;
tcp::acceptor acceptor_;
tcp::socket socket_;
std::shared_ptr<std::string const> doc_root_;
@ -541,8 +534,9 @@ public:
net::io_context& ioc,
tcp::endpoint endpoint,
std::shared_ptr<std::string const> const& doc_root)
: acceptor_(ioc)
, socket_(ioc)
: ioc_(ioc)
, acceptor_(beast::make_strand(ioc))
, socket_(beast::make_strand(ioc))
, doc_root_(doc_root)
{
beast::error_code ec;
@ -594,13 +588,14 @@ public:
do_accept()
{
acceptor_.async_accept(
socket_,
beast::bind_front_handler(
&listener::on_accept,
shared_from_this()));
}
void
on_accept(beast::error_code ec, tcp::socket socket)
on_accept(beast::error_code ec)
{
if(ec)
{
@ -610,10 +605,13 @@ public:
{
// Create the http session and run it
std::make_shared<http_session>(
std::move(socket),
std::move(socket_),
doc_root_)->run();
}
// Make sure each session gets its own strand
socket_ = tcp::socket(beast::make_strand(ioc_));
// Accept another connection
do_accept();
}

View File

@ -33,10 +33,6 @@ using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
//------------------------------------------------------------------------------
// The type of stream to use
using stream_type =
beast::ssl_stream<beast::tcp_stream<net::io_context::executor_type>>;
// Report a failure
void
fail(beast::error_code ec, char const* what)
@ -48,17 +44,18 @@ fail(beast::error_code ec, char const* what)
class session : public std::enable_shared_from_this<session>
{
tcp::resolver resolver_;
stream_type stream_;
beast::ssl_stream<beast::tcp_stream> stream_;
beast::flat_buffer buffer_; // (Must persist between reads)
http::request<http::empty_body> req_;
http::response<http::string_body> res_;
public:
// Resolver and stream require an io_context
// Objects are constructed with a strand to
// ensure that handlers do not execute concurrently.
explicit
session(net::io_context& ioc, ssl::context& ctx)
: resolver_(ioc)
, stream_(ioc, ctx)
: resolver_(beast::make_strand(ioc))
, stream_(beast::make_strand(ioc), ctx)
{
}

View File

@ -29,9 +29,6 @@ using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
//------------------------------------------------------------------------------
// The type of stream to use
using stream_type = beast::tcp_stream<net::io_context::executor_type>;
// Report a failure
void
fail(beast::error_code ec, char const* what)
@ -43,17 +40,18 @@ fail(beast::error_code ec, char const* what)
class session : public std::enable_shared_from_this<session>
{
tcp::resolver resolver_;
stream_type stream_;
beast::tcp_stream stream_;
beast::flat_buffer buffer_; // (Must persist between reads)
http::request<http::empty_body> req_;
http::response<http::string_body> res_;
public:
// Resolver and socket require an io_context
// Objects are constructed with a strand to
// ensure that handlers do not execute concurrently.
explicit
session(net::io_context& ioc)
: resolver_(ioc)
, stream_(ioc)
: resolver_(beast::make_strand(ioc))
, stream_(beast::make_strand(ioc))
{
}

View File

@ -33,11 +33,6 @@ using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
//------------------------------------------------------------------------------
// The type of stream to use
// Stackful coroutines are already stranded.
using stream_type =
beast::ssl_stream<beast::tcp_stream<net::io_context::executor_type>>;
// Report a failure
void
fail(beast::error_code ec, char const* what)
@ -60,7 +55,7 @@ do_session(
// These objects perform our I/O
tcp::resolver resolver(ioc);
stream_type stream(ioc, ctx);
beast::ssl_stream<beast::tcp_stream> stream(ioc, ctx);
// Set SNI Hostname (many hosts need this to handshake successfully)
if(! SSL_set_tlsext_host_name(stream.native_handle(), host.c_str()))

View File

@ -29,10 +29,6 @@ using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
//------------------------------------------------------------------------------
// The type of stream to use.
// Stackful coroutines are already stranded.
using stream_type = beast::tcp_stream<net::io_context::executor_type>;
// Report a failure
void
fail(beast::error_code ec, char const* what)
@ -53,8 +49,8 @@ do_session(
beast::error_code ec;
// These objects perform our I/O
tcp::resolver resolver{ioc};
stream_type stream(ioc);
tcp::resolver resolver(ioc);
beast::tcp_stream stream(ioc);
// Look up the domain name
auto const results = resolver.async_resolve(host, port, yield[ec]);

View File

@ -151,10 +151,7 @@ class worker : public std::enable_shared_from_this<worker>
crawl_report& report_;
tcp::resolver resolver_;
tcp::socket socket_;
net::steady_timer timer_;
net::strand<
net::io_context::executor_type> strand_;
beast::tcp_stream stream_;
beast::flat_buffer buffer_; // (Must persist between reads)
http::request<http::empty_body> req_;
http::response<http::string_body> res_;
@ -167,11 +164,8 @@ public:
crawl_report& report,
net::io_context& ioc)
: report_(report)
, resolver_(ioc)
, socket_(ioc)
, timer_(ioc,
(chrono::steady_clock::time_point::max)())
, strand_(ioc.get_executor())
, resolver_(beast::make_strand(ioc))
, stream_(beast::make_strand(ioc))
{
// Set up the common fields of the request
req_.version(11);
@ -184,44 +178,9 @@ public:
void
run()
{
// Run the timer. The timer is operated
// continuously, this simplifies the code.
on_timer({});
do_get_host();
}
void
on_timer(beast::error_code ec)
{
if(ec && ec != net::error::operation_aborted)
{
// Should never happen
report_.aggregate(
[](crawl_report& rep)
{
++rep.timer_failures;
});
return;
}
// Verify that the timer really expired since the deadline may have moved.
if(timer_.expiry() <= chrono::steady_clock::now())
{
socket_.shutdown(tcp::socket::shutdown_both, ec);
socket_.close(ec);
return;
}
// Wait on the timer
timer_.async_wait(
net::bind_executor(
strand_,
beast::bind_front_handler(
&worker::on_timer,
shared_from_this())));
}
void
do_get_host()
{
@ -230,27 +189,19 @@ public:
// nullptr means no more work
if(! host)
{
timer_.cancel_one();
return;
}
// The Host HTTP field is required
req_.set(http::field::host, host);
// Set the timer
timer_.expires_after(chrono::seconds(timeout));
// Set up an HTTP GET request message
// Look up the domain name
resolver_.async_resolve(
host,
"http",
net::bind_executor(
strand_,
beast::bind_front_handler(
&worker::on_resolve,
shared_from_this())));
beast::bind_front_handler(
&worker::on_resolve,
shared_from_this()));
}
void
@ -268,18 +219,16 @@ public:
return do_get_host();
}
// Set the timer
timer_.expires_after(chrono::seconds(timeout));
// Set a timeout on the operation
stream_.expires_after(std::chrono::seconds(10));
// Make the connection on the IP address we get from a lookup
net::async_connect(
socket_,
beast::async_connect(
stream_,
results,
net::bind_executor(
strand_,
beast::bind_front_handler(
&worker::on_connect,
shared_from_this())));
beast::bind_front_handler(
&worker::on_connect,
shared_from_this()));
}
void
@ -295,18 +244,16 @@ public:
return do_get_host();
}
// Set the timer
timer_.expires_after(chrono::seconds(timeout));
// Set a timeout on the operation
stream_.expires_after(std::chrono::seconds(10));
// Send the HTTP request to the remote host
http::async_write(
socket_,
stream_,
req_,
net::bind_executor(
strand_,
beast::bind_front_handler(
&worker::on_write,
shared_from_this())));
beast::bind_front_handler(
&worker::on_write,
shared_from_this()));
}
void
@ -325,21 +272,16 @@ public:
});
return do_get_host();
}
// Set the timer
timer_.expires_after(chrono::seconds(timeout));
// Receive the HTTP response
res_ = {};
http::async_read(
socket_,
stream_,
buffer_,
res_,
net::bind_executor(
strand_,
beast::bind_front_handler(
&worker::on_read,
shared_from_this())));
beast::bind_front_handler(
&worker::on_read,
shared_from_this()));
}
void
@ -368,8 +310,8 @@ public:
});
// Gracefully close the socket
socket_.shutdown(tcp::socket::shutdown_both, ec);
socket_.close(ec);
stream_.socket().shutdown(tcp::socket::shutdown_both, ec);
stream_.close();
// If we get here then the connection is closed gracefully
@ -412,7 +354,7 @@ int main(int argc, char* argv[])
auto const threads = std::max<int>(1, std::atoi(argv[1]));
// The io_context is required for all I/O
net::io_context ioc{1};
net::io_context ioc;
// The work keeps io_context::run from returning
auto work = net::make_work_guard(ioc);

View File

@ -57,7 +57,7 @@ int main(int argc, char** argv)
net::io_context ioc;
// The SSL context is required, and holds certificates
ssl::context ctx{ssl::context::sslv23_client};
ssl::context ctx(ssl::context::sslv23_client);
// This holds the root certificate used for verification
load_root_certificates(ctx);
@ -66,8 +66,8 @@ int main(int argc, char** argv)
ctx.set_verify_mode(ssl::verify_peer);
// These objects perform our I/O
tcp::resolver resolver{ioc};
beast::ssl_stream<tcp::socket> stream{ioc, ctx};
tcp::resolver resolver(ioc);
beast::ssl_stream<beast::tcp_stream> stream(ioc, ctx);
// Set SNI Hostname (many hosts need this to handshake successfully)
if(! SSL_set_tlsext_host_name(stream.native_handle(), host))
@ -80,7 +80,7 @@ int main(int argc, char** argv)
auto const results = resolver.resolve(host, port);
// Make the connection on the IP address we get from a lookup
net::connect(stream.next_layer(), results.begin(), results.end());
beast::connect(beast::get_lowest_layer(stream), results);
// Perform the SSL handshake
stream.handshake(ssl::stream_base::client);

View File

@ -53,14 +53,14 @@ int main(int argc, char** argv)
net::io_context ioc;
// These objects perform our I/O
tcp::resolver resolver{ioc};
tcp::socket socket{ioc};
tcp::resolver resolver(ioc);
beast::tcp_stream stream(ioc);
// Look up the domain name
auto const results = resolver.resolve(host, port);
// Make the connection on the IP address we get from a lookup
net::connect(socket, results.begin(), results.end());
beast::connect(stream, results);
// Set up an HTTP GET request message
http::request<http::string_body> req{http::verb::get, target, version};
@ -68,7 +68,7 @@ int main(int argc, char** argv)
req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
// Send the HTTP request to the remote host
http::write(socket, req);
http::write(stream, req);
// This buffer is used for reading and must be persisted
beast::flat_buffer buffer;
@ -77,14 +77,14 @@ int main(int argc, char** argv)
http::response<http::dynamic_body> res;
// Receive the HTTP response
http::read(socket, buffer, res);
http::read(stream, buffer, res);
// Write the message to standard out
std::cout << res << std::endl;
// Gracefully close the socket
beast::error_code ec;
socket.shutdown(tcp::socket::shutdown_both, ec);
stream.socket().shutdown(tcp::socket::shutdown_both, ec);
// not_connected happens sometimes
// so don't bother reporting it.

View File

@ -255,7 +255,7 @@ class session : public std::enable_shared_from_this<session>
}
};
beast::ssl_stream<beast::tcp_stream<net::io_context::strand>> stream_;
beast::ssl_stream<beast::tcp_stream> stream_;
beast::flat_buffer buffer_;
std::shared_ptr<std::string const> doc_root_;
http::request<http::string_body> req_;
@ -387,8 +387,10 @@ public:
// Accepts incoming connections and launches the sessions
class listener : public std::enable_shared_from_this<listener>
{
net::io_context& ioc_;
ssl::context& ctx_;
tcp::acceptor acceptor_;
tcp::socket socket_;
std::shared_ptr<std::string const> doc_root_;
public:
@ -397,8 +399,10 @@ public:
ssl::context& ctx,
tcp::endpoint endpoint,
std::shared_ptr<std::string const> const& doc_root)
: ctx_(ctx)
: ioc_(ioc)
, ctx_(ctx)
, acceptor_(ioc)
, socket_(beast::make_strand(ioc))
, doc_root_(doc_root)
{
beast::error_code ec;
@ -450,13 +454,14 @@ public:
do_accept()
{
acceptor_.async_accept(
socket_,
beast::bind_front_handler(
&listener::on_accept,
shared_from_this()));
}
void
on_accept(beast::error_code ec, tcp::socket socket)
on_accept(beast::error_code ec)
{
if(ec)
{
@ -466,11 +471,14 @@ public:
{
// Create the session and run it
std::make_shared<session>(
std::move(socket),
std::move(socket_),
ctx_,
doc_root_)->run();
}
// Make sure each session gets its own strand
socket_ = tcp::socket(beast::make_strand(ioc_));
// Accept another connection
do_accept();
}

View File

@ -251,7 +251,7 @@ class session : public std::enable_shared_from_this<session>
}
};
beast::tcp_stream<net::io_context::strand> stream_;
beast::tcp_stream stream_;
beast::flat_buffer buffer_;
std::shared_ptr<std::string const> doc_root_;
http::request<http::string_body> req_;
@ -259,7 +259,7 @@ class session : public std::enable_shared_from_this<session>
send_lambda lambda_;
public:
// Take ownership of the socket
// Take ownership of the stream
session(
tcp::socket&& socket,
std::shared_ptr<std::string const> const& doc_root)
@ -352,7 +352,9 @@ public:
// Accepts incoming connections and launches the sessions
class listener : public std::enable_shared_from_this<listener>
{
net::io_context& ioc_;
tcp::acceptor acceptor_;
tcp::socket socket_;
std::shared_ptr<std::string const> doc_root_;
public:
@ -360,7 +362,9 @@ public:
net::io_context& ioc,
tcp::endpoint endpoint,
std::shared_ptr<std::string const> const& doc_root)
: acceptor_(ioc)
: ioc_(ioc)
, acceptor_(beast::make_strand(ioc))
, socket_(beast::make_strand(ioc))
, doc_root_(doc_root)
{
beast::error_code ec;
@ -412,13 +416,14 @@ public:
do_accept()
{
acceptor_.async_accept(
socket_,
beast::bind_front_handler(
&listener::on_accept,
shared_from_this()));
}
void
on_accept(beast::error_code ec, tcp::socket socket)
on_accept(beast::error_code ec)
{
if(ec)
{
@ -428,10 +433,13 @@ public:
{
// Create the session and run it
std::make_shared<session>(
std::move(socket),
std::move(socket_),
doc_root_)->run();
}
// Make sure each session gets its own strand
socket_ = tcp::socket(beast::make_strand(ioc_));
// Accept another connection
do_accept();
}

View File

@ -207,11 +207,6 @@ handle_request(
//------------------------------------------------------------------------------
// The type of stream to use
// Stackful coroutines are already stranded.
using stream_type =
beast::ssl_stream<beast::tcp_stream<net::io_context::executor_type>>;
// Report a failure
void
fail(beast::error_code ec, char const* what)
@ -223,13 +218,13 @@ fail(beast::error_code ec, char const* what)
// The function object is used to send an HTTP message.
struct send_lambda
{
stream_type& stream_;
beast::ssl_stream<beast::tcp_stream>& stream_;
bool& close_;
beast::error_code& ec_;
net::yield_context yield_;
send_lambda(
stream_type& stream,
beast::ssl_stream<beast::tcp_stream>& stream,
bool& close,
beast::error_code& ec,
net::yield_context yield)
@ -258,7 +253,7 @@ struct send_lambda
// Handles an HTTP server connection
void
do_session(
stream_type& stream,
beast::ssl_stream<beast::tcp_stream>& stream,
std::shared_ptr<std::string const> const& doc_root,
net::yield_context yield)
{
@ -357,10 +352,11 @@ do_listen(
fail(ec, "accept");
else
net::spawn(
acceptor.get_executor().context(),
acceptor.get_executor(),
std::bind(
&do_session,
stream_type(std::move(socket), ctx),
beast::ssl_stream<beast::tcp_stream>(
std::move(socket), ctx),
doc_root,
std::placeholders::_1));
}

View File

@ -204,10 +204,6 @@ handle_request(
//------------------------------------------------------------------------------
// The type of stream to use.
// Stackful coroutines are already stranded.
using stream_type = beast::tcp_stream<net::io_context::executor_type>;
// Report a failure
void
fail(beast::error_code ec, char const* what)
@ -219,13 +215,13 @@ fail(beast::error_code ec, char const* what)
// The function object is used to send an HTTP message.
struct send_lambda
{
stream_type& stream_;
beast::tcp_stream& stream_;
bool& close_;
beast::error_code& ec_;
net::yield_context yield_;
send_lambda(
stream_type& stream,
beast::tcp_stream& stream,
bool& close,
beast::error_code& ec,
net::yield_context yield)
@ -254,7 +250,7 @@ struct send_lambda
// Handles an HTTP server connection
void
do_session(
stream_type& stream,
beast::tcp_stream& stream,
std::shared_ptr<std::string const> const& doc_root,
net::yield_context yield)
{
@ -339,10 +335,10 @@ do_listen(
fail(ec, "accept");
else
net::spawn(
acceptor.get_executor().context(),
acceptor.get_executor(),
std::bind(
&do_session,
stream_type(std::move(socket)),
beast::tcp_stream(std::move(socket)),
doc_root,
std::placeholders::_1));
}

View File

@ -99,7 +99,7 @@ private:
std::string doc_root_;
// The socket for the currently connected client.
tcp::socket socket_{acceptor_.get_executor().context()};
tcp::socket socket_{acceptor_.get_executor()};
// The buffer for performing reads
beast::flat_static_buffer<8192> buffer_;
@ -112,7 +112,7 @@ private:
// The timer putting a time limit on requests.
net::basic_waitable_timer<std::chrono::steady_clock> request_deadline_{
acceptor_.get_executor().context(), (std::chrono::steady_clock::time_point::max)()};
acceptor_.get_executor(), (std::chrono::steady_clock::time_point::max)()};
// The string-based response message.
boost::optional<http::response<http::string_body, http::basic_fields<alloc_t>>> string_response_;

View File

@ -208,13 +208,6 @@ handle_request(
//------------------------------------------------------------------------------
// The type of plain streams
using plain_stream_type = beast::tcp_stream<net::io_context::strand>;
// The type of TLS streams
using ssl_stream_type =
beast::ssl_stream<beast::tcp_stream<net::io_context::strand>>;
// Report a failure
void
fail(beast::error_code ec, char const* what)
@ -358,7 +351,7 @@ class plain_session
: public session<plain_session>
, public std::enable_shared_from_this<plain_session>
{
plain_stream_type stream_;
beast::tcp_stream stream_;
public:
// Create the session
@ -374,7 +367,7 @@ public:
}
// Called by the base class
plain_stream_type&
beast::tcp_stream&
stream()
{
return stream_;
@ -403,7 +396,7 @@ class ssl_session
: public session<ssl_session>
, public std::enable_shared_from_this<ssl_session>
{
ssl_stream_type stream_;
beast::ssl_stream<beast::tcp_stream> stream_;
public:
// Create the session
@ -420,7 +413,7 @@ public:
}
// Called by the base class
ssl_stream_type&
beast::ssl_stream<beast::tcp_stream>&
stream()
{
return stream_;
@ -442,6 +435,7 @@ public:
&ssl_session::on_handshake,
shared_from_this()));
}
void
on_handshake(
beast::error_code ec,
@ -484,14 +478,14 @@ public:
// Detects SSL handshakes
class detect_session : public std::enable_shared_from_this<detect_session>
{
plain_stream_type stream_;
beast::tcp_stream stream_;
ssl::context& ctx_;
std::shared_ptr<std::string const> doc_root_;
beast::flat_buffer buffer_;
public:
detect_session(
tcp::socket socket,
tcp::socket&& socket,
ssl::context& ctx,
std::shared_ptr<std::string const> const& doc_root)
: stream_(std::move(socket))
@ -544,8 +538,10 @@ public:
// Accepts incoming connections and launches the sessions
class listener : public std::enable_shared_from_this<listener>
{
net::io_context& ioc_;
ssl::context& ctx_;
tcp::acceptor acceptor_;
tcp::socket socket_;
std::shared_ptr<std::string const> doc_root_;
public:
@ -554,8 +550,10 @@ public:
ssl::context& ctx,
tcp::endpoint endpoint,
std::shared_ptr<std::string const> const& doc_root)
: ctx_(ctx)
, acceptor_(ioc)
: ioc_(ioc)
, ctx_(ctx)
, acceptor_(beast::make_strand(ioc))
, socket_(beast::make_strand(ioc))
, doc_root_(doc_root)
{
beast::error_code ec;
@ -607,13 +605,14 @@ public:
do_accept()
{
acceptor_.async_accept(
socket_,
beast::bind_front_handler(
&listener::on_accept,
shared_from_this()));
}
void
on_accept(beast::error_code ec, tcp::socket sock)
on_accept(beast::error_code ec)
{
if(ec)
{
@ -623,11 +622,14 @@ public:
{
// Create the detector session and run it
std::make_shared<detect_session>(
std::move(sock),
std::move(socket_),
ctx_,
doc_root_)->run();
}
// Make sure each session gets its own strand
socket_ = tcp::socket(beast::make_strand(ioc_));
// Accept another connection
do_accept();
}

View File

@ -76,7 +76,7 @@ private:
// The timer for putting a deadline on connection processing.
net::basic_waitable_timer<std::chrono::steady_clock> deadline_{
socket_.get_executor().context(), std::chrono::seconds(60)};
socket_.get_executor(), std::chrono::seconds(60)};
// Asynchronously receive a complete request message.
void

View File

@ -209,10 +209,6 @@ handle_request(
//------------------------------------------------------------------------------
// The type of TLS streams
using ssl_stream_type =
beast::ssl_stream<beast::tcp_stream<net::io_context::strand>>;
// Report a failure
void
fail(beast::error_code ec, char const* what)
@ -264,7 +260,7 @@ class session
}
};
ssl_stream_type stream_;
beast::ssl_stream<beast::tcp_stream> stream_;
beast::flat_buffer buffer_;
std::shared_ptr<std::string const> doc_root_;
http::request<http::string_body> req_;
@ -383,6 +379,7 @@ class listener
: public net::coroutine
, public std::enable_shared_from_this<listener>
{
net::io_context& ioc_;
ssl::context& ctx_;
tcp::acceptor acceptor_;
tcp::socket socket_;
@ -394,9 +391,10 @@ public:
ssl::context& ctx,
tcp::endpoint endpoint,
std::shared_ptr<std::string const> const& doc_root)
: ctx_(ctx)
, acceptor_(ioc)
, socket_(ioc)
: ioc_(ioc)
, ctx_(ctx)
, acceptor_(beast::make_strand(ioc))
, socket_(beast::make_strand(ioc))
, doc_root_(doc_root)
{
beast::error_code ec;
@ -470,6 +468,9 @@ public:
ctx_,
doc_root_)->run();
}
// Make sure each session gets its own strand
socket_ = tcp::socket(beast::make_strand(ioc_));
}
}
}

View File

@ -205,9 +205,6 @@ handle_request(
//------------------------------------------------------------------------------
// The type of stream to use
using stream_type = beast::tcp_stream<net::io_context::strand>;
// Report a failure
void
fail(beast::error_code ec, char const* what)
@ -258,7 +255,7 @@ class session
}
};
stream_type stream_;
beast::tcp_stream stream_;
beast::flat_buffer buffer_;
std::shared_ptr<std::string const> doc_root_;
http::request<http::string_body> req_;
@ -269,7 +266,7 @@ public:
// Take ownership of the socket
explicit
session(
tcp::socket socket,
tcp::socket&& socket,
std::shared_ptr<std::string const> const& doc_root)
: stream_(std::move(socket))
, doc_root_(doc_root)
@ -348,6 +345,7 @@ class listener
: public net::coroutine
, public std::enable_shared_from_this<listener>
{
net::io_context& ioc_;
tcp::acceptor acceptor_;
tcp::socket socket_;
std::shared_ptr<std::string const> doc_root_;
@ -357,8 +355,9 @@ public:
net::io_context& ioc,
tcp::endpoint endpoint,
std::shared_ptr<std::string const> const& doc_root)
: acceptor_(ioc)
, socket_(ioc)
: ioc_(ioc)
, acceptor_(beast::make_strand(ioc))
, socket_(beast::make_strand(ioc))
, doc_root_(doc_root)
{
beast::error_code ec;
@ -429,6 +428,9 @@ public:
std::move(socket_),
doc_root_)->run();
}
// Make sure each session gets its own strand
socket_ = tcp::socket(beast::make_strand(ioc_));
}
}
}

View File

@ -45,8 +45,8 @@ fail(beast::error_code ec, char const* what)
class session : public std::enable_shared_from_this<session>
{
tcp::resolver resolver_;
websocket::stream<beast::ssl_stream<
beast::tcp_stream<net::io_context::executor_type>>> ws_;
websocket::stream<
beast::ssl_stream<beast::tcp_stream>> ws_;
beast::multi_buffer buffer_;
std::string host_;
std::string text_;
@ -55,8 +55,8 @@ public:
// Resolver and socket require an io_context
explicit
session(net::io_context& ioc, ssl::context& ctx)
: resolver_(ioc)
, ws_(ioc, ctx)
: resolver_(beast::make_strand(ioc))
, ws_(beast::make_strand(ioc), ctx)
{
}

View File

@ -40,8 +40,7 @@ fail(beast::error_code ec, char const* what)
class session : public std::enable_shared_from_this<session>
{
tcp::resolver resolver_;
websocket::stream<
beast::tcp_stream<net::io_context::executor_type>> ws_;
websocket::stream<beast::tcp_stream> ws_;
beast::multi_buffer buffer_;
std::string host_;
std::string text_;
@ -50,8 +49,8 @@ public:
// Resolver and socket require an io_context
explicit
session(net::io_context& ioc)
: resolver_(ioc)
, ws_(ioc)
: resolver_(beast::make_strand(ioc))
, ws_(beast::make_strand(ioc))
{
}

View File

@ -54,9 +54,9 @@ do_session(
beast::error_code ec;
// These objects perform our I/O
tcp::resolver resolver{ioc};
websocket::stream<beast::ssl_stream<
beast::tcp_stream<net::io_context::executor_type>>> ws(ioc, ctx);
tcp::resolver resolver(ioc);
websocket::stream<
beast::ssl_stream<beast::tcp_stream>> ws(ioc, ctx);
// Look up the domain name
auto const results = resolver.async_resolve(host, port, yield[ec]);

View File

@ -48,9 +48,8 @@ do_session(
beast::error_code ec;
// These objects perform our I/O
tcp::resolver resolver{ioc};
websocket::stream<
beast::tcp_stream<net::io_context::executor_type>> ws(ioc);
tcp::resolver resolver(ioc);
websocket::stream<beast::tcp_stream> ws(ioc);
// Look up the domain name
auto const results = resolver.async_resolve(host, port, yield[ec]);

View File

@ -48,13 +48,13 @@ fail(beast::error_code ec, char const* what)
// Echoes back all received WebSocket messages
class session : public std::enable_shared_from_this<session>
{
websocket::stream<beast::ssl_stream<
beast::tcp_stream<net::io_context::strand>>> ws_;
websocket::stream<
beast::ssl_stream<beast::tcp_stream>> ws_;
beast::multi_buffer buffer_;
public:
// Take ownership of the socket
session(tcp::socket socket, ssl::context& ctx)
session(tcp::socket&& socket, ssl::context& ctx)
: ws_(std::move(socket), ctx)
{
}
@ -172,16 +172,20 @@ public:
// Accepts incoming connections and launches the sessions
class listener : public std::enable_shared_from_this<listener>
{
net::io_context& ioc_;
ssl::context& ctx_;
tcp::acceptor acceptor_;
tcp::socket socket_;
public:
listener(
net::io_context& ioc,
ssl::context& ctx,
tcp::endpoint endpoint)
: ctx_(ctx)
, acceptor_(ioc)
: ioc_(ioc)
, ctx_(ctx)
, acceptor_(beast::make_strand(ioc))
, socket_(beast::make_strand(ioc))
{
beast::error_code ec;
@ -232,13 +236,14 @@ public:
do_accept()
{
acceptor_.async_accept(
socket_,
beast::bind_front_handler(
&listener::on_accept,
shared_from_this()));
}
void
on_accept(beast::error_code ec, tcp::socket socket)
on_accept(beast::error_code ec)
{
if(ec)
{
@ -247,9 +252,12 @@ public:
else
{
// Create the session and run it
std::make_shared<session>(std::move(socket), ctx_)->run();
std::make_shared<session>(std::move(socket_), ctx_)->run();
}
// Make sure each session gets its own strand
socket_ = tcp::socket(beast::make_strand(ioc_));
// Accept another connection
do_accept();
}

View File

@ -43,13 +43,13 @@ fail(beast::error_code ec, char const* what)
// Echoes back all received WebSocket messages
class session : public std::enable_shared_from_this<session>
{
websocket::stream<beast::tcp_stream<net::io_context::strand>> ws_;
websocket::stream<beast::tcp_stream> ws_;
beast::multi_buffer buffer_;
public:
// Take ownership of the socket
explicit
session(tcp::socket socket)
session(tcp::socket&& socket)
: ws_(std::move(socket))
{
}
@ -146,13 +146,17 @@ public:
// Accepts incoming connections and launches the sessions
class listener : public std::enable_shared_from_this<listener>
{
net::io_context& ioc_;
tcp::acceptor acceptor_;
tcp::socket socket_;
public:
listener(
net::io_context& ioc,
tcp::endpoint endpoint)
: acceptor_(ioc)
: ioc_(ioc)
, acceptor_(ioc)
, socket_(beast::make_strand(ioc_))
{
beast::error_code ec;
@ -203,13 +207,14 @@ public:
do_accept()
{
acceptor_.async_accept(
socket_,
beast::bind_front_handler(
&listener::on_accept,
shared_from_this()));
}
void
on_accept(beast::error_code ec, tcp::socket socket)
on_accept(beast::error_code ec)
{
if(ec)
{
@ -218,9 +223,12 @@ public:
else
{
// Create the session and run it
std::make_shared<session>(std::move(socket))->run();
std::make_shared<session>(std::move(socket_))->run();
}
// Make sure each session gets its own strand
socket_ = tcp::socket(beast::make_strand(ioc_));
// Accept another connection
do_accept();
}

View File

@ -21,7 +21,7 @@
*/
class http_session : public boost::enable_shared_from_this<http_session>
{
beast::tcp_stream<net::io_context::strand> stream_;
beast::tcp_stream stream_;
beast::flat_buffer buffer_;
boost::shared_ptr<shared_state> state_;
http::request<http::string_body> req_;

View File

@ -16,7 +16,9 @@ listener(
net::io_context& ioc,
tcp::endpoint endpoint,
boost::shared_ptr<shared_state> const& state)
: acceptor_(ioc)
: ioc_(ioc)
, acceptor_(ioc)
, socket_(beast::make_strand(ioc))
, state_(state)
{
beast::error_code ec;
@ -61,6 +63,7 @@ run()
{
// Start accepting a connection
acceptor_.async_accept(
socket_,
beast::bind_front_handler(
&listener::on_accept,
shared_from_this()));
@ -80,18 +83,22 @@ fail(beast::error_code ec, char const* what)
// Handle a connection
void
listener::
on_accept(beast::error_code ec, tcp::socket socket)
on_accept(beast::error_code ec)
{
if(ec)
return fail(ec, "accept");
else
// Launch a new session for this connection
boost::make_shared<http_session>(
std::move(socket),
std::move(socket_),
state_)->run();
// Make sure each session gets its own strand
socket_ = tcp::socket(beast::make_strand(ioc_));
// Accept another connection
acceptor_.async_accept(
socket_,
beast::bind_front_handler(
&listener::on_accept,
shared_from_this()));

View File

@ -22,11 +22,13 @@ class shared_state;
// Accepts incoming connections and launches the sessions
class listener : public boost::enable_shared_from_this<listener>
{
net::io_context& ioc_;
tcp::acceptor acceptor_;
tcp::socket socket_;
boost::shared_ptr<shared_state> state_;
void fail(beast::error_code ec, char const* what);
void on_accept(beast::error_code ec, tcp::socket socket);
void on_accept(beast::error_code ec);
public:
listener(

View File

@ -83,17 +83,22 @@ void
websocket_session::
send(boost::shared_ptr<std::string const> const& ss)
{
// Get on the strand if we aren't already,
// otherwise we will concurrently access
// objects which are not thread-safe.
if(! ws_.get_executor().running_in_this_thread())
return net::post(
ws_.get_executor(),
beast::bind_front_handler(
&websocket_session::send,
shared_from_this(),
ss));
// Post our work to the strand, this ensures
// that the members of `this` will not be
// accessed concurrently.
net::post(
ws_.get_executor(),
beast::bind_front_handler(
&websocket_session::on_send,
shared_from_this(),
ss));
}
void
websocket_session::
on_send(boost::shared_ptr<std::string const> const& ss)
{
// Always add to queue
queue_.push_back(ss);

View File

@ -27,7 +27,7 @@ class shared_state;
class websocket_session : public boost::enable_shared_from_this<websocket_session>
{
beast::flat_buffer buffer_;
websocket::stream<beast::tcp_stream<net::io_context::strand>> ws_;
websocket::stream<beast::tcp_stream> ws_;
boost::shared_ptr<shared_state> state_;
std::vector<boost::shared_ptr<std::string const>> queue_;
@ -50,6 +50,10 @@ public:
// Send a message
void
send(boost::shared_ptr<std::string const> const& ss);
private:
void
on_send(boost::shared_ptr<std::string const> const& ss);
};
template<class Body, class Allocator>

View File

@ -38,11 +38,6 @@ using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
//------------------------------------------------------------------------------
// The type of websocket stream to use
// Stackful coroutines are already stranded.
using ws_type = websocket::stream<beast::ssl_stream<
beast::tcp_stream<net::io_context::executor_type>>>;
// Report a failure
void
fail(beast::error_code ec, char const* what)
@ -53,7 +48,8 @@ fail(beast::error_code ec, char const* what)
// Echoes back all received WebSocket messages
void
do_session(
ws_type& ws,
websocket::stream<
beast::ssl_stream<beast::tcp_stream>>& ws,
net::yield_context yield)
{
beast::error_code ec;
@ -153,10 +149,11 @@ do_listen(
fail(ec, "accept");
else
net::spawn(
acceptor.get_executor().context(),
acceptor.get_executor(),
std::bind(
&do_session,
ws_type(std::move(socket), ctx),
websocket::stream<beast::ssl_stream<
beast::tcp_stream>>(std::move(socket), ctx),
std::placeholders::_1));
}
}

View File

@ -33,11 +33,6 @@ using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
//------------------------------------------------------------------------------
// The type of websocket stream to use
// Stackful coroutines are already stranded.
using ws_type = websocket::stream<
beast::tcp_stream<net::io_context::executor_type>>;
// Report a failure
void
fail(beast::error_code ec, char const* what)
@ -47,7 +42,9 @@ fail(beast::error_code ec, char const* what)
// Echoes back all received WebSocket messages
void
do_session(ws_type& ws, net::yield_context yield)
do_session(
websocket::stream<beast::tcp_stream>& ws,
net::yield_context yield)
{
beast::error_code ec;
@ -133,10 +130,11 @@ do_listen(
fail(ec, "accept");
else
net::spawn(
acceptor.get_executor().context(),
acceptor.get_executor(),
std::bind(
&do_session,
ws_type(std::move(socket)),
websocket::stream<
beast::tcp_stream>(std::move(socket)),
std::placeholders::_1));
}
}
@ -157,7 +155,7 @@ int main(int argc, char* argv[])
auto const threads = std::max<int>(1, std::atoi(argv[3]));
// The io_context is required for all I/O
net::io_context ioc{threads};
net::io_context ioc(threads);
// Spawn a listening port
net::spawn(ioc,

View File

@ -78,13 +78,8 @@ setup_stream(websocket::stream<NextLayer>& ws)
//------------------------------------------------------------------------------
// The type of websocket stream to use
// Stackful coroutines are already stranded.
using ws_type = websocket::stream<
beast::tcp_stream<net::io_context::executor_type>>;
void
do_sync_session(ws_type& ws)
do_sync_session(websocket::stream<beast::tcp_stream>& ws)
{
beast::error_code ec;
@ -135,7 +130,8 @@ do_sync_listen(
std::thread(std::bind(
&do_sync_session,
ws_type(std::move(socket)))).detach();
websocket::stream<beast::tcp_stream>(
std::move(socket)))).detach();
}
}
@ -144,13 +140,13 @@ do_sync_listen(
// Echoes back all received WebSocket messages
class async_session : public std::enable_shared_from_this<async_session>
{
websocket::stream<beast::tcp_stream<net::io_context::strand>> ws_;
websocket::stream<beast::tcp_stream> ws_;
beast::multi_buffer buffer_;
public:
// Take ownership of the socket
explicit
async_session(tcp::socket socket)
async_session(tcp::socket&& socket)
: ws_(std::move(socket))
{
setup_stream(ws_);
@ -160,6 +156,11 @@ public:
void
run()
{
// Set suggested timeout settings for the websocket
ws_.set_option(
websocket::stream_base::suggested_settings(
websocket::role_type::server));
// Set a decorator to change the Server of the handshake
ws_.set_option(websocket::stream_base::decorator(
[](websocket::response_type& res)
@ -240,13 +241,17 @@ public:
// Accepts incoming connections and launches the sessions
class async_listener : public std::enable_shared_from_this<async_listener>
{
net::io_context& ioc_;
tcp::acceptor acceptor_;
tcp::socket socket_;
public:
async_listener(
net::io_context& ioc,
tcp::endpoint endpoint)
: acceptor_(ioc)
: ioc_(ioc)
, acceptor_(beast::make_strand(ioc))
, socket_(beast::make_strand(ioc))
{
beast::error_code ec;
@ -297,13 +302,14 @@ public:
do_accept()
{
acceptor_.async_accept(
socket_,
beast::bind_front_handler(
&async_listener::on_accept,
shared_from_this()));
}
void
on_accept(beast::error_code ec, tcp::socket socket)
on_accept(beast::error_code ec)
{
if(ec)
{
@ -312,9 +318,12 @@ public:
else
{
// Create the async_session and run it
std::make_shared<async_session>(std::move(socket))->run();
std::make_shared<async_session>(std::move(socket_))->run();
}
// Make sure each session gets its own strand
socket_ = tcp::socket(beast::make_strand(ioc_));
// Accept another connection
do_accept();
}
@ -323,12 +332,19 @@ public:
//------------------------------------------------------------------------------
void
do_coro_session(ws_type& ws, net::yield_context yield)
do_coro_session(
websocket::stream<beast::tcp_stream>& ws,
net::yield_context yield)
{
beast::error_code ec;
setup_stream(ws);
// Set suggested timeout settings for the websocket
ws.set_option(
websocket::stream_base::suggested_settings(
websocket::role_type::server));
// Set a decorator to change the Server of the handshake
ws.set_option(websocket::stream_base::decorator(
[](websocket::response_type& res)
@ -395,10 +411,11 @@ do_coro_listen(
}
net::spawn(
acceptor.get_executor().context(),
acceptor.get_executor(),
std::bind(
&do_coro_session,
ws_type(std::move(socket)),
websocket::stream<
beast::tcp_stream>(std::move(socket)),
std::placeholders::_1));
}
}

View File

@ -51,8 +51,7 @@ class session
: public net::coroutine
, public std::enable_shared_from_this<session>
{
websocket::stream<beast::ssl_stream<
beast::tcp_stream<net::io_context::strand>>> ws_;
websocket::stream<beast::ssl_stream<beast::tcp_stream>> ws_;
beast::multi_buffer buffer_;
public:
@ -166,6 +165,7 @@ class listener
: public net::coroutine
, public std::enable_shared_from_this<listener>
{
net::io_context& ioc_;
ssl::context& ctx_;
tcp::acceptor acceptor_;
tcp::socket socket_;
@ -175,7 +175,8 @@ public:
net::io_context& ioc,
ssl::context& ctx,
tcp::endpoint endpoint)
: ctx_(ctx)
: ioc_(ioc)
, ctx_(ctx)
, acceptor_(ioc)
, socket_(ioc)
{
@ -247,6 +248,9 @@ public:
// Create the session and run it
std::make_shared<session>(std::move(socket_), ctx_)->run();
}
// Make sure each session gets its own strand
socket_ = tcp::socket(beast::make_strand(ioc_));
}
}
}

View File

@ -46,8 +46,7 @@ class session
: public net::coroutine
, public std::enable_shared_from_this<session>
{
websocket::stream<
beast::tcp_stream<net::io_context::strand>> ws_;
websocket::stream<beast::tcp_stream> ws_;
beast::multi_buffer buffer_;
public:
@ -143,6 +142,7 @@ class listener
: public net::coroutine
, public std::enable_shared_from_this<listener>
{
net::io_context& ioc_;
tcp::acceptor acceptor_;
tcp::socket socket_;
@ -150,8 +150,9 @@ public:
listener(
net::io_context& ioc,
tcp::endpoint endpoint)
: acceptor_(ioc)
, socket_(ioc)
: ioc_(ioc)
, acceptor_(beast::make_strand(ioc))
, socket_(beast::make_strand(ioc))
{
beast::error_code ec;
@ -221,6 +222,9 @@ public:
// Create the session and run it
std::make_shared<session>(std::move(socket_))->run();
}
// Make sure each session gets its own strand
socket_ = tcp::socket(beast::make_strand(ioc_));
}
}
}

View File

@ -11,6 +11,7 @@
#define BOOST_BEAST_TEST_TCP_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/detail/get_io_context.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp>
#include <boost/beast/_experimental/test/handler.hpp>
#include <boost/asio/ip/tcp.hpp>
@ -60,26 +61,28 @@ run_for(
ioc.restart();
}
/** Connect two TCP/IP sockets together.
/** Connect two TCP sockets together.
*/
inline
template<class Executor>
bool
connect(
net::ip::tcp::socket& s1,
net::ip::tcp::socket& s2)
net::basic_stream_socket<net::ip::tcp, Executor>& s1,
net::basic_stream_socket<net::ip::tcp, Executor>& s2)
{
// Sockets must use the same I/O context
BOOST_ASSERT(
std::addressof(s1.get_executor().context()) ==
std::addressof(s2.get_executor().context()));
auto& ioc = s1.get_executor().context();
s1 = net::ip::tcp::socket(ioc);
s2 = net::ip::tcp::socket(ioc);
auto ioc1 = beast::detail::get_io_context(s1);
auto ioc2 = beast::detail::get_io_context(s2);
if(! BEAST_EXPECT(ioc1 != nullptr))
return false;
if(! BEAST_EXPECT(ioc2 != nullptr))
return false;
if(! BEAST_EXPECT(ioc1 == ioc2))
return false;
auto& ioc = *ioc1;
try
{
net::ip::tcp::acceptor a(
s1.get_executor().context());
net::basic_socket_acceptor<
net::ip::tcp, Executor> a(s1.get_executor());
auto ep = net::ip::tcp::endpoint(
net::ip::make_address_v4("127.0.0.1"), 0);
a.open(ep.protocol());

View File

@ -13,6 +13,7 @@
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/detail/stream_base.hpp>
#include <boost/beast/core/error.hpp>
#include <boost/beast/core/stream_traits.hpp>
#include <boost/beast/websocket/role.hpp> // VFALCO This is unfortunate
#include <boost/asio/async_result.hpp>
#include <boost/asio/basic_stream_socket.hpp>
@ -21,7 +22,6 @@
#include <boost/asio/is_executor.hpp>
#include <boost/core/empty_value.hpp>
#include <boost/config/workaround.hpp>
#include <boost/optional.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>
#include <chrono>
@ -42,14 +42,14 @@ namespace beast {
/** A stream socket wrapper with timeouts and associated executor.
This stream wraps a `net::basic_stream_socket` to provide
the following additional features:
the following features:
@li Optional timeouts may be specified for each logical asynchronous
operation performing any reading, writing, or connecting.
@li An <em>Executor</em> may be associated with the stream, which will
be used to invoke any completion handlers which do not already have
an associated executor. This achieves partial support for
an associated executor. This achieves support for
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1322r0.html">[P1322R0] Networking TS enhancement to enable custom I/O executors</a>.
Although the stream supports multiple concurrent outstanding asynchronous
@ -109,7 +109,7 @@ namespace beast {
HTTP response with a different timeout.
@code
void process_http_1 (tcp_stream<net::io_context::executor_type>& stream, net::yield_context yield)
void process_http_1 (tcp_stream& stream, net::yield_context yield)
{
flat_buffer buffer;
http::request<http::empty_body> req;
@ -133,7 +133,7 @@ namespace beast {
applies to the entire combined operation of reading and writing:
@code
void process_http_2 (tcp_stream<net::io_context::executor_type>& stream, net::yield_context yield)
void process_http_2 (tcp_stream& stream, net::yield_context yield)
{
flat_buffer buffer;
http::request<http::empty_body> req;
@ -155,7 +155,7 @@ namespace beast {
thusly:
@code
void do_ssl_handshake (net::ssl::stream<tcp_stream<net::io_context::executor_type>>& stream, net::yield_context yield)
void do_ssl_handshake (net::ssl::stream<tcp_stream>& stream, net::yield_context yield)
{
// Require that the SSL handshake take no longer than 10 seconds
stream.expires_after(std::chrono::seconds(10));
@ -176,7 +176,8 @@ namespace beast {
@tparam Executor A type meeting the requirements of <em>Executor</em> to
be used for submitting all completion handlers which do not already have an
associated executor.
associated executor. If this type is omitted, the default of `net::executor`
will be used.
@par Thread Safety
<em>Distinct objects</em>: Safe.@n
@ -190,12 +191,33 @@ namespace beast {
@li <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1322r0.html">[P1322R0] Networking TS enhancement to enable custom I/O executors</a>.
*/
template<class Protocol, class Executor>
template<
class Protocol,
class Executor = net::executor>
class basic_stream
#if ! BOOST_BEAST_DOXYGEN
: private detail::stream_base
#endif
{
public:
/// The type of the underlying socket.
using socket_type =
net::basic_stream_socket<Protocol, Executor>;
/** The type of the executor associated with the stream.
This will be the type of executor used to invoke completion
handlers which do not have an explicit associated executor.
*/
using executor_type = beast::executor_type<socket_type>;
/// The protocol type.
using protocol_type = Protocol;
/// The endpoint type.
using endpoint_type = typename Protocol::endpoint;
private:
static_assert(net::is_executor<Executor>::value,
"Executor requirements not met");
@ -206,33 +228,26 @@ public:
#endif
struct impl_type
: boost::enable_shared_from_this<impl_type>
, boost::empty_value<Executor>
{
// must come first
net::basic_stream_socket<
Protocol, Executor> socket;
op_state read;
op_state write;
net::basic_stream_socket<Protocol> socket;
impl_type(impl_type&&) = default;
template<class... Args>
explicit
impl_type(Executor const&, Args&&...);
template<class OtherProtocol>
impl_type(net::basic_stream_socket<OtherProtocol>&& socket_,
std::true_type);
template<class OtherProtocol>
impl_type(net::basic_stream_socket<OtherProtocol>&& socket_,
std::false_type);
impl_type(Args&&...);
impl_type& operator=(impl_type&&) = delete;
Executor const&
ex() const noexcept
beast::executor_type<socket_type>
ex() noexcept
{
return this->boost::empty_value<Executor>::get();
return this->socket.get_executor();
}
void reset(); // set timeouts to never
@ -248,13 +263,6 @@ private:
// but the implementation is still waiting on a timer.
boost::shared_ptr<impl_type> impl_;
// Restricted until P1322R0 is incorporated into Boost.Asio.
static_assert(
std::is_convertible<
decltype(std::declval<Executor const&>().context()),
net::io_context&>::value,
"Only net::io_context is currently supported for executor_type::context()");
template<bool, class, class> class async_op;
template<class, class, class>
@ -287,22 +295,6 @@ private:
#endif
public:
/** The type of the executor associated with the stream.
This will be the type of executor used to invoke completion
handlers which do not have an explicit associated executor.
*/
using executor_type = Executor;
/// The type of the underlying socket.
using socket_type = net::basic_stream_socket<Protocol>;
/// The protocol type.
using protocol_type = Protocol;
/// The endpoint type.
using endpoint_type = typename Protocol::endpoint;
/** Destructor
This function destroys the stream, cancelling any outstanding
@ -311,106 +303,20 @@ public:
*/
~basic_stream();
/** Construct the stream from an execution context.
/** Constructor
This constructor creates the stream from an execution context.
The underlying socket needs to be open and connected or accepted
before data can be sent or received on it.
@param ctx An object whose type meets the requirements of
<em>ExecutionContext</em>, which the stream will use to dispatch
handlers that do not have an explicit associated executor.
Currently, the only supported type for `ctx` is `net::io_context`.
This constructor creates the stream by forwarding all arguments
to the underlying socket. The socket then needs to be open and
connected or accepted before data can be sent or received on it.
@param args A list of parameters forwarded to the constructor of
the underlying socket.
@note This function does not participate in overload resolution unless:
@li `std::is_convertible<ExecutionContext&, net::execution_context&>::value` is `true`, and
@li `std::is_constructible<executor_type, typename ExecutionContext::executor_type>::value` is `true`.
@see <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1322r0.html">[P1322R0] Networking TS enhancement to enable custom I/O executors</a>
*/
template<
class ExecutionContext,
class... Args
#if ! BOOST_BEAST_DOXYGEN
, class = typename std::enable_if<
std::is_convertible<
ExecutionContext&,
net::execution_context&>::value &&
std::is_constructible<
executor_type,
typename ExecutionContext::executor_type>::value
>::type
#endif
>
explicit
basic_stream(ExecutionContext& ctx, Args&&... args);
/** Construct the stream from an executor.
This constructor creates the stream from an executor.
The underlying socket needs to be open and connected or accepted
before data can be sent or received on it.
@param ex The executor to use when dispatching handlers that do
not have an explicit associated executor.
Currently, only executors that return a `net::io_context&` from
`ex.context()` are supported.
@param args A list of parameters forwarded to the constructor of
the underlying socket.
@see <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1322r0.html">[P1322R0] Networking TS enhancement to enable custom I/O executors</a>
*/
template<class... Args>
explicit
basic_stream(
executor_type const& ex, Args&&... args);
basic_stream(Args&&... args);
/** Construct the stream from an existing socket.
This constructor creates the stream from an existing socket.
The underlying socket needs to be open and connected or accepted
before data can be sent or received on it.
@param socket The socket to construct from. Ownership of the
socket will be transferred by move-construction.
@param args A list of parameters forwarded to the constructor of
the underlying socket.
@note This function does not participate in overload resolution unless:
@li `OtherProtocol` is convertible to `Protocol`, and one of:
@li `executor_type` of the stream is constructible from the type of
context returned by calling `socket.get_executor().context()`, or
@li `executor_type` of the stream is constructible from the type of
executor returned by calling `socket.get_executor()`.
*/
template<
class OtherProtocol
#if ! BOOST_BEAST_DOXYGEN
,class = typename std::enable_if<
std::is_convertible<OtherProtocol, Protocol>::value && (
std::is_constructible<Executor,
decltype(std::declval<net::basic_stream_socket<
Protocol>&>().get_executor().context())>::value ||
std::is_constructible<Executor,
decltype(std::declval<net::basic_stream_socket<
Protocol>&>().get_executor())>::value)
>::type
#endif
>
explicit
basic_stream(net::basic_stream_socket<OtherProtocol>&& socket);
/** Move constructor.
/** Move constructor
@param other The other object from which the move will occur.

View File

@ -0,0 +1,107 @@
//
// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_DETAIL_GET_IO_CONTEXT_HPP
#define BOOST_BEAST_DETAIL_GET_IO_CONTEXT_HPP
#include <boost/beast/core/stream_traits.hpp>
#include <boost/asio/executor.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/strand.hpp>
#include <memory>
#include <type_traits>
namespace boost {
namespace beast {
namespace detail {
//------------------------------------------------------------------------------
inline
net::io_context*
get_io_context(net::io_context& ioc)
{
return std::addressof(ioc);
}
inline
net::io_context*
get_io_context(net::io_context::executor_type const& ex)
{
return std::addressof(ex.context());
}
inline
net::io_context*
get_io_context(net::strand<
net::io_context::executor_type> const& ex)
{
return std::addressof(
ex.get_inner_executor().context());
}
template<class Executor>
net::io_context*
get_io_context(net::strand<Executor> const& ex)
{
return get_io_context(ex.get_inner_executor());
}
template<
class T,
class = typename std::enable_if<
std::is_same<T, net::executor>::value>::type>
net::io_context*
get_io_context(T const& ex)
{
auto p = ex.template target<typename
net::io_context::executor_type>();
if(! p)
return nullptr;
return std::addressof(p->context());
}
inline
net::io_context*
get_io_context(...)
{
return nullptr;
}
//------------------------------------------------------------------------------
template<class T>
net::io_context*
get_io_context_impl(T& t, std::true_type)
{
return get_io_context(
t.get_executor());
}
template<class T>
net::io_context*
get_io_context_impl(T const&, std::false_type)
{
return nullptr;
}
// Returns the io_context*, or nullptr, for any object.
template<class T>
net::io_context*
get_io_context(T& t)
{
return get_io_context_impl(t,
has_get_executor<T>{});
}
} // detail
} // beast
} // boost
#endif

View File

@ -15,6 +15,7 @@
#include <boost/core/exchange.hpp>
#include <chrono>
#include <cstdint>
#include <utility>
namespace boost {
namespace beast {
@ -48,9 +49,10 @@ struct stream_base
bool pending = false; // if op is pending
bool timeout = false; // if timed out
template<class... Args>
explicit
op_state(net::io_context& ioc)
: timer(ioc)
op_state(Args&&... args)
: timer(std::forward<Args>(args)...)
{
}
};

View File

@ -32,44 +32,10 @@ template<class Protocol, class Executor>
template<class... Args>
basic_stream<Protocol, Executor>::
impl_type::
impl_type(
Executor const& ex_,
Args&&... args)
: boost::empty_value<Executor>(
boost::empty_init_t{}, ex_)
, read(ex().context())
, write(ex().context())
, socket(std::forward<Args>(args)...)
{
reset();
}
template<class Protocol, class Executor>
template<class OtherProtocol>
basic_stream<Protocol, Executor>::
impl_type::
impl_type(net::basic_stream_socket<OtherProtocol>&& socket_,
std::true_type)
: boost::empty_value<Executor>(
boost::empty_init_t{}, socket_.get_executor())
, read(ex().context())
, write(ex().context())
, socket(std::move(socket_))
{
reset();
}
template<class Protocol, class Executor>
template<class OtherProtocol>
basic_stream<Protocol, Executor>::
impl_type::
impl_type(net::basic_stream_socket<OtherProtocol>&& socket_,
std::false_type)
: boost::empty_value<Executor>(boost::empty_init_t{},
socket_.get_executor().context())
, read(ex().context())
, write(ex().context())
, socket(std::move(socket_))
impl_type(Args&&... args)
: socket(std::forward<Args>(args)...)
, read(ex())
, write(ex())
{
reset();
}
@ -434,40 +400,12 @@ basic_stream<Protocol, Executor>::
impl_->close();
}
template<class Protocol, class Executor>
template<class ExecutionContext, class... Args, class>
basic_stream<Protocol, Executor>::
basic_stream(ExecutionContext& ctx, Args&&... args)
: impl_(boost::make_shared<impl_type>(
ctx.get_executor(),
ctx, std::forward<Args>(args)...))
{
// Restriction is necessary until Asio fully supports P1322R0
static_assert(
std::is_same<ExecutionContext, net::io_context>::value,
"Only net::io_context is currently supported for ExecutionContext");
}
template<class Protocol, class Executor>
template<class... Args>
basic_stream<Protocol, Executor>::
basic_stream(
executor_type const& ex, Args&&... args)
basic_stream(Args&&... args)
: impl_(boost::make_shared<impl_type>(
ex,
ex.context(), std::forward<Args>(args)...))
{
}
template<class Protocol, class Executor>
template<class OtherProtocol, class>
basic_stream<Protocol, Executor>::
basic_stream(net::basic_stream_socket<OtherProtocol>&& socket)
: impl_(boost::make_shared<impl_type>(
std::move(socket),
std::is_constructible<Executor,
decltype(std::declval<net::basic_stream_socket<
Protocol>&>().get_executor())>{}))
std::forward<Args>(args)...))
{
}

View File

@ -438,10 +438,10 @@ using is_async_stream = std::integral_constant<bool,
@see close_socket
*/
template<class Protocol BOOST_ASIO_SVC_TPARAM>
template<class Protocol>
void
beast_close_socket(
net::basic_socket<Protocol BOOST_ASIO_SVC_TPARAM>& sock)
net::basic_socket<Protocol>& sock)
{
boost::system::error_code ec;
sock.close(ec);

View File

@ -12,20 +12,17 @@
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/basic_stream.hpp>
#include <boost/asio/executor.hpp>
#include <boost/asio/ip/tcp.hpp>
namespace boost {
namespace beast {
/** A TCP/IP stream socket with timeouts, rate limits, and executor.
@tparam Executor The type of executor to use for all completion
handlers which do not already have an associated executor.
/** A TCP/IP stream socket with timeouts, rate limits, and polymorphic executor.
@see basic_stream
*/
template<class Executor>
using tcp_stream = basic_stream<net::ip::tcp, Executor>;
using tcp_stream = basic_stream<net::ip::tcp, net::executor>;
} // beast
} // boost

View File

@ -30,6 +30,8 @@ using file_body = basic_file_body<file>;
} // beast
} // boost
#ifndef BOOST_BEAST_NO_FILE_BODY_WIN32
#include <boost/beast/http/impl/file_body_win32.ipp>
#endif
#endif

View File

@ -32,7 +32,7 @@ namespace beast {
namespace http {
namespace detail {
template<class, class, bool, class>
template<class, class, class, bool, class>
class write_some_win32_op;
} // detail
@ -52,7 +52,7 @@ struct basic_file_body<file_win32>
friend class reader;
friend struct basic_file_body<file_win32>;
template<class, class, bool, class>
template<class, class, class, bool, class>
friend class detail::write_some_win32_op;
template<
class Protocol, bool isRequest, class Fields>
@ -101,7 +101,7 @@ struct basic_file_body<file_win32>
class writer
{
template<class, class, bool, class>
template<class, class, class, bool, class>
friend class detail::write_some_win32_op;
template<
class Protocol, bool isRequest, class Fields>
@ -276,7 +276,6 @@ reset(file_win32&& file, error_code& ec)
namespace detail {
template<class Unsigned>
inline
boost::winapi::DWORD_
lowPart(Unsigned n)
{
@ -286,7 +285,6 @@ lowPart(Unsigned n)
}
template<class Unsigned>
inline
boost::winapi::DWORD_
highPart(Unsigned n, std::true_type)
{
@ -296,7 +294,6 @@ highPart(Unsigned n, std::true_type)
}
template<class Unsigned>
inline
boost::winapi::DWORD_
highPart(Unsigned, std::false_type)
{
@ -304,7 +301,6 @@ highPart(Unsigned, std::false_type)
}
template<class Unsigned>
inline
boost::winapi::DWORD_
highPart(Unsigned n)
{
@ -329,14 +325,17 @@ public:
#if BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR
template<
class Protocol, class Handler,
bool isRequest, class Fields>
class Protocol, class Executor,
class Handler, bool isRequest, class Fields>
class write_some_win32_op
: public beast::async_op_base<
Handler, typename net::basic_stream_socket<
Protocol>::executor_type>
: public beast::async_op_base<Handler, Executor>
{
net::basic_stream_socket<Protocol>& sock_;
static_assert(
std::is_same<Executor, net::io_context::executor_type>::value,
"Executor must be net::io_context::executor_type");
net::basic_stream_socket<
Protocol, Executor>& sock_;
serializer<isRequest,
basic_file_body<file_win32>, Fields>& sr_;
std::size_t bytes_transferred_ = 0;
@ -346,14 +345,14 @@ public:
template<class Handler_>
write_some_win32_op(
Handler_&& h,
net::basic_stream_socket<Protocol>& s,
net::basic_stream_socket<
Protocol, Executor>& s,
serializer<isRequest,
basic_file_body<file_win32>,Fields>& sr)
: async_op_base<
Handler, typename net::basic_stream_socket<
Protocol>::executor_type>(
std::forward<Handler_>(h),
s.get_executor())
Handler, Executor>(
std::forward<Handler_>(h),
s.get_executor())
, sock_(s)
, sr_(sr)
{
@ -442,10 +441,13 @@ public:
//------------------------------------------------------------------------------
template<class Protocol, bool isRequest, class Fields>
template<
class Protocol, class Executor,
bool isRequest, class Fields>
std::size_t
write_some(
net::basic_stream_socket<Protocol>& sock,
net::basic_stream_socket<
Protocol, Executor>& sock,
serializer<isRequest,
basic_file_body<file_win32>, Fields>& sr,
error_code& ec)
@ -509,21 +511,23 @@ write_some(
#if BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR
template<
class Protocol,
class Protocol, class Executor,
bool isRequest, class Fields,
class WriteHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(
WriteHandler, void(error_code, std::size_t))
async_write_some(
net::basic_stream_socket<Protocol>& sock,
net::basic_stream_socket<
Protocol, Executor>& sock,
serializer<isRequest,
basic_file_body<file_win32>, Fields>& sr,
WriteHandler&& handler)
{
BOOST_BEAST_HANDLER_INIT(
WriteHandler, void(error_code, std::size_t));
detail::write_some_win32_op<
Protocol,
Protocol, Executor,
BOOST_ASIO_HANDLER_TYPE(WriteHandler,
void(error_code, std::size_t)),
isRequest, Fields>{

View File

@ -19,7 +19,15 @@
#include <boost/beast/core/static_string.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/assert.hpp>
// This is for <boost/endian/buffers.hpp>
#if BOOST_WORKAROUND(BOOST_MSVC, > 0)
# pragma warning (push)
# pragma warning (disable: 4127) // conditional expression is constant
#endif
#include <boost/endian/buffers.hpp>
#if BOOST_WORKAROUND(BOOST_MSVC, > 0)
# pragma warning (pop)
#endif
#include <cstdint>
namespace boost {

View File

@ -103,7 +103,7 @@ struct stream<NextLayer, deflateSupported>::impl_type
template<class... Args>
impl_type(Args&&... args)
: stream(std::forward<Args>(args)...)
, timer(stream.get_executor().context())
, timer(stream.get_executor())
{
timeout_opt.handshake_timeout = none();
timeout_opt.idle_timeout = none();

View File

@ -25,14 +25,18 @@ namespace websocket {
namespace detail {
template<class Handler>
template<
class Protocol, class Executor,
class Handler>
class teardown_tcp_op
: public beast::async_op_base<
Handler, beast::executor_type<
net::ip::tcp::socket>>
net::basic_stream_socket<
Protocol, Executor>>>
, public net::coroutine
{
using socket_type = net::ip::tcp::socket;
using socket_type =
net::basic_stream_socket<Protocol, Executor>;
socket_type& s_;
role_type role_;
@ -46,8 +50,10 @@ public:
role_type role)
: async_op_base<Handler,
beast::executor_type<
net::ip::tcp::socket>>(
std::forward<Handler_>(h), s.get_executor())
net::basic_stream_socket<
Protocol, Executor>>>(
std::forward<Handler_>(h),
s.get_executor())
, s_(s)
, role_(role)
{
@ -60,7 +66,6 @@ public:
std::size_t bytes_transferred = 0,
bool cont = true)
{
using tcp = net::ip::tcp;
BOOST_ASIO_CORO_REENTER(*this)
{
nb_ = s_.non_blocking();
@ -68,7 +73,7 @@ public:
if(ec)
goto upcall;
if(role_ == role_type::server)
s_.shutdown(tcp::socket::shutdown_send, ec);
s_.shutdown(net::socket_base::shutdown_send, ec);
if(ec)
goto upcall;
for(;;)
@ -81,7 +86,7 @@ public:
{
BOOST_ASIO_CORO_YIELD
s_.async_wait(
net::ip::tcp::socket::wait_read,
net::socket_base::wait_read,
beast::detail::bind_continuation(std::move(*this)));
continue;
}
@ -100,7 +105,7 @@ public:
}
}
if(role_ == role_type::client)
s_.shutdown(tcp::socket::shutdown_send, ec);
s_.shutdown(net::socket_base::shutdown_send, ec);
if(ec)
goto upcall;
s_.close(ec);
@ -124,15 +129,17 @@ public:
//------------------------------------------------------------------------------
template<class Protocol, class Executor>
void
teardown(
role_type role,
net::ip::tcp::socket& socket,
net::basic_stream_socket<
Protocol, Executor>& socket,
error_code& ec)
{
if(role == role_type::server)
socket.shutdown(
net::ip::tcp::socket::shutdown_send, ec);
net::socket_base::shutdown_send, ec);
if(ec)
return;
for(;;)
@ -156,25 +163,32 @@ teardown(
}
if(role == role_type::client)
socket.shutdown(
net::ip::tcp::socket::shutdown_send, ec);
net::socket_base::shutdown_send, ec);
if(ec)
return;
socket.close(ec);
}
template<class TeardownHandler>
template<
class Protocol, class Executor,
class TeardownHandler>
void
async_teardown(
role_type role,
net::ip::tcp::socket& socket,
net::basic_stream_socket<
Protocol, Executor>& socket,
TeardownHandler&& handler)
{
static_assert(beast::detail::is_invocable<
TeardownHandler, void(error_code)>::value,
"TeardownHandler requirements not met");
detail::teardown_tcp_op<typename std::decay<
TeardownHandler>::type>(std::forward<
TeardownHandler>(handler), socket, role);
detail::teardown_tcp_op<
Protocol,
Executor,
typename std::decay<TeardownHandler>::type>(
std::forward<TeardownHandler>(handler),
socket,
role);
}
} // websocket

View File

@ -80,13 +80,12 @@ class frame_test;
To declare the @ref stream object with a @ref tcp_stream in a
multi-threaded asynchronous program using a strand, you may write:
@code
websocket::stream<tcp_stream<
net::io_context::strand>> ws{net::io_context::strand(ioc)};
websocket::stream<tcp_stream> ws{net::io_context::strand(ioc)};
@endcode
Alternatively, for a single-threaded or synchronous application
you may write:
@code
websocket::stream<tcp_stream<net::io_context::executor_type>> ws(ioc);
websocket::stream<tcp_stream> ws(ioc);
@endcode
@tparam NextLayer The type representing the next layer, to which

View File

@ -13,7 +13,7 @@
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/error.hpp>
#include <boost/beast/websocket/role.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/basic_stream_socket.hpp>
#include <type_traits>
namespace boost {
@ -125,11 +125,12 @@ namespace websocket {
@param ec Set to the error if any occurred.
*/
BOOST_BEAST_DECL
template<class Protocol, class Executor>
void
teardown(
role_type role,
net::ip::tcp::socket& socket,
net::basic_stream_socket<
Protocol, Executor>& socket,
error_code& ec);
/** Start tearing down a `net::ip::tcp::socket`.
@ -159,11 +160,14 @@ teardown(
manner equivalent to using net::io_context::post().
*/
template<class TeardownHandler>
template<
class Protocol, class Executor,
class TeardownHandler>
void
async_teardown(
role_type role,
net::ip::tcp::socket& socket,
net::basic_stream_socket<
Protocol, Executor>& socket,
TeardownHandler&& handler);
} // websocket

View File

@ -24,6 +24,7 @@ add_executable (tests-beast-core
_detail_bind_continuation.cpp
_detail_buffer.cpp
_detail_clamp.cpp
_detail_get_io_context.cpp
_detail_is_invocable.cpp
_detail_read.cpp
_detail_sha1.cpp

View File

@ -12,6 +12,7 @@ local SOURCES =
_detail_bind_continuation.cpp
_detail_buffer.cpp
_detail_clamp.cpp
_detail_get_io_context.cpp
_detail_is_invocable.cpp
_detail_read.cpp
_detail_sha1.cpp

View File

@ -0,0 +1,57 @@
//
// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/make_strand.hpp>
#include <boost/beast/core/detail/get_io_context.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp>
#include <boost/asio/strand.hpp>
namespace boost {
namespace beast {
namespace detail {
class get_io_context_test : public beast::unit_test::suite
{
public:
void
testFunction()
{
struct none
{
};
net::io_context ioc;
BEAST_EXPECT(get_io_context(5) == nullptr);
BEAST_EXPECT(get_io_context(none{}) == nullptr);
BEAST_EXPECT(get_io_context(ioc) == &ioc);
BEAST_EXPECT(get_io_context(ioc.get_executor()) == &ioc);
BEAST_EXPECT(get_io_context(make_strand(ioc)) == &ioc);
BEAST_EXPECT(get_io_context(net::executor(ioc.get_executor())) == &ioc);
#if 0
// VFALCO FIXME
BEAST_EXPECT(
get_io_context(
net::strand<net::executor>(
net::executor(ioc.get_executor()))) == &ioc);
#endif
}
void
run() override
{
testFunction();
}
};
BEAST_DEFINE_TESTSUITE(beast,core,get_io_context);
} // detail
} // beast
} // boost

View File

@ -303,7 +303,6 @@ private:
}
};
} // (anon)
class basic_stream_test
@ -319,9 +318,6 @@ public:
void
testSpecialMembers()
{
using stream_type = tcp_stream<
net::io_context::executor_type>;
net::io_context ioc;
// net::io_context::executor_type
@ -332,7 +328,8 @@ public:
basic_stream<tcp, executor> s2(ex);
basic_stream<tcp, executor> s3(ioc, tcp::v4());
basic_stream<tcp, executor> s4(std::move(s1));
s2.socket() = tcp::socket(ioc);
s2.socket() =
net::basic_stream_socket<tcp, executor>(ioc);
BEAST_EXPECT(s1.get_executor() == ex);
BEAST_EXPECT(s2.get_executor() == ex);
BEAST_EXPECT(s3.get_executor() == ex);
@ -358,14 +355,19 @@ public:
basic_stream<tcp, strand> s1(ex);
basic_stream<tcp, strand> s2(ex, tcp::v4());
basic_stream<tcp, strand> s3(std::move(s1));
s2.socket() = tcp::socket(ioc);
#if 0
s2.socket() = net::basic_stream_socket<
tcp, strand>(ioc);
#endif
BEAST_EXPECT(s1.get_executor() == ex);
BEAST_EXPECT(s2.get_executor() == ex);
BEAST_EXPECT(s3.get_executor() == ex);
#if 0
BEAST_EXPECT((! static_cast<
basic_stream<tcp, strand> const&>(
s2).socket().is_open()));
#endif
test_sync_stream<
basic_stream<
@ -378,6 +380,7 @@ public:
// construction from existing socket
#if 0
{
tcp::socket sock(ioc);
basic_stream<tcp, executor> stream(std::move(sock));
@ -387,22 +390,13 @@ public:
tcp::socket sock(ioc);
basic_stream<tcp, strand> stream(std::move(sock));
}
struct other_type
{
};
BOOST_STATIC_ASSERT(! std::is_constructible<
stream_type, other_type>::value);
BOOST_STATIC_ASSERT(! std::is_constructible<
stream_type, other_type, tcp::socket>::value);
#endif
// layers
{
net::socket_base::keep_alive opt;
stream_type s(ioc);
tcp_stream s(ioc);
s.socket().open(tcp::v4());
s.socket().get_option(opt);
BEAST_EXPECT(! opt.value());
@ -450,7 +444,7 @@ public:
void
testRead()
{
using stream_type = tcp_stream<
using stream_type = basic_stream<tcp,
net::io_context::executor_type>;
char buf[4];
@ -585,7 +579,7 @@ public:
void
testWrite()
{
using stream_type = tcp_stream<
using stream_type = basic_stream<tcp,
net::io_context::executor_type>;
char buf[4];
@ -667,7 +661,7 @@ public:
void
testConnect()
{
using stream_type = tcp_stream<
using stream_type = basic_stream<tcp,
net::io_context::executor_type>;
struct range
@ -1057,7 +1051,7 @@ public:
void
testMembers()
{
using stream_type = tcp_stream<
using stream_type = basic_stream<tcp,
net::io_context::executor_type>;
class handler
@ -1184,7 +1178,7 @@ public:
return {};
}
void process_http_1 (tcp_stream<net::io_context::executor_type>& stream, net::yield_context yield)
void process_http_1 (tcp_stream& stream, net::yield_context yield)
{
flat_buffer buffer;
http::request<http::empty_body> req;
@ -1201,7 +1195,7 @@ public:
http::async_write (stream, res, yield);
}
void process_http_2 (tcp_stream<net::io_context::executor_type>& stream, net::yield_context yield)
void process_http_2 (tcp_stream& stream, net::yield_context yield)
{
flat_buffer buffer;
http::request<http::empty_body> req;

View File

@ -9,3 +9,37 @@
// Test that header file is self-contained.
#include <boost/beast/core/tcp_stream.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp>
namespace boost {
namespace beast {
class tcp_stream_test
: public beast::unit_test::suite
{
public:
using tcp = net::ip::tcp;
void
testStream()
{
net::io_context ioc;
{
tcp::socket s(ioc);
tcp_stream s1(std::move(s));
}
}
void
run()
{
testStream();
pass();
}
};
BEAST_DEFINE_TESTSUITE(beast,core,tcp_stream);
} // beast
} // boost

View File

@ -10,6 +10,7 @@
// Test that header file is self-contained.
#include <boost/beast/websocket/stream.hpp>
#include <boost/beast/core/make_strand.hpp>
#include <boost/beast/core/tcp_stream.hpp>
#include <boost/asio/strand.hpp>
@ -157,11 +158,10 @@ public:
{
net::io_context ioc;
{
websocket::stream<tcp_stream<
net::io_context::strand>> ws{net::io_context::strand(ioc)};
websocket::stream<tcp_stream> ws{make_strand(ioc)};
}
{
websocket::stream<tcp_stream<net::io_context::executor_type>> ws(ioc);
websocket::stream<tcp_stream> ws(ioc);
}
}

View File

@ -28,6 +28,7 @@ public:
run() override
{
testJavadoc();
pass();
}
};

View File

@ -59,8 +59,8 @@ boost::ignore_unused(ec);
{
//[ws_snippet_6
std::string const host = "example.com";
net::ip::tcp::resolver r{ioc};
stream<tcp_stream<net::io_context::executor_type>> ws{ioc};
net::ip::tcp::resolver r(ioc);
stream<tcp_stream> ws(ioc);
auto const results = r.resolve(host, "ws");
connect(get_lowest_layer(ws), results.begin(), results.end());
//]
@ -69,7 +69,7 @@ boost::ignore_unused(ec);
{
//[ws_snippet_7
net::ip::tcp::acceptor acceptor{ioc};
stream<tcp_stream<net::io_context::executor_type>> ws{acceptor.get_executor().context()};
stream<tcp_stream> ws{acceptor.get_executor()};
acceptor.accept(get_lowest_layer(ws).socket());
//]
}