summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/beast/example/websocket/server
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/beast/example/websocket/server')
-rw-r--r--src/boost/libs/beast/example/websocket/server/CMakeLists.txt22
-rw-r--r--src/boost/libs/beast/example/websocket/server/Jamfile21
-rw-r--r--src/boost/libs/beast/example/websocket/server/async-ssl/CMakeLists.txt31
-rw-r--r--src/boost/libs/beast/example/websocket/server/async-ssl/Jamfile22
-rw-r--r--src/boost/libs/beast/example/websocket/server/async-ssl/websocket_server_async_ssl.cpp317
-rw-r--r--src/boost/libs/beast/example/websocket/server/async/CMakeLists.txt23
-rw-r--r--src/boost/libs/beast/example/websocket/server/async/Jamfile15
-rw-r--r--src/boost/libs/beast/example/websocket/server/async/websocket_server_async.cpp281
-rw-r--r--src/boost/libs/beast/example/websocket/server/chat-multi/CMakeLists.txt41
-rw-r--r--src/boost/libs/beast/example/websocket/server/chat-multi/Jamfile19
-rw-r--r--src/boost/libs/beast/example/websocket/server/chat-multi/beast.hpp19
-rw-r--r--src/boost/libs/beast/example/websocket/server/chat-multi/chat_client.html60
-rw-r--r--src/boost/libs/beast/example/websocket/server/chat-multi/http_session.cpp371
-rw-r--r--src/boost/libs/beast/example/websocket/server/chat-multi/http_session.hpp48
-rw-r--r--src/boost/libs/beast/example/websocket/server/chat-multi/listener.cpp101
-rw-r--r--src/boost/libs/beast/example/websocket/server/chat-multi/listener.hpp42
-rw-r--r--src/boost/libs/beast/example/websocket/server/chat-multi/main.cpp84
-rw-r--r--src/boost/libs/beast/example/websocket/server/chat-multi/net.hpp18
-rw-r--r--src/boost/libs/beast/example/websocket/server/chat-multi/shared_state.cpp59
-rw-r--r--src/boost/libs/beast/example/websocket/server/chat-multi/shared_state.hpp48
-rw-r--r--src/boost/libs/beast/example/websocket/server/chat-multi/websocket_session.cpp135
-rw-r--r--src/boost/libs/beast/example/websocket/server/chat-multi/websocket_session.hpp86
-rw-r--r--src/boost/libs/beast/example/websocket/server/coro-ssl/CMakeLists.txt31
-rw-r--r--src/boost/libs/beast/example/websocket/server/coro-ssl/Jamfile23
-rw-r--r--src/boost/libs/beast/example/websocket/server/coro-ssl/websocket_server_coro_ssl.cpp206
-rw-r--r--src/boost/libs/beast/example/websocket/server/coro/CMakeLists.txt23
-rw-r--r--src/boost/libs/beast/example/websocket/server/coro/Jamfile16
-rw-r--r--src/boost/libs/beast/example/websocket/server/coro/websocket_server_coro.cpp180
-rw-r--r--src/boost/libs/beast/example/websocket/server/fast/CMakeLists.txt23
-rw-r--r--src/boost/libs/beast/example/websocket/server/fast/Jamfile16
-rw-r--r--src/boost/libs/beast/example/websocket/server/fast/websocket_server_fast.cpp480
-rw-r--r--src/boost/libs/beast/example/websocket/server/stackless-ssl/CMakeLists.txt31
-rw-r--r--src/boost/libs/beast/example/websocket/server/stackless-ssl/Jamfile22
-rw-r--r--src/boost/libs/beast/example/websocket/server/stackless-ssl/websocket_server_stackless_ssl.cpp314
-rw-r--r--src/boost/libs/beast/example/websocket/server/stackless/CMakeLists.txt23
-rw-r--r--src/boost/libs/beast/example/websocket/server/stackless/Jamfile15
-rw-r--r--src/boost/libs/beast/example/websocket/server/stackless/websocket_server_stackless.cpp282
-rw-r--r--src/boost/libs/beast/example/websocket/server/sync-ssl/CMakeLists.txt31
-rw-r--r--src/boost/libs/beast/example/websocket/server/sync-ssl/Jamfile22
-rw-r--r--src/boost/libs/beast/example/websocket/server/sync-ssl/websocket_server_sync_ssl.cpp137
-rw-r--r--src/boost/libs/beast/example/websocket/server/sync/CMakeLists.txt23
-rw-r--r--src/boost/libs/beast/example/websocket/server/sync/Jamfile15
-rw-r--r--src/boost/libs/beast/example/websocket/server/sync/websocket_server_sync.cpp121
43 files changed, 3897 insertions, 0 deletions
diff --git a/src/boost/libs/beast/example/websocket/server/CMakeLists.txt b/src/boost/libs/beast/example/websocket/server/CMakeLists.txt
new file mode 100644
index 000000000..c5b8da5d6
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/CMakeLists.txt
@@ -0,0 +1,22 @@
+#
+# Copyright (c) 2013-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
+#
+
+add_subdirectory (async)
+add_subdirectory (chat-multi)
+add_subdirectory (coro)
+add_subdirectory (fast)
+add_subdirectory (stackless)
+add_subdirectory (sync)
+
+if (OPENSSL_FOUND)
+ add_subdirectory (async-ssl)
+ add_subdirectory (coro-ssl)
+ add_subdirectory (stackless-ssl)
+ add_subdirectory (sync-ssl)
+endif()
diff --git a/src/boost/libs/beast/example/websocket/server/Jamfile b/src/boost/libs/beast/example/websocket/server/Jamfile
new file mode 100644
index 000000000..ccfd63fa4
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/Jamfile
@@ -0,0 +1,21 @@
+#
+# Copyright (c) 2013-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
+#
+
+build-project async ;
+build-project chat-multi ;
+build-project coro ;
+build-project fast ;
+build-project stackless ;
+build-project sync ;
+
+# SSL
+build-project async-ssl ;
+build-project coro-ssl ;
+build-project stackless-ssl ;
+build-project sync-ssl ;
diff --git a/src/boost/libs/beast/example/websocket/server/async-ssl/CMakeLists.txt b/src/boost/libs/beast/example/websocket/server/async-ssl/CMakeLists.txt
new file mode 100644
index 000000000..8f1055d2f
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/async-ssl/CMakeLists.txt
@@ -0,0 +1,31 @@
+#
+# 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
+#
+
+if (OPENSSL_FOUND)
+ GroupSources(include/boost/beast beast)
+ GroupSources(example/common common)
+ GroupSources(example/websocket/server/async-ssl "/")
+
+ add_executable (websocket-server-async-ssl
+ ${BOOST_BEAST_FILES}
+ ${PROJECT_SOURCE_DIR}/example/common/server_certificate.hpp
+ Jamfile
+ websocket_server_async_ssl.cpp
+ )
+
+ set_property(TARGET websocket-server-async-ssl PROPERTY FOLDER "example-websocket-server")
+
+ target_link_libraries (websocket-server-async-ssl
+ OpenSSL::SSL OpenSSL::Crypto
+ lib-asio
+ lib-asio-ssl
+ lib-beast
+ )
+
+endif()
diff --git a/src/boost/libs/beast/example/websocket/server/async-ssl/Jamfile b/src/boost/libs/beast/example/websocket/server/async-ssl/Jamfile
new file mode 100644
index 000000000..f9b253a0c
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/async-ssl/Jamfile
@@ -0,0 +1,22 @@
+#
+# 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
+#
+
+import ac ;
+
+project
+ : requirements
+ [ ac.check-library /boost/beast//lib-asio-ssl : <library>/boost/beast//lib-asio-ssl/<link>static : <build>no ]
+ ;
+
+exe websocket-server-async-ssl :
+ websocket_server_async_ssl.cpp
+ :
+ <variant>coverage:<build>no
+ <variant>ubasan:<build>no
+ ;
diff --git a/src/boost/libs/beast/example/websocket/server/async-ssl/websocket_server_async_ssl.cpp b/src/boost/libs/beast/example/websocket/server/async-ssl/websocket_server_async_ssl.cpp
new file mode 100644
index 000000000..b79abbbfb
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/async-ssl/websocket_server_async_ssl.cpp
@@ -0,0 +1,317 @@
+//
+// Copyright (c) 2016-2019 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
+//
+
+//------------------------------------------------------------------------------
+//
+// Example: WebSocket SSL server, asynchronous
+//
+//------------------------------------------------------------------------------
+
+#include "example/common/server_certificate.hpp"
+
+#include <boost/beast/core.hpp>
+#include <boost/beast/ssl.hpp>
+#include <boost/beast/websocket.hpp>
+#include <boost/beast/websocket/ssl.hpp>
+#include <boost/asio/strand.hpp>
+#include <boost/asio/dispatch.hpp>
+#include <algorithm>
+#include <cstdlib>
+#include <functional>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <thread>
+#include <vector>
+
+namespace beast = boost::beast; // from <boost/beast.hpp>
+namespace http = beast::http; // from <boost/beast/http.hpp>
+namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
+namespace net = boost::asio; // from <boost/asio.hpp>
+namespace ssl = boost::asio::ssl; // from <boost/asio/ssl.hpp>
+using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
+
+//------------------------------------------------------------------------------
+
+// Report a failure
+void
+fail(beast::error_code ec, char const* what)
+{
+ std::cerr << what << ": " << ec.message() << "\n";
+}
+
+// Echoes back all received WebSocket messages
+class session : public std::enable_shared_from_this<session>
+{
+ websocket::stream<
+ beast::ssl_stream<beast::tcp_stream>> ws_;
+ beast::flat_buffer buffer_;
+
+public:
+ // Take ownership of the socket
+ session(tcp::socket&& socket, ssl::context& ctx)
+ : ws_(std::move(socket), ctx)
+ {
+ }
+
+ // Get on the correct executor
+ void
+ run()
+ {
+ // We need to be executing within a strand to perform async operations
+ // on the I/O objects in this session. Although not strictly necessary
+ // for single-threaded contexts, this example code is written to be
+ // thread-safe by default.
+ net::dispatch(ws_.get_executor(),
+ beast::bind_front_handler(
+ &session::on_run,
+ shared_from_this()));
+ }
+
+ // Start the asynchronous operation
+ void
+ on_run()
+ {
+ // Set the timeout.
+ beast::get_lowest_layer(ws_).expires_after(std::chrono::seconds(30));
+
+ // Perform the SSL handshake
+ ws_.next_layer().async_handshake(
+ ssl::stream_base::server,
+ beast::bind_front_handler(
+ &session::on_handshake,
+ shared_from_this()));
+ }
+
+ void
+ on_handshake(beast::error_code ec)
+ {
+ if(ec)
+ return fail(ec, "handshake");
+
+ // Turn off the timeout on the tcp_stream, because
+ // the websocket stream has its own timeout system.
+ beast::get_lowest_layer(ws_).expires_never();
+
+ // Set suggested timeout settings for the websocket
+ ws_.set_option(
+ websocket::stream_base::timeout::suggested(
+ beast::role_type::server));
+
+ // Set a decorator to change the Server of the handshake
+ ws_.set_option(websocket::stream_base::decorator(
+ [](websocket::response_type& res)
+ {
+ res.set(http::field::server,
+ std::string(BOOST_BEAST_VERSION_STRING) +
+ " websocket-server-async-ssl");
+ }));
+
+ // Accept the websocket handshake
+ ws_.async_accept(
+ beast::bind_front_handler(
+ &session::on_accept,
+ shared_from_this()));
+ }
+
+ void
+ on_accept(beast::error_code ec)
+ {
+ if(ec)
+ return fail(ec, "accept");
+
+ // Read a message
+ do_read();
+ }
+
+ void
+ do_read()
+ {
+ // Read a message into our buffer
+ ws_.async_read(
+ buffer_,
+ beast::bind_front_handler(
+ &session::on_read,
+ shared_from_this()));
+ }
+
+ void
+ on_read(
+ beast::error_code ec,
+ std::size_t bytes_transferred)
+ {
+ boost::ignore_unused(bytes_transferred);
+
+ // This indicates that the session was closed
+ if(ec == websocket::error::closed)
+ return;
+
+ if(ec)
+ fail(ec, "read");
+
+ // Echo the message
+ ws_.text(ws_.got_text());
+ ws_.async_write(
+ buffer_.data(),
+ beast::bind_front_handler(
+ &session::on_write,
+ shared_from_this()));
+ }
+
+ void
+ on_write(
+ beast::error_code ec,
+ std::size_t bytes_transferred)
+ {
+ boost::ignore_unused(bytes_transferred);
+
+ if(ec)
+ return fail(ec, "write");
+
+ // Clear the buffer
+ buffer_.consume(buffer_.size());
+
+ // Do another read
+ do_read();
+ }
+};
+
+//------------------------------------------------------------------------------
+
+// Accepts incoming connections and launches the sessions
+class listener : public std::enable_shared_from_this<listener>
+{
+ net::io_context& ioc_;
+ ssl::context& ctx_;
+ tcp::acceptor acceptor_;
+
+public:
+ listener(
+ net::io_context& ioc,
+ ssl::context& ctx,
+ tcp::endpoint endpoint)
+ : ioc_(ioc)
+ , ctx_(ctx)
+ , acceptor_(net::make_strand(ioc))
+ {
+ beast::error_code ec;
+
+ // Open the acceptor
+ acceptor_.open(endpoint.protocol(), ec);
+ if(ec)
+ {
+ fail(ec, "open");
+ return;
+ }
+
+ // Allow address reuse
+ acceptor_.set_option(net::socket_base::reuse_address(true), ec);
+ if(ec)
+ {
+ fail(ec, "set_option");
+ return;
+ }
+
+ // Bind to the server address
+ acceptor_.bind(endpoint, ec);
+ if(ec)
+ {
+ fail(ec, "bind");
+ return;
+ }
+
+ // Start listening for connections
+ acceptor_.listen(
+ net::socket_base::max_listen_connections, ec);
+ if(ec)
+ {
+ fail(ec, "listen");
+ return;
+ }
+ }
+
+ // Start accepting incoming connections
+ void
+ run()
+ {
+ do_accept();
+ }
+
+private:
+ void
+ do_accept()
+ {
+ // The new connection gets its own strand
+ acceptor_.async_accept(
+ net::make_strand(ioc_),
+ beast::bind_front_handler(
+ &listener::on_accept,
+ shared_from_this()));
+ }
+
+ void
+ on_accept(beast::error_code ec, tcp::socket socket)
+ {
+ if(ec)
+ {
+ fail(ec, "accept");
+ }
+ else
+ {
+ // Create the session and run it
+ std::make_shared<session>(std::move(socket), ctx_)->run();
+ }
+
+ // Accept another connection
+ do_accept();
+ }
+};
+
+//------------------------------------------------------------------------------
+
+int main(int argc, char* argv[])
+{
+ // Check command line arguments.
+ if (argc != 4)
+ {
+ std::cerr <<
+ "Usage: websocket-server-async-ssl <address> <port> <threads>\n" <<
+ "Example:\n" <<
+ " websocket-server-async-ssl 0.0.0.0 8080 1\n";
+ return EXIT_FAILURE;
+ }
+ auto const address = net::ip::make_address(argv[1]);
+ auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
+ auto const threads = std::max<int>(1, std::atoi(argv[3]));
+
+ // The io_context is required for all I/O
+ net::io_context ioc{threads};
+
+ // The SSL context is required, and holds certificates
+ ssl::context ctx{ssl::context::tlsv12};
+
+ // This holds the self-signed certificate used by the server
+ load_server_certificate(ctx);
+
+ // Create and launch a listening port
+ 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(
+ [&ioc]
+ {
+ ioc.run();
+ });
+ ioc.run();
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/boost/libs/beast/example/websocket/server/async/CMakeLists.txt b/src/boost/libs/beast/example/websocket/server/async/CMakeLists.txt
new file mode 100644
index 000000000..0e1ceb8b6
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/async/CMakeLists.txt
@@ -0,0 +1,23 @@
+#
+# 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
+#
+
+GroupSources(include/boost/beast beast)
+GroupSources(example/websocket/server/async "/")
+
+add_executable (websocket-server-async
+ ${BOOST_BEAST_FILES}
+ Jamfile
+ websocket_server_async.cpp
+)
+
+target_link_libraries(websocket-server-async
+ lib-asio
+ lib-beast)
+
+set_property(TARGET websocket-server-async PROPERTY FOLDER "example-websocket-server")
diff --git a/src/boost/libs/beast/example/websocket/server/async/Jamfile b/src/boost/libs/beast/example/websocket/server/async/Jamfile
new file mode 100644
index 000000000..e1e63e14d
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/async/Jamfile
@@ -0,0 +1,15 @@
+#
+# 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
+#
+
+exe websocket-server-async :
+ websocket_server_async.cpp
+ :
+ <variant>coverage:<build>no
+ <variant>ubasan:<build>no
+ ;
diff --git a/src/boost/libs/beast/example/websocket/server/async/websocket_server_async.cpp b/src/boost/libs/beast/example/websocket/server/async/websocket_server_async.cpp
new file mode 100644
index 000000000..4b9570868
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/async/websocket_server_async.cpp
@@ -0,0 +1,281 @@
+//
+// Copyright (c) 2016-2019 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
+//
+
+//------------------------------------------------------------------------------
+//
+// Example: WebSocket server, asynchronous
+//
+//------------------------------------------------------------------------------
+
+#include <boost/beast/core.hpp>
+#include <boost/beast/websocket.hpp>
+#include <boost/asio/dispatch.hpp>
+#include <boost/asio/strand.hpp>
+#include <algorithm>
+#include <cstdlib>
+#include <functional>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <thread>
+#include <vector>
+
+namespace beast = boost::beast; // from <boost/beast.hpp>
+namespace http = beast::http; // from <boost/beast/http.hpp>
+namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
+namespace net = boost::asio; // from <boost/asio.hpp>
+using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
+
+//------------------------------------------------------------------------------
+
+// Report a failure
+void
+fail(beast::error_code ec, char const* what)
+{
+ std::cerr << what << ": " << ec.message() << "\n";
+}
+
+// Echoes back all received WebSocket messages
+class session : public std::enable_shared_from_this<session>
+{
+ websocket::stream<beast::tcp_stream> ws_;
+ beast::flat_buffer buffer_;
+
+public:
+ // Take ownership of the socket
+ explicit
+ session(tcp::socket&& socket)
+ : ws_(std::move(socket))
+ {
+ }
+
+ // Get on the correct executor
+ void
+ run()
+ {
+ // We need to be executing within a strand to perform async operations
+ // on the I/O objects in this session. Although not strictly necessary
+ // for single-threaded contexts, this example code is written to be
+ // thread-safe by default.
+ net::dispatch(ws_.get_executor(),
+ beast::bind_front_handler(
+ &session::on_run,
+ shared_from_this()));
+ }
+
+ // Start the asynchronous operation
+ void
+ on_run()
+ {
+ // Set suggested timeout settings for the websocket
+ ws_.set_option(
+ websocket::stream_base::timeout::suggested(
+ beast::role_type::server));
+
+ // Set a decorator to change the Server of the handshake
+ ws_.set_option(websocket::stream_base::decorator(
+ [](websocket::response_type& res)
+ {
+ res.set(http::field::server,
+ std::string(BOOST_BEAST_VERSION_STRING) +
+ " websocket-server-async");
+ }));
+ // Accept the websocket handshake
+ ws_.async_accept(
+ beast::bind_front_handler(
+ &session::on_accept,
+ shared_from_this()));
+ }
+
+ void
+ on_accept(beast::error_code ec)
+ {
+ if(ec)
+ return fail(ec, "accept");
+
+ // Read a message
+ do_read();
+ }
+
+ void
+ do_read()
+ {
+ // Read a message into our buffer
+ ws_.async_read(
+ buffer_,
+ beast::bind_front_handler(
+ &session::on_read,
+ shared_from_this()));
+ }
+
+ void
+ on_read(
+ beast::error_code ec,
+ std::size_t bytes_transferred)
+ {
+ boost::ignore_unused(bytes_transferred);
+
+ // This indicates that the session was closed
+ if(ec == websocket::error::closed)
+ return;
+
+ if(ec)
+ fail(ec, "read");
+
+ // Echo the message
+ ws_.text(ws_.got_text());
+ ws_.async_write(
+ buffer_.data(),
+ beast::bind_front_handler(
+ &session::on_write,
+ shared_from_this()));
+ }
+
+ void
+ on_write(
+ beast::error_code ec,
+ std::size_t bytes_transferred)
+ {
+ boost::ignore_unused(bytes_transferred);
+
+ if(ec)
+ return fail(ec, "write");
+
+ // Clear the buffer
+ buffer_.consume(buffer_.size());
+
+ // Do another read
+ do_read();
+ }
+};
+
+//------------------------------------------------------------------------------
+
+// Accepts incoming connections and launches the sessions
+class listener : public std::enable_shared_from_this<listener>
+{
+ net::io_context& ioc_;
+ tcp::acceptor acceptor_;
+
+public:
+ listener(
+ net::io_context& ioc,
+ tcp::endpoint endpoint)
+ : ioc_(ioc)
+ , acceptor_(ioc)
+ {
+ beast::error_code ec;
+
+ // Open the acceptor
+ acceptor_.open(endpoint.protocol(), ec);
+ if(ec)
+ {
+ fail(ec, "open");
+ return;
+ }
+
+ // Allow address reuse
+ acceptor_.set_option(net::socket_base::reuse_address(true), ec);
+ if(ec)
+ {
+ fail(ec, "set_option");
+ return;
+ }
+
+ // Bind to the server address
+ acceptor_.bind(endpoint, ec);
+ if(ec)
+ {
+ fail(ec, "bind");
+ return;
+ }
+
+ // Start listening for connections
+ acceptor_.listen(
+ net::socket_base::max_listen_connections, ec);
+ if(ec)
+ {
+ fail(ec, "listen");
+ return;
+ }
+ }
+
+ // Start accepting incoming connections
+ void
+ run()
+ {
+ do_accept();
+ }
+
+private:
+ void
+ do_accept()
+ {
+ // The new connection gets its own strand
+ acceptor_.async_accept(
+ net::make_strand(ioc_),
+ beast::bind_front_handler(
+ &listener::on_accept,
+ shared_from_this()));
+ }
+
+ void
+ on_accept(beast::error_code ec, tcp::socket socket)
+ {
+ if(ec)
+ {
+ fail(ec, "accept");
+ }
+ else
+ {
+ // Create the session and run it
+ std::make_shared<session>(std::move(socket))->run();
+ }
+
+ // Accept another connection
+ do_accept();
+ }
+};
+
+//------------------------------------------------------------------------------
+
+int main(int argc, char* argv[])
+{
+ // Check command line arguments.
+ if (argc != 4)
+ {
+ std::cerr <<
+ "Usage: websocket-server-async <address> <port> <threads>\n" <<
+ "Example:\n" <<
+ " websocket-server-async 0.0.0.0 8080 1\n";
+ return EXIT_FAILURE;
+ }
+ auto const address = net::ip::make_address(argv[1]);
+ auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
+ auto const threads = std::max<int>(1, std::atoi(argv[3]));
+
+ // The io_context is required for all I/O
+ net::io_context ioc{threads};
+
+ // Create and launch a listening port
+ 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(
+ [&ioc]
+ {
+ ioc.run();
+ });
+ ioc.run();
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/boost/libs/beast/example/websocket/server/chat-multi/CMakeLists.txt b/src/boost/libs/beast/example/websocket/server/chat-multi/CMakeLists.txt
new file mode 100644
index 000000000..a256b000f
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/chat-multi/CMakeLists.txt
@@ -0,0 +1,41 @@
+#
+# 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
+#
+
+GroupSources(include/boost/beast beast)
+GroupSources(example/websocket/server/chat-multi "/")
+
+file (GLOB APP_FILES
+ beast.hpp
+ http_session.cpp
+ http_session.hpp
+ Jamfile
+ listener.cpp
+ listener.hpp
+ main.cpp
+ net.hpp
+ shared_state.cpp
+ shared_state.hpp
+ websocket_session.cpp
+ websocket_session.hpp
+ chat_client.html
+ README.md
+)
+
+source_group ("" FILES ${APP_FILES})
+
+add_executable (websocket-chat-multi
+ ${APP_FILES}
+ ${BOOST_BEAST_FILES}
+)
+
+target_link_libraries(websocket-chat-multi
+ lib-asio
+ lib-beast)
+
+set_property(TARGET websocket-chat-multi PROPERTY FOLDER "example-websocket-server")
diff --git a/src/boost/libs/beast/example/websocket/server/chat-multi/Jamfile b/src/boost/libs/beast/example/websocket/server/chat-multi/Jamfile
new file mode 100644
index 000000000..a8d49bfdd
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/chat-multi/Jamfile
@@ -0,0 +1,19 @@
+#
+# 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
+#
+
+exe websocket-chat-multi :
+ http_session.cpp
+ listener.cpp
+ main.cpp
+ shared_state.cpp
+ websocket_session.cpp
+ :
+ <variant>coverage:<build>no
+ <variant>ubasan:<build>no
+ ;
diff --git a/src/boost/libs/beast/example/websocket/server/chat-multi/beast.hpp b/src/boost/libs/beast/example/websocket/server/chat-multi/beast.hpp
new file mode 100644
index 000000000..0b7a9c61a
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/chat-multi/beast.hpp
@@ -0,0 +1,19 @@
+//
+// Copyright (c) 2016-2019 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/vinniefalco/CppCon2018
+//
+
+#ifndef BOOST_BEAST_EXAMPLE_WEBSOCKET_CHAT_MULTI_BEAST_HPP
+#define BOOST_BEAST_EXAMPLE_WEBSOCKET_CHAT_MULTI_BEAST_HPP
+
+#include <boost/beast.hpp>
+
+namespace beast = boost::beast; // from <boost/beast.hpp>
+namespace http = beast::http; // from <boost/beast/http.hpp>
+namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
+
+#endif
diff --git a/src/boost/libs/beast/example/websocket/server/chat-multi/chat_client.html b/src/boost/libs/beast/example/websocket/server/chat-multi/chat_client.html
new file mode 100644
index 000000000..2be69cdf0
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/chat-multi/chat_client.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8" />
+ <title>Boost.Beast WebSocket Chat Client</title>
+</head>
+<body>
+ <h1>Boost.Beast WebSocket Chat Client</h1>
+ <p>
+ <a href="http://www.boost.org/libs/beast">Boost.Beast</a>
+ <a href="http://www.boost.org/libs/beast/example/websocket/server/chat-multi">Source Code</a>
+ </p>
+ Server URI: <input class="draw-border" id="uri" size="47" value="ws://localhost:8080" style="margin-bottom: 5px;">
+ <button class="echo-button" id="connect">Connect</button>
+ <button class="echo-button" id="disconnect">Disconnect</button><br>
+ Your Name: <input class="draw-border" id="userName" size=47 style="margin-bottom: 5px;"><br>
+ <pre id="messages" style="width: 600px; height: 400px; white-space: normal; overflow: auto; border: solid 1px #cccccc; margin-bottom: 5px;"></pre>
+ <div style="margin-bottom: 5px;">
+ Message<br>
+ <input class="draw-border" id="sendMessage" size="74" value="">
+ <button class="echo-button" id="send">Send</button>
+ </div>
+ <script>
+ var ws = null;
+ function showMessage(msg) {
+ messages.innerText += msg + "\n";
+ messages.scrollTop = messages.scrollHeight - messages.clientHeight;
+ };
+ connect.onclick = function() {
+ ws = new WebSocket(uri.value);
+ ws.onopen = function(ev) {
+ showMessage("[connection opened]");
+ };
+ ws.onclose = function(ev) {
+ showMessage("[connection closed]");
+ };
+ ws.onmessage = function(ev) {
+ showMessage(ev.data);
+ };
+ ws.onerror = function(ev) {
+ showMessage("[error]");
+ console.log(ev);
+ };
+ };
+ disconnect.onclick = function() {
+ ws.close();
+ };
+ send.onclick = function() {
+ ws.send(userName.value + ": " + sendMessage.value);
+ sendMessage.value = "";
+ };
+ sendMessage.onkeyup = function(ev) {
+ ev.preventDefault();
+ if (ev.keyCode === 13) {
+ send.click();
+ }
+ }
+ </script>
+</body>
+</html>
diff --git a/src/boost/libs/beast/example/websocket/server/chat-multi/http_session.cpp b/src/boost/libs/beast/example/websocket/server/chat-multi/http_session.cpp
new file mode 100644
index 000000000..9d4dee871
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/chat-multi/http_session.cpp
@@ -0,0 +1,371 @@
+//
+// Copyright (c) 2016-2019 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/vinniefalco/CppCon2018
+//
+
+#include "http_session.hpp"
+#include "websocket_session.hpp"
+#include <boost/config.hpp>
+#include <iostream>
+
+#define BOOST_NO_CXX14_GENERIC_LAMBDAS
+
+//------------------------------------------------------------------------------
+
+// Return a reasonable mime type based on the extension of a file.
+beast::string_view
+mime_type(beast::string_view path)
+{
+ using beast::iequals;
+ auto const ext = [&path]
+ {
+ auto const pos = path.rfind(".");
+ if(pos == beast::string_view::npos)
+ return beast::string_view{};
+ return path.substr(pos);
+ }();
+ if(iequals(ext, ".htm")) return "text/html";
+ if(iequals(ext, ".html")) return "text/html";
+ if(iequals(ext, ".php")) return "text/html";
+ if(iequals(ext, ".css")) return "text/css";
+ if(iequals(ext, ".txt")) return "text/plain";
+ if(iequals(ext, ".js")) return "application/javascript";
+ if(iequals(ext, ".json")) return "application/json";
+ if(iequals(ext, ".xml")) return "application/xml";
+ if(iequals(ext, ".swf")) return "application/x-shockwave-flash";
+ if(iequals(ext, ".flv")) return "video/x-flv";
+ if(iequals(ext, ".png")) return "image/png";
+ if(iequals(ext, ".jpe")) return "image/jpeg";
+ if(iequals(ext, ".jpeg")) return "image/jpeg";
+ if(iequals(ext, ".jpg")) return "image/jpeg";
+ if(iequals(ext, ".gif")) return "image/gif";
+ if(iequals(ext, ".bmp")) return "image/bmp";
+ if(iequals(ext, ".ico")) return "image/vnd.microsoft.icon";
+ if(iequals(ext, ".tiff")) return "image/tiff";
+ if(iequals(ext, ".tif")) return "image/tiff";
+ if(iequals(ext, ".svg")) return "image/svg+xml";
+ if(iequals(ext, ".svgz")) return "image/svg+xml";
+ return "application/text";
+}
+
+// Append an HTTP rel-path to a local filesystem path.
+// The returned path is normalized for the platform.
+std::string
+path_cat(
+ beast::string_view base,
+ beast::string_view path)
+{
+ if(base.empty())
+ return std::string(path);
+ std::string result(base);
+#ifdef BOOST_MSVC
+ char constexpr path_separator = '\\';
+ if(result.back() == path_separator)
+ result.resize(result.size() - 1);
+ result.append(path.data(), path.size());
+ for(auto& c : result)
+ if(c == '/')
+ c = path_separator;
+#else
+ char constexpr path_separator = '/';
+ if(result.back() == path_separator)
+ result.resize(result.size() - 1);
+ result.append(path.data(), path.size());
+#endif
+ return result;
+}
+
+// This function produces an HTTP response for the given
+// request. The type of the response object depends on the
+// contents of the request, so the interface requires the
+// caller to pass a generic lambda for receiving the response.
+template<
+ class Body, class Allocator,
+ class Send>
+void
+handle_request(
+ beast::string_view doc_root,
+ http::request<Body, http::basic_fields<Allocator>>&& req,
+ Send&& send)
+{
+ // Returns a bad request response
+ auto const bad_request =
+ [&req](beast::string_view why)
+ {
+ http::response<http::string_body> res{http::status::bad_request, req.version()};
+ res.set(http::field::server, BOOST_BEAST_VERSION_STRING);
+ res.set(http::field::content_type, "text/html");
+ res.keep_alive(req.keep_alive());
+ res.body() = std::string(why);
+ res.prepare_payload();
+ return res;
+ };
+
+ // Returns a not found response
+ auto const not_found =
+ [&req](beast::string_view target)
+ {
+ http::response<http::string_body> res{http::status::not_found, req.version()};
+ res.set(http::field::server, BOOST_BEAST_VERSION_STRING);
+ res.set(http::field::content_type, "text/html");
+ res.keep_alive(req.keep_alive());
+ res.body() = "The resource '" + std::string(target) + "' was not found.";
+ res.prepare_payload();
+ return res;
+ };
+
+ // Returns a server error response
+ auto const server_error =
+ [&req](beast::string_view what)
+ {
+ http::response<http::string_body> res{http::status::internal_server_error, req.version()};
+ res.set(http::field::server, BOOST_BEAST_VERSION_STRING);
+ res.set(http::field::content_type, "text/html");
+ res.keep_alive(req.keep_alive());
+ res.body() = "An error occurred: '" + std::string(what) + "'";
+ res.prepare_payload();
+ return res;
+ };
+
+ // Make sure we can handle the method
+ if( req.method() != http::verb::get &&
+ req.method() != http::verb::head)
+ return send(bad_request("Unknown HTTP-method"));
+
+ // Request path must be absolute and not contain "..".
+ if( req.target().empty() ||
+ req.target()[0] != '/' ||
+ req.target().find("..") != beast::string_view::npos)
+ return send(bad_request("Illegal request-target"));
+
+ // Build the path to the requested file
+ std::string path = path_cat(doc_root, req.target());
+ if(req.target().back() == '/')
+ path.append("index.html");
+
+ // Attempt to open the file
+ beast::error_code ec;
+ http::file_body::value_type body;
+ body.open(path.c_str(), beast::file_mode::scan, ec);
+
+ // Handle the case where the file doesn't exist
+ if(ec == boost::system::errc::no_such_file_or_directory)
+ return send(not_found(req.target()));
+
+ // Handle an unknown error
+ if(ec)
+ return send(server_error(ec.message()));
+
+ // Cache the size since we need it after the move
+ auto const size = body.size();
+
+ // Respond to HEAD request
+ if(req.method() == http::verb::head)
+ {
+ http::response<http::empty_body> res{http::status::ok, req.version()};
+ res.set(http::field::server, BOOST_BEAST_VERSION_STRING);
+ res.set(http::field::content_type, mime_type(path));
+ res.content_length(size);
+ res.keep_alive(req.keep_alive());
+ return send(std::move(res));
+ }
+
+ // Respond to GET request
+ http::response<http::file_body> res{
+ std::piecewise_construct,
+ std::make_tuple(std::move(body)),
+ std::make_tuple(http::status::ok, req.version())};
+ res.set(http::field::server, BOOST_BEAST_VERSION_STRING);
+ res.set(http::field::content_type, mime_type(path));
+ res.content_length(size);
+ res.keep_alive(req.keep_alive());
+ return send(std::move(res));
+}
+
+//------------------------------------------------------------------------------
+
+struct http_session::send_lambda
+{
+ http_session& self_;
+
+ explicit
+ send_lambda(http_session& self)
+ : self_(self)
+ {
+ }
+
+ template<bool isRequest, class Body, class Fields>
+ void
+ operator()(http::message<isRequest, Body, Fields>&& msg) const
+ {
+ // The lifetime of the message has to extend
+ // for the duration of the async operation so
+ // we use a shared_ptr to manage it.
+ auto sp = boost::make_shared<
+ http::message<isRequest, Body, Fields>>(std::move(msg));
+
+ // Write the response
+ auto self = self_.shared_from_this();
+ http::async_write(
+ self_.stream_,
+ *sp,
+ [self, sp](beast::error_code ec, std::size_t bytes)
+ {
+ self->on_write(ec, bytes, sp->need_eof());
+ });
+ }
+};
+
+//------------------------------------------------------------------------------
+
+http_session::
+http_session(
+ tcp::socket&& socket,
+ boost::shared_ptr<shared_state> const& state)
+ : stream_(std::move(socket))
+ , state_(state)
+{
+}
+
+void
+http_session::
+run()
+{
+ do_read();
+}
+
+// Report a failure
+void
+http_session::
+fail(beast::error_code ec, char const* what)
+{
+ // Don't report on canceled operations
+ if(ec == net::error::operation_aborted)
+ return;
+
+ std::cerr << what << ": " << ec.message() << "\n";
+}
+
+void
+http_session::
+do_read()
+{
+ // Construct a new parser for each message
+ parser_.emplace();
+
+ // Apply a reasonable limit to the allowed size
+ // of the body in bytes to prevent abuse.
+ parser_->body_limit(10000);
+
+ // Set the timeout.
+ stream_.expires_after(std::chrono::seconds(30));
+
+ // Read a request
+ http::async_read(
+ stream_,
+ buffer_,
+ parser_->get(),
+ beast::bind_front_handler(
+ &http_session::on_read,
+ shared_from_this()));
+}
+
+void
+http_session::
+on_read(beast::error_code ec, std::size_t)
+{
+ // This means they closed the connection
+ if(ec == http::error::end_of_stream)
+ {
+ stream_.socket().shutdown(tcp::socket::shutdown_send, ec);
+ return;
+ }
+
+ // Handle the error, if any
+ if(ec)
+ return fail(ec, "read");
+
+ // See if it is a WebSocket Upgrade
+ if(websocket::is_upgrade(parser_->get()))
+ {
+ // Create a websocket session, transferring ownership
+ // of both the socket and the HTTP request.
+ boost::make_shared<websocket_session>(
+ stream_.release_socket(),
+ state_)->run(parser_->release());
+ return;
+ }
+
+ // Send the response
+#ifndef BOOST_NO_CXX14_GENERIC_LAMBDAS
+ //
+ // The following code requires generic
+ // lambdas, available in C++14 and later.
+ //
+ handle_request(
+ state_->doc_root(),
+ std::move(req_),
+ [this](auto&& response)
+ {
+ // The lifetime of the message has to extend
+ // for the duration of the async operation so
+ // we use a shared_ptr to manage it.
+ using response_type = typename std::decay<decltype(response)>::type;
+ auto sp = boost::make_shared<response_type>(std::forward<decltype(response)>(response));
+
+ #if 0
+ // NOTE This causes an ICE in gcc 7.3
+ // Write the response
+ http::async_write(this->stream_, *sp,
+ [self = shared_from_this(), sp](
+ beast::error_code ec, std::size_t bytes)
+ {
+ self->on_write(ec, bytes, sp->need_eof());
+ });
+ #else
+ // Write the response
+ auto self = shared_from_this();
+ http::async_write(stream_, *sp,
+ [self, sp](
+ beast::error_code ec, std::size_t bytes)
+ {
+ self->on_write(ec, bytes, sp->need_eof());
+ });
+ #endif
+ });
+#else
+ //
+ // This code uses the function object type send_lambda in
+ // place of a generic lambda which is not available in C++11
+ //
+ handle_request(
+ state_->doc_root(),
+ parser_->release(),
+ send_lambda(*this));
+
+#endif
+}
+
+void
+http_session::
+on_write(beast::error_code ec, std::size_t, bool close)
+{
+ // Handle the error, if any
+ if(ec)
+ return fail(ec, "write");
+
+ if(close)
+ {
+ // This means we should close the connection, usually because
+ // the response indicated the "Connection: close" semantic.
+ stream_.socket().shutdown(tcp::socket::shutdown_send, ec);
+ return;
+ }
+
+ // Read another request
+ do_read();
+}
diff --git a/src/boost/libs/beast/example/websocket/server/chat-multi/http_session.hpp b/src/boost/libs/beast/example/websocket/server/chat-multi/http_session.hpp
new file mode 100644
index 000000000..637a5d898
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/chat-multi/http_session.hpp
@@ -0,0 +1,48 @@
+//
+// Copyright (c) 2016-2019 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/vinniefalco/CppCon2018
+//
+
+#ifndef BOOST_BEAST_EXAMPLE_WEBSOCKET_CHAT_MULTI_HTTP_SESSION_HPP
+#define BOOST_BEAST_EXAMPLE_WEBSOCKET_CHAT_MULTI_HTTP_SESSION_HPP
+
+#include "net.hpp"
+#include "beast.hpp"
+#include "shared_state.hpp"
+#include <boost/optional.hpp>
+#include <boost/smart_ptr.hpp>
+#include <cstdlib>
+#include <memory>
+
+/** Represents an established HTTP connection
+*/
+class http_session : public boost::enable_shared_from_this<http_session>
+{
+ beast::tcp_stream stream_;
+ beast::flat_buffer buffer_;
+ boost::shared_ptr<shared_state> state_;
+
+ // The parser is stored in an optional container so we can
+ // construct it from scratch it at the beginning of each new message.
+ boost::optional<http::request_parser<http::string_body>> parser_;
+
+ struct send_lambda;
+
+ void fail(beast::error_code ec, char const* what);
+ void do_read();
+ void on_read(beast::error_code ec, std::size_t);
+ void on_write(beast::error_code ec, std::size_t, bool close);
+
+public:
+ http_session(
+ tcp::socket&& socket,
+ boost::shared_ptr<shared_state> const& state);
+
+ void run();
+};
+
+#endif
diff --git a/src/boost/libs/beast/example/websocket/server/chat-multi/listener.cpp b/src/boost/libs/beast/example/websocket/server/chat-multi/listener.cpp
new file mode 100644
index 000000000..8bbecb49b
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/chat-multi/listener.cpp
@@ -0,0 +1,101 @@
+//
+// Copyright (c) 2016-2019 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/vinniefalco/CppCon2018
+//
+
+#include "listener.hpp"
+#include "http_session.hpp"
+#include <iostream>
+
+listener::
+listener(
+ net::io_context& ioc,
+ tcp::endpoint endpoint,
+ boost::shared_ptr<shared_state> const& state)
+ : ioc_(ioc)
+ , acceptor_(ioc)
+ , state_(state)
+{
+ beast::error_code ec;
+
+ // Open the acceptor
+ acceptor_.open(endpoint.protocol(), ec);
+ if(ec)
+ {
+ fail(ec, "open");
+ return;
+ }
+
+ // Allow address reuse
+ acceptor_.set_option(net::socket_base::reuse_address(true), ec);
+ if(ec)
+ {
+ fail(ec, "set_option");
+ return;
+ }
+
+ // Bind to the server address
+ acceptor_.bind(endpoint, ec);
+ if(ec)
+ {
+ fail(ec, "bind");
+ return;
+ }
+
+ // Start listening for connections
+ acceptor_.listen(
+ net::socket_base::max_listen_connections, ec);
+ if(ec)
+ {
+ fail(ec, "listen");
+ return;
+ }
+}
+
+void
+listener::
+run()
+{
+ // The new connection gets its own strand
+ acceptor_.async_accept(
+ net::make_strand(ioc_),
+ beast::bind_front_handler(
+ &listener::on_accept,
+ shared_from_this()));
+}
+
+// Report a failure
+void
+listener::
+fail(beast::error_code ec, char const* what)
+{
+ // Don't report on canceled operations
+ if(ec == net::error::operation_aborted)
+ return;
+ std::cerr << what << ": " << ec.message() << "\n";
+}
+
+// Handle a connection
+void
+listener::
+on_accept(beast::error_code ec, tcp::socket socket)
+{
+ if(ec)
+ return fail(ec, "accept");
+ else
+ // Launch a new session for this connection
+ boost::make_shared<http_session>(
+ std::move(socket),
+ state_)->run();
+
+ // The new connection gets its own strand
+ acceptor_.async_accept(
+ net::make_strand(ioc_),
+ beast::bind_front_handler(
+ &listener::on_accept,
+ shared_from_this()));
+}
diff --git a/src/boost/libs/beast/example/websocket/server/chat-multi/listener.hpp b/src/boost/libs/beast/example/websocket/server/chat-multi/listener.hpp
new file mode 100644
index 000000000..a0c536e2e
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/chat-multi/listener.hpp
@@ -0,0 +1,42 @@
+//
+// Copyright (c) 2016-2019 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/vinniefalco/CppCon2018
+//
+
+#ifndef BOOST_BEAST_EXAMPLE_WEBSOCKET_CHAT_MULTI_LISTENER_HPP
+#define BOOST_BEAST_EXAMPLE_WEBSOCKET_CHAT_MULTI_LISTENER_HPP
+
+#include "beast.hpp"
+#include "net.hpp"
+#include <boost/smart_ptr.hpp>
+#include <memory>
+#include <string>
+
+// Forward declaration
+class shared_state;
+
+// Accepts incoming connections and launches the sessions
+class listener : public boost::enable_shared_from_this<listener>
+{
+ net::io_context& ioc_;
+ tcp::acceptor acceptor_;
+ boost::shared_ptr<shared_state> state_;
+
+ void fail(beast::error_code ec, char const* what);
+ void on_accept(beast::error_code ec, tcp::socket socket);
+
+public:
+ listener(
+ net::io_context& ioc,
+ tcp::endpoint endpoint,
+ boost::shared_ptr<shared_state> const& state);
+
+ // Start accepting incoming connections
+ void run();
+};
+
+#endif
diff --git a/src/boost/libs/beast/example/websocket/server/chat-multi/main.cpp b/src/boost/libs/beast/example/websocket/server/chat-multi/main.cpp
new file mode 100644
index 000000000..8645f1ded
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/chat-multi/main.cpp
@@ -0,0 +1,84 @@
+//
+// Copyright (c) 2016-2019 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/vinniefalco/CppCon2018
+//
+
+//------------------------------------------------------------------------------
+/*
+ WebSocket chat server, multi-threaded
+
+ This implements a multi-user chat room using WebSocket. The
+ `io_context` runs on any number of threads, specified at
+ the command line.
+
+*/
+//------------------------------------------------------------------------------
+
+#include "listener.hpp"
+#include "shared_state.hpp"
+
+#include <boost/asio/signal_set.hpp>
+#include <boost/smart_ptr.hpp>
+#include <iostream>
+#include <vector>
+
+int
+main(int argc, char* argv[])
+{
+ // Check command line arguments.
+ if (argc != 5)
+ {
+ std::cerr <<
+ "Usage: websocket-chat-multi <address> <port> <doc_root> <threads>\n" <<
+ "Example:\n" <<
+ " websocket-chat-server 0.0.0.0 8080 . 5\n";
+ return EXIT_FAILURE;
+ }
+ auto address = net::ip::make_address(argv[1]);
+ auto port = static_cast<unsigned short>(std::atoi(argv[2]));
+ auto doc_root = argv[3];
+ auto const threads = std::max<int>(1, std::atoi(argv[4]));
+
+ // The io_context is required for all I/O
+ net::io_context ioc;
+
+ // Create and launch a listening port
+ boost::make_shared<listener>(
+ ioc,
+ tcp::endpoint{address, port},
+ boost::make_shared<shared_state>(doc_root))->run();
+
+ // Capture SIGINT and SIGTERM to perform a clean shutdown
+ net::signal_set signals(ioc, SIGINT, SIGTERM);
+ signals.async_wait(
+ [&ioc](boost::system::error_code const&, int)
+ {
+ // Stop the io_context. This will cause run()
+ // to return immediately, eventually destroying the
+ // io_context and any remaining handlers in it.
+ ioc.stop();
+ });
+
+ // 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(
+ [&ioc]
+ {
+ ioc.run();
+ });
+ ioc.run();
+
+ // (If we get here, it means we got a SIGINT or SIGTERM)
+
+ // Block until all the threads exit
+ for(auto& t : v)
+ t.join();
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/boost/libs/beast/example/websocket/server/chat-multi/net.hpp b/src/boost/libs/beast/example/websocket/server/chat-multi/net.hpp
new file mode 100644
index 000000000..48a215355
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/chat-multi/net.hpp
@@ -0,0 +1,18 @@
+//
+// Copyright (c) 2016-2019 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/vinniefalco/CppCon2018
+//
+
+#ifndef BOOST_BEAST_EXAMPLE_WEBSOCKET_CHAT_MULTI_NET_HPP
+#define BOOST_BEAST_EXAMPLE_WEBSOCKET_CHAT_MULTI_NET_HPP
+
+#include <boost/asio.hpp>
+
+namespace net = boost::asio; // from <boost/asio.hpp>
+using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
+
+#endif
diff --git a/src/boost/libs/beast/example/websocket/server/chat-multi/shared_state.cpp b/src/boost/libs/beast/example/websocket/server/chat-multi/shared_state.cpp
new file mode 100644
index 000000000..9fceecc5d
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/chat-multi/shared_state.cpp
@@ -0,0 +1,59 @@
+//
+// Copyright (c) 2016-2019 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/vinniefalco/CppCon2018
+//
+
+#include "shared_state.hpp"
+#include "websocket_session.hpp"
+
+shared_state::
+shared_state(std::string doc_root)
+ : doc_root_(std::move(doc_root))
+{
+}
+
+void
+shared_state::
+join(websocket_session* session)
+{
+ std::lock_guard<std::mutex> lock(mutex_);
+ sessions_.insert(session);
+}
+
+void
+shared_state::
+leave(websocket_session* session)
+{
+ std::lock_guard<std::mutex> lock(mutex_);
+ sessions_.erase(session);
+}
+
+// Broadcast a message to all websocket client sessions
+void
+shared_state::
+send(std::string message)
+{
+ // Put the message in a shared pointer so we can re-use it for each client
+ auto const ss = boost::make_shared<std::string const>(std::move(message));
+
+ // Make a local list of all the weak pointers representing
+ // the sessions, so we can do the actual sending without
+ // holding the mutex:
+ std::vector<boost::weak_ptr<websocket_session>> v;
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+ v.reserve(sessions_.size());
+ for(auto p : sessions_)
+ v.emplace_back(p->weak_from_this());
+ }
+
+ // For each session in our local list, try to acquire a strong
+ // pointer. If successful, then send the message on that session.
+ for(auto const& wp : v)
+ if(auto sp = wp.lock())
+ sp->send(ss);
+}
diff --git a/src/boost/libs/beast/example/websocket/server/chat-multi/shared_state.hpp b/src/boost/libs/beast/example/websocket/server/chat-multi/shared_state.hpp
new file mode 100644
index 000000000..08f4b2d34
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/chat-multi/shared_state.hpp
@@ -0,0 +1,48 @@
+//
+// Copyright (c) 2016-2019 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/vinniefalco/CppCon2018
+//
+
+#ifndef BOOST_BEAST_EXAMPLE_WEBSOCKET_CHAT_MULTI_SHARED_STATE_HPP
+#define BOOST_BEAST_EXAMPLE_WEBSOCKET_CHAT_MULTI_SHARED_STATE_HPP
+
+#include <boost/smart_ptr.hpp>
+#include <memory>
+#include <mutex>
+#include <string>
+#include <unordered_set>
+
+// Forward declaration
+class websocket_session;
+
+// Represents the shared server state
+class shared_state
+{
+ std::string const doc_root_;
+
+ // This mutex synchronizes all access to sessions_
+ std::mutex mutex_;
+
+ // Keep a list of all the connected clients
+ std::unordered_set<websocket_session*> sessions_;
+
+public:
+ explicit
+ shared_state(std::string doc_root);
+
+ std::string const&
+ doc_root() const noexcept
+ {
+ return doc_root_;
+ }
+
+ void join (websocket_session* session);
+ void leave (websocket_session* session);
+ void send (std::string message);
+};
+
+#endif
diff --git a/src/boost/libs/beast/example/websocket/server/chat-multi/websocket_session.cpp b/src/boost/libs/beast/example/websocket/server/chat-multi/websocket_session.cpp
new file mode 100644
index 000000000..4807a5f1e
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/chat-multi/websocket_session.cpp
@@ -0,0 +1,135 @@
+//
+// Copyright (c) 2016-2019 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/vinniefalco/CppCon2018
+//
+
+#include "websocket_session.hpp"
+#include <iostream>
+
+websocket_session::
+websocket_session(
+ tcp::socket&& socket,
+ boost::shared_ptr<shared_state> const& state)
+ : ws_(std::move(socket))
+ , state_(state)
+{
+}
+
+websocket_session::
+~websocket_session()
+{
+ // Remove this session from the list of active sessions
+ state_->leave(this);
+}
+
+void
+websocket_session::
+fail(beast::error_code ec, char const* what)
+{
+ // Don't report these
+ if( ec == net::error::operation_aborted ||
+ ec == websocket::error::closed)
+ return;
+
+ std::cerr << what << ": " << ec.message() << "\n";
+}
+
+void
+websocket_session::
+on_accept(beast::error_code ec)
+{
+ // Handle the error, if any
+ if(ec)
+ return fail(ec, "accept");
+
+ // Add this session to the list of active sessions
+ state_->join(this);
+
+ // Read a message
+ ws_.async_read(
+ buffer_,
+ beast::bind_front_handler(
+ &websocket_session::on_read,
+ shared_from_this()));
+}
+
+void
+websocket_session::
+on_read(beast::error_code ec, std::size_t)
+{
+ // Handle the error, if any
+ if(ec)
+ return fail(ec, "read");
+
+ // Send to all connections
+ state_->send(beast::buffers_to_string(buffer_.data()));
+
+ // Clear the buffer
+ buffer_.consume(buffer_.size());
+
+ // Read another message
+ ws_.async_read(
+ buffer_,
+ beast::bind_front_handler(
+ &websocket_session::on_read,
+ shared_from_this()));
+}
+
+void
+websocket_session::
+send(boost::shared_ptr<std::string const> const& ss)
+{
+ // Post our work to the strand, this ensures
+ // that the members of `this` will not be
+ // accessed concurrently.
+
+ net::post(
+ ws_.get_executor(),
+ beast::bind_front_handler(
+ &websocket_session::on_send,
+ shared_from_this(),
+ ss));
+}
+
+void
+websocket_session::
+on_send(boost::shared_ptr<std::string const> const& ss)
+{
+ // Always add to queue
+ queue_.push_back(ss);
+
+ // Are we already writing?
+ if(queue_.size() > 1)
+ return;
+
+ // We are not currently writing, so send this immediately
+ ws_.async_write(
+ net::buffer(*queue_.front()),
+ beast::bind_front_handler(
+ &websocket_session::on_write,
+ shared_from_this()));
+}
+
+void
+websocket_session::
+on_write(beast::error_code ec, std::size_t)
+{
+ // Handle the error, if any
+ if(ec)
+ return fail(ec, "write");
+
+ // Remove the string from the queue
+ queue_.erase(queue_.begin());
+
+ // Send the next message if any
+ if(! queue_.empty())
+ ws_.async_write(
+ net::buffer(*queue_.front()),
+ beast::bind_front_handler(
+ &websocket_session::on_write,
+ shared_from_this()));
+}
diff --git a/src/boost/libs/beast/example/websocket/server/chat-multi/websocket_session.hpp b/src/boost/libs/beast/example/websocket/server/chat-multi/websocket_session.hpp
new file mode 100644
index 000000000..c47d48ac9
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/chat-multi/websocket_session.hpp
@@ -0,0 +1,86 @@
+//
+// Copyright (c) 2016-2019 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/vinniefalco/CppCon2018
+//
+
+#ifndef BOOST_BEAST_EXAMPLE_WEBSOCKET_CHAT_MULTI_WEBSOCKET_SESSION_HPP
+#define BOOST_BEAST_EXAMPLE_WEBSOCKET_CHAT_MULTI_WEBSOCKET_SESSION_HPP
+
+#include "net.hpp"
+#include "beast.hpp"
+#include "shared_state.hpp"
+
+#include <cstdlib>
+#include <memory>
+#include <string>
+#include <vector>
+
+// Forward declaration
+class shared_state;
+
+/** Represents an active WebSocket connection to the server
+*/
+class websocket_session : public boost::enable_shared_from_this<websocket_session>
+{
+ beast::flat_buffer buffer_;
+ websocket::stream<beast::tcp_stream> ws_;
+ boost::shared_ptr<shared_state> state_;
+ std::vector<boost::shared_ptr<std::string const>> queue_;
+
+ void fail(beast::error_code ec, char const* what);
+ void on_accept(beast::error_code ec);
+ void on_read(beast::error_code ec, std::size_t bytes_transferred);
+ void on_write(beast::error_code ec, std::size_t bytes_transferred);
+
+public:
+ websocket_session(
+ tcp::socket&& socket,
+ boost::shared_ptr<shared_state> const& state);
+
+ ~websocket_session();
+
+ template<class Body, class Allocator>
+ void
+ run(http::request<Body, http::basic_fields<Allocator>> req);
+
+ // Send a message
+ void
+ send(boost::shared_ptr<std::string const> const& ss);
+
+private:
+ void
+ on_send(boost::shared_ptr<std::string const> const& ss);
+};
+
+template<class Body, class Allocator>
+void
+websocket_session::
+run(http::request<Body, http::basic_fields<Allocator>> req)
+{
+ // Set suggested timeout settings for the websocket
+ ws_.set_option(
+ websocket::stream_base::timeout::suggested(
+ beast::role_type::server));
+
+ // Set a decorator to change the Server of the handshake
+ ws_.set_option(websocket::stream_base::decorator(
+ [](websocket::response_type& res)
+ {
+ res.set(http::field::server,
+ std::string(BOOST_BEAST_VERSION_STRING) +
+ " websocket-chat-multi");
+ }));
+
+ // Accept the websocket handshake
+ ws_.async_accept(
+ req,
+ beast::bind_front_handler(
+ &websocket_session::on_accept,
+ shared_from_this()));
+}
+
+#endif
diff --git a/src/boost/libs/beast/example/websocket/server/coro-ssl/CMakeLists.txt b/src/boost/libs/beast/example/websocket/server/coro-ssl/CMakeLists.txt
new file mode 100644
index 000000000..a302a2f56
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/coro-ssl/CMakeLists.txt
@@ -0,0 +1,31 @@
+#
+# 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
+#
+
+if (OPENSSL_FOUND)
+ GroupSources(include/boost/beast beast)
+ GroupSources(example/common common)
+ GroupSources(example/websocket/server/coro-ssl "/")
+
+ add_executable (websocket-server-coro-ssl
+ ${BOOST_BEAST_FILES}
+ ${PROJECT_SOURCE_DIR}/example/common/server_certificate.hpp
+ Jamfile
+ websocket_server_coro_ssl.cpp
+ )
+
+ set_property(TARGET websocket-server-coro-ssl PROPERTY FOLDER "example-websocket-server")
+
+ target_link_libraries (websocket-server-coro-ssl
+ OpenSSL::SSL OpenSSL::Crypto
+ lib-asio
+ lib-asio-ssl
+ lib-beast
+ )
+
+endif()
diff --git a/src/boost/libs/beast/example/websocket/server/coro-ssl/Jamfile b/src/boost/libs/beast/example/websocket/server/coro-ssl/Jamfile
new file mode 100644
index 000000000..621b0ce58
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/coro-ssl/Jamfile
@@ -0,0 +1,23 @@
+#
+# 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
+#
+
+import ac ;
+
+project
+ : requirements
+ [ ac.check-library /boost/beast//lib-asio-ssl : <library>/boost/beast//lib-asio-ssl/<link>static : <build>no ]
+ ;
+
+exe websocket-server-coro-ssl :
+ websocket_server_coro_ssl.cpp
+ :
+ <variant>coverage:<build>no
+ <variant>ubasan:<build>no
+ <library>/boost/coroutine//boost_coroutine
+ ;
diff --git a/src/boost/libs/beast/example/websocket/server/coro-ssl/websocket_server_coro_ssl.cpp b/src/boost/libs/beast/example/websocket/server/coro-ssl/websocket_server_coro_ssl.cpp
new file mode 100644
index 000000000..3e1785f00
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/coro-ssl/websocket_server_coro_ssl.cpp
@@ -0,0 +1,206 @@
+//
+// Copyright (c) 2016-2019 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
+//
+
+//------------------------------------------------------------------------------
+//
+// Example: WebSocket SSL server, coroutine
+//
+//------------------------------------------------------------------------------
+
+#include "example/common/server_certificate.hpp"
+
+#include <boost/beast/core.hpp>
+#include <boost/beast/ssl.hpp>
+#include <boost/beast/websocket.hpp>
+#include <boost/beast/websocket/ssl.hpp>
+#include <boost/asio/spawn.hpp>
+#include <algorithm>
+#include <cstdlib>
+#include <functional>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <thread>
+#include <vector>
+
+namespace beast = boost::beast; // from <boost/beast.hpp>
+namespace http = beast::http; // from <boost/beast/http.hpp>
+namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
+namespace net = boost::asio; // from <boost/asio.hpp>
+namespace ssl = boost::asio::ssl; // from <boost/asio/ssl.hpp>
+using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
+
+//------------------------------------------------------------------------------
+
+// Report a failure
+void
+fail(beast::error_code ec, char const* what)
+{
+ std::cerr << what << ": " << ec.message() << "\n";
+}
+
+// Echoes back all received WebSocket messages
+void
+do_session(
+ websocket::stream<
+ beast::ssl_stream<beast::tcp_stream>>& ws,
+ net::yield_context yield)
+{
+ beast::error_code ec;
+
+ // Set the timeout.
+ beast::get_lowest_layer(ws).expires_after(std::chrono::seconds(30));
+
+ // Perform the SSL handshake
+ ws.next_layer().async_handshake(ssl::stream_base::server, yield[ec]);
+ if(ec)
+ return fail(ec, "handshake");
+
+ // Turn off the timeout on the tcp_stream, because
+ // the websocket stream has its own timeout system.
+ beast::get_lowest_layer(ws).expires_never();
+
+ // Set suggested timeout settings for the websocket
+ ws.set_option(
+ websocket::stream_base::timeout::suggested(
+ beast::role_type::server));
+
+ // Set a decorator to change the Server of the handshake
+ ws.set_option(websocket::stream_base::decorator(
+ [](websocket::response_type& res)
+ {
+ res.set(http::field::server,
+ std::string(BOOST_BEAST_VERSION_STRING) +
+ " websocket-server-coro-ssl");
+ }));
+
+ // Accept the websocket handshake
+ ws.async_accept(yield[ec]);
+ if(ec)
+ return fail(ec, "accept");
+
+ for(;;)
+ {
+ // This buffer will hold the incoming message
+ beast::flat_buffer buffer;
+
+ // Read a message
+ ws.async_read(buffer, yield[ec]);
+
+ // This indicates that the session was closed
+ if(ec == websocket::error::closed)
+ break;
+
+ if(ec)
+ return fail(ec, "read");
+
+ // Echo the message back
+ ws.text(ws.got_text());
+ ws.async_write(buffer.data(), yield[ec]);
+ if(ec)
+ return fail(ec, "write");
+ }
+}
+
+//------------------------------------------------------------------------------
+
+// Accepts incoming connections and launches the sessions
+void
+do_listen(
+ net::io_context& ioc,
+ ssl::context& ctx,
+ tcp::endpoint endpoint,
+ net::yield_context yield)
+{
+ beast::error_code ec;
+
+ // Open the acceptor
+ tcp::acceptor acceptor(ioc);
+ acceptor.open(endpoint.protocol(), ec);
+ if(ec)
+ return fail(ec, "open");
+
+ // Allow address reuse
+ acceptor.set_option(net::socket_base::reuse_address(true), ec);
+ if(ec)
+ return fail(ec, "set_option");
+
+ // Bind to the server address
+ acceptor.bind(endpoint, ec);
+ if(ec)
+ return fail(ec, "bind");
+
+ // Start listening for connections
+ acceptor.listen(net::socket_base::max_listen_connections, ec);
+ if(ec)
+ return fail(ec, "listen");
+
+ for(;;)
+ {
+ tcp::socket socket(ioc);
+ acceptor.async_accept(socket, yield[ec]);
+ if(ec)
+ fail(ec, "accept");
+ else
+ boost::asio::spawn(
+ acceptor.get_executor(),
+ std::bind(
+ &do_session,
+ websocket::stream<beast::ssl_stream<
+ beast::tcp_stream>>(std::move(socket), ctx),
+ std::placeholders::_1));
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ // Check command line arguments.
+ if (argc != 4)
+ {
+ std::cerr <<
+ "Usage: websocket-server-coro-ssl <address> <port> <threads>\n" <<
+ "Example:\n" <<
+ " websocket-server-coro-ssl 0.0.0.0 8080 1\n";
+ return EXIT_FAILURE;
+ }
+ auto const address = net::ip::make_address(argv[1]);
+ auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
+ auto const threads = std::max<int>(1, std::atoi(argv[3]));
+
+ // The io_context is required for all I/O
+ net::io_context ioc{threads};
+
+ // The SSL context is required, and holds certificates
+ ssl::context ctx{ssl::context::tlsv12};
+
+ // This holds the self-signed certificate used by the server
+ load_server_certificate(ctx);
+
+ // Spawn a listening port
+ boost::asio::spawn(ioc,
+ std::bind(
+ &do_listen,
+ std::ref(ioc),
+ std::ref(ctx),
+ tcp::endpoint{address, port},
+ std::placeholders::_1));
+
+ // 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(
+ [&ioc]
+ {
+ ioc.run();
+ });
+ ioc.run();
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/boost/libs/beast/example/websocket/server/coro/CMakeLists.txt b/src/boost/libs/beast/example/websocket/server/coro/CMakeLists.txt
new file mode 100644
index 000000000..c8e408d1c
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/coro/CMakeLists.txt
@@ -0,0 +1,23 @@
+#
+# 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
+#
+
+GroupSources(include/boost/beast beast)
+GroupSources(example/websocket/server/coro "/")
+
+add_executable (websocket-server-coro
+ ${BOOST_BEAST_FILES}
+ Jamfile
+ websocket_server_coro.cpp
+)
+
+target_link_libraries(websocket-server-coro
+ lib-asio
+ lib-beast)
+
+set_property(TARGET websocket-server-coro PROPERTY FOLDER "example-websocket-server")
diff --git a/src/boost/libs/beast/example/websocket/server/coro/Jamfile b/src/boost/libs/beast/example/websocket/server/coro/Jamfile
new file mode 100644
index 000000000..5e8cbf948
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/coro/Jamfile
@@ -0,0 +1,16 @@
+#
+# 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
+#
+
+exe websocket-server-coro :
+ websocket_server_coro.cpp
+ :
+ <variant>coverage:<build>no
+ <variant>ubasan:<build>no
+ <library>/boost/coroutine//boost_coroutine
+ ;
diff --git a/src/boost/libs/beast/example/websocket/server/coro/websocket_server_coro.cpp b/src/boost/libs/beast/example/websocket/server/coro/websocket_server_coro.cpp
new file mode 100644
index 000000000..e15b01079
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/coro/websocket_server_coro.cpp
@@ -0,0 +1,180 @@
+//
+// Copyright (c) 2016-2019 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
+//
+
+//------------------------------------------------------------------------------
+//
+// Example: WebSocket server, coroutine
+//
+//------------------------------------------------------------------------------
+
+#include <boost/beast/core.hpp>
+#include <boost/beast/websocket.hpp>
+#include <boost/asio/spawn.hpp>
+#include <algorithm>
+#include <cstdlib>
+#include <functional>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <thread>
+#include <vector>
+
+namespace beast = boost::beast; // from <boost/beast.hpp>
+namespace http = beast::http; // from <boost/beast/http.hpp>
+namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
+namespace net = boost::asio; // from <boost/asio.hpp>
+using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
+
+//------------------------------------------------------------------------------
+
+// Report a failure
+void
+fail(beast::error_code ec, char const* what)
+{
+ std::cerr << what << ": " << ec.message() << "\n";
+}
+
+// Echoes back all received WebSocket messages
+void
+do_session(
+ websocket::stream<beast::tcp_stream>& ws,
+ net::yield_context yield)
+{
+ beast::error_code ec;
+
+ // Set suggested timeout settings for the websocket
+ ws.set_option(
+ websocket::stream_base::timeout::suggested(
+ beast::role_type::server));
+
+ // Set a decorator to change the Server of the handshake
+ ws.set_option(websocket::stream_base::decorator(
+ [](websocket::response_type& res)
+ {
+ res.set(http::field::server,
+ std::string(BOOST_BEAST_VERSION_STRING) +
+ " websocket-server-coro");
+ }));
+
+ // Accept the websocket handshake
+ ws.async_accept(yield[ec]);
+ if(ec)
+ return fail(ec, "accept");
+
+ for(;;)
+ {
+ // This buffer will hold the incoming message
+ beast::flat_buffer buffer;
+
+ // Read a message
+ ws.async_read(buffer, yield[ec]);
+
+ // This indicates that the session was closed
+ if(ec == websocket::error::closed)
+ break;
+
+ if(ec)
+ return fail(ec, "read");
+
+ // Echo the message back
+ ws.text(ws.got_text());
+ ws.async_write(buffer.data(), yield[ec]);
+ if(ec)
+ return fail(ec, "write");
+ }
+}
+
+//------------------------------------------------------------------------------
+
+// Accepts incoming connections and launches the sessions
+void
+do_listen(
+ net::io_context& ioc,
+ tcp::endpoint endpoint,
+ net::yield_context yield)
+{
+ beast::error_code ec;
+
+ // Open the acceptor
+ tcp::acceptor acceptor(ioc);
+ acceptor.open(endpoint.protocol(), ec);
+ if(ec)
+ return fail(ec, "open");
+
+ // Allow address reuse
+ acceptor.set_option(net::socket_base::reuse_address(true), ec);
+ if(ec)
+ return fail(ec, "set_option");
+
+ // Bind to the server address
+ acceptor.bind(endpoint, ec);
+ if(ec)
+ return fail(ec, "bind");
+
+ // Start listening for connections
+ acceptor.listen(net::socket_base::max_listen_connections, ec);
+ if(ec)
+ return fail(ec, "listen");
+
+ for(;;)
+ {
+ tcp::socket socket(ioc);
+ acceptor.async_accept(socket, yield[ec]);
+ if(ec)
+ fail(ec, "accept");
+ else
+ boost::asio::spawn(
+ acceptor.get_executor(),
+ std::bind(
+ &do_session,
+ websocket::stream<
+ beast::tcp_stream>(std::move(socket)),
+ std::placeholders::_1));
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ // Check command line arguments.
+ if (argc != 4)
+ {
+ std::cerr <<
+ "Usage: websocket-server-coro <address> <port> <threads>\n" <<
+ "Example:\n" <<
+ " websocket-server-coro 0.0.0.0 8080 1\n";
+ return EXIT_FAILURE;
+ }
+ auto const address = net::ip::make_address(argv[1]);
+ auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
+ auto const threads = std::max<int>(1, std::atoi(argv[3]));
+
+ // The io_context is required for all I/O
+ net::io_context ioc(threads);
+
+ // Spawn a listening port
+ boost::asio::spawn(ioc,
+ std::bind(
+ &do_listen,
+ std::ref(ioc),
+ tcp::endpoint{address, port},
+ std::placeholders::_1));
+
+ // 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(
+ [&ioc]
+ {
+ ioc.run();
+ });
+ ioc.run();
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/boost/libs/beast/example/websocket/server/fast/CMakeLists.txt b/src/boost/libs/beast/example/websocket/server/fast/CMakeLists.txt
new file mode 100644
index 000000000..93d469e91
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/fast/CMakeLists.txt
@@ -0,0 +1,23 @@
+#
+# 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
+#
+
+GroupSources(include/boost/beast beast)
+GroupSources(example/websocket/server/fast "/")
+
+add_executable (websocket-server-fast
+ ${BOOST_BEAST_FILES}
+ Jamfile
+ websocket_server_fast.cpp
+)
+
+target_link_libraries(websocket-server-fast
+ lib-asio
+ lib-beast)
+
+set_property(TARGET websocket-server-fast PROPERTY FOLDER "example-websocket-server")
diff --git a/src/boost/libs/beast/example/websocket/server/fast/Jamfile b/src/boost/libs/beast/example/websocket/server/fast/Jamfile
new file mode 100644
index 000000000..3e6cbf5b0
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/fast/Jamfile
@@ -0,0 +1,16 @@
+#
+# 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
+#
+
+exe websocket-server-fast :
+ websocket_server_fast.cpp
+ :
+ <variant>coverage:<build>no
+ <variant>ubasan:<build>no
+ <library>/boost/coroutine//boost_coroutine
+ ;
diff --git a/src/boost/libs/beast/example/websocket/server/fast/websocket_server_fast.cpp b/src/boost/libs/beast/example/websocket/server/fast/websocket_server_fast.cpp
new file mode 100644
index 000000000..7f2a5e3cb
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/fast/websocket_server_fast.cpp
@@ -0,0 +1,480 @@
+//
+// Copyright (c) 2016-2019 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
+//
+
+//------------------------------------------------------------------------------
+//
+// Example: WebSocket server, fast
+//
+//------------------------------------------------------------------------------
+
+/* This server contains the following ports:
+
+ Synchronous <base port + 0>
+ Asynchronous <base port + 1>
+ Coroutine <base port + 2>
+
+ This program is optimized for the Autobahn|Testsuite
+ benchmarking and WebSocket compliants testing program.
+
+ See:
+ https://github.com/crossbario/autobahn-testsuite
+*/
+
+#include <boost/beast/core.hpp>
+#include <boost/beast/http.hpp>
+#include <boost/beast/version.hpp>
+#include <boost/beast/websocket.hpp>
+#include <boost/asio/spawn.hpp>
+#include <boost/asio/strand.hpp>
+#include <algorithm>
+#include <cstdlib>
+#include <functional>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <thread>
+#include <vector>
+
+namespace beast = boost::beast; // from <boost/beast.hpp>
+namespace http = beast::http; // from <boost/beast/http.hpp>
+namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
+namespace net = boost::asio; // from <boost/asio.hpp>
+using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
+
+//------------------------------------------------------------------------------
+
+// Report a failure
+void
+fail(beast::error_code ec, char const* what)
+{
+ std::cerr << (std::string(what) + ": " + ec.message() + "\n");
+}
+
+// Adjust settings on the stream
+template<class NextLayer>
+void
+setup_stream(websocket::stream<NextLayer>& ws)
+{
+ // These values are tuned for Autobahn|Testsuite, and
+ // should also be generally helpful for increased performance.
+
+ websocket::permessage_deflate pmd;
+ pmd.client_enable = true;
+ pmd.server_enable = true;
+ pmd.compLevel = 3;
+ ws.set_option(pmd);
+
+ ws.auto_fragment(false);
+
+ // Autobahn|Testsuite needs this
+ ws.read_message_max(64 * 1024 * 1024);
+}
+
+//------------------------------------------------------------------------------
+
+void
+do_sync_session(websocket::stream<beast::tcp_stream>& ws)
+{
+ beast::error_code ec;
+
+ setup_stream(ws);
+
+ // Set a decorator to change the Server of the handshake
+ ws.set_option(websocket::stream_base::decorator(
+ [](websocket::response_type& res)
+ {
+ res.set(http::field::server, std::string(
+ BOOST_BEAST_VERSION_STRING) + "-Sync");
+ }));
+
+ ws.accept(ec);
+ if(ec)
+ return fail(ec, "accept");
+
+ for(;;)
+ {
+ beast::flat_buffer buffer;
+
+ ws.read(buffer, ec);
+ if(ec == websocket::error::closed)
+ break;
+ if(ec)
+ return fail(ec, "read");
+ ws.text(ws.got_text());
+ ws.write(buffer.data(), ec);
+ if(ec)
+ return fail(ec, "write");
+ }
+}
+
+void
+do_sync_listen(
+ net::io_context& ioc,
+ tcp::endpoint endpoint)
+{
+ beast::error_code ec;
+ tcp::acceptor acceptor{ioc, endpoint};
+ for(;;)
+ {
+ tcp::socket socket{ioc};
+
+ acceptor.accept(socket, ec);
+ if(ec)
+ return fail(ec, "accept");
+
+ std::thread(std::bind(
+ &do_sync_session,
+ websocket::stream<beast::tcp_stream>(
+ std::move(socket)))).detach();
+ }
+}
+
+//------------------------------------------------------------------------------
+
+// Echoes back all received WebSocket messages
+class async_session : public std::enable_shared_from_this<async_session>
+{
+ websocket::stream<beast::tcp_stream> ws_;
+ beast::flat_buffer buffer_;
+
+public:
+ // Take ownership of the socket
+ explicit
+ async_session(tcp::socket&& socket)
+ : ws_(std::move(socket))
+ {
+ setup_stream(ws_);
+ }
+
+ // Start the asynchronous operation
+ void
+ run()
+ {
+ // Set suggested timeout settings for the websocket
+ ws_.set_option(
+ websocket::stream_base::timeout::suggested(
+ beast::role_type::server));
+
+ // Set a decorator to change the Server of the handshake
+ ws_.set_option(websocket::stream_base::decorator(
+ [](websocket::response_type& res)
+ {
+ res.set(http::field::server, std::string(
+ BOOST_BEAST_VERSION_STRING) + "-Async");
+ }));
+
+ // Accept the websocket handshake
+ ws_.async_accept(
+ beast::bind_front_handler(
+ &async_session::on_accept,
+ shared_from_this()));
+ }
+
+ void
+ on_accept(beast::error_code ec)
+ {
+ if(ec)
+ return fail(ec, "accept");
+
+ // Read a message
+ do_read();
+ }
+
+ void
+ do_read()
+ {
+ // Read a message into our buffer
+ ws_.async_read(
+ buffer_,
+ beast::bind_front_handler(
+ &async_session::on_read,
+ shared_from_this()));
+ }
+
+ void
+ on_read(
+ beast::error_code ec,
+ std::size_t bytes_transferred)
+ {
+ boost::ignore_unused(bytes_transferred);
+
+ // This indicates that the async_session was closed
+ if(ec == websocket::error::closed)
+ return;
+
+ if(ec)
+ fail(ec, "read");
+
+ // Echo the message
+ ws_.text(ws_.got_text());
+ ws_.async_write(
+ buffer_.data(),
+ beast::bind_front_handler(
+ &async_session::on_write,
+ shared_from_this()));
+ }
+
+ void
+ on_write(
+ beast::error_code ec,
+ std::size_t bytes_transferred)
+ {
+ boost::ignore_unused(bytes_transferred);
+
+ if(ec)
+ return fail(ec, "write");
+
+ // Clear the buffer
+ buffer_.consume(buffer_.size());
+
+ // Do another read
+ do_read();
+ }
+};
+
+// Accepts incoming connections and launches the sessions
+class async_listener : public std::enable_shared_from_this<async_listener>
+{
+ net::io_context& ioc_;
+ tcp::acceptor acceptor_;
+
+public:
+ async_listener(
+ net::io_context& ioc,
+ tcp::endpoint endpoint)
+ : ioc_(ioc)
+ , acceptor_(net::make_strand(ioc))
+ {
+ beast::error_code ec;
+
+ // Open the acceptor
+ acceptor_.open(endpoint.protocol(), ec);
+ if(ec)
+ {
+ fail(ec, "open");
+ return;
+ }
+
+ // Allow address reuse
+ acceptor_.set_option(net::socket_base::reuse_address(true), ec);
+ if(ec)
+ {
+ fail(ec, "set_option");
+ return;
+ }
+
+ // Bind to the server address
+ acceptor_.bind(endpoint, ec);
+ if(ec)
+ {
+ fail(ec, "bind");
+ return;
+ }
+
+ // Start listening for connections
+ acceptor_.listen(
+ net::socket_base::max_listen_connections, ec);
+ if(ec)
+ {
+ fail(ec, "listen");
+ return;
+ }
+ }
+
+ // Start accepting incoming connections
+ void
+ run()
+ {
+ do_accept();
+ }
+
+private:
+ void
+ do_accept()
+ {
+ // The new connection gets its own strand
+ acceptor_.async_accept(
+ net::make_strand(ioc_),
+ beast::bind_front_handler(
+ &async_listener::on_accept,
+ shared_from_this()));
+ }
+
+ void
+ on_accept(beast::error_code ec, tcp::socket socket)
+ {
+ if(ec)
+ {
+ fail(ec, "accept");
+ }
+ else
+ {
+ // Create the async_session and run it
+ std::make_shared<async_session>(std::move(socket))->run();
+ }
+
+ // Accept another connection
+ do_accept();
+ }
+};
+
+//------------------------------------------------------------------------------
+
+void
+do_coro_session(
+ websocket::stream<beast::tcp_stream>& ws,
+ net::yield_context yield)
+{
+ beast::error_code ec;
+
+ setup_stream(ws);
+
+ // Set suggested timeout settings for the websocket
+ ws.set_option(
+ websocket::stream_base::timeout::suggested(
+ beast::role_type::server));
+
+ // Set a decorator to change the Server of the handshake
+ ws.set_option(websocket::stream_base::decorator(
+ [](websocket::response_type& res)
+ {
+ res.set(http::field::server, std::string(
+ BOOST_BEAST_VERSION_STRING) + "-Fiber");
+ }));
+
+ ws.async_accept(yield[ec]);
+ if(ec)
+ return fail(ec, "accept");
+
+ for(;;)
+ {
+ beast::flat_buffer buffer;
+
+ ws.async_read(buffer, yield[ec]);
+ if(ec == websocket::error::closed)
+ break;
+ if(ec)
+ return fail(ec, "read");
+
+ ws.text(ws.got_text());
+ ws.async_write(buffer.data(), yield[ec]);
+ if(ec)
+ return fail(ec, "write");
+ }
+}
+
+void
+do_coro_listen(
+ net::io_context& ioc,
+ tcp::endpoint endpoint,
+ net::yield_context yield)
+{
+ beast::error_code ec;
+
+ tcp::acceptor acceptor(ioc);
+ acceptor.open(endpoint.protocol(), ec);
+ if(ec)
+ return fail(ec, "open");
+
+ acceptor.set_option(net::socket_base::reuse_address(true), ec);
+ if(ec)
+ return fail(ec, "set_option");
+
+ acceptor.bind(endpoint, ec);
+ if(ec)
+ return fail(ec, "bind");
+
+ acceptor.listen(net::socket_base::max_listen_connections, ec);
+ if(ec)
+ return fail(ec, "listen");
+
+ for(;;)
+ {
+ tcp::socket socket(ioc);
+
+ acceptor.async_accept(socket, yield[ec]);
+ if(ec)
+ {
+ fail(ec, "accept");
+ continue;
+ }
+
+ boost::asio::spawn(
+ acceptor.get_executor(),
+ std::bind(
+ &do_coro_session,
+ websocket::stream<
+ beast::tcp_stream>(std::move(socket)),
+ std::placeholders::_1));
+ }
+}
+
+//------------------------------------------------------------------------------
+
+int main(int argc, char* argv[])
+{
+ // Check command line arguments.
+ if (argc != 4)
+ {
+ std::cerr <<
+ "Usage: websocket-server-fast <address> <starting-port> <threads>\n" <<
+ "Example:\n"
+ " websocket-server-fast 0.0.0.0 8080 1\n"
+ " Connect to:\n"
+ " starting-port+0 for synchronous,\n"
+ " starting-port+1 for asynchronous,\n"
+ " starting-port+2 for coroutine.\n";
+ return EXIT_FAILURE;
+ }
+ auto const address = net::ip::make_address(argv[1]);
+ auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
+ auto const threads = std::max<int>(1, std::atoi(argv[3]));
+
+ // The io_context is required for all I/O
+ net::io_context ioc{threads};
+
+ // Create sync port
+ std::thread(beast::bind_front_handler(
+ &do_sync_listen,
+ std::ref(ioc),
+ tcp::endpoint{
+ address,
+ static_cast<unsigned short>(port + 0u)}
+ )).detach();
+
+ // Create async port
+ std::make_shared<async_listener>(
+ ioc,
+ tcp::endpoint{
+ address,
+ static_cast<unsigned short>(port + 1u)})->run();
+
+ // Create coro port
+ boost::asio::spawn(ioc,
+ std::bind(
+ &do_coro_listen,
+ std::ref(ioc),
+ tcp::endpoint{
+ address,
+ static_cast<unsigned short>(port + 2u)},
+ std::placeholders::_1));
+
+ // 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(
+ [&ioc]
+ {
+ ioc.run();
+ });
+ ioc.run();
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/boost/libs/beast/example/websocket/server/stackless-ssl/CMakeLists.txt b/src/boost/libs/beast/example/websocket/server/stackless-ssl/CMakeLists.txt
new file mode 100644
index 000000000..7ae66a07b
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/stackless-ssl/CMakeLists.txt
@@ -0,0 +1,31 @@
+#
+# 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
+#
+
+if (OPENSSL_FOUND)
+ GroupSources(include/boost/beast beast)
+ GroupSources(example/common common)
+ GroupSources(example/websocket/server/stackless-ssl "/")
+
+ add_executable (websocket-server-stackless-ssl
+ ${BOOST_BEAST_FILES}
+ ${PROJECT_SOURCE_DIR}/example/common/server_certificate.hpp
+ Jamfile
+ websocket_server_stackless_ssl.cpp
+ )
+
+ set_property(TARGET websocket-server-stackless-ssl PROPERTY FOLDER "example-websocket-server")
+
+ target_link_libraries (websocket-server-stackless-ssl
+ OpenSSL::SSL OpenSSL::Crypto
+ lib-asio
+ lib-asio-ssl
+ lib-beast
+ )
+
+endif()
diff --git a/src/boost/libs/beast/example/websocket/server/stackless-ssl/Jamfile b/src/boost/libs/beast/example/websocket/server/stackless-ssl/Jamfile
new file mode 100644
index 000000000..b0eaa4aa2
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/stackless-ssl/Jamfile
@@ -0,0 +1,22 @@
+#
+# 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
+#
+
+import ac ;
+
+project
+ : requirements
+ [ ac.check-library /boost/beast//lib-asio-ssl : <library>/boost/beast//lib-asio-ssl/<link>static : <build>no ]
+ ;
+
+exe websocket-server-stackless-ssl :
+ websocket_server_stackless_ssl.cpp
+ :
+ <variant>coverage:<build>no
+ <variant>ubasan:<build>no
+ ;
diff --git a/src/boost/libs/beast/example/websocket/server/stackless-ssl/websocket_server_stackless_ssl.cpp b/src/boost/libs/beast/example/websocket/server/stackless-ssl/websocket_server_stackless_ssl.cpp
new file mode 100644
index 000000000..c6eaec60c
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/stackless-ssl/websocket_server_stackless_ssl.cpp
@@ -0,0 +1,314 @@
+//
+// Copyright (c) 2016-2019 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
+//
+
+//------------------------------------------------------------------------------
+//
+// Example: WebSocket SSL server, stackless coroutine
+//
+//------------------------------------------------------------------------------
+
+#include "example/common/server_certificate.hpp"
+
+#include <boost/beast/core.hpp>
+#include <boost/beast/ssl.hpp>
+#include <boost/beast/websocket.hpp>
+#include <boost/beast/websocket/ssl.hpp>
+#include <boost/asio/coroutine.hpp>
+#include <boost/asio/strand.hpp>
+#include <boost/asio/dispatch.hpp>
+#include <algorithm>
+#include <cstdlib>
+#include <functional>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <thread>
+#include <vector>
+
+namespace beast = boost::beast; // from <boost/beast.hpp>
+namespace http = beast::http; // from <boost/beast/http.hpp>
+namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
+namespace net = boost::asio; // from <boost/asio.hpp>
+namespace ssl = boost::asio::ssl; // from <boost/asio/ssl.hpp>
+using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
+
+//------------------------------------------------------------------------------
+
+// Report a failure
+void
+fail(beast::error_code ec, char const* what)
+{
+ std::cerr << what << ": " << ec.message() << "\n";
+}
+
+// Echoes back all received WebSocket messages
+class session
+ : public boost::asio::coroutine
+ , public std::enable_shared_from_this<session>
+{
+ websocket::stream<beast::ssl_stream<beast::tcp_stream>> ws_;
+ beast::flat_buffer buffer_;
+
+public:
+ // Take ownership of the socket
+ session(tcp::socket&& socket, ssl::context& ctx)
+ : ws_(std::move(socket), ctx)
+ {
+ }
+
+ // Start the asynchronous operation
+ void
+ run()
+ {
+ // We need to be executing within a strand to perform async operations
+ // on the I/O objects in this session. Although not strictly necessary
+ // for single-threaded contexts, this example code is written to be
+ // thread-safe by default.
+ net::dispatch(ws_.get_executor(),
+ beast::bind_front_handler(&session::loop,
+ shared_from_this(),
+ beast::error_code{},
+ 0));
+ }
+
+ #include <boost/asio/yield.hpp>
+
+ void
+ loop(
+ beast::error_code ec,
+ std::size_t bytes_transferred)
+ {
+ boost::ignore_unused(bytes_transferred);
+
+ reenter(*this)
+ {
+ // Set the timeout.
+ beast::get_lowest_layer(ws_).expires_after(std::chrono::seconds(30));
+
+ // Perform the SSL handshake
+ yield ws_.next_layer().async_handshake(
+ ssl::stream_base::server,
+ std::bind(
+ &session::loop,
+ shared_from_this(),
+ std::placeholders::_1,
+ 0));
+ if(ec)
+ return fail(ec, "handshake");
+
+ // Turn off the timeout on the tcp_stream, because
+ // the websocket stream has its own timeout system.
+ beast::get_lowest_layer(ws_).expires_never();
+
+ // Set suggested timeout settings for the websocket
+ ws_.set_option(
+ websocket::stream_base::timeout::suggested(
+ beast::role_type::server));
+
+ // Set a decorator to change the Server of the handshake
+ ws_.set_option(websocket::stream_base::decorator(
+ [](websocket::response_type& res)
+ {
+ res.set(http::field::server,
+ std::string(BOOST_BEAST_VERSION_STRING) +
+ " websocket-server-stackless-ssl");
+ }));
+
+ // Accept the websocket handshake
+ yield ws_.async_accept(
+ std::bind(
+ &session::loop,
+ shared_from_this(),
+ std::placeholders::_1,
+ 0));
+ if(ec)
+ return fail(ec, "accept");
+
+ for(;;)
+ {
+ // Read a message into our buffer
+ yield ws_.async_read(
+ buffer_,
+ 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
+ return;
+ }
+ if(ec)
+ fail(ec, "read");
+
+ // Echo the message
+ ws_.text(ws_.got_text());
+ yield ws_.async_write(
+ buffer_.data(),
+ std::bind(
+ &session::loop,
+ shared_from_this(),
+ std::placeholders::_1,
+ std::placeholders::_2));
+ if(ec)
+ return fail(ec, "write");
+
+ // Clear the buffer
+ buffer_.consume(buffer_.size());
+ }
+ }
+ }
+
+ #include <boost/asio/unyield.hpp>
+};
+
+//------------------------------------------------------------------------------
+
+// Accepts incoming connections and launches the sessions
+class listener
+ : public boost::asio::coroutine
+ , public std::enable_shared_from_this<listener>
+{
+ net::io_context& ioc_;
+ ssl::context& ctx_;
+ tcp::acceptor acceptor_;
+ tcp::socket socket_;
+
+public:
+ listener(
+ net::io_context& ioc,
+ ssl::context& ctx,
+ tcp::endpoint endpoint)
+ : ioc_(ioc)
+ , ctx_(ctx)
+ , acceptor_(ioc)
+ , socket_(ioc)
+ {
+ beast::error_code ec;
+
+ // Open the acceptor
+ acceptor_.open(endpoint.protocol(), ec);
+ if(ec)
+ {
+ fail(ec, "open");
+ return;
+ }
+
+ // Allow address reuse
+ acceptor_.set_option(net::socket_base::reuse_address(true), ec);
+ if(ec)
+ {
+ fail(ec, "set_option");
+ return;
+ }
+
+ // Bind to the server address
+ acceptor_.bind(endpoint, ec);
+ if(ec)
+ {
+ fail(ec, "bind");
+ return;
+ }
+
+ // Start listening for connections
+ acceptor_.listen(
+ net::socket_base::max_listen_connections, ec);
+ if(ec)
+ {
+ fail(ec, "listen");
+ return;
+ }
+ }
+
+ // Start accepting incoming connections
+ void
+ run()
+ {
+ loop();
+ }
+
+private:
+
+ #include <boost/asio/yield.hpp>
+
+ void
+ loop(beast::error_code ec = {})
+ {
+ reenter(*this)
+ {
+ for(;;)
+ {
+ yield acceptor_.async_accept(
+ socket_,
+ std::bind(
+ &listener::loop,
+ shared_from_this(),
+ std::placeholders::_1));
+ if(ec)
+ {
+ fail(ec, "accept");
+ }
+ else
+ {
+ // Create the session and run it
+ std::make_shared<session>(std::move(socket_), ctx_)->run();
+ }
+
+ // Make sure each session gets its own strand
+ socket_ = tcp::socket(net::make_strand(ioc_));
+ }
+ }
+ }
+
+ #include <boost/asio/unyield.hpp>
+};
+
+//------------------------------------------------------------------------------
+
+int main(int argc, char* argv[])
+{
+ // Check command line arguments.
+ if (argc != 4)
+ {
+ std::cerr <<
+ "Usage: websocket-server-async-ssl <address> <port> <threads>\n" <<
+ "Example:\n" <<
+ " websocket-server-async-ssl 0.0.0.0 8080 1\n";
+ return EXIT_FAILURE;
+ }
+ auto const address = net::ip::make_address(argv[1]);
+ auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
+ auto const threads = std::max<int>(1, std::atoi(argv[3]));
+
+ // The io_context is required for all I/O
+ net::io_context ioc{threads};
+
+ // The SSL context is required, and holds certificates
+ ssl::context ctx{ssl::context::tlsv12};
+
+ // This holds the self-signed certificate used by the server
+ load_server_certificate(ctx);
+
+ // Create and launch a listening port
+ 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(
+ [&ioc]
+ {
+ ioc.run();
+ });
+ ioc.run();
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/boost/libs/beast/example/websocket/server/stackless/CMakeLists.txt b/src/boost/libs/beast/example/websocket/server/stackless/CMakeLists.txt
new file mode 100644
index 000000000..b260ca48b
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/stackless/CMakeLists.txt
@@ -0,0 +1,23 @@
+#
+# 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
+#
+
+GroupSources(include/boost/beast beast)
+GroupSources(example/websocket/server/stackless "/")
+
+add_executable (websocket-server-stackless
+ ${BOOST_BEAST_FILES}
+ Jamfile
+ websocket_server_stackless.cpp
+)
+
+target_link_libraries(websocket-server-stackless
+ lib-asio
+ lib-beast)
+
+set_property(TARGET websocket-server-stackless PROPERTY FOLDER "example-websocket-server")
diff --git a/src/boost/libs/beast/example/websocket/server/stackless/Jamfile b/src/boost/libs/beast/example/websocket/server/stackless/Jamfile
new file mode 100644
index 000000000..ce9ab8987
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/stackless/Jamfile
@@ -0,0 +1,15 @@
+#
+# 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
+#
+
+exe websocket-server-stackless :
+ websocket_server_stackless.cpp
+ :
+ <variant>coverage:<build>no
+ <variant>ubasan:<build>no
+ ;
diff --git a/src/boost/libs/beast/example/websocket/server/stackless/websocket_server_stackless.cpp b/src/boost/libs/beast/example/websocket/server/stackless/websocket_server_stackless.cpp
new file mode 100644
index 000000000..c57fe2899
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/stackless/websocket_server_stackless.cpp
@@ -0,0 +1,282 @@
+//
+// Copyright (c) 2016-2019 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
+//
+
+//------------------------------------------------------------------------------
+//
+// Example: WebSocket server, stackless coroutine
+//
+//------------------------------------------------------------------------------
+
+#include <boost/beast/core.hpp>
+#include <boost/beast/websocket.hpp>
+#include <boost/asio/coroutine.hpp>
+#include <boost/asio/strand.hpp>
+#include <boost/asio/dispatch.hpp>
+#include <algorithm>
+#include <cstdlib>
+#include <functional>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <thread>
+#include <vector>
+
+namespace beast = boost::beast; // from <boost/beast.hpp>
+namespace http = beast::http; // from <boost/beast/http.hpp>
+namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
+namespace net = boost::asio; // from <boost/asio.hpp>
+using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
+
+//------------------------------------------------------------------------------
+
+// Report a failure
+void
+fail(beast::error_code ec, char const* what)
+{
+ std::cerr << what << ": " << ec.message() << "\n";
+}
+
+// Echoes back all received WebSocket messages
+class session
+ : public boost::asio::coroutine
+ , public std::enable_shared_from_this<session>
+{
+ websocket::stream<beast::tcp_stream> ws_;
+ beast::flat_buffer buffer_;
+
+public:
+ // Take ownership of the socket
+ explicit
+ session(tcp::socket socket)
+ : ws_(std::move(socket))
+ {
+ }
+
+ // Start the asynchronous operation
+ void
+ run()
+ {
+ // We need to be executing within a strand to perform async operations
+ // on the I/O objects in this session. Although not strictly necessary
+ // for single-threaded contexts, this example code is written to be
+ // thread-safe by default.
+ net::dispatch(ws_.get_executor(),
+ beast::bind_front_handler(&session::loop,
+ shared_from_this(),
+ beast::error_code{},
+ 0));
+ }
+
+ #include <boost/asio/yield.hpp>
+
+ void
+ loop(
+ beast::error_code ec,
+ std::size_t bytes_transferred)
+ {
+ boost::ignore_unused(bytes_transferred);
+ reenter(*this)
+ {
+ // Set suggested timeout settings for the websocket
+ ws_.set_option(
+ websocket::stream_base::timeout::suggested(
+ beast::role_type::server));
+
+ // Set a decorator to change the Server of the handshake
+ ws_.set_option(websocket::stream_base::decorator(
+ [](websocket::response_type& res)
+ {
+ res.set(http::field::server,
+ std::string(BOOST_BEAST_VERSION_STRING) +
+ " websocket-server-stackless");
+ }));
+
+ // Accept the websocket handshake
+ yield ws_.async_accept(
+ std::bind(
+ &session::loop,
+ shared_from_this(),
+ std::placeholders::_1,
+ 0));
+ if(ec)
+ return fail(ec, "accept");
+
+ for(;;)
+ {
+ // Read a message into our buffer
+ yield ws_.async_read(
+ buffer_,
+ 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
+ return;
+ }
+ if(ec)
+ fail(ec, "read");
+
+ // Echo the message
+ ws_.text(ws_.got_text());
+ yield ws_.async_write(
+ buffer_.data(),
+ std::bind(
+ &session::loop,
+ shared_from_this(),
+ std::placeholders::_1,
+ std::placeholders::_2));
+ if(ec)
+ return fail(ec, "write");
+
+ // Clear the buffer
+ buffer_.consume(buffer_.size());
+ }
+ }
+ }
+
+ #include <boost/asio/unyield.hpp>
+};
+
+//------------------------------------------------------------------------------
+
+// Accepts incoming connections and launches the sessions
+class listener
+ : public boost::asio::coroutine
+ , public std::enable_shared_from_this<listener>
+{
+ net::io_context& ioc_;
+ tcp::acceptor acceptor_;
+ tcp::socket socket_;
+
+public:
+ listener(
+ net::io_context& ioc,
+ tcp::endpoint endpoint)
+ : ioc_(ioc)
+ , acceptor_(net::make_strand(ioc))
+ , socket_(net::make_strand(ioc))
+ {
+ beast::error_code ec;
+
+ // Open the acceptor
+ acceptor_.open(endpoint.protocol(), ec);
+ if(ec)
+ {
+ fail(ec, "open");
+ return;
+ }
+
+ // Allow address reuse
+ acceptor_.set_option(net::socket_base::reuse_address(true), ec);
+ if(ec)
+ {
+ fail(ec, "set_option");
+ return;
+ }
+
+ // Bind to the server address
+ acceptor_.bind(endpoint, ec);
+ if(ec)
+ {
+ fail(ec, "bind");
+ return;
+ }
+
+ // Start listening for connections
+ acceptor_.listen(
+ net::socket_base::max_listen_connections, ec);
+ if(ec)
+ {
+ fail(ec, "listen");
+ return;
+ }
+ }
+
+ // Start accepting incoming connections
+ void
+ run()
+ {
+ loop();
+ }
+
+private:
+
+ #include <boost/asio/yield.hpp>
+
+ void
+ loop(beast::error_code ec = {})
+ {
+ reenter(*this)
+ {
+ for(;;)
+ {
+ yield acceptor_.async_accept(
+ socket_,
+ std::bind(
+ &listener::loop,
+ shared_from_this(),
+ std::placeholders::_1));
+ if(ec)
+ {
+ fail(ec, "accept");
+ }
+ else
+ {
+ // Create the session and run it
+ std::make_shared<session>(std::move(socket_))->run();
+ }
+
+ // Make sure each session gets its own strand
+ socket_ = tcp::socket(net::make_strand(ioc_));
+ }
+ }
+ }
+
+ #include <boost/asio/unyield.hpp>
+};
+
+//------------------------------------------------------------------------------
+
+int main(int argc, char* argv[])
+{
+ // Check command line arguments.
+ if (argc != 4)
+ {
+ std::cerr <<
+ "Usage: websocket-server-stackless <address> <port> <threads>\n" <<
+ "Example:\n" <<
+ " websocket-server-stackless 0.0.0.0 8080 1\n";
+ return EXIT_FAILURE;
+ }
+ auto const address = net::ip::make_address(argv[1]);
+ auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
+ auto const threads = std::max<int>(1, std::atoi(argv[3]));
+
+ // The io_context is required for all I/O
+ net::io_context ioc{threads};
+
+ // Create and launch a listening port
+ 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(
+ [&ioc]
+ {
+ ioc.run();
+ });
+ ioc.run();
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/boost/libs/beast/example/websocket/server/sync-ssl/CMakeLists.txt b/src/boost/libs/beast/example/websocket/server/sync-ssl/CMakeLists.txt
new file mode 100644
index 000000000..0ad254ce5
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/sync-ssl/CMakeLists.txt
@@ -0,0 +1,31 @@
+#
+# 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
+#
+
+if (OPENSSL_FOUND)
+ GroupSources(include/boost/beast beast)
+ GroupSources(example/common common)
+ GroupSources(example/websocket/server/sync-ssl "/")
+
+ add_executable (websocket-server-sync-ssl
+ ${BOOST_BEAST_FILES}
+ ${PROJECT_SOURCE_DIR}/example/common/server_certificate.hpp
+ Jamfile
+ websocket_server_sync_ssl.cpp
+ )
+
+ set_property(TARGET websocket-server-sync-ssl PROPERTY FOLDER "example-websocket-server")
+
+ target_link_libraries (websocket-server-sync-ssl
+ OpenSSL::SSL OpenSSL::Crypto
+ lib-asio
+ lib-asio-ssl
+ lib-beast
+ )
+
+endif()
diff --git a/src/boost/libs/beast/example/websocket/server/sync-ssl/Jamfile b/src/boost/libs/beast/example/websocket/server/sync-ssl/Jamfile
new file mode 100644
index 000000000..55ac35b84
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/sync-ssl/Jamfile
@@ -0,0 +1,22 @@
+#
+# 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
+#
+
+import ac ;
+
+project
+ : requirements
+ [ ac.check-library /boost/beast//lib-asio-ssl : <library>/boost/beast//lib-asio-ssl/<link>static : <build>no ]
+ ;
+
+exe websocket-server-sync-ssl :
+ websocket_server_sync_ssl.cpp
+ :
+ <variant>coverage:<build>no
+ <variant>ubasan:<build>no
+ ;
diff --git a/src/boost/libs/beast/example/websocket/server/sync-ssl/websocket_server_sync_ssl.cpp b/src/boost/libs/beast/example/websocket/server/sync-ssl/websocket_server_sync_ssl.cpp
new file mode 100644
index 000000000..5a7b4dc06
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/sync-ssl/websocket_server_sync_ssl.cpp
@@ -0,0 +1,137 @@
+//
+// Copyright (c) 2016-2019 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
+//
+
+//------------------------------------------------------------------------------
+//
+// Example: WebSocket SSL server, synchronous
+//
+//------------------------------------------------------------------------------
+
+#include "example/common/server_certificate.hpp"
+
+#include <boost/beast/core.hpp>
+#include <boost/beast/ssl.hpp>
+#include <boost/beast/websocket.hpp>
+#include <boost/beast/websocket/ssl.hpp>
+#include <boost/asio/ip/tcp.hpp>
+#include <boost/asio/ssl/stream.hpp>
+#include <cstdlib>
+#include <functional>
+#include <iostream>
+#include <string>
+#include <thread>
+
+namespace beast = boost::beast; // from <boost/beast.hpp>
+namespace http = beast::http; // from <boost/beast/http.hpp>
+namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
+namespace net = boost::asio; // from <boost/asio.hpp>
+namespace ssl = boost::asio::ssl; // from <boost/asio/ssl.hpp>
+using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
+
+//------------------------------------------------------------------------------
+
+// Echoes back all received WebSocket messages
+void
+do_session(tcp::socket& socket, ssl::context& ctx)
+{
+ try
+ {
+ // Construct the websocket stream around the socket
+ websocket::stream<beast::ssl_stream<tcp::socket&>> ws{socket, ctx};
+
+ // Perform the SSL handshake
+ ws.next_layer().handshake(ssl::stream_base::server);
+
+ // Set a decorator to change the Server of the handshake
+ ws.set_option(websocket::stream_base::decorator(
+ [](websocket::response_type& res)
+ {
+ res.set(http::field::server,
+ std::string(BOOST_BEAST_VERSION_STRING) +
+ " websocket-server-sync-ssl");
+ }));
+
+ // Accept the websocket handshake
+ ws.accept();
+
+ for(;;)
+ {
+ // This buffer will hold the incoming message
+ beast::flat_buffer buffer;
+
+ // Read a message
+ ws.read(buffer);
+
+ // Echo the message back
+ ws.text(ws.got_text());
+ ws.write(buffer.data());
+ }
+ }
+ catch(beast::system_error const& se)
+ {
+ // This indicates that the session was closed
+ if(se.code() != websocket::error::closed)
+ std::cerr << "Error: " << se.code().message() << std::endl;
+ }
+ catch(std::exception const& e)
+ {
+ std::cerr << "Error: " << e.what() << std::endl;
+ }
+}
+
+//------------------------------------------------------------------------------
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ // Check command line arguments.
+ if (argc != 3)
+ {
+ std::cerr <<
+ "Usage: websocket-server-sync-ssl <address> <port>\n" <<
+ "Example:\n" <<
+ " websocket-server-sync-ssl 0.0.0.0 8080\n";
+ return EXIT_FAILURE;
+ }
+ auto const address = net::ip::make_address(argv[1]);
+ auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
+
+ // The io_context is required for all I/O
+ net::io_context ioc{1};
+
+ // The SSL context is required, and holds certificates
+ ssl::context ctx{ssl::context::tlsv12};
+
+ // This holds the self-signed certificate used by the server
+ load_server_certificate(ctx);
+
+ // The acceptor receives incoming connections
+ tcp::acceptor acceptor{ioc, {address, port}};
+ for(;;)
+ {
+ // This will receive the new connection
+ tcp::socket socket{ioc};
+
+ // Block until we get a connection
+ acceptor.accept(socket);
+
+ // Launch the session, transferring ownership of the socket
+ std::thread{std::bind(
+ &do_session,
+ std::move(socket),
+ std::ref(ctx))}.detach();
+ }
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << "Error: " << e.what() << std::endl;
+ return EXIT_FAILURE;
+ }
+}
diff --git a/src/boost/libs/beast/example/websocket/server/sync/CMakeLists.txt b/src/boost/libs/beast/example/websocket/server/sync/CMakeLists.txt
new file mode 100644
index 000000000..486998615
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/sync/CMakeLists.txt
@@ -0,0 +1,23 @@
+#
+# 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
+#
+
+GroupSources(include/boost/beast beast)
+GroupSources(example/websocket/server/sync "/")
+
+add_executable (websocket-server-sync
+ ${BOOST_BEAST_FILES}
+ Jamfile
+ websocket_server_sync.cpp
+)
+
+target_link_libraries(websocket-server-sync
+ lib-asio
+ lib-beast)
+
+set_property(TARGET websocket-server-sync PROPERTY FOLDER "example-websocket-server")
diff --git a/src/boost/libs/beast/example/websocket/server/sync/Jamfile b/src/boost/libs/beast/example/websocket/server/sync/Jamfile
new file mode 100644
index 000000000..7fd14ce4a
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/sync/Jamfile
@@ -0,0 +1,15 @@
+#
+# 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
+#
+
+exe websocket-server-sync :
+ websocket_server_sync.cpp
+ :
+ <variant>coverage:<build>no
+ <variant>ubasan:<build>no
+ ;
diff --git a/src/boost/libs/beast/example/websocket/server/sync/websocket_server_sync.cpp b/src/boost/libs/beast/example/websocket/server/sync/websocket_server_sync.cpp
new file mode 100644
index 000000000..2f75c468e
--- /dev/null
+++ b/src/boost/libs/beast/example/websocket/server/sync/websocket_server_sync.cpp
@@ -0,0 +1,121 @@
+//
+// Copyright (c) 2016-2019 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
+//
+
+//------------------------------------------------------------------------------
+//
+// Example: WebSocket server, synchronous
+//
+//------------------------------------------------------------------------------
+
+#include <boost/beast/core.hpp>
+#include <boost/beast/websocket.hpp>
+#include <boost/asio/ip/tcp.hpp>
+#include <cstdlib>
+#include <functional>
+#include <iostream>
+#include <string>
+#include <thread>
+
+namespace beast = boost::beast; // from <boost/beast.hpp>
+namespace http = beast::http; // from <boost/beast/http.hpp>
+namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
+namespace net = boost::asio; // from <boost/asio.hpp>
+using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
+
+//------------------------------------------------------------------------------
+
+// Echoes back all received WebSocket messages
+void
+do_session(tcp::socket& socket)
+{
+ try
+ {
+ // Construct the stream by moving in the socket
+ websocket::stream<tcp::socket> ws{std::move(socket)};
+
+ // Set a decorator to change the Server of the handshake
+ ws.set_option(websocket::stream_base::decorator(
+ [](websocket::response_type& res)
+ {
+ res.set(http::field::server,
+ std::string(BOOST_BEAST_VERSION_STRING) +
+ " websocket-server-sync");
+ }));
+
+ // Accept the websocket handshake
+ ws.accept();
+
+ for(;;)
+ {
+ // This buffer will hold the incoming message
+ beast::flat_buffer buffer;
+
+ // Read a message
+ ws.read(buffer);
+
+ // Echo the message back
+ ws.text(ws.got_text());
+ ws.write(buffer.data());
+ }
+ }
+ catch(beast::system_error const& se)
+ {
+ // This indicates that the session was closed
+ if(se.code() != websocket::error::closed)
+ std::cerr << "Error: " << se.code().message() << std::endl;
+ }
+ catch(std::exception const& e)
+ {
+ std::cerr << "Error: " << e.what() << std::endl;
+ }
+}
+
+//------------------------------------------------------------------------------
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ // Check command line arguments.
+ if (argc != 3)
+ {
+ std::cerr <<
+ "Usage: websocket-server-sync <address> <port>\n" <<
+ "Example:\n" <<
+ " websocket-server-sync 0.0.0.0 8080\n";
+ return EXIT_FAILURE;
+ }
+ auto const address = net::ip::make_address(argv[1]);
+ auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
+
+ // The io_context is required for all I/O
+ net::io_context ioc{1};
+
+ // The acceptor receives incoming connections
+ tcp::acceptor acceptor{ioc, {address, port}};
+ for(;;)
+ {
+ // This will receive the new connection
+ tcp::socket socket{ioc};
+
+ // Block until we get a connection
+ acceptor.accept(socket);
+
+ // Launch the session, transferring ownership of the socket
+ std::thread{std::bind(
+ &do_session,
+ std::move(socket))}.detach();
+ }
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << "Error: " << e.what() << std::endl;
+ return EXIT_FAILURE;
+ }
+}