mirror of
https://github.com/boostorg/beast.git
synced 2025-07-31 21:34:46 +02:00
Add websocket async echo ssl server test:
This adds a new asynchronous websocket echo server which supports TLS/SSL connections.
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
1.0.0-b39
|
||||
|
||||
WebSocket:
|
||||
|
||||
* Add websocket async echo ssl server test:
|
||||
|
||||
API Changes:
|
||||
|
||||
* Refactor http::header contents
|
||||
|
@@ -176,6 +176,7 @@ if (NOT OPENSSL_FOUND)
|
||||
message("OpenSSL not found. Not building SSL tests and examples")
|
||||
else()
|
||||
add_subdirectory (examples/ssl)
|
||||
add_subdirectory (test/websocket/ssl)
|
||||
endif()
|
||||
|
||||
add_subdirectory (test)
|
||||
|
22
test/websocket/ssl/CMakeLists.txt
Normal file
22
test/websocket/ssl/CMakeLists.txt
Normal file
@@ -0,0 +1,22 @@
|
||||
# Part of Beast
|
||||
|
||||
GroupSources(extras/beast extras)
|
||||
GroupSources(include/beast beast)
|
||||
|
||||
GroupSources(test/websocket/ssl "/")
|
||||
|
||||
include_directories(${OPENSSL_INCLUDE_DIR})
|
||||
|
||||
add_executable (websocket-ssl-tests
|
||||
${BEAST_INCLUDES}
|
||||
${EXTRAS_INCLUDES}
|
||||
../../../extras/beast/unit_test/main.cpp
|
||||
websocket_async_ssl_echo_server.hpp
|
||||
ssl_server.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(websocket-ssl-tests ${OPENSSL_LIBRARIES})
|
||||
|
||||
if (NOT WIN32)
|
||||
target_link_libraries(websocket-ssl-tests ${Boost_LIBRARIES} Threads::Threads)
|
||||
endif()
|
158
test/websocket/ssl/ssl_server.cpp
Normal file
158
test/websocket/ssl/ssl_server.cpp
Normal file
@@ -0,0 +1,158 @@
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
|
||||
#include "websocket_async_ssl_echo_server.hpp"
|
||||
|
||||
#include <beast/websocket/stream.hpp>
|
||||
#include <beast/core/to_string.hpp>
|
||||
#include <beast/unit_test/suite.hpp>
|
||||
#include <beast/test/yield_to.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
|
||||
namespace beast {
|
||||
namespace websocket {
|
||||
|
||||
class ssl_server_test
|
||||
: public beast::unit_test::suite
|
||||
, public test::enable_yield_to
|
||||
{
|
||||
public:
|
||||
using self = ssl_server_test;
|
||||
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
||||
using address_type = boost::asio::ip::address;
|
||||
using socket_type = boost::asio::ip::tcp::socket;
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
/*
|
||||
The certificate was generated from CMD.EXE on Windows 10 using:
|
||||
|
||||
winpty openssl dhparam -out dh.pem 2048
|
||||
winpty openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 10000 -out cert.pem -subj "//C=US\ST=CA\L=Los Angeles\O=Beast\CN=www.example.com"
|
||||
*/
|
||||
|
||||
std::string const cert =
|
||||
"-----BEGIN CERTIFICATE-----\n"
|
||||
"MIIDaDCCAlCgAwIBAgIJAO8vBu8i8exWMA0GCSqGSIb3DQEBCwUAMEkxCzAJBgNV\n"
|
||||
"BAYTAlVTMQswCQYDVQQIDAJDQTEtMCsGA1UEBwwkTG9zIEFuZ2VsZXNPPUJlYXN0\n"
|
||||
"Q049d3d3LmV4YW1wbGUuY29tMB4XDTE3MDUwMzE4MzkxMloXDTQ0MDkxODE4Mzkx\n"
|
||||
"MlowSTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMS0wKwYDVQQHDCRMb3MgQW5n\n"
|
||||
"ZWxlc089QmVhc3RDTj13d3cuZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUA\n"
|
||||
"A4IBDwAwggEKAoIBAQDJ7BRKFO8fqmsEXw8v9YOVXyrQVsVbjSSGEs4Vzs4cJgcF\n"
|
||||
"xqGitbnLIrOgiJpRAPLy5MNcAXE1strVGfdEf7xMYSZ/4wOrxUyVw/Ltgsft8m7b\n"
|
||||
"Fu8TsCzO6XrxpnVtWk506YZ7ToTa5UjHfBi2+pWTxbpN12UhiZNUcrRsqTFW+6fO\n"
|
||||
"9d7xm5wlaZG8cMdg0cO1bhkz45JSl3wWKIES7t3EfKePZbNlQ5hPy7Pd5JTmdGBp\n"
|
||||
"yY8anC8u4LPbmgW0/U31PH0rRVfGcBbZsAoQw5Tc5dnb6N2GEIbq3ehSfdDHGnrv\n"
|
||||
"enu2tOK9Qx6GEzXh3sekZkxcgh+NlIxCNxu//Dk9AgMBAAGjUzBRMB0GA1UdDgQW\n"
|
||||
"BBTZh0N9Ne1OD7GBGJYz4PNESHuXezAfBgNVHSMEGDAWgBTZh0N9Ne1OD7GBGJYz\n"
|
||||
"4PNESHuXezAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCmTJVT\n"
|
||||
"LH5Cru1vXtzb3N9dyolcVH82xFVwPewArchgq+CEkajOU9bnzCqvhM4CryBb4cUs\n"
|
||||
"gqXWp85hAh55uBOqXb2yyESEleMCJEiVTwm/m26FdONvEGptsiCmF5Gxi0YRtn8N\n"
|
||||
"V+KhrQaAyLrLdPYI7TrwAOisq2I1cD0mt+xgwuv/654Rl3IhOMx+fKWKJ9qLAiaE\n"
|
||||
"fQyshjlPP9mYVxWOxqctUdQ8UnsUKKGEUcVrA08i1OAnVKlPFjKBvk+r7jpsTPcr\n"
|
||||
"9pWXTO9JrYMML7d+XRSZA1n3856OqZDX4403+9FnXCvfcLZLLKTBvwwFgEFGpzjK\n"
|
||||
"UEVbkhd5qstF6qWK\n"
|
||||
"-----END CERTIFICATE-----\n";
|
||||
|
||||
std::string const key =
|
||||
"-----BEGIN PRIVATE KEY-----\n"
|
||||
"MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDJ7BRKFO8fqmsE\n"
|
||||
"Xw8v9YOVXyrQVsVbjSSGEs4Vzs4cJgcFxqGitbnLIrOgiJpRAPLy5MNcAXE1strV\n"
|
||||
"GfdEf7xMYSZ/4wOrxUyVw/Ltgsft8m7bFu8TsCzO6XrxpnVtWk506YZ7ToTa5UjH\n"
|
||||
"fBi2+pWTxbpN12UhiZNUcrRsqTFW+6fO9d7xm5wlaZG8cMdg0cO1bhkz45JSl3wW\n"
|
||||
"KIES7t3EfKePZbNlQ5hPy7Pd5JTmdGBpyY8anC8u4LPbmgW0/U31PH0rRVfGcBbZ\n"
|
||||
"sAoQw5Tc5dnb6N2GEIbq3ehSfdDHGnrvenu2tOK9Qx6GEzXh3sekZkxcgh+NlIxC\n"
|
||||
"Nxu//Dk9AgMBAAECggEBAK1gV8uETg4SdfE67f9v/5uyK0DYQH1ro4C7hNiUycTB\n"
|
||||
"oiYDd6YOA4m4MiQVJuuGtRR5+IR3eI1zFRMFSJs4UqYChNwqQGys7CVsKpplQOW+\n"
|
||||
"1BCqkH2HN/Ix5662Dv3mHJemLCKUON77IJKoq0/xuZ04mc9csykox6grFWB3pjXY\n"
|
||||
"OEn9U8pt5KNldWfpfAZ7xu9WfyvthGXlhfwKEetOuHfAQv7FF6s25UIEU6Hmnwp9\n"
|
||||
"VmYp2twfMGdztz/gfFjKOGxf92RG+FMSkyAPq/vhyB7oQWxa+vdBn6BSdsfn27Qs\n"
|
||||
"bTvXrGe4FYcbuw4WkAKTljZX7TUegkXiwFoSps0jegECgYEA7o5AcRTZVUmmSs8W\n"
|
||||
"PUHn89UEuDAMFVk7grG1bg8exLQSpugCykcqXt1WNrqB7x6nB+dbVANWNhSmhgCg\n"
|
||||
"VrV941vbx8ketqZ9YInSbGPWIU/tss3r8Yx2Ct3mQpvpGC6iGHzEc/NHJP8Efvh/\n"
|
||||
"CcUWmLjLGJYYeP5oNu5cncC3fXUCgYEA2LANATm0A6sFVGe3sSLO9un1brA4zlZE\n"
|
||||
"Hjd3KOZnMPt73B426qUOcw5B2wIS8GJsUES0P94pKg83oyzmoUV9vJpJLjHA4qmL\n"
|
||||
"CDAd6CjAmE5ea4dFdZwDDS8F9FntJMdPQJA9vq+JaeS+k7ds3+7oiNe+RUIHR1Sz\n"
|
||||
"VEAKh3Xw66kCgYB7KO/2Mchesu5qku2tZJhHF4QfP5cNcos511uO3bmJ3ln+16uR\n"
|
||||
"GRqz7Vu0V6f7dvzPJM/O2QYqV5D9f9dHzN2YgvU9+QSlUeFK9PyxPv3vJt/WP1//\n"
|
||||
"zf+nbpaRbwLxnCnNsKSQJFpnrE166/pSZfFbmZQpNlyeIuJU8czZGQTifQKBgHXe\n"
|
||||
"/pQGEZhVNab+bHwdFTxXdDzr+1qyrodJYLaM7uFES9InVXQ6qSuJO+WosSi2QXlA\n"
|
||||
"hlSfwwCwGnHXAPYFWSp5Owm34tbpp0mi8wHQ+UNgjhgsE2qwnTBUvgZ3zHpPORtD\n"
|
||||
"23KZBkTmO40bIEyIJ1IZGdWO32q79nkEBTY+v/lRAoGBAI1rbouFYPBrTYQ9kcjt\n"
|
||||
"1yfu4JF5MvO9JrHQ9tOwkqDmNCWx9xWXbgydsn/eFtuUMULWsG3lNjfst/Esb8ch\n"
|
||||
"k5cZd6pdJZa4/vhEwrYYSuEjMCnRb0lUsm7TsHxQrUd6Fi/mUuFU/haC0o0chLq7\n"
|
||||
"pVOUFq5mW8p0zbtfHbjkgxyF\n"
|
||||
"-----END PRIVATE KEY-----\n";
|
||||
|
||||
std::string const dh =
|
||||
"-----BEGIN DH PARAMETERS-----\n"
|
||||
"MIIBCAKCAQEArzQc5mpm0Fs8yahDeySj31JZlwEphUdZ9StM2D8+Fo7TMduGtSi+\n"
|
||||
"/HRWVwHcTFAgrxVdm+dl474mOUqqaz4MpzIb6+6OVfWHbQJmXPepZKyu4LgUPvY/\n"
|
||||
"4q3/iDMjIS0fLOu/bLuObwU5ccZmDgfhmz1GanRlTQOiYRty3FiOATWZBRh6uv4u\n"
|
||||
"tff4A9Bm3V9tLx9S6djq31w31Gl7OQhryodW28kc16t9TvO1BzcV3HjRPwpe701X\n"
|
||||
"oEEZdnZWANkkpR/m/pfgdmGPU66S2sXMHgsliViQWpDCYeehrvFRHEdR9NV+XJfC\n"
|
||||
"QMUk26jPTIVTLfXmmwU0u8vUkpR7LQKkwwIBAg==\n"
|
||||
"-----END DH PARAMETERS-----\n";
|
||||
|
||||
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
||||
using address_type = boost::asio::ip::address;
|
||||
::websocket::async_ssl_echo_server server{
|
||||
&log, 1, cert, key, dh};
|
||||
error_code ec;
|
||||
server.open(endpoint_type{
|
||||
address_type::from_string("127.0.0.1"), 6000 }, ec);
|
||||
auto const ep = server.local_endpoint();
|
||||
|
||||
using boost::asio::connect;
|
||||
using socket = boost::asio::ip::tcp::socket;
|
||||
using io_service = boost::asio::io_service;
|
||||
namespace ssl = boost::asio::ssl;
|
||||
|
||||
// Perform SSL handshaking
|
||||
io_service ios;
|
||||
using stream_type = ssl::stream<socket>;
|
||||
ssl::context ctx{ssl::context::sslv23};
|
||||
stream_type stream{ios_, ctx};
|
||||
stream.next_layer().connect(ep);
|
||||
stream.set_verify_mode(ssl::verify_none);
|
||||
stream.handshake(ssl::stream_base::client);
|
||||
|
||||
// Secure WebSocket connect and send message using Beast
|
||||
beast::websocket::stream<stream_type&> ws{stream};
|
||||
ws.handshake("localhost", "/");
|
||||
ws.write(boost::asio::buffer("Hello, world!"));
|
||||
|
||||
// Receive Secure WebSocket message, print and close using Beast
|
||||
beast::streambuf sb;
|
||||
beast::websocket::opcode op;
|
||||
ws.read(op, sb);
|
||||
ws.close(beast::websocket::close_code::normal);
|
||||
try
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
ws.read(op, sb);
|
||||
sb.consume(sb.size());
|
||||
}
|
||||
}
|
||||
catch(system_error const& se)
|
||||
{
|
||||
if(se.code() != beast::websocket::error::closed)
|
||||
throw;
|
||||
}
|
||||
log << to_string(sb.data()) << std::endl;
|
||||
|
||||
pass();
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(ssl_server,websocket,beast);
|
||||
|
||||
} // websocket
|
||||
} // beast
|
308
test/websocket/ssl/websocket_async_ssl_echo_server.hpp
Normal file
308
test/websocket/ssl/websocket_async_ssl_echo_server.hpp
Normal file
@@ -0,0 +1,308 @@
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
|
||||
#ifndef WEBSOCKET_ASYNC_SSL_ECHO_SERVER_HPP
|
||||
#define WEBSOCKET_ASYNC_SSL_ECHO_SERVER_HPP
|
||||
|
||||
#include <beast/core/placeholders.hpp>
|
||||
#include <beast/core/streambuf.hpp>
|
||||
#include <beast/websocket/ssl.hpp>
|
||||
#include <beast/websocket/stream.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
#include <typeindex>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
namespace websocket {
|
||||
|
||||
/** Asynchronous WebSocket echo client/server
|
||||
*/
|
||||
class async_ssl_echo_server
|
||||
{
|
||||
public:
|
||||
using error_code = beast::error_code;
|
||||
using address_type = boost::asio::ip::address;
|
||||
using socket_type = boost::asio::ip::tcp::socket;
|
||||
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
||||
|
||||
private:
|
||||
std::ostream* log_;
|
||||
boost::asio::io_service ios_;
|
||||
socket_type sock_;
|
||||
endpoint_type ep_;
|
||||
boost::asio::ip::tcp::acceptor acceptor_;
|
||||
std::vector<std::thread> thread_;
|
||||
boost::optional<boost::asio::io_service::work> work_;
|
||||
boost::asio::ssl::context ctx_;
|
||||
|
||||
public:
|
||||
async_ssl_echo_server(async_ssl_echo_server const&) = delete;
|
||||
async_ssl_echo_server& operator=(async_ssl_echo_server const&) = delete;
|
||||
|
||||
/** Constructor.
|
||||
|
||||
@param log A pointer to a stream to log to, or `nullptr`
|
||||
to disable logging.
|
||||
|
||||
@param threads The number of threads in the io_service.
|
||||
*/
|
||||
async_ssl_echo_server(std::ostream* log,
|
||||
std::size_t threads, std::string const& cert,
|
||||
std::string const& key, std::string const& tmp_dh)
|
||||
: log_(log)
|
||||
, sock_(ios_)
|
||||
, acceptor_(ios_)
|
||||
, work_(ios_)
|
||||
, ctx_(boost::asio::ssl::context::sslv23)
|
||||
|
||||
{
|
||||
ctx_.set_password_callback(
|
||||
[](std::size_t size,
|
||||
boost::asio::ssl::context_base::password_purpose)
|
||||
{
|
||||
return "test";
|
||||
});
|
||||
|
||||
ctx_.set_options(
|
||||
boost::asio::ssl::context::default_workarounds |
|
||||
boost::asio::ssl::context::no_sslv2 |
|
||||
boost::asio::ssl::context::single_dh_use);
|
||||
|
||||
ctx_.use_certificate_chain(
|
||||
boost::asio::buffer(cert.data(), cert.size()));
|
||||
|
||||
ctx_.use_private_key(
|
||||
boost::asio::buffer(key.data(), key.size()),
|
||||
boost::asio::ssl::context::file_format::pem);
|
||||
|
||||
ctx_.use_tmp_dh(
|
||||
boost::asio::buffer(tmp_dh.data(), tmp_dh.size()));
|
||||
|
||||
thread_.reserve(threads);
|
||||
for(std::size_t i = 0; i < threads; ++i)
|
||||
thread_.emplace_back(
|
||||
[&]{ ios_.run(); });
|
||||
}
|
||||
|
||||
/** Destructor.
|
||||
*/
|
||||
~async_ssl_echo_server()
|
||||
{
|
||||
work_ = boost::none;
|
||||
error_code ec;
|
||||
ios_.dispatch(
|
||||
[&]{ acceptor_.close(ec); });
|
||||
for(auto& t : thread_)
|
||||
t.join();
|
||||
}
|
||||
|
||||
/** Return the listening endpoint.
|
||||
*/
|
||||
endpoint_type
|
||||
local_endpoint() const
|
||||
{
|
||||
return acceptor_.local_endpoint();
|
||||
}
|
||||
|
||||
/** Open a listening port.
|
||||
|
||||
@param ep The address and port to bind to.
|
||||
|
||||
@param ec Set to the error, if any occurred.
|
||||
*/
|
||||
void
|
||||
open(endpoint_type const& ep, error_code& ec)
|
||||
{
|
||||
acceptor_.open(ep.protocol(), ec);
|
||||
if(ec)
|
||||
return fail("open", ec);
|
||||
acceptor_.set_option(
|
||||
boost::asio::socket_base::reuse_address{true});
|
||||
acceptor_.bind(ep, ec);
|
||||
if(ec)
|
||||
return fail("bind", ec);
|
||||
acceptor_.listen(
|
||||
boost::asio::socket_base::max_connections, ec);
|
||||
if(ec)
|
||||
return fail("listen", ec);
|
||||
acceptor_.async_accept(sock_, ep_,
|
||||
std::bind(&async_ssl_echo_server::on_accept, this,
|
||||
beast::asio::placeholders::error));
|
||||
}
|
||||
|
||||
private:
|
||||
class connection
|
||||
{
|
||||
struct data
|
||||
{
|
||||
async_ssl_echo_server& server;
|
||||
endpoint_type ep;
|
||||
int state = 0;
|
||||
beast::websocket::stream<
|
||||
boost::asio::ssl::stream<socket_type>> ws;
|
||||
boost::asio::io_service::strand strand;
|
||||
beast::websocket::opcode op;
|
||||
beast::streambuf db;
|
||||
std::size_t id;
|
||||
|
||||
data(async_ssl_echo_server& server_,
|
||||
endpoint_type const& ep_,
|
||||
socket_type&& sock_)
|
||||
: server(server_)
|
||||
, ep(ep_)
|
||||
, ws(sock_.get_io_service(), server_.ctx_)
|
||||
, strand(ws.get_io_service())
|
||||
, id([]
|
||||
{
|
||||
static std::atomic<std::size_t> n{0};
|
||||
return ++n;
|
||||
}())
|
||||
{
|
||||
// VFALCO This hack works around
|
||||
// ssl::stream broken ctors
|
||||
ws.next_layer().next_layer() = std::move(sock_);
|
||||
}
|
||||
};
|
||||
|
||||
// VFALCO This could be unique_ptr in [Net.TS]
|
||||
std::shared_ptr<data> d_;
|
||||
|
||||
public:
|
||||
connection(connection&&) = default;
|
||||
connection(connection const&) = default;
|
||||
connection& operator=(connection&&) = delete;
|
||||
connection& operator=(connection const&) = delete;
|
||||
|
||||
template<class... Args>
|
||||
explicit
|
||||
connection(async_ssl_echo_server& server,
|
||||
endpoint_type const& ep, socket_type&& sock,
|
||||
Args&&... args)
|
||||
: d_(std::make_shared<data>(server, ep,
|
||||
std::forward<socket_type>(sock),
|
||||
std::forward<Args>(args)...))
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
run()
|
||||
{
|
||||
(*this)(error_code{});
|
||||
}
|
||||
|
||||
void
|
||||
operator()(error_code ec)
|
||||
{
|
||||
auto& d = *d_;
|
||||
switch(d.state)
|
||||
{
|
||||
// SSL handshake
|
||||
case 0:
|
||||
d.state = 1;
|
||||
d.ws.next_layer().async_handshake(
|
||||
boost::asio::ssl::stream_base::server,
|
||||
d.strand.wrap(std::move(*this)));
|
||||
return;
|
||||
|
||||
// WebSocket handshake
|
||||
case 1:
|
||||
if(ec)
|
||||
return fail("async_handshake", ec);
|
||||
d.state = 2;
|
||||
d.ws.async_accept_ex(
|
||||
[](beast::websocket::response_type& res)
|
||||
{
|
||||
res.fields.insert(
|
||||
"Server", "async_ssl_echo_server");
|
||||
},
|
||||
d.strand.wrap(std::move(*this)));
|
||||
return;
|
||||
|
||||
case 2:
|
||||
if(ec)
|
||||
return fail("async_handshake", ec);
|
||||
// [[fallthrough]]
|
||||
|
||||
// WebSocket read
|
||||
case 3:
|
||||
if(ec)
|
||||
return fail("async_write", ec);
|
||||
d.db.consume(d.db.size());
|
||||
d.state = 4;
|
||||
d.ws.async_read(d.op, d.db,
|
||||
d.strand.wrap(std::move(*this)));
|
||||
return;
|
||||
|
||||
// WebSocket write
|
||||
case 4:
|
||||
if(ec == beast::websocket::error::closed)
|
||||
return;
|
||||
if(ec)
|
||||
return fail("async_read", ec);
|
||||
d.state = 3;
|
||||
d.ws.set_option(
|
||||
beast::websocket::message_type(d.op));
|
||||
d.ws.async_write(d.db.data(),
|
||||
d.strand.wrap(std::move(*this)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
fail(std::string what, error_code ec)
|
||||
{
|
||||
auto& d = *d_;
|
||||
if(d.server.log_)
|
||||
if(ec != beast::websocket::error::closed)
|
||||
d.server.fail("[#" + std::to_string(d.id) +
|
||||
" " + boost::lexical_cast<std::string>(d.ep) +
|
||||
"] " + what, ec);
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
fail(std::string what, error_code ec)
|
||||
{
|
||||
if(log_)
|
||||
{
|
||||
static std::mutex m;
|
||||
std::lock_guard<std::mutex> lock{m};
|
||||
(*log_) << what << ": " <<
|
||||
ec.message() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
on_accept(error_code ec)
|
||||
{
|
||||
if(! acceptor_.is_open())
|
||||
return;
|
||||
if(ec == boost::asio::error::operation_aborted)
|
||||
return;
|
||||
if(ec)
|
||||
fail("accept", ec);
|
||||
connection{*this, ep_, std::move(sock_)}.run();
|
||||
acceptor_.async_accept(sock_, ep_,
|
||||
std::bind(&async_ssl_echo_server::on_accept, this,
|
||||
beast::asio::placeholders::error));
|
||||
}
|
||||
};
|
||||
|
||||
} // websocket
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user