forked from anarthal/boost-modules-bench
-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.hpp
119 lines (102 loc) · 3.02 KB
/
main.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#ifdef USE_MODULES
# ifdef HAS_STDLIB_MODULES
import std;
import std.compat;
# else
# include <coroutine>
# include <cstdlib>
# include <exception>
# include <system_error>
# endif
import asio;
#else
# include <asio/awaitable.hpp>
# include <asio/buffer.hpp>
# include <asio/co_spawn.hpp>
# include <asio/connect.hpp>
# include <asio/deferred.hpp>
# include <asio/detached.hpp>
# include <asio/io_context.hpp>
# include <asio/ip/address_v4.hpp>
# include <asio/ip/tcp.hpp>
# include <asio/ssl/error.hpp>
# include <asio/ssl/stream.hpp>
# include <asio/this_coro.hpp>
#endif
namespace bench {
namespace net = asio;
namespace ssl = asio::ssl;
using tcp = asio::ip::tcp;
using std::error_code;
inline void fail(error_code ec, char const* what)
{
if(ec == net::ssl::error::stream_truncated)
return;
exit(1);
}
inline net::awaitable<void> do_session(tcp::socket client_sock)
{
char buff [4096] {};
auto ex = co_await net::this_coro::executor;
ssl::context ctx {ssl::context::tls_client};
ssl::stream<tcp::socket> stream {std::move(client_sock), ctx};
co_await stream.async_handshake(ssl::stream_base::server, net::deferred);
co_await stream.async_read_some(net::buffer(buff), net::deferred);
co_await stream.async_write_some(net::buffer(buff), net::deferred);
co_await stream.async_shutdown(net::deferred);
stream.next_layer().close();
}
inline net::awaitable<void> do_listen()
{
auto ex = co_await net::this_coro::executor;
error_code ec;
tcp::endpoint endpoint {net::ip::address_v4::loopback(), 3000};
// Open the acceptor
tcp::acceptor acceptor{ex};
acceptor.open(endpoint.protocol(), ec);
if(ec)
fail(ec, "open");
// Allow address reuse
acceptor.set_option(net::socket_base::reuse_address(true), ec);
if(ec)
fail(ec, "set_option");
// Bind to the server address
acceptor.bind(endpoint, ec);
if(ec)
fail(ec, "bind");
// Start listening for connections
acceptor.listen(net::socket_base::max_listen_connections, ec);
if(ec)
fail(ec, "listen");
for(;;)
{
tcp::socket socket{ex};
co_await acceptor.async_accept(socket, net::deferred);
net::co_spawn(ex, [s = std::move(socket)] mutable {
return do_session(std::move(s));
}, net::detached);
}
}
inline int main_impl()
{
// The io_context is required for all I/O
net::io_context ioc;
// Spawn a listening port
net::co_spawn(
ioc,
do_listen,
// on completion, spawn will call this function
[](std::exception_ptr ex)
{
// if an exception occurred in the coroutine,
// it's something critical, e.g. out of memory
// we capture normal errors in the ec
// so we just rethrow the exception here,
// which will cause `ioc.run()` to throw
if (ex)
std::rethrow_exception(ex);
});
ioc.run();
return 0;
}
}