forked from boostorg/beast
Update for Net-TS Asio (API Change):
fix #769 The following classes are removed: * handler_type * async_result * async_completion * is_dynamic_buffer * is_const_buffer_sequence * is_mutable_buffer_sequence * handler_alloc Actions Required: * Use BOOST_ASIO_HANDLER_TYPE instead of handler_type * Use BOOST_ASIO_INITFN_RESULT_TYPE instead of async_result * Use boost::asio::async_completion * Use boost::asio::is_dynamic_buffer * Use boost::asio::is_const_buffer_sequence * Use boost::asio::is_mutable_buffer_sequence * boost::asio::associated_allocator_t replaces handler_alloc
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
#include <boost/beast/http.hpp>
|
||||
#include <boost/beast/websocket.hpp>
|
||||
#include <boost/beast/version.hpp>
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/ssl/stream.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
@@ -235,15 +236,16 @@ class websocket_session
|
||||
boost::beast::multi_buffer buffer_;
|
||||
|
||||
protected:
|
||||
boost::asio::io_service::strand strand_;
|
||||
boost::asio::strand<
|
||||
boost::asio::io_context::executor_type> strand_;
|
||||
boost::asio::steady_timer timer_;
|
||||
|
||||
public:
|
||||
// Construct the session
|
||||
explicit
|
||||
websocket_session(boost::asio::io_service& ios)
|
||||
: strand_(ios)
|
||||
, timer_(ios,
|
||||
websocket_session(boost::asio::io_context& ioc)
|
||||
: strand_(ioc.get_executor())
|
||||
, timer_(ioc,
|
||||
(std::chrono::steady_clock::time_point::max)())
|
||||
{
|
||||
}
|
||||
@@ -254,15 +256,17 @@ public:
|
||||
do_accept(http::request<Body, http::basic_fields<Allocator>> req)
|
||||
{
|
||||
// Set the timer
|
||||
timer_.expires_from_now(std::chrono::seconds(15));
|
||||
timer_.expires_after(std::chrono::seconds(15));
|
||||
|
||||
// Accept the websocket handshake
|
||||
derived().ws().async_accept(
|
||||
req,
|
||||
strand_.wrap(std::bind(
|
||||
&websocket_session::on_accept,
|
||||
derived().shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&websocket_session::on_accept,
|
||||
derived().shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
}
|
||||
|
||||
// Called when the timer expires.
|
||||
@@ -273,15 +277,17 @@ public:
|
||||
return fail(ec, "timer");
|
||||
|
||||
// Verify that the timer really expired since the deadline may have moved.
|
||||
if(timer_.expires_at() <= std::chrono::steady_clock::now())
|
||||
if(timer_.expiry() <= std::chrono::steady_clock::now())
|
||||
derived().do_timeout();
|
||||
|
||||
// Wait on the timer
|
||||
timer_.async_wait(
|
||||
strand_.wrap(std::bind(
|
||||
&websocket_session::on_timer,
|
||||
derived().shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&websocket_session::on_timer,
|
||||
derived().shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -302,16 +308,18 @@ public:
|
||||
do_read()
|
||||
{
|
||||
// Set the timer
|
||||
timer_.expires_from_now(std::chrono::seconds(15));
|
||||
timer_.expires_after(std::chrono::seconds(15));
|
||||
|
||||
// Read a message into our buffer
|
||||
derived().ws().async_read(
|
||||
buffer_,
|
||||
strand_.wrap(std::bind(
|
||||
&websocket_session::on_read,
|
||||
derived().shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&websocket_session::on_read,
|
||||
derived().shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -336,11 +344,13 @@ public:
|
||||
derived().ws().text(derived().ws().got_text());
|
||||
derived().ws().async_write(
|
||||
buffer_.data(),
|
||||
strand_.wrap(std::bind(
|
||||
&websocket_session::on_write,
|
||||
derived().shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&websocket_session::on_write,
|
||||
derived().shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -378,7 +388,7 @@ public:
|
||||
explicit
|
||||
plain_websocket_session(tcp::socket socket)
|
||||
: websocket_session<plain_websocket_session>(
|
||||
socket.get_io_service())
|
||||
socket.get_executor().context())
|
||||
, ws_(std::move(socket))
|
||||
{
|
||||
}
|
||||
@@ -412,15 +422,17 @@ public:
|
||||
close_ = true;
|
||||
|
||||
// Set the timer
|
||||
timer_.expires_from_now(std::chrono::seconds(15));
|
||||
timer_.expires_after(std::chrono::seconds(15));
|
||||
|
||||
// Close the WebSocket Connection
|
||||
ws_.async_close(
|
||||
websocket::close_code::normal,
|
||||
strand_.wrap(std::bind(
|
||||
&plain_websocket_session::on_close,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&plain_websocket_session::on_close,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -443,7 +455,8 @@ class ssl_websocket_session
|
||||
, public std::enable_shared_from_this<ssl_websocket_session>
|
||||
{
|
||||
websocket::stream<ssl_stream<tcp::socket>> ws_;
|
||||
boost::asio::io_service::strand strand_;
|
||||
boost::asio::strand<
|
||||
boost::asio::io_context::executor_type> strand_;
|
||||
bool eof_ = false;
|
||||
|
||||
public:
|
||||
@@ -451,9 +464,9 @@ public:
|
||||
explicit
|
||||
ssl_websocket_session(ssl_stream<tcp::socket> stream)
|
||||
: websocket_session<ssl_websocket_session>(
|
||||
stream.get_io_service())
|
||||
stream.get_executor().context())
|
||||
, ws_(std::move(stream))
|
||||
, strand_(ws_.get_io_service())
|
||||
, strand_(ws_.get_executor())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -483,14 +496,16 @@ public:
|
||||
eof_ = true;
|
||||
|
||||
// Set the timer
|
||||
timer_.expires_from_now(std::chrono::seconds(15));
|
||||
timer_.expires_after(std::chrono::seconds(15));
|
||||
|
||||
// Perform the SSL shutdown
|
||||
ws_.next_layer().async_shutdown(
|
||||
strand_.wrap(std::bind(
|
||||
&ssl_websocket_session::on_shutdown,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&ssl_websocket_session::on_shutdown,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -630,10 +645,12 @@ class http_session
|
||||
http::async_write(
|
||||
self_.derived().stream(),
|
||||
msg_,
|
||||
self_.strand_.wrap(std::bind(
|
||||
&http_session::on_write,
|
||||
self_.derived().shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
boost::asio::bind_executor(
|
||||
self_.strand_,
|
||||
std::bind(
|
||||
&http_session::on_write,
|
||||
self_.derived().shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -652,20 +669,21 @@ class http_session
|
||||
|
||||
protected:
|
||||
boost::asio::steady_timer timer_;
|
||||
boost::asio::io_service::strand strand_;
|
||||
boost::asio::strand<
|
||||
boost::asio::io_context::executor_type> strand_;
|
||||
boost::beast::flat_buffer buffer_;
|
||||
|
||||
public:
|
||||
// Construct the session
|
||||
http_session(
|
||||
boost::asio::io_service& ios,
|
||||
boost::asio::io_context& ioc,
|
||||
boost::beast::flat_buffer buffer,
|
||||
std::string const& doc_root)
|
||||
: doc_root_(doc_root)
|
||||
, queue_(*this)
|
||||
, timer_(ios,
|
||||
, timer_(ioc,
|
||||
(std::chrono::steady_clock::time_point::max)())
|
||||
, strand_(ios)
|
||||
, strand_(ioc.get_executor())
|
||||
, buffer_(std::move(buffer))
|
||||
{
|
||||
}
|
||||
@@ -674,17 +692,19 @@ public:
|
||||
do_read()
|
||||
{
|
||||
// Set the timer
|
||||
timer_.expires_from_now(std::chrono::seconds(15));
|
||||
timer_.expires_after(std::chrono::seconds(15));
|
||||
|
||||
// Read a request
|
||||
http::async_read(
|
||||
derived().stream(),
|
||||
buffer_,
|
||||
req_,
|
||||
strand_.wrap(std::bind(
|
||||
&http_session::on_read,
|
||||
derived().shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&http_session::on_read,
|
||||
derived().shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
}
|
||||
|
||||
// Called when the timer expires.
|
||||
@@ -695,15 +715,17 @@ public:
|
||||
return fail(ec, "timer");
|
||||
|
||||
// Verify that the timer really expired since the deadline may have moved.
|
||||
if(timer_.expires_at() <= std::chrono::steady_clock::now())
|
||||
if(timer_.expiry() <= std::chrono::steady_clock::now())
|
||||
return derived().do_timeout();
|
||||
|
||||
// Wait on the timer
|
||||
timer_.async_wait(
|
||||
strand_.wrap(std::bind(
|
||||
&http_session::on_timer,
|
||||
derived().shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&http_session::on_timer,
|
||||
derived().shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -769,7 +791,8 @@ class plain_http_session
|
||||
, public std::enable_shared_from_this<plain_http_session>
|
||||
{
|
||||
tcp::socket socket_;
|
||||
boost::asio::io_service::strand strand_;
|
||||
boost::asio::strand<
|
||||
boost::asio::io_context::executor_type> strand_;
|
||||
|
||||
public:
|
||||
// Create the http_session
|
||||
@@ -778,11 +801,11 @@ public:
|
||||
boost::beast::flat_buffer buffer,
|
||||
std::string const& doc_root)
|
||||
: http_session<plain_http_session>(
|
||||
socket.get_io_service(),
|
||||
socket.get_executor().context(),
|
||||
std::move(buffer),
|
||||
doc_root)
|
||||
, socket_(std::move(socket))
|
||||
, strand_(socket_.get_io_service())
|
||||
, strand_(socket_.get_executor())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -838,7 +861,8 @@ class ssl_http_session
|
||||
, public std::enable_shared_from_this<ssl_http_session>
|
||||
{
|
||||
ssl_stream<tcp::socket> stream_;
|
||||
boost::asio::io_service::strand strand_;
|
||||
boost::asio::strand<
|
||||
boost::asio::io_context::executor_type> strand_;
|
||||
bool eof_ = false;
|
||||
|
||||
public:
|
||||
@@ -849,11 +873,11 @@ public:
|
||||
boost::beast::flat_buffer buffer,
|
||||
std::string const& doc_root)
|
||||
: http_session<ssl_http_session>(
|
||||
socket.get_io_service(),
|
||||
socket.get_executor().context(),
|
||||
std::move(buffer),
|
||||
doc_root)
|
||||
, stream_(std::move(socket), ctx)
|
||||
, strand_(stream_.get_io_service())
|
||||
, strand_(stream_.get_executor())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -880,18 +904,20 @@ public:
|
||||
on_timer({});
|
||||
|
||||
// Set the timer
|
||||
timer_.expires_from_now(std::chrono::seconds(15));
|
||||
timer_.expires_after(std::chrono::seconds(15));
|
||||
|
||||
// Perform the SSL handshake
|
||||
// Note, this is the buffered version of the handshake.
|
||||
stream_.async_handshake(
|
||||
ssl::stream_base::server,
|
||||
buffer_.data(),
|
||||
strand_.wrap(std::bind(
|
||||
&ssl_http_session::on_handshake,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&ssl_http_session::on_handshake,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
}
|
||||
void
|
||||
on_handshake(
|
||||
@@ -917,14 +943,16 @@ public:
|
||||
eof_ = true;
|
||||
|
||||
// Set the timer
|
||||
timer_.expires_from_now(std::chrono::seconds(15));
|
||||
timer_.expires_after(std::chrono::seconds(15));
|
||||
|
||||
// Perform the SSL shutdown
|
||||
stream_.async_shutdown(
|
||||
strand_.wrap(std::bind(
|
||||
&ssl_http_session::on_shutdown,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&ssl_http_session::on_shutdown,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -962,7 +990,8 @@ class detect_session : public std::enable_shared_from_this<detect_session>
|
||||
{
|
||||
tcp::socket socket_;
|
||||
ssl::context& ctx_;
|
||||
boost::asio::io_service::strand strand_;
|
||||
boost::asio::strand<
|
||||
boost::asio::io_context::executor_type> strand_;
|
||||
std::string const& doc_root_;
|
||||
boost::beast::flat_buffer buffer_;
|
||||
|
||||
@@ -974,7 +1003,7 @@ public:
|
||||
std::string const& doc_root)
|
||||
: socket_(std::move(socket))
|
||||
, ctx_(ctx)
|
||||
, strand_(socket_.get_io_service())
|
||||
, strand_(socket_.get_executor())
|
||||
, doc_root_(doc_root)
|
||||
{
|
||||
}
|
||||
@@ -986,11 +1015,13 @@ public:
|
||||
async_detect_ssl(
|
||||
socket_,
|
||||
buffer_,
|
||||
strand_.wrap(std::bind(
|
||||
&detect_session::on_detect,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&detect_session::on_detect,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
|
||||
}
|
||||
|
||||
@@ -1029,13 +1060,13 @@ class listener : public std::enable_shared_from_this<listener>
|
||||
|
||||
public:
|
||||
listener(
|
||||
boost::asio::io_service& ios,
|
||||
boost::asio::io_context& ioc,
|
||||
ssl::context& ctx,
|
||||
tcp::endpoint endpoint,
|
||||
std::string const& doc_root)
|
||||
: ctx_(ctx)
|
||||
, acceptor_(ios)
|
||||
, socket_(ios)
|
||||
, acceptor_(ioc)
|
||||
, socket_(ioc)
|
||||
, doc_root_(doc_root)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
@@ -1058,7 +1089,7 @@ public:
|
||||
|
||||
// Start listening for connections
|
||||
acceptor_.listen(
|
||||
boost::asio::socket_base::max_connections, ec);
|
||||
boost::asio::socket_base::max_listen_connections, ec);
|
||||
if(ec)
|
||||
{
|
||||
fail(ec, "listen");
|
||||
@@ -1120,13 +1151,13 @@ int main(int argc, char* argv[])
|
||||
" advanced-server-flex 0.0.0.0 8080 . 1\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto const address = boost::asio::ip::address::from_string(argv[1]);
|
||||
auto const address = boost::asio::ip::make_address(argv[1]);
|
||||
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
|
||||
std::string const doc_root = argv[3];
|
||||
auto const threads = std::max<std::size_t>(1, std::atoi(argv[4]));
|
||||
auto const threads = std::max<int>(1, std::atoi(argv[4]));
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios{threads};
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc{threads};
|
||||
|
||||
// The SSL context is required, and holds certificates
|
||||
ssl::context ctx{ssl::context::sslv23};
|
||||
@@ -1136,7 +1167,7 @@ int main(int argc, char* argv[])
|
||||
|
||||
// Create and launch a listening port
|
||||
std::make_shared<listener>(
|
||||
ios,
|
||||
ioc,
|
||||
ctx,
|
||||
tcp::endpoint{address, port},
|
||||
doc_root)->run();
|
||||
@@ -1146,11 +1177,11 @@ int main(int argc, char* argv[])
|
||||
v.reserve(threads - 1);
|
||||
for(auto i = threads - 1; i > 0; --i)
|
||||
v.emplace_back(
|
||||
[&ios]
|
||||
[&ioc]
|
||||
{
|
||||
ios.run();
|
||||
ioc.run();
|
||||
});
|
||||
ios.run();
|
||||
ioc.run();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <boost/beast/http.hpp>
|
||||
#include <boost/beast/websocket.hpp>
|
||||
#include <boost/beast/version.hpp>
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
@@ -214,7 +215,8 @@ fail(boost::system::error_code ec, char const* what)
|
||||
class websocket_session : public std::enable_shared_from_this<websocket_session>
|
||||
{
|
||||
websocket::stream<tcp::socket> ws_;
|
||||
boost::asio::io_service::strand strand_;
|
||||
boost::asio::strand<
|
||||
boost::asio::io_context::executor_type> strand_;
|
||||
boost::asio::steady_timer timer_;
|
||||
boost::beast::multi_buffer buffer_;
|
||||
|
||||
@@ -223,8 +225,8 @@ public:
|
||||
explicit
|
||||
websocket_session(tcp::socket socket)
|
||||
: ws_(std::move(socket))
|
||||
, strand_(ws_.get_io_service())
|
||||
, timer_(ws_.get_io_service(),
|
||||
, strand_(ws_.get_executor())
|
||||
, timer_(ws_.get_executor().context(),
|
||||
(std::chrono::steady_clock::time_point::max)())
|
||||
{
|
||||
}
|
||||
@@ -239,15 +241,17 @@ public:
|
||||
on_timer({});
|
||||
|
||||
// Set the timer
|
||||
timer_.expires_from_now(std::chrono::seconds(15));
|
||||
timer_.expires_after(std::chrono::seconds(15));
|
||||
|
||||
// Accept the websocket handshake
|
||||
ws_.async_accept(
|
||||
req,
|
||||
strand_.wrap(std::bind(
|
||||
&websocket_session::on_accept,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&websocket_session::on_accept,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
}
|
||||
|
||||
// Called when the timer expires.
|
||||
@@ -258,7 +262,7 @@ public:
|
||||
return fail(ec, "timer");
|
||||
|
||||
// Verify that the timer really expired since the deadline may have moved.
|
||||
if(timer_.expires_at() <= std::chrono::steady_clock::now())
|
||||
if(timer_.expiry() <= std::chrono::steady_clock::now())
|
||||
{
|
||||
// Closing the socket cancels all outstanding operations. They
|
||||
// will complete with boost::asio::error::operation_aborted
|
||||
@@ -269,10 +273,12 @@ public:
|
||||
|
||||
// Wait on the timer
|
||||
timer_.async_wait(
|
||||
strand_.wrap(std::bind(
|
||||
&websocket_session::on_timer,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&websocket_session::on_timer,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -293,16 +299,18 @@ public:
|
||||
do_read()
|
||||
{
|
||||
// Set the timer
|
||||
timer_.expires_from_now(std::chrono::seconds(15));
|
||||
timer_.expires_after(std::chrono::seconds(15));
|
||||
|
||||
// Read a message into our buffer
|
||||
ws_.async_read(
|
||||
buffer_,
|
||||
strand_.wrap(std::bind(
|
||||
&websocket_session::on_read,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&websocket_session::on_read,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -327,11 +335,13 @@ public:
|
||||
ws_.text(ws_.got_text());
|
||||
ws_.async_write(
|
||||
buffer_.data(),
|
||||
strand_.wrap(std::bind(
|
||||
&websocket_session::on_write,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&websocket_session::on_write,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -432,10 +442,12 @@ class http_session : public std::enable_shared_from_this<http_session>
|
||||
http::async_write(
|
||||
self_.socket_,
|
||||
msg_,
|
||||
self_.strand_.wrap(std::bind(
|
||||
&http_session::on_write,
|
||||
self_.shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
boost::asio::bind_executor(
|
||||
self_.strand_,
|
||||
std::bind(
|
||||
&http_session::on_write,
|
||||
self_.shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -449,7 +461,8 @@ class http_session : public std::enable_shared_from_this<http_session>
|
||||
};
|
||||
|
||||
tcp::socket socket_;
|
||||
boost::asio::io_service::strand strand_;
|
||||
boost::asio::strand<
|
||||
boost::asio::io_context::executor_type> strand_;
|
||||
boost::asio::steady_timer timer_;
|
||||
boost::beast::flat_buffer buffer_;
|
||||
std::string const& doc_root_;
|
||||
@@ -463,8 +476,8 @@ public:
|
||||
tcp::socket socket,
|
||||
std::string const& doc_root)
|
||||
: socket_(std::move(socket))
|
||||
, strand_(socket_.get_io_service())
|
||||
, timer_(socket_.get_io_service(),
|
||||
, strand_(socket_.get_executor())
|
||||
, timer_(socket_.get_executor().context(),
|
||||
(std::chrono::steady_clock::time_point::max)())
|
||||
, doc_root_(doc_root)
|
||||
, queue_(*this)
|
||||
@@ -486,14 +499,16 @@ public:
|
||||
do_read()
|
||||
{
|
||||
// Set the timer
|
||||
timer_.expires_from_now(std::chrono::seconds(15));
|
||||
timer_.expires_after(std::chrono::seconds(15));
|
||||
|
||||
// Read a request
|
||||
http::async_read(socket_, buffer_, req_,
|
||||
strand_.wrap(std::bind(
|
||||
&http_session::on_read,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&http_session::on_read,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
}
|
||||
|
||||
// Called when the timer expires.
|
||||
@@ -504,7 +519,7 @@ public:
|
||||
return fail(ec, "timer");
|
||||
|
||||
// Verify that the timer really expired since the deadline may have moved.
|
||||
if(timer_.expires_at() <= std::chrono::steady_clock::now())
|
||||
if(timer_.expiry() <= std::chrono::steady_clock::now())
|
||||
{
|
||||
// Closing the socket cancels all outstanding operations. They
|
||||
// will complete with boost::asio::error::operation_aborted
|
||||
@@ -515,10 +530,12 @@ public:
|
||||
|
||||
// Wait on the timer
|
||||
timer_.async_wait(
|
||||
strand_.wrap(std::bind(
|
||||
&http_session::on_timer,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&http_session::on_timer,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -599,11 +616,11 @@ class listener : public std::enable_shared_from_this<listener>
|
||||
|
||||
public:
|
||||
listener(
|
||||
boost::asio::io_service& ios,
|
||||
boost::asio::io_context& ioc,
|
||||
tcp::endpoint endpoint,
|
||||
std::string const& doc_root)
|
||||
: acceptor_(ios)
|
||||
, socket_(ios)
|
||||
: acceptor_(ioc)
|
||||
, socket_(ioc)
|
||||
, doc_root_(doc_root)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
@@ -626,7 +643,7 @@ public:
|
||||
|
||||
// Start listening for connections
|
||||
acceptor_.listen(
|
||||
boost::asio::socket_base::max_connections, ec);
|
||||
boost::asio::socket_base::max_listen_connections, ec);
|
||||
if(ec)
|
||||
{
|
||||
fail(ec, "listen");
|
||||
@@ -687,17 +704,17 @@ int main(int argc, char* argv[])
|
||||
" advanced-server 0.0.0.0 8080 . 1\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto const address = boost::asio::ip::address::from_string(argv[1]);
|
||||
auto const address = boost::asio::ip::make_address(argv[1]);
|
||||
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
|
||||
std::string const doc_root = argv[3];
|
||||
auto const threads = std::max<std::size_t>(1, std::atoi(argv[4]));
|
||||
auto const threads = std::max<int>(1, std::atoi(argv[4]));
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios{threads};
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc{threads};
|
||||
|
||||
// Create and launch a listening port
|
||||
std::make_shared<listener>(
|
||||
ios,
|
||||
ioc,
|
||||
tcp::endpoint{address, port},
|
||||
doc_root)->run();
|
||||
|
||||
@@ -706,11 +723,11 @@ int main(int argc, char* argv[])
|
||||
v.reserve(threads - 1);
|
||||
for(auto i = threads - 1; i > 0; --i)
|
||||
v.emplace_back(
|
||||
[&ios]
|
||||
[&ioc]
|
||||
{
|
||||
ios.run();
|
||||
ioc.run();
|
||||
});
|
||||
ios.run();
|
||||
ioc.run();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -61,7 +61,8 @@ is_ssl_handshake(
|
||||
ConstBufferSequence const& buffers)
|
||||
{
|
||||
// Make sure buffers meets the requirements
|
||||
static_assert(boost::beast::is_const_buffer_sequence<ConstBufferSequence>::value,
|
||||
static_assert(
|
||||
boost::asio::is_const_buffer_sequence<ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
|
||||
// We need at least one byte to really do anything
|
||||
@@ -135,7 +136,8 @@ detect_ssl(
|
||||
// Make sure arguments meet the requirements
|
||||
static_assert(beast::is_sync_read_stream<SyncReadStream>::value,
|
||||
"SyncReadStream requirements not met");
|
||||
static_assert(beast::is_dynamic_buffer<DynamicBuffer>::value,
|
||||
static_assert(
|
||||
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
|
||||
"DynamicBuffer requirements not met");
|
||||
|
||||
// Loop until an error occurs or we get a definitive answer
|
||||
@@ -219,15 +221,15 @@ detect_ssl(
|
||||
Regardless of whether the asynchronous operation completes
|
||||
immediately or not, the handler will not be invoked from within
|
||||
this function. Invocation of the handler will be performed in a
|
||||
manner equivalent to using `boost::asio::io_service::post`.
|
||||
manner equivalent to using `boost::asio::io_context::post`.
|
||||
*/
|
||||
template<
|
||||
class AsyncReadStream,
|
||||
class DynamicBuffer,
|
||||
class CompletionToken>
|
||||
boost::beast::async_return_type< /*< The [link beast.ref.boost__beast__async_return_type `async_return_type`] customizes the return value based on the completion token >*/
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE( /*< `BOOST_ASIO_INITFN_RESULT_TYPE` customizes the return value based on the completion token >*/
|
||||
CompletionToken,
|
||||
void(boost::beast::error_code, boost::tribool)> /*< This is the signature for the completion handler >*/
|
||||
void(boost::beast::error_code, boost::tribool)) /*< This is the signature for the completion handler >*/
|
||||
async_detect_ssl(
|
||||
AsyncReadStream& stream,
|
||||
DynamicBuffer& buffer,
|
||||
@@ -249,9 +251,9 @@ template<
|
||||
class AsyncReadStream,
|
||||
class DynamicBuffer,
|
||||
class CompletionToken>
|
||||
boost::beast::async_return_type<
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
CompletionToken,
|
||||
void(boost::beast::error_code, boost::tribool)>
|
||||
void(boost::beast::error_code, boost::tribool))
|
||||
async_detect_ssl(
|
||||
AsyncReadStream& stream,
|
||||
DynamicBuffer& buffer,
|
||||
@@ -262,26 +264,29 @@ async_detect_ssl(
|
||||
// Make sure arguments meet the requirements
|
||||
static_assert(beast::is_async_read_stream<AsyncReadStream>::value,
|
||||
"SyncReadStream requirements not met");
|
||||
static_assert(beast::is_dynamic_buffer<DynamicBuffer>::value,
|
||||
static_assert(
|
||||
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
|
||||
"DynamicBuffer requirements not met");
|
||||
|
||||
// This helper manages some of the handler's lifetime and
|
||||
// uses the result and handler specializations associated with
|
||||
// the completion token to help customize the return value.
|
||||
//
|
||||
beast::async_completion<
|
||||
boost::asio::async_completion<
|
||||
CompletionToken, void(beast::error_code, boost::tribool)> init{token};
|
||||
|
||||
// Create the composed operation and launch it. This is a constructor
|
||||
// call followed by invocation of operator(). We use handler_type
|
||||
// call followed by invocation of operator(). We use BOOST_ASIO_HANDLER_TYPE
|
||||
// to convert the completion token into the correct handler type,
|
||||
// allowing user defined specializations of the async result template
|
||||
// to take effect.
|
||||
//
|
||||
detect_ssl_op<AsyncReadStream, DynamicBuffer, beast::handler_type<
|
||||
CompletionToken, void(beast::error_code, boost::tribool)>>{
|
||||
stream, buffer, init.completion_handler}(
|
||||
beast::error_code{}, 0);
|
||||
detect_ssl_op<
|
||||
AsyncReadStream,
|
||||
DynamicBuffer,
|
||||
BOOST_ASIO_HANDLER_TYPE(
|
||||
CompletionToken, void(beast::error_code, boost::tribool))>{
|
||||
stream, buffer, init.completion_handler}(beast::error_code{}, 0);
|
||||
|
||||
// This hook lets the caller see a return value when appropriate.
|
||||
// For example this might return std::future<error_code, boost::tribool> if
|
||||
@@ -336,6 +341,35 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
// Associated allocator support. This is Asio's system for
|
||||
// allowing the final completion handler to customize the
|
||||
// memory allocation strategy used for composed operation
|
||||
// states. A composed operation needs to use the same allocator
|
||||
// as the final handler. These declarations achieve that.
|
||||
|
||||
using allocator_type =
|
||||
boost::asio::associated_allocator_t<Handler>;
|
||||
|
||||
allocator_type
|
||||
get_allocator() const noexcept
|
||||
{
|
||||
return boost::asio::get_associated_allocator(handler_);
|
||||
}
|
||||
|
||||
// Executor hook. This is Asio's system for customizing the
|
||||
// manner in which asynchronous completion handlers are invoked.
|
||||
// A composed operation needs to use the same executor to invoke
|
||||
// intermediate completion handlers as that used to invoke the
|
||||
// final handler.
|
||||
|
||||
using executor_type = boost::asio::associated_executor_t<
|
||||
Handler, decltype(stream_.get_executor())>;
|
||||
|
||||
executor_type get_executor() const noexcept
|
||||
{
|
||||
return boost::asio::get_associated_executor(handler_, stream_.get_executor());
|
||||
}
|
||||
|
||||
// Determines if the next asynchronous operation represents a
|
||||
// continuation of the asynchronous flow of control associated
|
||||
// with the final handler. If we are past step two, it means
|
||||
@@ -358,34 +392,6 @@ public:
|
||||
asio_handler_is_continuation(std::addressof(op->handler_));
|
||||
}
|
||||
|
||||
// Handler hook forwarding. These free functions invoke the hooks
|
||||
// associated with the final completion handler. In effect, they
|
||||
// make the Asio implementation treat our composed operation the
|
||||
// same way it would treat the final completion handler for the
|
||||
// purpose of memory allocation and invocation.
|
||||
//
|
||||
// Our implementation just passes through the call to the hook
|
||||
// associated with the final handler.
|
||||
|
||||
friend void* asio_handler_allocate(std::size_t size, detect_ssl_op* op)
|
||||
{
|
||||
using boost::asio::asio_handler_allocate;
|
||||
return asio_handler_allocate(size, std::addressof(op->handler_));
|
||||
}
|
||||
|
||||
friend void asio_handler_deallocate(void* p, std::size_t size, detect_ssl_op* op)
|
||||
{
|
||||
using boost::asio::asio_handler_deallocate;
|
||||
return asio_handler_deallocate(p, size, std::addressof(op->handler_));
|
||||
}
|
||||
|
||||
template<class Function>
|
||||
friend void asio_handler_invoke(Function&& f, detect_ssl_op* op)
|
||||
{
|
||||
using boost::asio::asio_handler_invoke;
|
||||
return asio_handler_invoke(f, std::addressof(op->handler_));
|
||||
}
|
||||
|
||||
// Our main entry point. This will get called as our
|
||||
// intermediate operations complete. Definition below.
|
||||
//
|
||||
@@ -424,12 +430,13 @@ operator()(boost::beast::error_code ec, std::size_t bytes_transferred)
|
||||
// We need to invoke the handler, but the guarantee
|
||||
// is that the handler will not be called before the
|
||||
// call to async_detect_ssl returns, so we must post
|
||||
// the operation to the io_service. The helper function
|
||||
// the operation to the executor. The helper function
|
||||
// `bind_handler` lets us bind arguments in a safe way
|
||||
// that preserves the type customization hooks of the
|
||||
// original handler.
|
||||
step_ = 1;
|
||||
return stream_.get_io_service().post(
|
||||
return boost::asio::post(
|
||||
stream_.get_executor(),
|
||||
beast::bind_handler(std::move(*this), ec, 0));
|
||||
}
|
||||
|
||||
|
||||
+239
-270
@@ -10,21 +10,21 @@
|
||||
#ifndef BOOST_BEAST_EXAMPLE_COMMON_SESSION_ALLOC_HPP
|
||||
#define BOOST_BEAST_EXAMPLE_COMMON_SESSION_ALLOC_HPP
|
||||
|
||||
#include <boost/asio/handler_alloc_hook.hpp>
|
||||
#include <boost/asio/associated_allocator.hpp>
|
||||
#include <boost/asio/associated_executor.hpp>
|
||||
#include <boost/asio/handler_continuation_hook.hpp>
|
||||
#include <boost/asio/handler_invoke_hook.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/intrusive/list.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class Context>
|
||||
class session_alloc_base
|
||||
{
|
||||
template<class Handler>
|
||||
class wrapped_handler;
|
||||
|
||||
protected:
|
||||
class pool_t
|
||||
{
|
||||
using hook_type =
|
||||
@@ -78,23 +78,18 @@ class session_alloc_base
|
||||
boost::intrusive::constant_time_size<
|
||||
true>>::type;
|
||||
|
||||
Context* ctx_;
|
||||
std::size_t refs_ = 1; // shared count
|
||||
std::size_t high_ = 0; // highest used
|
||||
std::size_t size_ = 0; // size of buf_
|
||||
char* buf_ = nullptr; // a large block
|
||||
list_type list_; // list of allocations
|
||||
|
||||
explicit
|
||||
pool_t(Context* ctx)
|
||||
: ctx_(ctx)
|
||||
{
|
||||
}
|
||||
pool_t() = default;
|
||||
|
||||
public:
|
||||
static
|
||||
pool_t&
|
||||
construct(Context* ctx);
|
||||
construct();
|
||||
|
||||
~pool_t();
|
||||
|
||||
@@ -110,73 +105,178 @@ class session_alloc_base
|
||||
void
|
||||
dealloc(void* pv, std::size_t n);
|
||||
};
|
||||
|
||||
pool_t& pool_;
|
||||
|
||||
public:
|
||||
session_alloc_base& operator=(session_alloc_base const&) = delete;
|
||||
|
||||
~session_alloc_base()
|
||||
{
|
||||
pool_.release();
|
||||
}
|
||||
|
||||
session_alloc_base()
|
||||
: pool_(pool_t::construct(nullptr))
|
||||
{
|
||||
static_assert(std::is_same<Context, std::nullptr_t>::value,
|
||||
"Context requirements not met");
|
||||
}
|
||||
|
||||
session_alloc_base(session_alloc_base const& other)
|
||||
: pool_(other.pool_.addref())
|
||||
{
|
||||
}
|
||||
|
||||
template<class DeducedContext, class = typename
|
||||
std::enable_if<! std::is_same<
|
||||
session_alloc_base<Context>,
|
||||
typename std::decay<DeducedContext>::type
|
||||
>::value>::type>
|
||||
explicit
|
||||
session_alloc_base(DeducedContext& ctx)
|
||||
: pool_(pool_t::construct(std::addressof(ctx)))
|
||||
{
|
||||
static_assert(! std::is_same<Context, std::nullptr_t>::value,
|
||||
"Context requirements not met");
|
||||
}
|
||||
|
||||
template<class Handler>
|
||||
wrapped_handler<typename std::decay<Handler>::type>
|
||||
wrap(Handler&& handler)
|
||||
{
|
||||
return wrapped_handler<
|
||||
typename std::decay<Handler>::type>(
|
||||
std::forward<Handler>(handler), *this);
|
||||
}
|
||||
|
||||
protected:
|
||||
void*
|
||||
alloc(std::size_t n)
|
||||
{
|
||||
return pool_.alloc(n);
|
||||
}
|
||||
|
||||
void
|
||||
dealloc(void* p, std::size_t n)
|
||||
{
|
||||
pool_.dealloc(p, n);
|
||||
}
|
||||
};
|
||||
|
||||
template<class Context>
|
||||
auto
|
||||
session_alloc_base<Context>::
|
||||
pool_t::
|
||||
construct() ->
|
||||
pool_t&
|
||||
{
|
||||
return *(new pool_t);
|
||||
}
|
||||
|
||||
template<class Context>
|
||||
session_alloc_base<Context>::
|
||||
pool_t::
|
||||
~pool_t()
|
||||
{
|
||||
BOOST_ASSERT(list_.size() == 0);
|
||||
if(buf_)
|
||||
delete[] buf_;
|
||||
}
|
||||
|
||||
template<class Context>
|
||||
auto
|
||||
session_alloc_base<Context>::
|
||||
pool_t::
|
||||
addref() ->
|
||||
pool_t&
|
||||
{
|
||||
++refs_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class Context>
|
||||
void
|
||||
session_alloc_base<Context>::
|
||||
pool_t::
|
||||
release()
|
||||
{
|
||||
if(--refs_)
|
||||
return;
|
||||
delete this;
|
||||
}
|
||||
|
||||
template<class Context>
|
||||
void*
|
||||
session_alloc_base<Context>::
|
||||
pool_t::
|
||||
alloc(std::size_t n)
|
||||
{
|
||||
if(list_.empty() && size_ < high_)
|
||||
{
|
||||
if(buf_)
|
||||
delete[] buf_;
|
||||
buf_ = new char[high_];
|
||||
size_ = high_;
|
||||
}
|
||||
if(buf_)
|
||||
{
|
||||
char* end;
|
||||
std::size_t used;
|
||||
if(list_.empty())
|
||||
{
|
||||
end = buf_;
|
||||
used = sizeof(element) + n;
|
||||
}
|
||||
else
|
||||
{
|
||||
end = list_.back().end();
|
||||
used = list_.back().used() +
|
||||
sizeof(element) + n;
|
||||
}
|
||||
if(end >= buf_ && end +
|
||||
sizeof(element) + n <= buf_ + size_)
|
||||
{
|
||||
auto& e = *new(end) element{n, used};
|
||||
list_.push_back(e);
|
||||
high_ = (std::max)(high_, used);
|
||||
return e.data();
|
||||
}
|
||||
}
|
||||
std::size_t const used =
|
||||
sizeof(element) + n + (
|
||||
buf_ && ! list_.empty() ?
|
||||
list_.back().used() : 0);
|
||||
auto& e = *new(new char[sizeof(element) + n]) element{n, used};
|
||||
list_.push_back(e);
|
||||
high_ = (std::max)(high_, used);
|
||||
return e.data();
|
||||
}
|
||||
|
||||
template<class Context>
|
||||
void
|
||||
session_alloc_base<Context>::
|
||||
pool_t::
|
||||
dealloc(void* pv, std::size_t n)
|
||||
{
|
||||
auto& e = *(reinterpret_cast<element*>(pv) - 1);
|
||||
BOOST_ASSERT(e.size() == n);
|
||||
if( (e.end() > buf_ + size_) ||
|
||||
reinterpret_cast<char*>(&e) < buf_)
|
||||
{
|
||||
list_.erase(list_.iterator_to(e));
|
||||
e.~element();
|
||||
delete[] reinterpret_cast<char*>(&e);
|
||||
return;
|
||||
}
|
||||
list_.erase(list_.iterator_to(e));
|
||||
e.~element();
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class T, class Context = std::nullptr_t>
|
||||
class session_alloc : public session_alloc_base<Context>
|
||||
template<class T>
|
||||
class session_alloc
|
||||
: private detail::session_alloc_base<void>
|
||||
{
|
||||
template<class U, class C>
|
||||
template<class U>
|
||||
friend class session_alloc;
|
||||
|
||||
template<class Handler>
|
||||
class wrapped_handler
|
||||
{
|
||||
// Can't friend partial specializations,
|
||||
// so we just friend the whole thing.
|
||||
template<class T, class Executor>
|
||||
friend struct boost::asio::associated_executor;
|
||||
|
||||
Handler h_;
|
||||
session_alloc<char> alloc_;
|
||||
|
||||
public:
|
||||
wrapped_handler(wrapped_handler&&) = default;
|
||||
wrapped_handler(wrapped_handler const&) = default;
|
||||
|
||||
template<class DeducedHandler>
|
||||
wrapped_handler(
|
||||
DeducedHandler&& h,
|
||||
session_alloc const& alloc)
|
||||
: h_(std::forward<DeducedHandler>(h))
|
||||
, alloc_(alloc)
|
||||
{
|
||||
}
|
||||
|
||||
using allocator_type = session_alloc<char>;
|
||||
|
||||
allocator_type
|
||||
get_allocator() const noexcept;
|
||||
|
||||
template<class... Args>
|
||||
void
|
||||
operator()(Args&&... args) const
|
||||
{
|
||||
h_(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
friend
|
||||
bool
|
||||
asio_handler_is_continuation(wrapped_handler* w)
|
||||
{
|
||||
using boost::asio::asio_handler_is_continuation;
|
||||
return asio_handler_is_continuation(std::addressof(w->h_));
|
||||
}
|
||||
};
|
||||
|
||||
using pool_t = typename
|
||||
detail::session_alloc_base<void>::pool_t;
|
||||
|
||||
pool_t& pool_;
|
||||
|
||||
public:
|
||||
using value_type = T;
|
||||
using is_always_equal = std::false_type;
|
||||
@@ -193,21 +293,32 @@ public:
|
||||
using other = session_alloc<U>;
|
||||
};
|
||||
|
||||
session_alloc() = default;
|
||||
session_alloc(session_alloc const&) = default;
|
||||
session_alloc& operator=(session_alloc const&) = delete;
|
||||
|
||||
~session_alloc()
|
||||
{
|
||||
pool_.release();
|
||||
}
|
||||
|
||||
session_alloc()
|
||||
: pool_(pool_t::construct())
|
||||
{
|
||||
}
|
||||
|
||||
session_alloc(session_alloc const& other) noexcept
|
||||
: pool_(other.pool_.addref())
|
||||
{
|
||||
}
|
||||
|
||||
template<class U>
|
||||
session_alloc(session_alloc<U> const& other)
|
||||
: session_alloc_base<Context>(static_cast<
|
||||
session_alloc_base<Context> const&>(other))
|
||||
session_alloc(session_alloc<U> const& other) noexcept
|
||||
: pool_(other.pool_)
|
||||
{
|
||||
}
|
||||
|
||||
explicit
|
||||
session_alloc(Context& ctx)
|
||||
: session_alloc_base<Context>(ctx)
|
||||
{
|
||||
}
|
||||
template<class Handler>
|
||||
wrapped_handler<typename std::decay<Handler>::type>
|
||||
wrap(Handler&& handler);
|
||||
|
||||
value_type*
|
||||
allocate(size_type n)
|
||||
@@ -257,209 +368,67 @@ public:
|
||||
{
|
||||
return ! (lhs == rhs);
|
||||
}
|
||||
|
||||
protected:
|
||||
void*
|
||||
alloc(std::size_t n)
|
||||
{
|
||||
return pool_.alloc(n);
|
||||
}
|
||||
|
||||
void
|
||||
dealloc(void* p, std::size_t n)
|
||||
{
|
||||
pool_.dealloc(p, n);
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Context>
|
||||
template<class T>
|
||||
template<class Handler>
|
||||
class session_alloc_base<Context>::wrapped_handler
|
||||
auto
|
||||
session_alloc<T>::
|
||||
wrapped_handler<Handler>::
|
||||
get_allocator() const noexcept ->
|
||||
allocator_type
|
||||
{
|
||||
Handler h_;
|
||||
session_alloc_base alloc_;
|
||||
|
||||
void*
|
||||
alloc(std::size_t size)
|
||||
{
|
||||
return alloc_.alloc(size);
|
||||
}
|
||||
|
||||
void
|
||||
dealloc(void* p, std::size_t size)
|
||||
{
|
||||
alloc_.dealloc(p, size);
|
||||
}
|
||||
|
||||
public:
|
||||
wrapped_handler(wrapped_handler&&) = default;
|
||||
wrapped_handler(wrapped_handler const&) = default;
|
||||
|
||||
template<class DeducedHandler>
|
||||
explicit
|
||||
wrapped_handler(DeducedHandler&& h,
|
||||
session_alloc_base const& alloc)
|
||||
: h_(std::forward<DeducedHandler>(h))
|
||||
, alloc_(alloc)
|
||||
{
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
void
|
||||
operator()(Args&&... args) const
|
||||
{
|
||||
h_(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
friend
|
||||
void*
|
||||
asio_handler_allocate(
|
||||
std::size_t size, wrapped_handler* w)
|
||||
{
|
||||
return w->alloc(size);
|
||||
}
|
||||
|
||||
friend
|
||||
void
|
||||
asio_handler_deallocate(
|
||||
void* p, std::size_t size, wrapped_handler* w)
|
||||
{
|
||||
w->dealloc(p, size);
|
||||
}
|
||||
|
||||
friend
|
||||
bool
|
||||
asio_handler_is_continuation(wrapped_handler* w)
|
||||
{
|
||||
using boost::asio::asio_handler_is_continuation;
|
||||
return asio_handler_is_continuation(std::addressof(w->h_));
|
||||
}
|
||||
|
||||
template<class F>
|
||||
friend
|
||||
void
|
||||
asio_handler_invoke(F&& f, wrapped_handler* w)
|
||||
{
|
||||
using boost::asio::asio_handler_invoke;
|
||||
asio_handler_invoke(
|
||||
f, std::addressof(w->h_));
|
||||
}
|
||||
};
|
||||
return alloc_;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Context>
|
||||
template<class T>
|
||||
template<class Handler>
|
||||
auto
|
||||
session_alloc_base<Context>::
|
||||
pool_t::
|
||||
construct(Context* ctx) ->
|
||||
pool_t&
|
||||
session_alloc<T>::
|
||||
wrap(Handler&& handler) ->
|
||||
wrapped_handler<typename std::decay<Handler>::type>
|
||||
{
|
||||
using boost::asio::asio_handler_allocate;
|
||||
return *new(asio_handler_allocate(
|
||||
sizeof(pool_t), ctx)) pool_t{ctx};
|
||||
return wrapped_handler<
|
||||
typename std::decay<Handler>::type>(
|
||||
std::forward<Handler>(handler), *this);
|
||||
}
|
||||
|
||||
template<class Context>
|
||||
session_alloc_base<Context>::
|
||||
pool_t::
|
||||
~pool_t()
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
template<class T, class Handler, class Executor>
|
||||
struct associated_executor<
|
||||
session_alloc<T>::wrapped_handler<Handler>, Executor>
|
||||
{
|
||||
BOOST_ASSERT(list_.size() == 0);
|
||||
if(buf_)
|
||||
using type = typename
|
||||
associated_executor<Handler, Executor>::type;
|
||||
|
||||
static
|
||||
type
|
||||
get(session_alloc<T>::wrapped_handler<Handler> const& h,
|
||||
Executor const& ex = Executor()) noexcept
|
||||
{
|
||||
using boost::asio::asio_handler_deallocate;
|
||||
asio_handler_deallocate(buf_, size_, ctx_);
|
||||
return associated_executor<
|
||||
Handler, Executor>::get(h.h_, ex);
|
||||
}
|
||||
}
|
||||
|
||||
template<class Context>
|
||||
auto
|
||||
session_alloc_base<Context>::
|
||||
pool_t::
|
||||
addref() ->
|
||||
pool_t&
|
||||
{
|
||||
++refs_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class Context>
|
||||
void
|
||||
session_alloc_base<Context>::
|
||||
pool_t::
|
||||
release()
|
||||
{
|
||||
if(--refs_)
|
||||
return;
|
||||
this->~pool_t();
|
||||
using boost::asio::asio_handler_deallocate;
|
||||
asio_handler_deallocate(this, sizeof(*this), ctx_);
|
||||
}
|
||||
|
||||
template<class Context>
|
||||
void*
|
||||
session_alloc_base<Context>::
|
||||
pool_t::
|
||||
alloc(std::size_t n)
|
||||
{
|
||||
if(list_.empty() && size_ < high_)
|
||||
{
|
||||
if(buf_)
|
||||
{
|
||||
using boost::asio::asio_handler_deallocate;
|
||||
asio_handler_deallocate(buf_, size_, ctx_);
|
||||
}
|
||||
using boost::asio::asio_handler_allocate;
|
||||
buf_ = reinterpret_cast<char*>(
|
||||
asio_handler_allocate(high_, ctx_));
|
||||
size_ = high_;
|
||||
}
|
||||
if(buf_)
|
||||
{
|
||||
char* end;
|
||||
std::size_t used;
|
||||
if(list_.empty())
|
||||
{
|
||||
end = buf_;
|
||||
used = sizeof(element) + n;
|
||||
}
|
||||
else
|
||||
{
|
||||
end = list_.back().end();
|
||||
used = list_.back().used() +
|
||||
sizeof(element) + n;
|
||||
}
|
||||
if(end >= buf_ && end +
|
||||
sizeof(element) + n <= buf_ + size_)
|
||||
{
|
||||
auto& e = *new(end) element{n, used};
|
||||
list_.push_back(e);
|
||||
high_ = (std::max)(high_, used);
|
||||
return e.data();
|
||||
}
|
||||
}
|
||||
std::size_t const used =
|
||||
sizeof(element) + n + (
|
||||
buf_ && ! list_.empty() ?
|
||||
list_.back().used() : 0);
|
||||
using boost::asio::asio_handler_allocate;
|
||||
auto& e = *new(asio_handler_allocate(
|
||||
sizeof(element) + n, ctx_)) element{n, used};
|
||||
list_.push_back(e);
|
||||
high_ = (std::max)(high_, used);
|
||||
return e.data();
|
||||
}
|
||||
|
||||
template<class Context>
|
||||
void
|
||||
session_alloc_base<Context>::
|
||||
pool_t::
|
||||
dealloc(void* pv, std::size_t n)
|
||||
{
|
||||
auto& e = *(reinterpret_cast<element*>(pv) - 1);
|
||||
BOOST_ASSERT(e.size() == n);
|
||||
if( (e.end() > buf_ + size_) ||
|
||||
reinterpret_cast<char*>(&e) < buf_)
|
||||
{
|
||||
list_.erase(list_.iterator_to(e));
|
||||
e.~element();
|
||||
using boost::asio::asio_handler_deallocate;
|
||||
asio_handler_deallocate(
|
||||
&e, sizeof(e) + n, ctx_);
|
||||
return;
|
||||
}
|
||||
list_.erase(list_.iterator_to(e));
|
||||
e.~element();
|
||||
}
|
||||
};
|
||||
} // asio
|
||||
} // boost
|
||||
|
||||
#endif
|
||||
|
||||
@@ -52,9 +52,6 @@ public:
|
||||
/// Structure for use with deprecated impl_type.
|
||||
using impl_struct = typename stream_type::impl_struct;
|
||||
|
||||
/// (Deprecated: Use native_handle_type.) The underlying implementation type.
|
||||
using impl_type = typename stream_type::impl_type;
|
||||
|
||||
/// The type of the next layer.
|
||||
using next_layer_type = typename stream_type::next_layer_type;
|
||||
|
||||
@@ -64,14 +61,16 @@ public:
|
||||
ssl_stream(
|
||||
boost::asio::ip::tcp::socket socket,
|
||||
boost::asio::ssl::context& ctx)
|
||||
: p_(new stream_type{socket.get_io_service(), ctx})
|
||||
: p_(new stream_type{
|
||||
socket.get_executor().context(), ctx})
|
||||
, ctx_(&ctx)
|
||||
{
|
||||
p_->next_layer() = std::move(socket);
|
||||
}
|
||||
|
||||
ssl_stream(ssl_stream&& other)
|
||||
: p_(new stream_type(other.get_io_service(), *other.ctx_))
|
||||
: p_(new stream_type(
|
||||
other.get_executor().context(), *other.ctx_))
|
||||
, ctx_(other.ctx_)
|
||||
{
|
||||
using std::swap;
|
||||
@@ -80,8 +79,8 @@ public:
|
||||
|
||||
ssl_stream& operator=(ssl_stream&& other)
|
||||
{
|
||||
std::unique_ptr<stream_type> p(
|
||||
new stream_type{other.get_io_service(), other.ctx_});
|
||||
std::unique_ptr<stream_type> p(new stream_type{
|
||||
other.get_executor().context(), other.ctx_});
|
||||
using std::swap;
|
||||
swap(p_, p);
|
||||
swap(p_, other.p_);
|
||||
@@ -89,10 +88,10 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
boost::asio::io_service&
|
||||
get_io_service()
|
||||
decltype(p_->get_executor())
|
||||
get_executor() noexcept
|
||||
{
|
||||
return p_->get_io_service();
|
||||
return p_->get_executor();
|
||||
}
|
||||
|
||||
native_handle_type
|
||||
@@ -101,12 +100,6 @@ public:
|
||||
return p_->native_handle();
|
||||
}
|
||||
|
||||
impl_type
|
||||
impl()
|
||||
{
|
||||
return p_->impl();
|
||||
}
|
||||
|
||||
next_layer_type const&
|
||||
next_layer() const
|
||||
{
|
||||
|
||||
@@ -1,230 +0,0 @@
|
||||
//
|
||||
// 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_EXAMPLE_COMMON_WRITE_MSG_HPP
|
||||
#define BOOST_BEAST_EXAMPLE_COMMON_WRITE_MSG_HPP
|
||||
|
||||
#include <boost/beast/core/async_result.hpp>
|
||||
#include <boost/beast/core/handler_ptr.hpp>
|
||||
#include <boost/beast/core/type_traits.hpp>
|
||||
#include <boost/beast/http/message.hpp>
|
||||
#include <boost/beast/http/write.hpp>
|
||||
#include <boost/beast/http/type_traits.hpp>
|
||||
#include <boost/asio/handler_alloc_hook.hpp>
|
||||
#include <boost/asio/handler_continuation_hook.hpp>
|
||||
#include <boost/asio/handler_invoke_hook.hpp>
|
||||
|
||||
namespace detail {
|
||||
|
||||
/** Composed operation to send an HTTP message
|
||||
|
||||
This implements the composed operation needed for the
|
||||
@ref async_write_msg function.
|
||||
*/
|
||||
template<
|
||||
class AsyncWriteStream,
|
||||
class Handler,
|
||||
bool isRequest, class Body, class Fields>
|
||||
class write_msg_op
|
||||
{
|
||||
// This composed operation has a state which is not trivial
|
||||
// to copy (msg) so we need to store the state in an allocated
|
||||
// object.
|
||||
//
|
||||
struct data
|
||||
{
|
||||
// The stream we are writing to
|
||||
AsyncWriteStream& stream;
|
||||
|
||||
// The message we are sending. Note that this composed
|
||||
// operation takes ownership of the message and destroys
|
||||
// it when it is done.
|
||||
//
|
||||
boost::beast::http::message<isRequest, Body, Fields> msg;
|
||||
|
||||
// Serializer for the message
|
||||
boost::beast::http::serializer<isRequest, Body, Fields> sr;
|
||||
|
||||
data(
|
||||
Handler& handler,
|
||||
AsyncWriteStream& stream_,
|
||||
boost::beast::http::message<isRequest, Body, Fields>&& msg_)
|
||||
: stream(stream_)
|
||||
, msg(std::move(msg_))
|
||||
, sr(msg)
|
||||
{
|
||||
boost::ignore_unused(handler);
|
||||
}
|
||||
};
|
||||
|
||||
// `handler_ptr` is a utility which helps to manage a composed
|
||||
// operation's state. It is similar to a shared pointer, but
|
||||
// it uses handler allocation hooks to allocate and free memory,
|
||||
// and it also helps to meet Asio's deallocate-before-invocation
|
||||
// guarantee.
|
||||
//
|
||||
boost::beast::handler_ptr<data, Handler> d_;
|
||||
|
||||
public:
|
||||
// Asio can move and copy the handler, we support both
|
||||
write_msg_op(write_msg_op&&) = default;
|
||||
write_msg_op(write_msg_op const&) = default;
|
||||
|
||||
// Constructor
|
||||
//
|
||||
// We take the handler as a template type to
|
||||
// support both const and rvalue references.
|
||||
//
|
||||
template<
|
||||
class DeducedHandler,
|
||||
class... Args>
|
||||
write_msg_op(
|
||||
DeducedHandler&& h,
|
||||
AsyncWriteStream& s,
|
||||
Args&&... args)
|
||||
: d_(std::forward<DeducedHandler>(h),
|
||||
s, std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
|
||||
// Entry point
|
||||
//
|
||||
// The initiation function calls this to start the operation
|
||||
//
|
||||
void
|
||||
operator()()
|
||||
{
|
||||
auto& d = *d_;
|
||||
boost::beast::http::async_write(
|
||||
d.stream, d.sr, std::move(*this));
|
||||
}
|
||||
|
||||
// Completion handler
|
||||
//
|
||||
// This gets called when boost::beast::http::async_write completes
|
||||
//
|
||||
void
|
||||
operator()(boost::beast::error_code ec)
|
||||
{
|
||||
d_.invoke(ec);
|
||||
}
|
||||
|
||||
//
|
||||
// These hooks are necessary for Asio
|
||||
//
|
||||
// The meaning is explained in the Beast documentation
|
||||
//
|
||||
|
||||
friend
|
||||
void* asio_handler_allocate(
|
||||
std::size_t size, write_msg_op* op)
|
||||
{
|
||||
using boost::asio::asio_handler_allocate;
|
||||
return asio_handler_allocate(
|
||||
size, std::addressof(op->d_.handler()));
|
||||
}
|
||||
|
||||
friend
|
||||
void asio_handler_deallocate(
|
||||
void* p, std::size_t size, write_msg_op* op)
|
||||
{
|
||||
using boost::asio::asio_handler_deallocate;
|
||||
asio_handler_deallocate(
|
||||
p, size, std::addressof(op->d_.handler()));
|
||||
}
|
||||
|
||||
friend
|
||||
bool asio_handler_is_continuation(write_msg_op* op)
|
||||
{
|
||||
using boost::asio::asio_handler_is_continuation;
|
||||
return asio_handler_is_continuation(std::addressof(op->d_.handler()));
|
||||
}
|
||||
|
||||
template<class Function>
|
||||
friend
|
||||
void asio_handler_invoke(Function&& f, write_msg_op* op)
|
||||
{
|
||||
using boost::asio::asio_handler_invoke;
|
||||
asio_handler_invoke(
|
||||
f, std::addressof(op->d_.handler()));
|
||||
}
|
||||
};
|
||||
|
||||
} // detail
|
||||
|
||||
/** Write an HTTP message to a stream asynchronously
|
||||
|
||||
This function is used to write a complete message to a stream asynchronously
|
||||
using HTTP/1. The function call always returns immediately. The asynchronous
|
||||
operation will continue until one of the following conditions is true:
|
||||
|
||||
@li The entire message is written.
|
||||
|
||||
@li An error occurs.
|
||||
|
||||
This operation is implemented in terms of zero or more calls to the stream's
|
||||
`async_write_some` function, and is known as a <em>composed operation</em>.
|
||||
The program must ensure that the stream performs no other write operations
|
||||
until this operation completes. The algorithm will use a temporary
|
||||
@ref serializer to produce buffers. If the semantics of the message
|
||||
indicate that the connection should be closed after the message is sent,
|
||||
the error delivered by this function
|
||||
will be @ref error::end_of_stream
|
||||
|
||||
@param stream The stream to which the data is to be written.
|
||||
The type must support the @b AsyncWriteStream concept.
|
||||
|
||||
@param msg The message to write. The function will take ownership
|
||||
of the object as if by move constrction.
|
||||
|
||||
@param handler The handler to be called when the operation
|
||||
completes. Copies will be made of the handler as required.
|
||||
The equivalent function signature of the handler must be:
|
||||
@code void handler(
|
||||
error_code const& error // result of operation
|
||||
); @endcode
|
||||
Regardless of whether the asynchronous operation completes
|
||||
immediately or not, the handler will not be invoked from within
|
||||
this function. Invocation of the handler will be performed in a
|
||||
manner equivalent to using `boost::asio::io_service::post`.
|
||||
*/
|
||||
template<
|
||||
class AsyncWriteStream,
|
||||
bool isRequest, class Body, class Fields,
|
||||
class WriteHandler>
|
||||
boost::beast::async_return_type<WriteHandler, void(boost::beast::error_code)>
|
||||
async_write_msg(
|
||||
AsyncWriteStream& stream,
|
||||
boost::beast::http::message<isRequest, Body, Fields>&& msg,
|
||||
WriteHandler&& handler)
|
||||
{
|
||||
static_assert(
|
||||
boost::beast::is_async_write_stream<AsyncWriteStream>::value,
|
||||
"AsyncWriteStream requirements not met");
|
||||
|
||||
static_assert(boost::beast::http::is_body<Body>::value,
|
||||
"Body requirements not met");
|
||||
|
||||
static_assert(boost::beast::http::is_body_reader<Body>::value,
|
||||
"BodyReader requirements not met");
|
||||
|
||||
boost::beast::async_completion<WriteHandler, void(boost::beast::error_code)> init{handler};
|
||||
|
||||
::detail::write_msg_op<
|
||||
AsyncWriteStream,
|
||||
boost::beast::handler_type<WriteHandler, void(boost::beast::error_code)>,
|
||||
isRequest, Body, Fields>{
|
||||
init.completion_handler,
|
||||
stream,
|
||||
std::move(msg)}();
|
||||
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -62,7 +62,8 @@ send_expect_100_continue(
|
||||
static_assert(is_sync_stream<SyncStream>::value,
|
||||
"SyncStream requirements not met");
|
||||
|
||||
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
|
||||
static_assert(
|
||||
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
|
||||
"DynamicBuffer requirements not met");
|
||||
|
||||
// Insert or replace the Expect field
|
||||
@@ -123,7 +124,8 @@ receive_expect_100_continue(
|
||||
static_assert(is_sync_stream<SyncStream>::value,
|
||||
"SyncStream requirements not met");
|
||||
|
||||
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
|
||||
static_assert(
|
||||
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
|
||||
"DynamicBuffer requirements not met");
|
||||
|
||||
// Declare a parser for a request with a string body
|
||||
@@ -194,9 +196,6 @@ send_cgi_response(
|
||||
static_assert(is_sync_write_stream<SyncWriteStream>::value,
|
||||
"SyncWriteStream requirements not met");
|
||||
|
||||
using boost::asio::buffer_cast;
|
||||
using boost::asio::buffer_size;
|
||||
|
||||
// Set up the response. We use the buffer_body type,
|
||||
// allowing serialization to use manually provided buffers.
|
||||
response<buffer_body> res;
|
||||
@@ -293,7 +292,8 @@ void do_server_head(
|
||||
{
|
||||
static_assert(is_sync_stream<SyncStream>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
|
||||
static_assert(
|
||||
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
|
||||
"DynamicBuffer requirments not met");
|
||||
|
||||
// We deliver this payload for all GET requests
|
||||
@@ -386,7 +386,8 @@ do_head_request(
|
||||
// Do some type checking to be a good citizen
|
||||
static_assert(is_sync_stream<SyncStream>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(is_dynamic_buffer<DynamicBuffer>::value,
|
||||
static_assert(
|
||||
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
|
||||
"DynamicBuffer requirments not met");
|
||||
|
||||
// The interfaces we are using are low level and do not
|
||||
@@ -589,10 +590,6 @@ public:
|
||||
void
|
||||
operator()(error_code& ec, ConstBufferSequence const& buffers) const
|
||||
{
|
||||
// These asio functions are needed to access a buffer's contents
|
||||
using boost::asio::buffer_cast;
|
||||
using boost::asio::buffer_size;
|
||||
|
||||
// Error codes must be cleared on success
|
||||
ec = {};
|
||||
|
||||
@@ -600,15 +597,16 @@ public:
|
||||
std::size_t bytes_transferred = 0;
|
||||
|
||||
// Loop over the buffer sequence
|
||||
for(auto it = buffers.begin(); it != buffers.end(); ++ it)
|
||||
for(auto it = boost::asio::buffer_sequence_begin(buffers);
|
||||
it != boost::asio::buffer_sequence_end(buffers); ++it)
|
||||
{
|
||||
// This is the next buffer in the sequence
|
||||
boost::asio::const_buffer const buffer = *it;
|
||||
|
||||
// Write it to the std::ostream
|
||||
os_.write(
|
||||
buffer_cast<char const*>(buffer),
|
||||
buffer_size(buffer));
|
||||
reinterpret_cast<char const*>(buffer.data()),
|
||||
buffer.size());
|
||||
|
||||
// If the std::ostream fails, convert it to an error code
|
||||
if(os_.fail())
|
||||
@@ -714,13 +712,12 @@ read_istream(
|
||||
if(is.rdbuf()->in_avail() > 0)
|
||||
{
|
||||
// Get a mutable buffer sequence for writing
|
||||
auto const mb = buffer.prepare(
|
||||
auto const b = buffer.prepare(
|
||||
static_cast<std::size_t>(is.rdbuf()->in_avail()));
|
||||
|
||||
// Now get everything we can from the istream
|
||||
buffer.commit(static_cast<std::size_t>(is.readsome(
|
||||
boost::asio::buffer_cast<char*>(mb),
|
||||
boost::asio::buffer_size(mb))));
|
||||
reinterpret_cast<char*>(b.data()), b.size())));
|
||||
}
|
||||
else if(buffer.size() == 0)
|
||||
{
|
||||
@@ -729,12 +726,10 @@ read_istream(
|
||||
if(! is.eof())
|
||||
{
|
||||
// Get a mutable buffer sequence for writing
|
||||
auto const mb = buffer.prepare(1024);
|
||||
auto const b = buffer.prepare(1024);
|
||||
|
||||
// Try to get more from the istream. This might block.
|
||||
is.read(
|
||||
boost::asio::buffer_cast<char*>(mb),
|
||||
boost::asio::buffer_size(mb));
|
||||
is.read(reinterpret_cast<char*>(b.data()), b.size());
|
||||
|
||||
// If an error occurs on the istream then return it to the caller.
|
||||
if(is.fail() && ! is.eof())
|
||||
|
||||
+61
-83
@@ -23,7 +23,7 @@ auto
|
||||
async_echo(AsyncStream& stream, CompletionToken&& token)
|
||||
|
||||
//]
|
||||
-> boost::beast::async_return_type<CompletionToken, void(boost::beast::error_code)>;
|
||||
-> BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(boost::beast::error_code));
|
||||
|
||||
//[example_core_echo_op_2
|
||||
|
||||
@@ -61,14 +61,14 @@ async_echo(AsyncStream& stream, CompletionToken&& token)
|
||||
Regardless of whether the asynchronous operation completes
|
||||
immediately or not, the handler will not be invoked from within
|
||||
this function. Invocation of the handler will be performed in a
|
||||
manner equivalent to using `boost::asio::io_service::post`.
|
||||
manner equivalent to using `boost::asio::io_context::post`.
|
||||
*/
|
||||
template<
|
||||
class AsyncStream,
|
||||
class CompletionToken>
|
||||
boost::beast::async_return_type< /*< The [link beast.ref.boost__beast__async_return_type `async_return_type`] customizes the return value based on the completion token >*/
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE( /*< `BOOST_ASIO_INITFN_RESULT_TYPE` customizes the return value based on the completion token >*/
|
||||
CompletionToken,
|
||||
void(boost::beast::error_code)> /*< This is the signature for the completion handler >*/
|
||||
void(boost::beast::error_code)) /*< This is the signature for the completion handler >*/
|
||||
async_echo(
|
||||
AsyncStream& stream,
|
||||
CompletionToken&& token);
|
||||
@@ -95,11 +95,13 @@ class echo_op
|
||||
// The buffer used to hold the input and output data.
|
||||
//
|
||||
// We use a custom allocator for performance, this allows
|
||||
// the implementation of the io_service to make efficient
|
||||
// the implementation of the io_context to make efficient
|
||||
// re-use of memory allocated by composed operations during
|
||||
// a continuation.
|
||||
//
|
||||
boost::asio::basic_streambuf<boost::beast::handler_alloc<char, Handler>> buffer;
|
||||
boost::asio::basic_streambuf<typename std::allocator_traits<
|
||||
boost::asio::associated_allocator_t<Handler> >::
|
||||
template rebind_alloc<char> > buffer;
|
||||
|
||||
// handler_ptr requires that the first parameter to the
|
||||
// contained object constructor is a reference to the
|
||||
@@ -108,7 +110,7 @@ class echo_op
|
||||
explicit state(Handler& handler, AsyncStream& stream_)
|
||||
: stream(stream_)
|
||||
, buffer((std::numeric_limits<std::size_t>::max)(),
|
||||
boost::beast::handler_alloc<char, Handler>{handler})
|
||||
boost::asio::get_associated_allocator(handler))
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -116,14 +118,10 @@ class echo_op
|
||||
// The operation's data is kept in a cheap-to-copy smart
|
||||
// pointer container called `handler_ptr`. This efficiently
|
||||
// satisfies the CopyConstructible requirements of completion
|
||||
// handlers.
|
||||
// handlers with expensive-to-copy state.
|
||||
//
|
||||
// `handler_ptr` uses these memory allocation hooks associated
|
||||
// with the final completion handler, in order to allocate the
|
||||
// storage for `state`:
|
||||
//
|
||||
// asio_handler_allocate
|
||||
// asio_handler_deallocate
|
||||
// `handler_ptr` uses the allocator associated with the final
|
||||
// completion handler, in order to allocate the storage for `state`.
|
||||
//
|
||||
boost::beast::handler_ptr<state, Handler> p_;
|
||||
|
||||
@@ -144,30 +142,45 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
// Associated allocator support. This is Asio's system for
|
||||
// allowing the final completion handler to customize the
|
||||
// memory allocation strategy used for composed operation
|
||||
// states. A composed operation needs to use the same allocator
|
||||
// as the final handler. These declarations achieve that.
|
||||
|
||||
using allocator_type =
|
||||
boost::asio::associated_allocator_t<Handler>;
|
||||
|
||||
allocator_type
|
||||
get_allocator() const noexcept
|
||||
{
|
||||
return boost::asio::get_associated_allocator(p_.handler());
|
||||
}
|
||||
|
||||
// Executor hook. This is Asio's system for customizing the
|
||||
// manner in which asynchronous completion handlers are invoked.
|
||||
// A composed operation needs to use the same executor to invoke
|
||||
// intermediate completion handlers as that used to invoke the
|
||||
// final handler.
|
||||
|
||||
using executor_type = boost::asio::associated_executor_t<
|
||||
Handler, decltype(p_->stream.get_executor())>;
|
||||
|
||||
executor_type get_executor() const noexcept
|
||||
{
|
||||
return boost::asio::get_associated_executor(
|
||||
p_.handler(), p_->stream.get_executor());
|
||||
}
|
||||
|
||||
// (DEPRECATED)
|
||||
template<class AsyncStream_, class Handler_>
|
||||
friend bool asio_handler_is_continuation(
|
||||
echo_op<AsyncStream_, Handler_>* op);
|
||||
|
||||
// The entry point for this handler. This will get called
|
||||
// as our intermediate operations complete. Definition below.
|
||||
//
|
||||
void operator()(boost::beast::error_code ec, std::size_t bytes_transferred);
|
||||
|
||||
// The next four functions are required for our class
|
||||
// to meet the requirements for composed operations.
|
||||
// Definitions and exposition will follow.
|
||||
|
||||
template<class AsyncStream_, class Handler_, class Function>
|
||||
friend void asio_handler_invoke(
|
||||
Function&& f, echo_op<AsyncStream_, Handler_>* op);
|
||||
|
||||
template<class AsyncStream_, class Handler_>
|
||||
friend void* asio_handler_allocate(
|
||||
std::size_t size, echo_op<AsyncStream_, Handler_>* op);
|
||||
|
||||
template<class AsyncStream_, class Handler_>
|
||||
friend void asio_handler_deallocate(
|
||||
void* p, std::size_t size, echo_op<AsyncStream_, Handler_>* op);
|
||||
|
||||
template<class AsyncStream_, class Handler_>
|
||||
friend bool asio_handler_is_continuation(
|
||||
echo_op<AsyncStream_, Handler_>* op);
|
||||
};
|
||||
|
||||
//]
|
||||
@@ -226,44 +239,6 @@ operator()(boost::beast::error_code ec, std::size_t bytes_transferred)
|
||||
|
||||
//[example_core_echo_op_6
|
||||
|
||||
// Handler hook forwarding. These free functions invoke the hooks
|
||||
// associated with the final completion handler. In effect, they
|
||||
// make the Asio implementation treat our composed operation the
|
||||
// same way it would treat the final completion handler for the
|
||||
// purpose of memory allocation and invocation.
|
||||
//
|
||||
// Our implementation just passes the call through to the hook
|
||||
// associated with the final handler. The "using" statements are
|
||||
// structured to permit argument dependent lookup. Always use
|
||||
// `std::addressof` or its equivalent to pass the pointer to the
|
||||
// handler, otherwise an unwanted overload of `operator&` may be
|
||||
// called instead.
|
||||
|
||||
template<class AsyncStream, class Handler, class Function>
|
||||
void asio_handler_invoke(
|
||||
Function&& f, echo_op<AsyncStream, Handler>* op)
|
||||
{
|
||||
using boost::asio::asio_handler_invoke;
|
||||
return asio_handler_invoke(f, std::addressof(op->p_.handler()));
|
||||
}
|
||||
|
||||
template<class AsyncStream, class Handler>
|
||||
void* asio_handler_allocate(
|
||||
std::size_t size, echo_op<AsyncStream, Handler>* op)
|
||||
{
|
||||
using boost::asio::asio_handler_allocate;
|
||||
return asio_handler_allocate(size, std::addressof(op->p_.handler()));
|
||||
}
|
||||
|
||||
template<class AsyncStream, class Handler>
|
||||
void asio_handler_deallocate(
|
||||
void* p, std::size_t size, echo_op<AsyncStream, Handler>* op)
|
||||
{
|
||||
using boost::asio::asio_handler_deallocate;
|
||||
return asio_handler_deallocate(p, size,
|
||||
std::addressof(op->p_.handler()));
|
||||
}
|
||||
|
||||
// Determines if the next asynchronous operation represents a
|
||||
// continuation of the asynchronous flow of control associated
|
||||
// with the final handler. If we are past step one, it means
|
||||
@@ -297,7 +272,7 @@ class echo_op;
|
||||
// Read a line and echo it back
|
||||
//
|
||||
template<class AsyncStream, class CompletionToken>
|
||||
boost::beast::async_return_type<CompletionToken, void(boost::beast::error_code)>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(boost::beast::error_code))
|
||||
async_echo(AsyncStream& stream, CompletionToken&& token)
|
||||
{
|
||||
// Make sure stream meets the requirements. We use static_assert
|
||||
@@ -310,16 +285,20 @@ async_echo(AsyncStream& stream, CompletionToken&& token)
|
||||
// uses the result and handler specializations associated with
|
||||
// the completion token to help customize the return value.
|
||||
//
|
||||
boost::beast::async_completion<CompletionToken, void(boost::beast::error_code)> init{token};
|
||||
boost::asio::async_completion<CompletionToken, void(boost::beast::error_code)> init{token};
|
||||
|
||||
// Create the composed operation and launch it. This is a constructor
|
||||
// call followed by invocation of operator(). We use handler_type
|
||||
// call followed by invocation of operator(). We use BOOST_ASIO_HANDLER_TYPE
|
||||
// to convert the completion token into the correct handler type,
|
||||
// allowing user-defined specializations of the async_result template
|
||||
// to be used.
|
||||
//
|
||||
echo_op<AsyncStream, boost::beast::handler_type<CompletionToken, void(boost::beast::error_code)>>{
|
||||
stream, init.completion_handler}(boost::beast::error_code{}, 0);
|
||||
echo_op<
|
||||
AsyncStream,
|
||||
BOOST_ASIO_HANDLER_TYPE(
|
||||
CompletionToken, void(boost::beast::error_code))>{
|
||||
stream,
|
||||
init.completion_handler}(boost::beast::error_code{}, 0);
|
||||
|
||||
// This hook lets the caller see a return value when appropriate.
|
||||
// For example this might return std::future<error_code> if
|
||||
@@ -333,16 +312,15 @@ async_echo(AsyncStream& stream, CompletionToken&& token)
|
||||
|
||||
int main(int, char** argv)
|
||||
{
|
||||
using address_type = boost::asio::ip::address;
|
||||
using socket_type = boost::asio::ip::tcp::socket;
|
||||
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
||||
|
||||
// Create a listening socket, accept a connection, perform
|
||||
// the echo, and then shut everything down and exit.
|
||||
boost::asio::io_service ios;
|
||||
socket_type sock{ios};
|
||||
boost::asio::ip::tcp::acceptor acceptor{ios};
|
||||
endpoint_type ep{address_type::from_string("0.0.0.0"), 0};
|
||||
boost::asio::io_context ioc;
|
||||
socket_type sock{ioc};
|
||||
boost::asio::ip::tcp::acceptor acceptor{ioc};
|
||||
endpoint_type ep{boost::asio::ip::make_address("0.0.0.0"), 0};
|
||||
acceptor.open(ep.protocol());
|
||||
acceptor.bind(ep);
|
||||
acceptor.listen();
|
||||
@@ -353,6 +331,6 @@ int main(int, char** argv)
|
||||
if(ec)
|
||||
std::cerr << argv[0] << ": " << ec.message() << std::endl;
|
||||
});
|
||||
ios.run();
|
||||
ioc.run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -50,11 +50,11 @@ class session : public std::enable_shared_from_this<session>
|
||||
http::response<http::string_body> res_;
|
||||
|
||||
public:
|
||||
// Resolver and stream require an io_service
|
||||
// Resolver and stream require an io_context
|
||||
explicit
|
||||
session(boost::asio::io_service& ios, ssl::context& ctx)
|
||||
: resolver_(ios)
|
||||
, stream_(ios, ctx)
|
||||
session(boost::asio::io_context& ioc, ssl::context& ctx)
|
||||
: resolver_(ioc)
|
||||
, stream_(ioc, ctx)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -73,7 +73,9 @@ public:
|
||||
req_.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
|
||||
|
||||
// Look up the domain name
|
||||
resolver_.async_resolve({host, port},
|
||||
resolver_.async_resolve(
|
||||
host,
|
||||
port,
|
||||
std::bind(
|
||||
&session::on_resolve,
|
||||
shared_from_this(),
|
||||
@@ -84,7 +86,7 @@ public:
|
||||
void
|
||||
on_resolve(
|
||||
boost::system::error_code ec,
|
||||
tcp::resolver::iterator result)
|
||||
tcp::resolver::results_type results)
|
||||
{
|
||||
if(ec)
|
||||
return fail(ec, "resolve");
|
||||
@@ -92,7 +94,8 @@ public:
|
||||
// Make the connection on the IP address we get from a lookup
|
||||
boost::asio::async_connect(
|
||||
stream_.next_layer(),
|
||||
result,
|
||||
results.begin(),
|
||||
results.end(),
|
||||
std::bind(
|
||||
&session::on_connect,
|
||||
shared_from_this(),
|
||||
@@ -202,8 +205,8 @@ int main(int argc, char** argv)
|
||||
auto const port = argv[2];
|
||||
auto const target = argv[3];
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios;
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc;
|
||||
|
||||
// The SSL context is required, and holds certificates
|
||||
ssl::context ctx{ssl::context::sslv23_client};
|
||||
@@ -212,11 +215,11 @@ int main(int argc, char** argv)
|
||||
load_root_certificates(ctx);
|
||||
|
||||
// Launch the asynchronous operation
|
||||
std::make_shared<session>(ios, ctx)->run(host, port, target);
|
||||
std::make_shared<session>(ioc, ctx)->run(host, port, target);
|
||||
|
||||
// Run the I/O service. The call will return when
|
||||
// the get operation is complete.
|
||||
ios.run();
|
||||
ioc.run();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -46,11 +46,11 @@ class session : public std::enable_shared_from_this<session>
|
||||
http::response<http::string_body> res_;
|
||||
|
||||
public:
|
||||
// Resolver and socket require an io_service
|
||||
// Resolver and socket require an io_context
|
||||
explicit
|
||||
session(boost::asio::io_service& ios)
|
||||
: resolver_(ios)
|
||||
, socket_(ios)
|
||||
session(boost::asio::io_context& ioc)
|
||||
: resolver_(ioc)
|
||||
, socket_(ioc)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -69,7 +69,9 @@ public:
|
||||
req_.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
|
||||
|
||||
// Look up the domain name
|
||||
resolver_.async_resolve({host, port},
|
||||
resolver_.async_resolve(
|
||||
host,
|
||||
port,
|
||||
std::bind(
|
||||
&session::on_resolve,
|
||||
shared_from_this(),
|
||||
@@ -80,13 +82,16 @@ public:
|
||||
void
|
||||
on_resolve(
|
||||
boost::system::error_code ec,
|
||||
tcp::resolver::iterator result)
|
||||
tcp::resolver::results_type results)
|
||||
{
|
||||
if(ec)
|
||||
return fail(ec, "resolve");
|
||||
|
||||
// Make the connection on the IP address we get from a lookup
|
||||
boost::asio::async_connect(socket_, result,
|
||||
boost::asio::async_connect(
|
||||
socket_,
|
||||
results.begin(),
|
||||
results.end(),
|
||||
std::bind(
|
||||
&session::on_connect,
|
||||
shared_from_this(),
|
||||
@@ -168,15 +173,15 @@ int main(int argc, char** argv)
|
||||
auto const port = argv[2];
|
||||
auto const target = argv[3];
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios;
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc;
|
||||
|
||||
// Launch the asynchronous operation
|
||||
std::make_shared<session>(ios)->run(host, port, target);
|
||||
std::make_shared<session>(ioc)->run(host, port, target);
|
||||
|
||||
// Run the I/O service. The call will return when
|
||||
// the get operation is complete.
|
||||
ios.run();
|
||||
ioc.run();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -46,23 +46,23 @@ do_session(
|
||||
std::string const& host,
|
||||
std::string const& port,
|
||||
std::string const& target,
|
||||
boost::asio::io_service& ios,
|
||||
boost::asio::io_context& ioc,
|
||||
ssl::context& ctx,
|
||||
boost::asio::yield_context yield)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
|
||||
// These objects perform our I/O
|
||||
tcp::resolver resolver{ios};
|
||||
ssl::stream<tcp::socket> stream{ios, ctx};
|
||||
tcp::resolver resolver{ioc};
|
||||
ssl::stream<tcp::socket> stream{ioc, ctx};
|
||||
|
||||
// Look up the domain name
|
||||
auto const lookup = resolver.async_resolve({host, port}, yield[ec]);
|
||||
auto const results = resolver.async_resolve(host, port, yield[ec]);
|
||||
if(ec)
|
||||
return fail(ec, "resolve");
|
||||
|
||||
// Make the connection on the IP address we get from a lookup
|
||||
boost::asio::async_connect(stream.next_layer(), lookup, yield[ec]);
|
||||
boost::asio::async_connect(stream.next_layer(), results.begin(), results.end(), yield[ec]);
|
||||
if(ec)
|
||||
return fail(ec, "connect");
|
||||
|
||||
@@ -126,8 +126,8 @@ int main(int argc, char** argv)
|
||||
auto const port = argv[2];
|
||||
auto const target = argv[3];
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios;
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc;
|
||||
|
||||
// The SSL context is required, and holds certificates
|
||||
ssl::context ctx{ssl::context::sslv23_client};
|
||||
@@ -136,18 +136,18 @@ int main(int argc, char** argv)
|
||||
load_root_certificates(ctx);
|
||||
|
||||
// Launch the asynchronous operation
|
||||
boost::asio::spawn(ios, std::bind(
|
||||
boost::asio::spawn(ioc, std::bind(
|
||||
&do_session,
|
||||
std::string(host),
|
||||
std::string(port),
|
||||
std::string(target),
|
||||
std::ref(ios),
|
||||
std::ref(ioc),
|
||||
std::ref(ctx),
|
||||
std::placeholders::_1));
|
||||
|
||||
// Run the I/O service. The call will return when
|
||||
// the get operation is complete.
|
||||
ios.run();
|
||||
ioc.run();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -42,22 +42,22 @@ do_session(
|
||||
std::string const& host,
|
||||
std::string const& port,
|
||||
std::string const& target,
|
||||
boost::asio::io_service& ios,
|
||||
boost::asio::io_context& ioc,
|
||||
boost::asio::yield_context yield)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
|
||||
// These objects perform our I/O
|
||||
tcp::resolver resolver{ios};
|
||||
tcp::socket socket{ios};
|
||||
tcp::resolver resolver{ioc};
|
||||
tcp::socket socket{ioc};
|
||||
|
||||
// Look up the domain name
|
||||
auto const lookup = resolver.async_resolve({host, port}, yield[ec]);
|
||||
auto const results = resolver.async_resolve(host, port, yield[ec]);
|
||||
if(ec)
|
||||
return fail(ec, "resolve");
|
||||
|
||||
// Make the connection on the IP address we get from a lookup
|
||||
boost::asio::async_connect(socket, lookup, yield[ec]);
|
||||
boost::asio::async_connect(socket, results.begin(), results.end(), yield[ec]);
|
||||
if(ec)
|
||||
return fail(ec, "connect");
|
||||
|
||||
@@ -114,21 +114,21 @@ int main(int argc, char** argv)
|
||||
auto const port = argv[2];
|
||||
auto const target = argv[3];
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios;
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc;
|
||||
|
||||
// Launch the asynchronous operation
|
||||
boost::asio::spawn(ios, std::bind(
|
||||
boost::asio::spawn(ioc, std::bind(
|
||||
&do_session,
|
||||
std::string(host),
|
||||
std::string(port),
|
||||
std::string(target),
|
||||
std::ref(ios),
|
||||
std::ref(ioc),
|
||||
std::placeholders::_1));
|
||||
|
||||
// Run the I/O service. The call will return when
|
||||
// the get operation is complete.
|
||||
ios.run();
|
||||
ioc.run();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -18,10 +18,11 @@
|
||||
#include <boost/beast/core.hpp>
|
||||
#include <boost/beast/http.hpp>
|
||||
#include <boost/beast/version.hpp>
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/asio/connect.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cstdlib>
|
||||
@@ -43,16 +44,17 @@ namespace chrono = std::chrono; // from <chrono>
|
||||
// This structure aggregates statistics on all the sites
|
||||
class crawl_report
|
||||
{
|
||||
boost::asio::io_service& ios_;
|
||||
boost::asio::io_service::strand strand_;
|
||||
boost::asio::io_context& ioc_;
|
||||
boost::asio::strand<
|
||||
boost::asio::io_context::executor_type> strand_;
|
||||
std::atomic<std::size_t> index_;
|
||||
std::vector<char const*> const& hosts_;
|
||||
std::size_t count_ = 0;
|
||||
|
||||
public:
|
||||
crawl_report(boost::asio::io_service& ios)
|
||||
: ios_(ios)
|
||||
, strand_(ios_)
|
||||
crawl_report(boost::asio::io_context& ioc)
|
||||
: ioc_(ioc)
|
||||
, strand_(ioc_.get_executor())
|
||||
, index_(0)
|
||||
, hosts_(urls_large_data())
|
||||
{
|
||||
@@ -64,18 +66,19 @@ public:
|
||||
void
|
||||
aggregate(F const& f)
|
||||
{
|
||||
ios_.post(strand_.wrap(
|
||||
[&, f]
|
||||
{
|
||||
f(*this);
|
||||
if(count_ % 100 == 0)
|
||||
boost::asio::post(
|
||||
strand_,
|
||||
[&, f]
|
||||
{
|
||||
std::cerr <<
|
||||
"Progress: " << count_ << " of " << hosts_.size() << "\n";
|
||||
//std::cerr << *this;
|
||||
}
|
||||
++count_;
|
||||
}));
|
||||
f(*this);
|
||||
if(count_ % 100 == 0)
|
||||
{
|
||||
std::cerr <<
|
||||
"Progress: " << count_ << " of " << hosts_.size() << "\n";
|
||||
//std::cerr << *this;
|
||||
}
|
||||
++count_;
|
||||
});
|
||||
}
|
||||
|
||||
// Returns the next host to check
|
||||
@@ -148,7 +151,8 @@ class worker : public std::enable_shared_from_this<worker>
|
||||
tcp::resolver resolver_;
|
||||
tcp::socket socket_;
|
||||
boost::asio::steady_timer timer_;
|
||||
boost::asio::io_service::strand strand_;
|
||||
boost::asio::strand<
|
||||
boost::asio::io_context::executor_type> strand_;
|
||||
boost::beast::flat_buffer buffer_; // (Must persist between reads)
|
||||
http::request<http::empty_body> req_;
|
||||
http::response<http::string_body> res_;
|
||||
@@ -156,16 +160,16 @@ class worker : public std::enable_shared_from_this<worker>
|
||||
public:
|
||||
worker(worker&&) = default;
|
||||
|
||||
// Resolver and socket require an io_service
|
||||
// Resolver and socket require an io_context
|
||||
worker(
|
||||
crawl_report& report,
|
||||
boost::asio::io_service& ios)
|
||||
boost::asio::io_context& ioc)
|
||||
: report_(report)
|
||||
, resolver_(ios)
|
||||
, socket_(ios)
|
||||
, timer_(ios,
|
||||
, resolver_(ioc)
|
||||
, socket_(ioc)
|
||||
, timer_(ioc,
|
||||
(chrono::steady_clock::time_point::max)())
|
||||
, strand_(ios)
|
||||
, strand_(ioc.get_executor())
|
||||
{
|
||||
// Set up the common fields of the request
|
||||
req_.version(11);
|
||||
@@ -200,7 +204,7 @@ public:
|
||||
}
|
||||
|
||||
// Verify that the timer really expired since the deadline may have moved.
|
||||
if(timer_.expires_at() <= chrono::steady_clock::now())
|
||||
if(timer_.expiry() <= chrono::steady_clock::now())
|
||||
{
|
||||
socket_.shutdown(tcp::socket::shutdown_both, ec);
|
||||
socket_.close(ec);
|
||||
@@ -209,10 +213,12 @@ public:
|
||||
|
||||
// Wait on the timer
|
||||
timer_.async_wait(
|
||||
strand_.wrap(std::bind(
|
||||
&worker::on_timer,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&worker::on_timer,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -224,8 +230,7 @@ public:
|
||||
// nullptr means no more work
|
||||
if(! host)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
timer_.cancel(ec);
|
||||
timer_.cancel_one();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -233,23 +238,26 @@ public:
|
||||
req_.set(http::field::host, host);
|
||||
|
||||
// Set the timer
|
||||
timer_.expires_from_now(chrono::seconds(timeout));
|
||||
timer_.expires_after(chrono::seconds(timeout));
|
||||
|
||||
// Set up an HTTP GET request message
|
||||
// Look up the domain name
|
||||
resolver_.async_resolve(
|
||||
tcp::resolver::query{host, "http"},
|
||||
strand_.wrap(std::bind(
|
||||
&worker::on_resolve,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
host,
|
||||
"http",
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&worker::on_resolve,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
}
|
||||
|
||||
void
|
||||
on_resolve(
|
||||
boost::system::error_code ec,
|
||||
tcp::resolver::iterator result)
|
||||
tcp::resolver::results_type results)
|
||||
{
|
||||
if(ec)
|
||||
{
|
||||
@@ -262,16 +270,19 @@ public:
|
||||
}
|
||||
|
||||
// Set the timer
|
||||
timer_.expires_from_now(chrono::seconds(timeout));
|
||||
timer_.expires_after(chrono::seconds(timeout));
|
||||
|
||||
// Make the connection on the IP address we get from a lookup
|
||||
boost::asio::async_connect(
|
||||
socket_,
|
||||
result,
|
||||
strand_.wrap(std::bind(
|
||||
&worker::on_connect,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
results.begin(),
|
||||
results.end(),
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&worker::on_connect,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -288,17 +299,19 @@ public:
|
||||
}
|
||||
|
||||
// Set the timer
|
||||
timer_.expires_from_now(chrono::seconds(timeout));
|
||||
timer_.expires_after(chrono::seconds(timeout));
|
||||
|
||||
// Send the HTTP request to the remote host
|
||||
http::async_write(
|
||||
socket_,
|
||||
req_,
|
||||
strand_.wrap(std::bind(
|
||||
&worker::on_write,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&worker::on_write,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -319,18 +332,20 @@ public:
|
||||
}
|
||||
|
||||
// Set the timer
|
||||
timer_.expires_from_now(chrono::seconds(timeout));
|
||||
timer_.expires_after(chrono::seconds(timeout));
|
||||
|
||||
// Receive the HTTP response
|
||||
http::async_read(
|
||||
socket_,
|
||||
buffer_,
|
||||
res_,
|
||||
strand_.wrap(std::bind(
|
||||
&worker::on_read,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&worker::on_read,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -400,41 +415,41 @@ int main(int argc, char* argv[])
|
||||
" http-crawl 100 1\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto const threads = std::max<std::size_t>(1, std::atoi(argv[1]));
|
||||
auto const threads = std::max<int>(1, std::atoi(argv[1]));
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios{1};
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc{1};
|
||||
|
||||
// The work keeps io_service::run from returning
|
||||
boost::optional<boost::asio::io_service::work> work{ios};
|
||||
// The work keeps io_context::run from returning
|
||||
auto work = boost::asio::make_work_guard(ioc);
|
||||
|
||||
// The report holds the aggregated statistics
|
||||
crawl_report report{ios};
|
||||
crawl_report report{ioc};
|
||||
|
||||
timer t;
|
||||
|
||||
// Create and launch the worker threads.
|
||||
std::vector<std::thread> workers;
|
||||
workers.reserve(threads + 1);
|
||||
for(std::size_t i = 0; i < threads; ++i)
|
||||
for(int i = 0; i < threads; ++i)
|
||||
workers.emplace_back(
|
||||
[&report]
|
||||
{
|
||||
// We use a separate io_service for each worker because
|
||||
// We use a separate io_context for each worker because
|
||||
// the asio resolver simulates asynchronous operation using
|
||||
// a dedicated worker thread per io_service, and we want to
|
||||
// a dedicated worker thread per io_context, and we want to
|
||||
// do a lot of name resolutions in parallel.
|
||||
boost::asio::io_service ios{1};
|
||||
std::make_shared<worker>(report, ios)->run();
|
||||
ios.run();
|
||||
boost::asio::io_context ioc{1};
|
||||
std::make_shared<worker>(report, ioc)->run();
|
||||
ioc.run();
|
||||
});
|
||||
|
||||
// Add another thread to run the main io_service which
|
||||
// Add another thread to run the main io_context which
|
||||
// is used to aggregate the statistics
|
||||
workers.emplace_back(
|
||||
[&ios]
|
||||
[&ioc]
|
||||
{
|
||||
ios.run();
|
||||
ioc.run();
|
||||
});
|
||||
|
||||
// Now block until all threads exit
|
||||
@@ -442,11 +457,10 @@ int main(int argc, char* argv[])
|
||||
{
|
||||
auto& thread = workers[i];
|
||||
|
||||
// If this is the last thread, destroy the
|
||||
// If this is the last thread, reset the
|
||||
// work object so that it can return from run.
|
||||
//if(&thread == &workers.back())
|
||||
if(i == workers.size() - 1)
|
||||
work = boost::none;
|
||||
work.reset();
|
||||
|
||||
// Wait for the thread to exit
|
||||
thread.join();
|
||||
|
||||
@@ -47,8 +47,8 @@ int main(int argc, char** argv)
|
||||
auto const port = argv[2];
|
||||
auto const target = argv[3];
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios;
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc;
|
||||
|
||||
// The SSL context is required, and holds certificates
|
||||
ssl::context ctx{ssl::context::sslv23_client};
|
||||
@@ -57,14 +57,14 @@ int main(int argc, char** argv)
|
||||
load_root_certificates(ctx);
|
||||
|
||||
// These objects perform our I/O
|
||||
tcp::resolver resolver{ios};
|
||||
ssl::stream<tcp::socket> stream{ios, ctx};
|
||||
tcp::resolver resolver{ioc};
|
||||
ssl::stream<tcp::socket> stream{ioc, ctx};
|
||||
|
||||
// Look up the domain name
|
||||
auto const lookup = resolver.resolve({host, port});
|
||||
auto const results = resolver.resolve(host, port);
|
||||
|
||||
// Make the connection on the IP address we get from a lookup
|
||||
boost::asio::connect(stream.next_layer(), lookup);
|
||||
boost::asio::connect(stream.next_layer(), results.begin(), results.end());
|
||||
|
||||
// Perform the SSL handshake
|
||||
stream.handshake(ssl::stream_base::client);
|
||||
|
||||
@@ -45,18 +45,18 @@ int main(int argc, char** argv)
|
||||
auto const port = argv[2];
|
||||
auto const target = argv[3];
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios;
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc;
|
||||
|
||||
// These objects perform our I/O
|
||||
tcp::resolver resolver{ios};
|
||||
tcp::socket socket{ios};
|
||||
tcp::resolver resolver{ioc};
|
||||
tcp::socket socket{ioc};
|
||||
|
||||
// Look up the domain name
|
||||
auto const lookup = resolver.resolve({host, port});
|
||||
auto const results = resolver.resolve(host, port);
|
||||
|
||||
// Make the connection on the IP address we get from a lookup
|
||||
boost::asio::connect(socket, lookup);
|
||||
boost::asio::connect(socket, results.begin(), results.end());
|
||||
|
||||
// Set up an HTTP GET request message
|
||||
http::request<http::string_body> req{http::verb::get, target, 11};
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <boost/beast/core.hpp>
|
||||
#include <boost/beast/http.hpp>
|
||||
#include <boost/beast/version.hpp>
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/ssl/stream.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
@@ -244,18 +245,21 @@ class session : public std::enable_shared_from_this<session>
|
||||
http::async_write(
|
||||
self_.stream_,
|
||||
*sp,
|
||||
self_.strand_.wrap(std::bind(
|
||||
&session::on_write,
|
||||
self_.shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2,
|
||||
! sp->keep_alive())));
|
||||
boost::asio::bind_executor(
|
||||
self_.strand_,
|
||||
std::bind(
|
||||
&session::on_write,
|
||||
self_.shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2,
|
||||
! sp->keep_alive())));
|
||||
}
|
||||
};
|
||||
|
||||
tcp::socket socket_;
|
||||
ssl::stream<tcp::socket&> stream_;
|
||||
boost::asio::io_service::strand strand_;
|
||||
boost::asio::strand<
|
||||
boost::asio::io_context::executor_type> strand_;
|
||||
boost::beast::flat_buffer buffer_;
|
||||
std::string const& doc_root_;
|
||||
http::request<http::string_body> req_;
|
||||
@@ -271,7 +275,7 @@ public:
|
||||
std::string const& doc_root)
|
||||
: socket_(std::move(socket))
|
||||
, stream_(socket_, ctx)
|
||||
, strand_(socket_.get_io_service())
|
||||
, strand_(socket_.get_executor())
|
||||
, doc_root_(doc_root)
|
||||
, lambda_(*this)
|
||||
{
|
||||
@@ -284,10 +288,12 @@ public:
|
||||
// Perform the SSL handshake
|
||||
stream_.async_handshake(
|
||||
ssl::stream_base::server,
|
||||
strand_.wrap(std::bind(
|
||||
&session::on_handshake,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::on_handshake,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -304,11 +310,13 @@ public:
|
||||
{
|
||||
// Read a request
|
||||
http::async_read(stream_, buffer_, req_,
|
||||
strand_.wrap(std::bind(
|
||||
&session::on_read,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::on_read,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -359,10 +367,12 @@ public:
|
||||
{
|
||||
// Perform the SSL shutdown
|
||||
stream_.async_shutdown(
|
||||
strand_.wrap(std::bind(
|
||||
&session::on_shutdown,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::on_shutdown,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -387,13 +397,13 @@ class listener : public std::enable_shared_from_this<listener>
|
||||
|
||||
public:
|
||||
listener(
|
||||
boost::asio::io_service& ios,
|
||||
boost::asio::io_context& ioc,
|
||||
ssl::context& ctx,
|
||||
tcp::endpoint endpoint,
|
||||
std::string const& doc_root)
|
||||
: ctx_(ctx)
|
||||
, acceptor_(ios)
|
||||
, socket_(ios)
|
||||
, acceptor_(ioc)
|
||||
, socket_(ioc)
|
||||
, doc_root_(doc_root)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
@@ -416,7 +426,7 @@ public:
|
||||
|
||||
// Start listening for connections
|
||||
acceptor_.listen(
|
||||
boost::asio::socket_base::max_connections, ec);
|
||||
boost::asio::socket_base::max_listen_connections, ec);
|
||||
if(ec)
|
||||
{
|
||||
fail(ec, "listen");
|
||||
@@ -478,13 +488,13 @@ int main(int argc, char* argv[])
|
||||
" http-server-async-ssl 0.0.0.0 8080 . 1\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto const address = boost::asio::ip::address::from_string(argv[1]);
|
||||
auto const address = boost::asio::ip::make_address(argv[1]);
|
||||
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
|
||||
std::string const doc_root = argv[3];
|
||||
auto const threads = std::max<std::size_t>(1, std::atoi(argv[4]));
|
||||
auto const threads = std::max<int>(1, std::atoi(argv[4]));
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios{threads};
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc{threads};
|
||||
|
||||
// The SSL context is required, and holds certificates
|
||||
ssl::context ctx{ssl::context::sslv23};
|
||||
@@ -494,7 +504,7 @@ int main(int argc, char* argv[])
|
||||
|
||||
// Create and launch a listening port
|
||||
std::make_shared<listener>(
|
||||
ios,
|
||||
ioc,
|
||||
ctx,
|
||||
tcp::endpoint{address, port},
|
||||
doc_root)->run();
|
||||
@@ -504,11 +514,11 @@ int main(int argc, char* argv[])
|
||||
v.reserve(threads - 1);
|
||||
for(auto i = threads - 1; i > 0; --i)
|
||||
v.emplace_back(
|
||||
[&ios]
|
||||
[&ioc]
|
||||
{
|
||||
ios.run();
|
||||
ioc.run();
|
||||
});
|
||||
ios.run();
|
||||
ioc.run();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <boost/beast/core.hpp>
|
||||
#include <boost/beast/http.hpp>
|
||||
#include <boost/beast/version.hpp>
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <boost/config.hpp>
|
||||
@@ -240,17 +241,20 @@ class session : public std::enable_shared_from_this<session>
|
||||
http::async_write(
|
||||
self_.socket_,
|
||||
*sp,
|
||||
self_.strand_.wrap(std::bind(
|
||||
&session::on_write,
|
||||
self_.shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2,
|
||||
! sp->keep_alive())));
|
||||
boost::asio::bind_executor(
|
||||
self_.strand_,
|
||||
std::bind(
|
||||
&session::on_write,
|
||||
self_.shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2,
|
||||
! sp->keep_alive())));
|
||||
}
|
||||
};
|
||||
|
||||
tcp::socket socket_;
|
||||
boost::asio::io_service::strand strand_;
|
||||
boost::asio::strand<
|
||||
boost::asio::io_context::executor_type> strand_;
|
||||
boost::beast::flat_buffer buffer_;
|
||||
std::string const& doc_root_;
|
||||
http::request<http::string_body> req_;
|
||||
@@ -264,7 +268,7 @@ public:
|
||||
tcp::socket socket,
|
||||
std::string const& doc_root)
|
||||
: socket_(std::move(socket))
|
||||
, strand_(socket_.get_io_service())
|
||||
, strand_(socket_.get_executor())
|
||||
, doc_root_(doc_root)
|
||||
, lambda_(*this)
|
||||
{
|
||||
@@ -282,11 +286,13 @@ public:
|
||||
{
|
||||
// Read a request
|
||||
http::async_read(socket_, buffer_, req_,
|
||||
strand_.wrap(std::bind(
|
||||
&session::on_read,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::on_read,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -354,11 +360,11 @@ class listener : public std::enable_shared_from_this<listener>
|
||||
|
||||
public:
|
||||
listener(
|
||||
boost::asio::io_service& ios,
|
||||
boost::asio::io_context& ioc,
|
||||
tcp::endpoint endpoint,
|
||||
std::string const& doc_root)
|
||||
: acceptor_(ios)
|
||||
, socket_(ios)
|
||||
: acceptor_(ioc)
|
||||
, socket_(ioc)
|
||||
, doc_root_(doc_root)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
@@ -381,7 +387,7 @@ public:
|
||||
|
||||
// Start listening for connections
|
||||
acceptor_.listen(
|
||||
boost::asio::socket_base::max_connections, ec);
|
||||
boost::asio::socket_base::max_listen_connections, ec);
|
||||
if(ec)
|
||||
{
|
||||
fail(ec, "listen");
|
||||
@@ -442,17 +448,17 @@ int main(int argc, char* argv[])
|
||||
" http-server-async 0.0.0.0 8080 . 1\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto const address = boost::asio::ip::address::from_string(argv[1]);
|
||||
auto const address = boost::asio::ip::make_address(argv[1]);
|
||||
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
|
||||
std::string const doc_root = argv[3];
|
||||
auto const threads = std::max<std::size_t>(1, std::atoi(argv[4]));
|
||||
auto const threads = std::max<int>(1, std::atoi(argv[4]));
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios{threads};
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc{threads};
|
||||
|
||||
// Create and launch a listening port
|
||||
std::make_shared<listener>(
|
||||
ios,
|
||||
ioc,
|
||||
tcp::endpoint{address, port},
|
||||
doc_root)->run();
|
||||
|
||||
@@ -461,11 +467,11 @@ int main(int argc, char* argv[])
|
||||
v.reserve(threads - 1);
|
||||
for(auto i = threads - 1; i > 0; --i)
|
||||
v.emplace_back(
|
||||
[&ios]
|
||||
[&ioc]
|
||||
{
|
||||
ios.run();
|
||||
ioc.run();
|
||||
});
|
||||
ios.run();
|
||||
ioc.run();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -308,7 +308,7 @@ do_session(
|
||||
// Accepts incoming connections and launches the sessions
|
||||
void
|
||||
do_listen(
|
||||
boost::asio::io_service& ios,
|
||||
boost::asio::io_context& ioc,
|
||||
ssl::context& ctx,
|
||||
tcp::endpoint endpoint,
|
||||
std::string const& doc_root,
|
||||
@@ -317,7 +317,7 @@ do_listen(
|
||||
boost::system::error_code ec;
|
||||
|
||||
// Open the acceptor
|
||||
tcp::acceptor acceptor(ios);
|
||||
tcp::acceptor acceptor(ioc);
|
||||
acceptor.open(endpoint.protocol(), ec);
|
||||
if(ec)
|
||||
return fail(ec, "open");
|
||||
@@ -328,19 +328,19 @@ do_listen(
|
||||
return fail(ec, "bind");
|
||||
|
||||
// Start listening for connections
|
||||
acceptor.listen(boost::asio::socket_base::max_connections, ec);
|
||||
acceptor.listen(boost::asio::socket_base::max_listen_connections, ec);
|
||||
if(ec)
|
||||
return fail(ec, "listen");
|
||||
|
||||
for(;;)
|
||||
{
|
||||
tcp::socket socket(ios);
|
||||
tcp::socket socket(ioc);
|
||||
acceptor.async_accept(socket, yield[ec]);
|
||||
if(ec)
|
||||
fail(ec, "accept");
|
||||
else
|
||||
boost::asio::spawn(
|
||||
acceptor.get_io_service(),
|
||||
acceptor.get_executor().context(),
|
||||
std::bind(
|
||||
&do_session,
|
||||
std::move(socket),
|
||||
@@ -361,13 +361,13 @@ int main(int argc, char* argv[])
|
||||
" http-server-coro-ssl 0.0.0.0 8080 . 1\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto const address = boost::asio::ip::address::from_string(argv[1]);
|
||||
auto const address = boost::asio::ip::make_address(argv[1]);
|
||||
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
|
||||
std::string const doc_root = argv[3];
|
||||
auto const threads = std::max<std::size_t>(1, std::atoi(argv[4]));
|
||||
auto const threads = std::max<int>(1, std::atoi(argv[4]));
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios{threads};
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc{threads};
|
||||
|
||||
// The SSL context is required, and holds certificates
|
||||
ssl::context ctx{ssl::context::sslv23};
|
||||
@@ -376,10 +376,10 @@ int main(int argc, char* argv[])
|
||||
load_server_certificate(ctx);
|
||||
|
||||
// Spawn a listening port
|
||||
boost::asio::spawn(ios,
|
||||
boost::asio::spawn(ioc,
|
||||
std::bind(
|
||||
&do_listen,
|
||||
std::ref(ios),
|
||||
std::ref(ioc),
|
||||
std::ref(ctx),
|
||||
tcp::endpoint{address, port},
|
||||
doc_root,
|
||||
@@ -390,11 +390,11 @@ int main(int argc, char* argv[])
|
||||
v.reserve(threads - 1);
|
||||
for(auto i = threads - 1; i > 0; --i)
|
||||
v.emplace_back(
|
||||
[&ios]
|
||||
[&ioc]
|
||||
{
|
||||
ios.run();
|
||||
ioc.run();
|
||||
});
|
||||
ios.run();
|
||||
ioc.run();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -293,7 +293,7 @@ do_session(
|
||||
// Accepts incoming connections and launches the sessions
|
||||
void
|
||||
do_listen(
|
||||
boost::asio::io_service& ios,
|
||||
boost::asio::io_context& ioc,
|
||||
tcp::endpoint endpoint,
|
||||
std::string const& doc_root,
|
||||
boost::asio::yield_context yield)
|
||||
@@ -301,7 +301,7 @@ do_listen(
|
||||
boost::system::error_code ec;
|
||||
|
||||
// Open the acceptor
|
||||
tcp::acceptor acceptor(ios);
|
||||
tcp::acceptor acceptor(ioc);
|
||||
acceptor.open(endpoint.protocol(), ec);
|
||||
if(ec)
|
||||
return fail(ec, "open");
|
||||
@@ -312,19 +312,19 @@ do_listen(
|
||||
return fail(ec, "bind");
|
||||
|
||||
// Start listening for connections
|
||||
acceptor.listen(boost::asio::socket_base::max_connections, ec);
|
||||
acceptor.listen(boost::asio::socket_base::max_listen_connections, ec);
|
||||
if(ec)
|
||||
return fail(ec, "listen");
|
||||
|
||||
for(;;)
|
||||
{
|
||||
tcp::socket socket(ios);
|
||||
tcp::socket socket(ioc);
|
||||
acceptor.async_accept(socket, yield[ec]);
|
||||
if(ec)
|
||||
fail(ec, "accept");
|
||||
else
|
||||
boost::asio::spawn(
|
||||
acceptor.get_io_service(),
|
||||
acceptor.get_executor().context(),
|
||||
std::bind(
|
||||
&do_session,
|
||||
std::move(socket),
|
||||
@@ -344,19 +344,19 @@ int main(int argc, char* argv[])
|
||||
" http-server-coro 0.0.0.0 8080 . 1\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto const address = boost::asio::ip::address::from_string(argv[1]);
|
||||
auto const address = boost::asio::ip::make_address(argv[1]);
|
||||
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
|
||||
std::string const doc_root = argv[3];
|
||||
auto const threads = std::max<std::size_t>(1, std::atoi(argv[4]));
|
||||
auto const threads = std::max<int>(1, std::atoi(argv[4]));
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios{threads};
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc{threads};
|
||||
|
||||
// Spawn a listening port
|
||||
boost::asio::spawn(ios,
|
||||
boost::asio::spawn(ioc,
|
||||
std::bind(
|
||||
&do_listen,
|
||||
std::ref(ios),
|
||||
std::ref(ioc),
|
||||
tcp::endpoint{address, port},
|
||||
doc_root,
|
||||
std::placeholders::_1));
|
||||
@@ -366,11 +366,11 @@ int main(int argc, char* argv[])
|
||||
v.reserve(threads - 1);
|
||||
for(auto i = threads - 1; i > 0; --i)
|
||||
v.emplace_back(
|
||||
[&ios]
|
||||
[&ioc]
|
||||
{
|
||||
ios.run();
|
||||
ioc.run();
|
||||
});
|
||||
ios.run();
|
||||
ioc.run();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ private:
|
||||
std::string doc_root_;
|
||||
|
||||
// The socket for the currently connected client.
|
||||
tcp::socket socket_{acceptor_.get_io_service()};
|
||||
tcp::socket socket_{acceptor_.get_executor().context()};
|
||||
|
||||
// The buffer for performing reads
|
||||
boost::beast::flat_static_buffer<8192> buffer_;
|
||||
@@ -110,7 +110,7 @@ private:
|
||||
|
||||
// The timer putting a time limit on requests.
|
||||
boost::asio::basic_waitable_timer<std::chrono::steady_clock> request_deadline_{
|
||||
acceptor_.get_io_service(), (std::chrono::steady_clock::time_point::max)()};
|
||||
acceptor_.get_executor().context(), (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_;
|
||||
@@ -142,7 +142,7 @@ private:
|
||||
else
|
||||
{
|
||||
// Request must be fully processed within 60 seconds.
|
||||
request_deadline_.expires_from_now(
|
||||
request_deadline_.expires_after(
|
||||
std::chrono::seconds(60));
|
||||
|
||||
read_request();
|
||||
@@ -288,7 +288,7 @@ private:
|
||||
void check_deadline()
|
||||
{
|
||||
// The deadline may have moved, so check it has really passed.
|
||||
if (request_deadline_.expires_at() <= std::chrono::steady_clock::now())
|
||||
if (request_deadline_.expiry() <= std::chrono::steady_clock::now())
|
||||
{
|
||||
// Close socket to cancel any outstanding operation.
|
||||
boost::beast::error_code ec;
|
||||
@@ -322,14 +322,14 @@ int main(int argc, char* argv[])
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
auto address = ip::address::from_string(argv[1]);
|
||||
auto const address = boost::asio::ip::make_address(argv[1]);
|
||||
unsigned short port = static_cast<unsigned short>(std::atoi(argv[2]));
|
||||
std::string doc_root = argv[3];
|
||||
int num_workers = std::atoi(argv[4]);
|
||||
bool spin = (std::strcmp(argv[5], "spin") == 0);
|
||||
|
||||
boost::asio::io_service ios{1};
|
||||
tcp::acceptor acceptor{ios, {address, port}};
|
||||
boost::asio::io_context ioc{1};
|
||||
tcp::acceptor acceptor{ioc, {address, port}};
|
||||
|
||||
std::list<http_worker> workers;
|
||||
for (int i = 0; i < num_workers; ++i)
|
||||
@@ -339,9 +339,9 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
|
||||
if (spin)
|
||||
for (;;) ios.poll();
|
||||
for (;;) ioc.poll();
|
||||
else
|
||||
ios.run();
|
||||
ioc.run();
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <boost/beast/core.hpp>
|
||||
#include <boost/beast/http.hpp>
|
||||
#include <boost/beast/version.hpp>
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/ssl/stream.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
@@ -255,12 +256,14 @@ class session
|
||||
http::async_write(
|
||||
self_.derived().stream(),
|
||||
*sp,
|
||||
self_.strand_.wrap(std::bind(
|
||||
&session::on_write,
|
||||
self_.derived().shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2,
|
||||
! sp->keep_alive())));
|
||||
boost::asio::bind_executor(
|
||||
self_.strand_,
|
||||
std::bind(
|
||||
&session::on_write,
|
||||
self_.derived().shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2,
|
||||
! sp->keep_alive())));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -270,19 +273,20 @@ class session
|
||||
send_lambda lambda_;
|
||||
|
||||
protected:
|
||||
boost::asio::io_service::strand strand_;
|
||||
boost::asio::strand<
|
||||
boost::asio::io_context::executor_type> strand_;
|
||||
boost::beast::flat_buffer buffer_;
|
||||
|
||||
public:
|
||||
// Take ownership of the buffer
|
||||
explicit
|
||||
session(
|
||||
boost::asio::io_service& ios,
|
||||
boost::asio::io_context& ioc,
|
||||
boost::beast::flat_buffer buffer,
|
||||
std::string const& doc_root)
|
||||
: doc_root_(doc_root)
|
||||
, lambda_(*this)
|
||||
, strand_(ios)
|
||||
, strand_(ioc.get_executor())
|
||||
, buffer_(std::move(buffer))
|
||||
{
|
||||
}
|
||||
@@ -295,11 +299,13 @@ public:
|
||||
derived().stream(),
|
||||
buffer_,
|
||||
req_,
|
||||
strand_.wrap(std::bind(
|
||||
&session::on_read,
|
||||
derived().shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::on_read,
|
||||
derived().shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -352,7 +358,8 @@ class plain_session
|
||||
, public std::enable_shared_from_this<plain_session>
|
||||
{
|
||||
tcp::socket socket_;
|
||||
boost::asio::io_service::strand strand_;
|
||||
boost::asio::strand<
|
||||
boost::asio::io_context::executor_type> strand_;
|
||||
|
||||
public:
|
||||
// Create the session
|
||||
@@ -361,11 +368,11 @@ public:
|
||||
boost::beast::flat_buffer buffer,
|
||||
std::string const& doc_root)
|
||||
: session<plain_session>(
|
||||
socket.get_io_service(),
|
||||
socket.get_executor().context(),
|
||||
std::move(buffer),
|
||||
doc_root)
|
||||
, socket_(std::move(socket))
|
||||
, strand_(socket_.get_io_service())
|
||||
, strand_(socket_.get_executor())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -401,7 +408,8 @@ class ssl_session
|
||||
{
|
||||
tcp::socket socket_;
|
||||
ssl::stream<tcp::socket&> stream_;
|
||||
boost::asio::io_service::strand strand_;
|
||||
boost::asio::strand<
|
||||
boost::asio::io_context::executor_type> strand_;
|
||||
|
||||
public:
|
||||
// Create the session
|
||||
@@ -411,12 +419,12 @@ public:
|
||||
boost::beast::flat_buffer buffer,
|
||||
std::string const& doc_root)
|
||||
: session<ssl_session>(
|
||||
socket.get_io_service(),
|
||||
socket.get_executor().context(),
|
||||
std::move(buffer),
|
||||
doc_root)
|
||||
, socket_(std::move(socket))
|
||||
, stream_(socket_, ctx)
|
||||
, strand_(stream_.get_io_service())
|
||||
, strand_(stream_.get_executor())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -436,11 +444,13 @@ public:
|
||||
stream_.async_handshake(
|
||||
ssl::stream_base::server,
|
||||
buffer_.data(),
|
||||
strand_.wrap(std::bind(
|
||||
&ssl_session::on_handshake,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&ssl_session::on_handshake,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
}
|
||||
void
|
||||
on_handshake(
|
||||
@@ -461,10 +471,12 @@ public:
|
||||
{
|
||||
// Perform the SSL shutdown
|
||||
stream_.async_shutdown(
|
||||
strand_.wrap(std::bind(
|
||||
&ssl_session::on_shutdown,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&ssl_session::on_shutdown,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -484,7 +496,8 @@ class detect_session : public std::enable_shared_from_this<detect_session>
|
||||
{
|
||||
tcp::socket socket_;
|
||||
ssl::context& ctx_;
|
||||
boost::asio::io_service::strand strand_;
|
||||
boost::asio::strand<
|
||||
boost::asio::io_context::executor_type> strand_;
|
||||
std::string const& doc_root_;
|
||||
boost::beast::flat_buffer buffer_;
|
||||
|
||||
@@ -496,7 +509,7 @@ public:
|
||||
std::string const& doc_root)
|
||||
: socket_(std::move(socket))
|
||||
, ctx_(ctx)
|
||||
, strand_(socket_.get_io_service())
|
||||
, strand_(socket_.get_executor())
|
||||
, doc_root_(doc_root)
|
||||
{
|
||||
}
|
||||
@@ -508,11 +521,13 @@ public:
|
||||
async_detect_ssl(
|
||||
socket_,
|
||||
buffer_,
|
||||
strand_.wrap(std::bind(
|
||||
&detect_session::on_detect,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&detect_session::on_detect,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
|
||||
}
|
||||
|
||||
@@ -545,21 +560,22 @@ public:
|
||||
class listener : public std::enable_shared_from_this<listener>
|
||||
{
|
||||
ssl::context& ctx_;
|
||||
boost::asio::io_service::strand strand_;
|
||||
boost::asio::strand<
|
||||
boost::asio::io_context::executor_type> strand_;
|
||||
tcp::acceptor acceptor_;
|
||||
tcp::socket socket_;
|
||||
std::string const& doc_root_;
|
||||
|
||||
public:
|
||||
listener(
|
||||
boost::asio::io_service& ios,
|
||||
boost::asio::io_context& ioc,
|
||||
ssl::context& ctx,
|
||||
tcp::endpoint endpoint,
|
||||
std::string const& doc_root)
|
||||
: ctx_(ctx)
|
||||
, strand_(ios)
|
||||
, acceptor_(ios)
|
||||
, socket_(ios)
|
||||
, strand_(ioc.get_executor())
|
||||
, acceptor_(ioc)
|
||||
, socket_(ioc)
|
||||
, doc_root_(doc_root)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
@@ -582,7 +598,7 @@ public:
|
||||
|
||||
// Start listening for connections
|
||||
acceptor_.listen(
|
||||
boost::asio::socket_base::max_connections, ec);
|
||||
boost::asio::socket_base::max_listen_connections, ec);
|
||||
if(ec)
|
||||
{
|
||||
fail(ec, "listen");
|
||||
@@ -644,13 +660,13 @@ int main(int argc, char* argv[])
|
||||
" http-server-sync 0.0.0.0 8080 .\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto const address = boost::asio::ip::address::from_string(argv[1]);
|
||||
auto const address = boost::asio::ip::make_address(argv[1]);
|
||||
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
|
||||
std::string const doc_root = argv[3];
|
||||
auto const threads = std::max<std::size_t>(1, std::atoi(argv[4]));
|
||||
auto const threads = std::max<int>(1, std::atoi(argv[4]));
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios{threads};
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc{threads};
|
||||
|
||||
// The SSL context is required, and holds certificates
|
||||
ssl::context ctx{ssl::context::sslv23};
|
||||
@@ -660,7 +676,7 @@ int main(int argc, char* argv[])
|
||||
|
||||
// Create and launch a listening port
|
||||
std::make_shared<listener>(
|
||||
ios,
|
||||
ioc,
|
||||
ctx,
|
||||
tcp::endpoint{address, port},
|
||||
doc_root)->run();
|
||||
@@ -670,11 +686,11 @@ int main(int argc, char* argv[])
|
||||
v.reserve(threads - 1);
|
||||
for(auto i = threads - 1; i > 0; --i)
|
||||
v.emplace_back(
|
||||
[&ios]
|
||||
[&ioc]
|
||||
{
|
||||
ios.run();
|
||||
ioc.run();
|
||||
});
|
||||
ios.run();
|
||||
ioc.run();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ private:
|
||||
|
||||
// The timer for putting a deadline on connection processing.
|
||||
boost::asio::basic_waitable_timer<std::chrono::steady_clock> deadline_{
|
||||
socket_.get_io_service(), std::chrono::seconds(60)};
|
||||
socket_.get_executor().context(), std::chrono::seconds(60)};
|
||||
|
||||
// Asynchronously receive a complete request message.
|
||||
void
|
||||
@@ -231,16 +231,16 @@ main(int argc, char* argv[])
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
auto address = ip::address::from_string(argv[1]);
|
||||
auto const address = boost::asio::ip::make_address(argv[1]);
|
||||
unsigned short port = static_cast<unsigned short>(std::atoi(argv[2]));
|
||||
|
||||
boost::asio::io_service ios{1};
|
||||
boost::asio::io_context ioc{1};
|
||||
|
||||
tcp::acceptor acceptor{ios, {address, port}};
|
||||
tcp::socket socket{ios};
|
||||
tcp::acceptor acceptor{ioc, {address, port}};
|
||||
tcp::socket socket{ioc};
|
||||
http_server(acceptor, socket);
|
||||
|
||||
ios.run();
|
||||
ioc.run();
|
||||
}
|
||||
catch(std::exception const& e)
|
||||
{
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <boost/beast/core.hpp>
|
||||
#include <boost/beast/http.hpp>
|
||||
#include <boost/beast/version.hpp>
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/asio/coroutine.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/ssl/stream.hpp>
|
||||
@@ -247,18 +248,21 @@ class session
|
||||
http::async_write(
|
||||
self_.socket_,
|
||||
*sp,
|
||||
self_.strand_.wrap(std::bind(
|
||||
&session::loop,
|
||||
self_.shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2,
|
||||
! sp->keep_alive())));
|
||||
boost::asio::bind_executor(
|
||||
self_.strand_,
|
||||
std::bind(
|
||||
&session::loop,
|
||||
self_.shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2,
|
||||
! sp->keep_alive())));
|
||||
}
|
||||
};
|
||||
|
||||
tcp::socket socket_;
|
||||
ssl::stream<tcp::socket&> stream_;
|
||||
boost::asio::io_service::strand strand_;
|
||||
boost::asio::strand<
|
||||
boost::asio::io_context::executor_type> strand_;
|
||||
boost::beast::flat_buffer buffer_;
|
||||
std::string const& doc_root_;
|
||||
http::request<http::string_body> req_;
|
||||
@@ -274,7 +278,7 @@ public:
|
||||
std::string const& doc_root)
|
||||
: socket_(std::move(socket))
|
||||
, stream_(socket_, ctx)
|
||||
, strand_(socket_.get_io_service())
|
||||
, strand_(socket_.get_executor())
|
||||
, doc_root_(doc_root)
|
||||
, lambda_(*this)
|
||||
{
|
||||
@@ -300,12 +304,14 @@ public:
|
||||
// Perform the SSL handshake
|
||||
yield stream_.async_handshake(
|
||||
ssl::stream_base::server,
|
||||
strand_.wrap(std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
0,
|
||||
false)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
0,
|
||||
false)));
|
||||
if(ec)
|
||||
return fail(ec, "handshake");
|
||||
|
||||
@@ -313,12 +319,14 @@ public:
|
||||
{
|
||||
// Read a request
|
||||
yield http::async_read(stream_, buffer_, req_,
|
||||
strand_.wrap(std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2,
|
||||
false)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2,
|
||||
false)));
|
||||
if(ec == http::error::end_of_stream)
|
||||
{
|
||||
// The remote host closed the connection
|
||||
@@ -344,12 +352,14 @@ public:
|
||||
|
||||
// Perform the SSL shutdown
|
||||
yield stream_.async_shutdown(
|
||||
strand_.wrap(std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
0,
|
||||
false)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
0,
|
||||
false)));
|
||||
if(ec)
|
||||
return fail(ec, "shutdown");
|
||||
|
||||
@@ -373,13 +383,13 @@ class listener
|
||||
|
||||
public:
|
||||
listener(
|
||||
boost::asio::io_service& ios,
|
||||
boost::asio::io_context& ioc,
|
||||
ssl::context& ctx,
|
||||
tcp::endpoint endpoint,
|
||||
std::string const& doc_root)
|
||||
: ctx_(ctx)
|
||||
, acceptor_(ios)
|
||||
, socket_(ios)
|
||||
, acceptor_(ioc)
|
||||
, socket_(ioc)
|
||||
, doc_root_(doc_root)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
@@ -402,7 +412,7 @@ public:
|
||||
|
||||
// Start listening for connections
|
||||
acceptor_.listen(
|
||||
boost::asio::socket_base::max_connections, ec);
|
||||
boost::asio::socket_base::max_listen_connections, ec);
|
||||
if(ec)
|
||||
{
|
||||
fail(ec, "listen");
|
||||
@@ -464,13 +474,13 @@ int main(int argc, char* argv[])
|
||||
" http-server-stackless-ssl 0.0.0.0 8080 . 1\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto const address = boost::asio::ip::address::from_string(argv[1]);
|
||||
auto const address = boost::asio::ip::make_address(argv[1]);
|
||||
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
|
||||
std::string const doc_root = argv[3];
|
||||
auto const threads = std::max<std::size_t>(1, std::atoi(argv[4]));
|
||||
auto const threads = std::max<int>(1, std::atoi(argv[4]));
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios{threads};
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc{threads};
|
||||
|
||||
// The SSL context is required, and holds certificates
|
||||
ssl::context ctx{ssl::context::sslv23};
|
||||
@@ -480,7 +490,7 @@ int main(int argc, char* argv[])
|
||||
|
||||
// Create and launch a listening port
|
||||
std::make_shared<listener>(
|
||||
ios,
|
||||
ioc,
|
||||
ctx,
|
||||
tcp::endpoint{address, port},
|
||||
doc_root)->run();
|
||||
@@ -490,11 +500,11 @@ int main(int argc, char* argv[])
|
||||
v.reserve(threads - 1);
|
||||
for(auto i = threads - 1; i > 0; --i)
|
||||
v.emplace_back(
|
||||
[&ios]
|
||||
[&ioc]
|
||||
{
|
||||
ios.run();
|
||||
ioc.run();
|
||||
});
|
||||
ios.run();
|
||||
ioc.run();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <boost/beast/core.hpp>
|
||||
#include <boost/beast/http.hpp>
|
||||
#include <boost/beast/version.hpp>
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/asio/coroutine.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
@@ -244,17 +245,20 @@ class session
|
||||
http::async_write(
|
||||
self_.socket_,
|
||||
*sp,
|
||||
self_.strand_.wrap(std::bind(
|
||||
&session::loop,
|
||||
self_.shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2,
|
||||
! sp->keep_alive())));
|
||||
boost::asio::bind_executor(
|
||||
self_.strand_,
|
||||
std::bind(
|
||||
&session::loop,
|
||||
self_.shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2,
|
||||
! sp->keep_alive())));
|
||||
}
|
||||
};
|
||||
|
||||
tcp::socket socket_;
|
||||
boost::asio::io_service::strand strand_;
|
||||
boost::asio::strand<
|
||||
boost::asio::io_context::executor_type> strand_;
|
||||
boost::beast::flat_buffer buffer_;
|
||||
std::string const& doc_root_;
|
||||
http::request<http::string_body> req_;
|
||||
@@ -268,7 +272,7 @@ public:
|
||||
tcp::socket socket,
|
||||
std::string const& doc_root)
|
||||
: socket_(std::move(socket))
|
||||
, strand_(socket_.get_io_service())
|
||||
, strand_(socket_.get_executor())
|
||||
, doc_root_(doc_root)
|
||||
, lambda_(*this)
|
||||
{
|
||||
@@ -295,12 +299,14 @@ public:
|
||||
{
|
||||
// Read a request
|
||||
yield http::async_read(socket_, buffer_, req_,
|
||||
strand_.wrap(std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2,
|
||||
false)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2,
|
||||
false)));
|
||||
if(ec == http::error::end_of_stream)
|
||||
{
|
||||
// The remote host closed the connection
|
||||
@@ -346,11 +352,11 @@ class listener
|
||||
|
||||
public:
|
||||
listener(
|
||||
boost::asio::io_service& ios,
|
||||
boost::asio::io_context& ioc,
|
||||
tcp::endpoint endpoint,
|
||||
std::string const& doc_root)
|
||||
: acceptor_(ios)
|
||||
, socket_(ios)
|
||||
: acceptor_(ioc)
|
||||
, socket_(ioc)
|
||||
, doc_root_(doc_root)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
@@ -372,7 +378,7 @@ public:
|
||||
}
|
||||
|
||||
// Start listening for connections
|
||||
acceptor_.listen(boost::asio::socket_base::max_connections, ec);
|
||||
acceptor_.listen(boost::asio::socket_base::max_listen_connections, ec);
|
||||
if(ec)
|
||||
{
|
||||
fail(ec, "listen");
|
||||
@@ -433,17 +439,17 @@ int main(int argc, char* argv[])
|
||||
" http-server-stackless 0.0.0.0 8080 . 1\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto const address = boost::asio::ip::address::from_string(argv[1]);
|
||||
auto const address = boost::asio::ip::make_address(argv[1]);
|
||||
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
|
||||
std::string const doc_root = argv[3];
|
||||
auto const threads = std::max<std::size_t>(1, std::atoi(argv[4]));
|
||||
auto const threads = std::max<int>(1, std::atoi(argv[4]));
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios{threads};
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc{threads};
|
||||
|
||||
// Create and launch a listening port
|
||||
std::make_shared<listener>(
|
||||
ios,
|
||||
ioc,
|
||||
tcp::endpoint{address, port},
|
||||
doc_root)->run();
|
||||
|
||||
@@ -452,11 +458,11 @@ int main(int argc, char* argv[])
|
||||
v.reserve(threads - 1);
|
||||
for(auto i = threads - 1; i > 0; --i)
|
||||
v.emplace_back(
|
||||
[&ios]
|
||||
[&ioc]
|
||||
{
|
||||
ios.run();
|
||||
ioc.run();
|
||||
});
|
||||
ios.run();
|
||||
ioc.run();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -311,12 +311,12 @@ int main(int argc, char* argv[])
|
||||
" http-server-sync-ssl 0.0.0.0 8080 .\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto const address = boost::asio::ip::address::from_string(argv[1]);
|
||||
auto const address = boost::asio::ip::make_address(argv[1]);
|
||||
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
|
||||
std::string const doc_root = argv[3];
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios{1};
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc{1};
|
||||
|
||||
// The SSL context is required, and holds certificates
|
||||
ssl::context ctx{ssl::context::sslv23};
|
||||
@@ -325,11 +325,11 @@ int main(int argc, char* argv[])
|
||||
load_server_certificate(ctx);
|
||||
|
||||
// The acceptor receives incoming connections
|
||||
tcp::acceptor acceptor{ios, {address, port}};
|
||||
tcp::acceptor acceptor{ioc, {address, port}};
|
||||
for(;;)
|
||||
{
|
||||
// This will receive the new connection
|
||||
tcp::socket socket{ios};
|
||||
tcp::socket socket{ioc};
|
||||
|
||||
// Block until we get a connection
|
||||
acceptor.accept(socket);
|
||||
|
||||
@@ -298,19 +298,19 @@ int main(int argc, char* argv[])
|
||||
" http-server-sync 0.0.0.0 8080 .\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto const address = boost::asio::ip::address::from_string(argv[1]);
|
||||
auto const address = boost::asio::ip::make_address(argv[1]);
|
||||
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
|
||||
std::string const doc_root = argv[3];
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios{1};
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc{1};
|
||||
|
||||
// The acceptor receives incoming connections
|
||||
tcp::acceptor acceptor{ios, {address, port}};
|
||||
tcp::acceptor acceptor{ioc, {address, port}};
|
||||
for(;;)
|
||||
{
|
||||
// This will receive the new connection
|
||||
tcp::socket socket{ios};
|
||||
tcp::socket socket{ioc};
|
||||
|
||||
// Block until we get a connection
|
||||
acceptor.accept(socket);
|
||||
|
||||
@@ -50,11 +50,11 @@ class session : public std::enable_shared_from_this<session>
|
||||
std::string text_;
|
||||
|
||||
public:
|
||||
// Resolver and socket require an io_service
|
||||
// Resolver and socket require an io_context
|
||||
explicit
|
||||
session(boost::asio::io_service& ios, ssl::context& ctx)
|
||||
: resolver_(ios)
|
||||
, ws_(ios, ctx)
|
||||
session(boost::asio::io_context& ioc, ssl::context& ctx)
|
||||
: resolver_(ioc)
|
||||
, ws_(ioc, ctx)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -70,7 +70,9 @@ public:
|
||||
text_ = text;
|
||||
|
||||
// Look up the domain name
|
||||
resolver_.async_resolve({host, port},
|
||||
resolver_.async_resolve(
|
||||
host,
|
||||
port,
|
||||
std::bind(
|
||||
&session::on_resolve,
|
||||
shared_from_this(),
|
||||
@@ -81,7 +83,7 @@ public:
|
||||
void
|
||||
on_resolve(
|
||||
boost::system::error_code ec,
|
||||
tcp::resolver::iterator result)
|
||||
tcp::resolver::results_type results)
|
||||
{
|
||||
if(ec)
|
||||
return fail(ec, "resolve");
|
||||
@@ -89,7 +91,8 @@ public:
|
||||
// Make the connection on the IP address we get from a lookup
|
||||
boost::asio::async_connect(
|
||||
ws_.next_layer().next_layer(),
|
||||
result,
|
||||
results.begin(),
|
||||
results.end(),
|
||||
std::bind(
|
||||
&session::on_connect,
|
||||
shared_from_this(),
|
||||
@@ -209,8 +212,8 @@ int main(int argc, char** argv)
|
||||
auto const port = argv[2];
|
||||
auto const text = argv[3];
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios;
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc;
|
||||
|
||||
// The SSL context is required, and holds certificates
|
||||
ssl::context ctx{ssl::context::sslv23_client};
|
||||
@@ -219,11 +222,11 @@ int main(int argc, char** argv)
|
||||
load_root_certificates(ctx);
|
||||
|
||||
// Launch the asynchronous operation
|
||||
std::make_shared<session>(ios, ctx)->run(host, port, text);
|
||||
std::make_shared<session>(ioc, ctx)->run(host, port, text);
|
||||
|
||||
// Run the I/O service. The call will return when
|
||||
// the get operation is complete.
|
||||
ios.run();
|
||||
ioc.run();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -45,11 +45,11 @@ class session : public std::enable_shared_from_this<session>
|
||||
std::string text_;
|
||||
|
||||
public:
|
||||
// Resolver and socket require an io_service
|
||||
// Resolver and socket require an io_context
|
||||
explicit
|
||||
session(boost::asio::io_service& ios)
|
||||
: resolver_(ios)
|
||||
, ws_(ios)
|
||||
session(boost::asio::io_context& ioc)
|
||||
: resolver_(ioc)
|
||||
, ws_(ioc)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -65,7 +65,9 @@ public:
|
||||
text_ = text;
|
||||
|
||||
// Look up the domain name
|
||||
resolver_.async_resolve({host, port},
|
||||
resolver_.async_resolve(
|
||||
host,
|
||||
port,
|
||||
std::bind(
|
||||
&session::on_resolve,
|
||||
shared_from_this(),
|
||||
@@ -76,7 +78,7 @@ public:
|
||||
void
|
||||
on_resolve(
|
||||
boost::system::error_code ec,
|
||||
tcp::resolver::iterator result)
|
||||
tcp::resolver::results_type results)
|
||||
{
|
||||
if(ec)
|
||||
return fail(ec, "resolve");
|
||||
@@ -84,7 +86,8 @@ public:
|
||||
// Make the connection on the IP address we get from a lookup
|
||||
boost::asio::async_connect(
|
||||
ws_.next_layer(),
|
||||
result,
|
||||
results.begin(),
|
||||
results.end(),
|
||||
std::bind(
|
||||
&session::on_connect,
|
||||
shared_from_this(),
|
||||
@@ -189,15 +192,15 @@ int main(int argc, char** argv)
|
||||
auto const port = argv[2];
|
||||
auto const text = argv[3];
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios;
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc;
|
||||
|
||||
// Launch the asynchronous operation
|
||||
std::make_shared<session>(ios)->run(host, port, text);
|
||||
std::make_shared<session>(ioc)->run(host, port, text);
|
||||
|
||||
// Run the I/O service. The call will return when
|
||||
// the get operation is complete.
|
||||
ios.run();
|
||||
ioc.run();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -46,23 +46,23 @@ do_session(
|
||||
std::string const& host,
|
||||
std::string const& port,
|
||||
std::string const& text,
|
||||
boost::asio::io_service& ios,
|
||||
boost::asio::io_context& ioc,
|
||||
ssl::context& ctx,
|
||||
boost::asio::yield_context yield)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
|
||||
// These objects perform our I/O
|
||||
tcp::resolver resolver{ios};
|
||||
websocket::stream<ssl::stream<tcp::socket>> ws{ios, ctx};
|
||||
tcp::resolver resolver{ioc};
|
||||
websocket::stream<ssl::stream<tcp::socket>> ws{ioc, ctx};
|
||||
|
||||
// Look up the domain name
|
||||
auto const lookup = resolver.async_resolve({host, port}, yield[ec]);
|
||||
auto const results = resolver.async_resolve(host, port, yield[ec]);
|
||||
if(ec)
|
||||
return fail(ec, "resolve");
|
||||
|
||||
// Make the connection on the IP address we get from a lookup
|
||||
boost::asio::async_connect(ws.next_layer().next_layer(), lookup, yield[ec]);
|
||||
boost::asio::async_connect(ws.next_layer().next_layer(), results.begin(), results.end(), yield[ec]);
|
||||
if(ec)
|
||||
return fail(ec, "connect");
|
||||
|
||||
@@ -117,8 +117,8 @@ int main(int argc, char** argv)
|
||||
auto const port = argv[2];
|
||||
auto const text = argv[3];
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios;
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc;
|
||||
|
||||
// The SSL context is required, and holds certificates
|
||||
ssl::context ctx{ssl::context::sslv23_client};
|
||||
@@ -127,18 +127,18 @@ int main(int argc, char** argv)
|
||||
load_root_certificates(ctx);
|
||||
|
||||
// Launch the asynchronous operation
|
||||
boost::asio::spawn(ios, std::bind(
|
||||
boost::asio::spawn(ioc, std::bind(
|
||||
&do_session,
|
||||
std::string(host),
|
||||
std::string(port),
|
||||
std::string(text),
|
||||
std::ref(ios),
|
||||
std::ref(ioc),
|
||||
std::ref(ctx),
|
||||
std::placeholders::_1));
|
||||
|
||||
// Run the I/O service. The call will return when
|
||||
// the get operation is complete.
|
||||
ios.run();
|
||||
ioc.run();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -41,22 +41,22 @@ do_session(
|
||||
std::string const& host,
|
||||
std::string const& port,
|
||||
std::string const& text,
|
||||
boost::asio::io_service& ios,
|
||||
boost::asio::io_context& ioc,
|
||||
boost::asio::yield_context yield)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
|
||||
// These objects perform our I/O
|
||||
tcp::resolver resolver{ios};
|
||||
websocket::stream<tcp::socket> ws{ios};
|
||||
tcp::resolver resolver{ioc};
|
||||
websocket::stream<tcp::socket> ws{ioc};
|
||||
|
||||
// Look up the domain name
|
||||
auto const lookup = resolver.async_resolve({host, port}, yield[ec]);
|
||||
auto const results = resolver.async_resolve(host, port, yield[ec]);
|
||||
if(ec)
|
||||
return fail(ec, "resolve");
|
||||
|
||||
// Make the connection on the IP address we get from a lookup
|
||||
boost::asio::async_connect(ws.next_layer(), lookup, yield[ec]);
|
||||
boost::asio::async_connect(ws.next_layer(), results.begin(), results.end(), yield[ec]);
|
||||
if(ec)
|
||||
return fail(ec, "connect");
|
||||
|
||||
@@ -106,21 +106,21 @@ int main(int argc, char** argv)
|
||||
auto const port = argv[2];
|
||||
auto const text = argv[3];
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios;
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc;
|
||||
|
||||
// Launch the asynchronous operation
|
||||
boost::asio::spawn(ios, std::bind(
|
||||
boost::asio::spawn(ioc, std::bind(
|
||||
&do_session,
|
||||
std::string(host),
|
||||
std::string(port),
|
||||
std::string(text),
|
||||
std::ref(ios),
|
||||
std::ref(ioc),
|
||||
std::placeholders::_1));
|
||||
|
||||
// Run the I/O service. The call will return when
|
||||
// the get operation is complete.
|
||||
ios.run();
|
||||
ioc.run();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -47,8 +47,8 @@ int main(int argc, char** argv)
|
||||
auto const port = argv[2];
|
||||
auto const text = argv[3];
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios;
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc;
|
||||
|
||||
// The SSL context is required, and holds certificates
|
||||
ssl::context ctx{ssl::context::sslv23_client};
|
||||
@@ -57,14 +57,14 @@ int main(int argc, char** argv)
|
||||
load_root_certificates(ctx);
|
||||
|
||||
// These objects perform our I/O
|
||||
tcp::resolver resolver{ios};
|
||||
websocket::stream<ssl::stream<tcp::socket>> ws{ios, ctx};
|
||||
tcp::resolver resolver{ioc};
|
||||
websocket::stream<ssl::stream<tcp::socket>> ws{ioc, ctx};
|
||||
|
||||
// Look up the domain name
|
||||
auto const lookup = resolver.resolve({host, port});
|
||||
auto const results = resolver.resolve(host, port);
|
||||
|
||||
// Make the connection on the IP address we get from a lookup
|
||||
boost::asio::connect(ws.next_layer().next_layer(), lookup);
|
||||
boost::asio::connect(ws.next_layer().next_layer(), results.begin(), results.end());
|
||||
|
||||
// Perform the SSL handshake
|
||||
ws.next_layer().handshake(ssl::stream_base::client);
|
||||
|
||||
@@ -44,18 +44,18 @@ int main(int argc, char** argv)
|
||||
auto const port = argv[2];
|
||||
auto const text = argv[3];
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios;
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc;
|
||||
|
||||
// These objects perform our I/O
|
||||
tcp::resolver resolver{ios};
|
||||
websocket::stream<tcp::socket> ws{ios};
|
||||
tcp::resolver resolver{ioc};
|
||||
websocket::stream<tcp::socket> ws{ioc};
|
||||
|
||||
// Look up the domain name
|
||||
auto const lookup = resolver.resolve({host, port});
|
||||
auto const results = resolver.resolve(host, port);
|
||||
|
||||
// Make the connection on the IP address we get from a lookup
|
||||
boost::asio::connect(ws.next_layer(), lookup);
|
||||
boost::asio::connect(ws.next_layer(), results.begin(), results.end());
|
||||
|
||||
// Perform the websocket handshake
|
||||
ws.handshake(host, "/");
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <boost/beast/core.hpp>
|
||||
#include <boost/beast/websocket.hpp>
|
||||
#include <boost/beast/websocket/ssl.hpp>
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/ssl/stream.hpp>
|
||||
@@ -48,7 +49,8 @@ class session : public std::enable_shared_from_this<session>
|
||||
{
|
||||
tcp::socket socket_;
|
||||
websocket::stream<ssl::stream<tcp::socket&>> ws_;
|
||||
boost::asio::io_service::strand strand_;
|
||||
boost::asio::strand<
|
||||
boost::asio::io_context::executor_type> strand_;
|
||||
boost::beast::multi_buffer buffer_;
|
||||
|
||||
public:
|
||||
@@ -56,7 +58,7 @@ public:
|
||||
session(tcp::socket socket, ssl::context& ctx)
|
||||
: socket_(std::move(socket))
|
||||
, ws_(socket_, ctx)
|
||||
, strand_(ws_.get_io_service())
|
||||
, strand_(ws_.get_executor())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -67,10 +69,12 @@ public:
|
||||
// Perform the SSL handshake
|
||||
ws_.next_layer().async_handshake(
|
||||
ssl::stream_base::server,
|
||||
strand_.wrap(std::bind(
|
||||
&session::on_handshake,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::on_handshake,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -81,10 +85,12 @@ public:
|
||||
|
||||
// Accept the websocket handshake
|
||||
ws_.async_accept(
|
||||
strand_.wrap(std::bind(
|
||||
&session::on_accept,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::on_accept,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -103,11 +109,13 @@ public:
|
||||
// Read a message into our buffer
|
||||
ws_.async_read(
|
||||
buffer_,
|
||||
strand_.wrap(std::bind(
|
||||
&session::on_read,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::on_read,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -128,11 +136,13 @@ public:
|
||||
ws_.text(ws_.got_text());
|
||||
ws_.async_write(
|
||||
buffer_.data(),
|
||||
strand_.wrap(std::bind(
|
||||
&session::on_write,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::on_write,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -164,12 +174,12 @@ class listener : public std::enable_shared_from_this<listener>
|
||||
|
||||
public:
|
||||
listener(
|
||||
boost::asio::io_service& ios,
|
||||
boost::asio::io_context& ioc,
|
||||
ssl::context& ctx,
|
||||
tcp::endpoint endpoint)
|
||||
: ctx_(ctx)
|
||||
, acceptor_(ios)
|
||||
, socket_(ios)
|
||||
, acceptor_(ioc)
|
||||
, socket_(ioc)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
|
||||
@@ -191,7 +201,7 @@ public:
|
||||
|
||||
// Start listening for connections
|
||||
acceptor_.listen(
|
||||
boost::asio::socket_base::max_connections, ec);
|
||||
boost::asio::socket_base::max_listen_connections, ec);
|
||||
if(ec)
|
||||
{
|
||||
fail(ec, "listen");
|
||||
@@ -250,12 +260,12 @@ int main(int argc, char* argv[])
|
||||
" websocket-server-async-ssl 0.0.0.0 8080 1\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto const address = boost::asio::ip::address::from_string(argv[1]);
|
||||
auto const address = boost::asio::ip::make_address(argv[1]);
|
||||
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
|
||||
auto const threads = std::max<std::size_t>(1, std::atoi(argv[3]));
|
||||
auto const threads = std::max<int>(1, std::atoi(argv[3]));
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios{threads};
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc{threads};
|
||||
|
||||
// The SSL context is required, and holds certificates
|
||||
ssl::context ctx{ssl::context::sslv23};
|
||||
@@ -264,18 +274,18 @@ int main(int argc, char* argv[])
|
||||
load_server_certificate(ctx);
|
||||
|
||||
// Create and launch a listening port
|
||||
std::make_shared<listener>(ios, ctx, tcp::endpoint{address, port})->run();
|
||||
std::make_shared<listener>(ioc, ctx, tcp::endpoint{address, port})->run();
|
||||
|
||||
// Run the I/O service on the requested number of threads
|
||||
std::vector<std::thread> v;
|
||||
v.reserve(threads - 1);
|
||||
for(auto i = threads - 1; i > 0; --i)
|
||||
v.emplace_back(
|
||||
[&ios]
|
||||
[&ioc]
|
||||
{
|
||||
ios.run();
|
||||
ioc.run();
|
||||
});
|
||||
ios.run();
|
||||
ioc.run();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include <boost/beast/core.hpp>
|
||||
#include <boost/beast/websocket.hpp>
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <algorithm>
|
||||
@@ -42,7 +43,8 @@ fail(boost::system::error_code ec, char const* what)
|
||||
class session : public std::enable_shared_from_this<session>
|
||||
{
|
||||
websocket::stream<tcp::socket> ws_;
|
||||
boost::asio::io_service::strand strand_;
|
||||
boost::asio::strand<
|
||||
boost::asio::io_context::executor_type> strand_;
|
||||
boost::beast::multi_buffer buffer_;
|
||||
|
||||
public:
|
||||
@@ -50,7 +52,7 @@ public:
|
||||
explicit
|
||||
session(tcp::socket socket)
|
||||
: ws_(std::move(socket))
|
||||
, strand_(ws_.get_io_service())
|
||||
, strand_(ws_.get_executor())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -60,10 +62,12 @@ public:
|
||||
{
|
||||
// Accept the websocket handshake
|
||||
ws_.async_accept(
|
||||
strand_.wrap(std::bind(
|
||||
&session::on_accept,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::on_accept,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -82,11 +86,13 @@ public:
|
||||
// Read a message into our buffer
|
||||
ws_.async_read(
|
||||
buffer_,
|
||||
strand_.wrap(std::bind(
|
||||
&session::on_read,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::on_read,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -107,11 +113,13 @@ public:
|
||||
ws_.text(ws_.got_text());
|
||||
ws_.async_write(
|
||||
buffer_.data(),
|
||||
strand_.wrap(std::bind(
|
||||
&session::on_write,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::on_write,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -142,10 +150,10 @@ class listener : public std::enable_shared_from_this<listener>
|
||||
|
||||
public:
|
||||
listener(
|
||||
boost::asio::io_service& ios,
|
||||
boost::asio::io_context& ioc,
|
||||
tcp::endpoint endpoint)
|
||||
: acceptor_(ios)
|
||||
, socket_(ios)
|
||||
: acceptor_(ioc)
|
||||
, socket_(ioc)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
|
||||
@@ -167,7 +175,7 @@ public:
|
||||
|
||||
// Start listening for connections
|
||||
acceptor_.listen(
|
||||
boost::asio::socket_base::max_connections, ec);
|
||||
boost::asio::socket_base::max_listen_connections, ec);
|
||||
if(ec)
|
||||
{
|
||||
fail(ec, "listen");
|
||||
@@ -226,26 +234,26 @@ int main(int argc, char* argv[])
|
||||
" websocket-server-async 0.0.0.0 8080 1\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto const address = boost::asio::ip::address::from_string(argv[1]);
|
||||
auto const address = boost::asio::ip::make_address(argv[1]);
|
||||
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
|
||||
auto const threads = std::max<std::size_t>(1, std::atoi(argv[3]));
|
||||
auto const threads = std::max<int>(1, std::atoi(argv[3]));
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios{threads};
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc{threads};
|
||||
|
||||
// Create and launch a listening port
|
||||
std::make_shared<listener>(ios, tcp::endpoint{address, port})->run();
|
||||
std::make_shared<listener>(ioc, tcp::endpoint{address, port})->run();
|
||||
|
||||
// Run the I/O service on the requested number of threads
|
||||
std::vector<std::thread> v;
|
||||
v.reserve(threads - 1);
|
||||
for(auto i = threads - 1; i > 0; --i)
|
||||
v.emplace_back(
|
||||
[&ios]
|
||||
[&ioc]
|
||||
{
|
||||
ios.run();
|
||||
ioc.run();
|
||||
});
|
||||
ios.run();
|
||||
ioc.run();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ do_session(
|
||||
// Accepts incoming connections and launches the sessions
|
||||
void
|
||||
do_listen(
|
||||
boost::asio::io_service& ios,
|
||||
boost::asio::io_context& ioc,
|
||||
ssl::context& ctx,
|
||||
tcp::endpoint endpoint,
|
||||
boost::asio::yield_context yield)
|
||||
@@ -101,7 +101,7 @@ do_listen(
|
||||
boost::system::error_code ec;
|
||||
|
||||
// Open the acceptor
|
||||
tcp::acceptor acceptor(ios);
|
||||
tcp::acceptor acceptor(ioc);
|
||||
acceptor.open(endpoint.protocol(), ec);
|
||||
if(ec)
|
||||
return fail(ec, "open");
|
||||
@@ -112,19 +112,19 @@ do_listen(
|
||||
return fail(ec, "bind");
|
||||
|
||||
// Start listening for connections
|
||||
acceptor.listen(boost::asio::socket_base::max_connections, ec);
|
||||
acceptor.listen(boost::asio::socket_base::max_listen_connections, ec);
|
||||
if(ec)
|
||||
return fail(ec, "listen");
|
||||
|
||||
for(;;)
|
||||
{
|
||||
tcp::socket socket(ios);
|
||||
tcp::socket socket(ioc);
|
||||
acceptor.async_accept(socket, yield[ec]);
|
||||
if(ec)
|
||||
fail(ec, "accept");
|
||||
else
|
||||
boost::asio::spawn(
|
||||
acceptor.get_io_service(),
|
||||
acceptor.get_executor().context(),
|
||||
std::bind(
|
||||
&do_session,
|
||||
std::move(socket),
|
||||
@@ -144,12 +144,12 @@ int main(int argc, char* argv[])
|
||||
" websocket-server-coro-ssl 0.0.0.0 8080 1\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto const address = boost::asio::ip::address::from_string(argv[1]);
|
||||
auto const address = boost::asio::ip::make_address(argv[1]);
|
||||
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
|
||||
auto const threads = std::max<std::size_t>(1, std::atoi(argv[3]));
|
||||
auto const threads = std::max<int>(1, std::atoi(argv[3]));
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios{threads};
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc{threads};
|
||||
|
||||
// The SSL context is required, and holds certificates
|
||||
ssl::context ctx{ssl::context::sslv23};
|
||||
@@ -158,10 +158,10 @@ int main(int argc, char* argv[])
|
||||
load_server_certificate(ctx);
|
||||
|
||||
// Spawn a listening port
|
||||
boost::asio::spawn(ios,
|
||||
boost::asio::spawn(ioc,
|
||||
std::bind(
|
||||
&do_listen,
|
||||
std::ref(ios),
|
||||
std::ref(ioc),
|
||||
std::ref(ctx),
|
||||
tcp::endpoint{address, port},
|
||||
std::placeholders::_1));
|
||||
@@ -171,11 +171,11 @@ int main(int argc, char* argv[])
|
||||
v.reserve(threads - 1);
|
||||
for(auto i = threads - 1; i > 0; --i)
|
||||
v.emplace_back(
|
||||
[&ios]
|
||||
[&ioc]
|
||||
{
|
||||
ios.run();
|
||||
ioc.run();
|
||||
});
|
||||
ios.run();
|
||||
ioc.run();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -80,14 +80,14 @@ do_session(tcp::socket& socket, boost::asio::yield_context yield)
|
||||
// Accepts incoming connections and launches the sessions
|
||||
void
|
||||
do_listen(
|
||||
boost::asio::io_service& ios,
|
||||
boost::asio::io_context& ioc,
|
||||
tcp::endpoint endpoint,
|
||||
boost::asio::yield_context yield)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
|
||||
// Open the acceptor
|
||||
tcp::acceptor acceptor(ios);
|
||||
tcp::acceptor acceptor(ioc);
|
||||
acceptor.open(endpoint.protocol(), ec);
|
||||
if(ec)
|
||||
return fail(ec, "open");
|
||||
@@ -98,19 +98,19 @@ do_listen(
|
||||
return fail(ec, "bind");
|
||||
|
||||
// Start listening for connections
|
||||
acceptor.listen(boost::asio::socket_base::max_connections, ec);
|
||||
acceptor.listen(boost::asio::socket_base::max_listen_connections, ec);
|
||||
if(ec)
|
||||
return fail(ec, "listen");
|
||||
|
||||
for(;;)
|
||||
{
|
||||
tcp::socket socket(ios);
|
||||
tcp::socket socket(ioc);
|
||||
acceptor.async_accept(socket, yield[ec]);
|
||||
if(ec)
|
||||
fail(ec, "accept");
|
||||
else
|
||||
boost::asio::spawn(
|
||||
acceptor.get_io_service(),
|
||||
acceptor.get_executor().context(),
|
||||
std::bind(
|
||||
&do_session,
|
||||
std::move(socket),
|
||||
@@ -129,18 +129,18 @@ int main(int argc, char* argv[])
|
||||
" websocket-server-coro 0.0.0.0 8080 1\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto const address = boost::asio::ip::address::from_string(argv[1]);
|
||||
auto const address = boost::asio::ip::make_address(argv[1]);
|
||||
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
|
||||
auto const threads = std::max<std::size_t>(1, std::atoi(argv[3]));
|
||||
auto const threads = std::max<int>(1, std::atoi(argv[3]));
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios{threads};
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc{threads};
|
||||
|
||||
// Spawn a listening port
|
||||
boost::asio::spawn(ios,
|
||||
boost::asio::spawn(ioc,
|
||||
std::bind(
|
||||
&do_listen,
|
||||
std::ref(ios),
|
||||
std::ref(ioc),
|
||||
tcp::endpoint{address, port},
|
||||
std::placeholders::_1));
|
||||
|
||||
@@ -149,11 +149,11 @@ int main(int argc, char* argv[])
|
||||
v.reserve(threads - 1);
|
||||
for(auto i = threads - 1; i > 0; --i)
|
||||
v.emplace_back(
|
||||
[&ios]
|
||||
[&ioc]
|
||||
{
|
||||
ios.run();
|
||||
ioc.run();
|
||||
});
|
||||
ios.run();
|
||||
ioc.run();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <boost/beast/http.hpp>
|
||||
#include <boost/beast/version.hpp>
|
||||
#include <boost/beast/websocket.hpp>
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/asio/spawn.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
@@ -113,14 +114,14 @@ do_sync_session(tcp::socket& socket)
|
||||
|
||||
void
|
||||
do_sync_listen(
|
||||
boost::asio::io_service& ios,
|
||||
boost::asio::io_context& ioc,
|
||||
tcp::endpoint endpoint)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
tcp::acceptor acceptor{ios, endpoint};
|
||||
tcp::acceptor acceptor{ioc, endpoint};
|
||||
for(;;)
|
||||
{
|
||||
tcp::socket socket{ios};
|
||||
tcp::socket socket{ioc};
|
||||
|
||||
acceptor.accept(socket, ec);
|
||||
if(ec)
|
||||
@@ -138,7 +139,8 @@ do_sync_listen(
|
||||
class async_session : public std::enable_shared_from_this<async_session>
|
||||
{
|
||||
websocket::stream<tcp::socket> ws_;
|
||||
boost::asio::io_service::strand strand_;
|
||||
boost::asio::strand<
|
||||
boost::asio::io_context::executor_type> strand_;
|
||||
boost::beast::multi_buffer buffer_;
|
||||
|
||||
public:
|
||||
@@ -146,7 +148,7 @@ public:
|
||||
explicit
|
||||
async_session(tcp::socket socket)
|
||||
: ws_(std::move(socket))
|
||||
, strand_(ws_.get_io_service())
|
||||
, strand_(ws_.get_executor())
|
||||
{
|
||||
setup_stream(ws_);
|
||||
}
|
||||
@@ -162,10 +164,12 @@ public:
|
||||
res.set(http::field::server,
|
||||
"Boost.Beast.async/" + std::to_string(BOOST_BEAST_VERSION));
|
||||
},
|
||||
strand_.wrap(std::bind(
|
||||
&async_session::on_accept,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&async_session::on_accept,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -184,11 +188,13 @@ public:
|
||||
// Read a message into our buffer
|
||||
ws_.async_read(
|
||||
buffer_,
|
||||
strand_.wrap(std::bind(
|
||||
&async_session::on_read,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&async_session::on_read,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -209,11 +215,13 @@ public:
|
||||
ws_.text(ws_.got_text());
|
||||
ws_.async_write(
|
||||
buffer_.data(),
|
||||
strand_.wrap(std::bind(
|
||||
&async_session::on_write,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&async_session::on_write,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -237,17 +245,18 @@ public:
|
||||
// Accepts incoming connections and launches the sessions
|
||||
class async_listener : public std::enable_shared_from_this<async_listener>
|
||||
{
|
||||
boost::asio::io_service::strand strand_;
|
||||
boost::asio::strand<
|
||||
boost::asio::io_context::executor_type> strand_;
|
||||
tcp::acceptor acceptor_;
|
||||
tcp::socket socket_;
|
||||
|
||||
public:
|
||||
async_listener(
|
||||
boost::asio::io_service& ios,
|
||||
boost::asio::io_context& ioc,
|
||||
tcp::endpoint endpoint)
|
||||
: strand_(ios)
|
||||
, acceptor_(ios)
|
||||
, socket_(ios)
|
||||
: strand_(ioc.get_executor())
|
||||
, acceptor_(ioc)
|
||||
, socket_(ioc)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
|
||||
@@ -269,7 +278,7 @@ public:
|
||||
|
||||
// Start listening for connections
|
||||
acceptor_.listen(
|
||||
boost::asio::socket_base::max_connections, ec);
|
||||
boost::asio::socket_base::max_listen_connections, ec);
|
||||
if(ec)
|
||||
{
|
||||
fail(ec, "listen");
|
||||
@@ -291,10 +300,12 @@ public:
|
||||
{
|
||||
acceptor_.async_accept(
|
||||
socket_,
|
||||
strand_.wrap(std::bind(
|
||||
&async_listener::on_accept,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&async_listener::on_accept,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -354,13 +365,13 @@ do_coro_session(tcp::socket& socket, boost::asio::yield_context yield)
|
||||
|
||||
void
|
||||
do_coro_listen(
|
||||
boost::asio::io_service& ios,
|
||||
boost::asio::io_context& ioc,
|
||||
tcp::endpoint endpoint,
|
||||
boost::asio::yield_context yield)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
|
||||
tcp::acceptor acceptor(ios);
|
||||
tcp::acceptor acceptor(ioc);
|
||||
acceptor.open(endpoint.protocol(), ec);
|
||||
if(ec)
|
||||
return fail(ec, "open");
|
||||
@@ -369,13 +380,13 @@ do_coro_listen(
|
||||
if(ec)
|
||||
return fail(ec, "bind");
|
||||
|
||||
acceptor.listen(boost::asio::socket_base::max_connections, ec);
|
||||
acceptor.listen(boost::asio::socket_base::max_listen_connections, ec);
|
||||
if(ec)
|
||||
return fail(ec, "listen");
|
||||
|
||||
for(;;)
|
||||
{
|
||||
tcp::socket socket(ios);
|
||||
tcp::socket socket(ioc);
|
||||
|
||||
acceptor.async_accept(socket, yield[ec]);
|
||||
if(ec)
|
||||
@@ -385,7 +396,7 @@ do_coro_listen(
|
||||
}
|
||||
|
||||
boost::asio::spawn(
|
||||
acceptor.get_io_service(),
|
||||
acceptor.get_executor().context(),
|
||||
std::bind(
|
||||
&do_coro_session,
|
||||
std::move(socket),
|
||||
@@ -410,17 +421,17 @@ int main(int argc, char* argv[])
|
||||
" starting-port+2 for coroutine.\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto const address = boost::asio::ip::address::from_string(argv[1]);
|
||||
auto const address = boost::asio::ip::make_address(argv[1]);
|
||||
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
|
||||
auto const threads = std::max<std::size_t>(1, std::atoi(argv[3]));
|
||||
auto const threads = std::max<int>(1, std::atoi(argv[3]));
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios{threads};
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc{threads};
|
||||
|
||||
// Create sync port
|
||||
std::thread(std::bind(
|
||||
&do_sync_listen,
|
||||
std::ref(ios),
|
||||
std::ref(ioc),
|
||||
tcp::endpoint{
|
||||
address,
|
||||
static_cast<unsigned short>(port + 0u)}
|
||||
@@ -428,16 +439,16 @@ int main(int argc, char* argv[])
|
||||
|
||||
// Create async port
|
||||
std::make_shared<async_listener>(
|
||||
ios,
|
||||
ioc,
|
||||
tcp::endpoint{
|
||||
address,
|
||||
static_cast<unsigned short>(port + 1u)})->run();
|
||||
|
||||
// Create coro port
|
||||
boost::asio::spawn(ios,
|
||||
boost::asio::spawn(ioc,
|
||||
std::bind(
|
||||
&do_coro_listen,
|
||||
std::ref(ios),
|
||||
std::ref(ioc),
|
||||
tcp::endpoint{
|
||||
address,
|
||||
static_cast<unsigned short>(port + 2u)},
|
||||
@@ -448,11 +459,11 @@ int main(int argc, char* argv[])
|
||||
v.reserve(threads - 1);
|
||||
for(auto i = threads - 1; i > 0; --i)
|
||||
v.emplace_back(
|
||||
[&ios]
|
||||
[&ioc]
|
||||
{
|
||||
ios.run();
|
||||
ioc.run();
|
||||
});
|
||||
ios.run();
|
||||
ioc.run();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <boost/beast/core.hpp>
|
||||
#include <boost/beast/websocket.hpp>
|
||||
#include <boost/beast/websocket/ssl.hpp>
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/asio/coroutine.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/ssl/stream.hpp>
|
||||
@@ -51,7 +52,8 @@ class session
|
||||
{
|
||||
tcp::socket socket_;
|
||||
websocket::stream<ssl::stream<tcp::socket&>> ws_;
|
||||
boost::asio::io_service::strand strand_;
|
||||
boost::asio::strand<
|
||||
boost::asio::io_context::executor_type> strand_;
|
||||
boost::beast::multi_buffer buffer_;
|
||||
|
||||
public:
|
||||
@@ -59,7 +61,7 @@ public:
|
||||
session(tcp::socket socket, ssl::context& ctx)
|
||||
: socket_(std::move(socket))
|
||||
, ws_(socket_, ctx)
|
||||
, strand_(ws_.get_io_service())
|
||||
, strand_(ws_.get_executor())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -83,21 +85,25 @@ public:
|
||||
// Perform the SSL handshake
|
||||
yield ws_.next_layer().async_handshake(
|
||||
ssl::stream_base::server,
|
||||
strand_.wrap(std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
0)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
0)));
|
||||
if(ec)
|
||||
return fail(ec, "handshake");
|
||||
|
||||
// Accept the websocket handshake
|
||||
yield ws_.async_accept(
|
||||
strand_.wrap(std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
0)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
0)));
|
||||
if(ec)
|
||||
return fail(ec, "accept");
|
||||
|
||||
@@ -106,11 +112,13 @@ public:
|
||||
// Read a message into our buffer
|
||||
yield ws_.async_read(
|
||||
buffer_,
|
||||
strand_.wrap(std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
if(ec == websocket::error::closed)
|
||||
{
|
||||
// This indicates that the session was closed
|
||||
@@ -123,11 +131,13 @@ public:
|
||||
ws_.text(ws_.got_text());
|
||||
yield ws_.async_write(
|
||||
buffer_.data(),
|
||||
strand_.wrap(std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
if(ec)
|
||||
return fail(ec, "write");
|
||||
|
||||
@@ -152,12 +162,12 @@ class listener
|
||||
|
||||
public:
|
||||
listener(
|
||||
boost::asio::io_service& ios,
|
||||
boost::asio::io_context& ioc,
|
||||
ssl::context& ctx,
|
||||
tcp::endpoint endpoint)
|
||||
: ctx_(ctx)
|
||||
, acceptor_(ios)
|
||||
, socket_(ios)
|
||||
, acceptor_(ioc)
|
||||
, socket_(ioc)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
|
||||
@@ -179,7 +189,7 @@ public:
|
||||
|
||||
// Start listening for connections
|
||||
acceptor_.listen(
|
||||
boost::asio::socket_base::max_connections, ec);
|
||||
boost::asio::socket_base::max_listen_connections, ec);
|
||||
if(ec)
|
||||
{
|
||||
fail(ec, "listen");
|
||||
@@ -238,12 +248,12 @@ int main(int argc, char* argv[])
|
||||
" websocket-server-async-ssl 0.0.0.0 8080 1\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto const address = boost::asio::ip::address::from_string(argv[1]);
|
||||
auto const address = boost::asio::ip::make_address(argv[1]);
|
||||
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
|
||||
auto const threads = std::max<std::size_t>(1, std::atoi(argv[3]));
|
||||
auto const threads = std::max<int>(1, std::atoi(argv[3]));
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios{threads};
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc{threads};
|
||||
|
||||
// The SSL context is required, and holds certificates
|
||||
ssl::context ctx{ssl::context::sslv23};
|
||||
@@ -252,18 +262,18 @@ int main(int argc, char* argv[])
|
||||
load_server_certificate(ctx);
|
||||
|
||||
// Create and launch a listening port
|
||||
std::make_shared<listener>(ios, ctx, tcp::endpoint{address, port})->run();
|
||||
std::make_shared<listener>(ioc, ctx, tcp::endpoint{address, port})->run();
|
||||
|
||||
// Run the I/O service on the requested number of threads
|
||||
std::vector<std::thread> v;
|
||||
v.reserve(threads - 1);
|
||||
for(auto i = threads - 1; i > 0; --i)
|
||||
v.emplace_back(
|
||||
[&ios]
|
||||
[&ioc]
|
||||
{
|
||||
ios.run();
|
||||
ioc.run();
|
||||
});
|
||||
ios.run();
|
||||
ioc.run();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include <boost/beast/core.hpp>
|
||||
#include <boost/beast/websocket.hpp>
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/asio/coroutine.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
@@ -45,7 +46,8 @@ class session
|
||||
, public std::enable_shared_from_this<session>
|
||||
{
|
||||
websocket::stream<tcp::socket> ws_;
|
||||
boost::asio::io_service::strand strand_;
|
||||
boost::asio::strand<
|
||||
boost::asio::io_context::executor_type> strand_;
|
||||
boost::beast::multi_buffer buffer_;
|
||||
|
||||
public:
|
||||
@@ -53,7 +55,7 @@ public:
|
||||
explicit
|
||||
session(tcp::socket socket)
|
||||
: ws_(std::move(socket))
|
||||
, strand_(ws_.get_io_service())
|
||||
, strand_(ws_.get_executor())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -75,11 +77,13 @@ public:
|
||||
{
|
||||
// Accept the websocket handshake
|
||||
yield ws_.async_accept(
|
||||
strand_.wrap(std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
0)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
0)));
|
||||
if(ec)
|
||||
return fail(ec, "accept");
|
||||
|
||||
@@ -88,11 +92,13 @@ public:
|
||||
// Read a message into our buffer
|
||||
yield ws_.async_read(
|
||||
buffer_,
|
||||
strand_.wrap(std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
if(ec == websocket::error::closed)
|
||||
{
|
||||
// This indicates that the session was closed
|
||||
@@ -105,11 +111,13 @@ public:
|
||||
ws_.text(ws_.got_text());
|
||||
yield ws_.async_write(
|
||||
buffer_.data(),
|
||||
strand_.wrap(std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
boost::asio::bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
&session::loop,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2)));
|
||||
if(ec)
|
||||
return fail(ec, "write");
|
||||
|
||||
@@ -133,10 +141,10 @@ class listener
|
||||
|
||||
public:
|
||||
listener(
|
||||
boost::asio::io_service& ios,
|
||||
boost::asio::io_context& ioc,
|
||||
tcp::endpoint endpoint)
|
||||
: acceptor_(ios)
|
||||
, socket_(ios)
|
||||
: acceptor_(ioc)
|
||||
, socket_(ioc)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
|
||||
@@ -158,7 +166,7 @@ public:
|
||||
|
||||
// Start listening for connections
|
||||
acceptor_.listen(
|
||||
boost::asio::socket_base::max_connections, ec);
|
||||
boost::asio::socket_base::max_listen_connections, ec);
|
||||
if(ec)
|
||||
{
|
||||
fail(ec, "listen");
|
||||
@@ -217,26 +225,26 @@ int main(int argc, char* argv[])
|
||||
" websocket-server-stackless 0.0.0.0 8080 1\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto const address = boost::asio::ip::address::from_string(argv[1]);
|
||||
auto const address = boost::asio::ip::make_address(argv[1]);
|
||||
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
|
||||
auto const threads = std::max<std::size_t>(1, std::atoi(argv[3]));
|
||||
auto const threads = std::max<int>(1, std::atoi(argv[3]));
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios{threads};
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc{threads};
|
||||
|
||||
// Create and launch a listening port
|
||||
std::make_shared<listener>(ios, tcp::endpoint{address, port})->run();
|
||||
std::make_shared<listener>(ioc, tcp::endpoint{address, port})->run();
|
||||
|
||||
// Run the I/O service on the requested number of threads
|
||||
std::vector<std::thread> v;
|
||||
v.reserve(threads - 1);
|
||||
for(auto i = threads - 1; i > 0; --i)
|
||||
v.emplace_back(
|
||||
[&ios]
|
||||
[&ioc]
|
||||
{
|
||||
ios.run();
|
||||
ioc.run();
|
||||
});
|
||||
ios.run();
|
||||
ioc.run();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -87,11 +87,11 @@ int main(int argc, char* argv[])
|
||||
" websocket-server-sync-ssl 0.0.0.0 8080\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto const address = boost::asio::ip::address::from_string(argv[1]);
|
||||
auto const address = boost::asio::ip::make_address(argv[1]);
|
||||
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios{1};
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc{1};
|
||||
|
||||
// The SSL context is required, and holds certificates
|
||||
ssl::context ctx{ssl::context::sslv23};
|
||||
@@ -100,11 +100,11 @@ int main(int argc, char* argv[])
|
||||
load_server_certificate(ctx);
|
||||
|
||||
// The acceptor receives incoming connections
|
||||
tcp::acceptor acceptor{ios, {address, port}};
|
||||
tcp::acceptor acceptor{ioc, {address, port}};
|
||||
for(;;)
|
||||
{
|
||||
// This will receive the new connection
|
||||
tcp::socket socket{ios};
|
||||
tcp::socket socket{ioc};
|
||||
|
||||
// Block until we get a connection
|
||||
acceptor.accept(socket);
|
||||
|
||||
@@ -79,18 +79,18 @@ int main(int argc, char* argv[])
|
||||
" websocket-server-sync 0.0.0.0 8080\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto const address = boost::asio::ip::address::from_string(argv[1]);
|
||||
auto const address = boost::asio::ip::make_address(argv[1]);
|
||||
auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
|
||||
|
||||
// The io_service is required for all I/O
|
||||
boost::asio::io_service ios{1};
|
||||
// The io_context is required for all I/O
|
||||
boost::asio::io_context ioc{1};
|
||||
|
||||
// The acceptor receives incoming connections
|
||||
tcp::acceptor acceptor{ios, {address, port}};
|
||||
tcp::acceptor acceptor{ioc, {address, port}};
|
||||
for(;;)
|
||||
{
|
||||
// This will receive the new connection
|
||||
tcp::socket socket{ios};
|
||||
tcp::socket socket{ioc};
|
||||
|
||||
// Block until we get a connection
|
||||
acceptor.accept(socket);
|
||||
|
||||
Reference in New Issue
Block a user