]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/beast/example/websocket/server/coro/websocket_server_coro.cpp
bump version to 18.2.4-pve3
[ceph.git] / ceph / src / boost / libs / beast / example / websocket / server / coro / websocket_server_coro.cpp
1 //
2 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/boostorg/beast
8 //
9
10 //------------------------------------------------------------------------------
11 //
12 // Example: WebSocket server, coroutine
13 //
14 //------------------------------------------------------------------------------
15
16 #include <boost/beast/core.hpp>
17 #include <boost/beast/websocket.hpp>
18 #include <boost/asio/spawn.hpp>
19 #include <algorithm>
20 #include <cstdlib>
21 #include <functional>
22 #include <iostream>
23 #include <memory>
24 #include <string>
25 #include <thread>
26 #include <vector>
27
28 namespace beast = boost::beast; // from <boost/beast.hpp>
29 namespace http = beast::http; // from <boost/beast/http.hpp>
30 namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
31 namespace net = boost::asio; // from <boost/asio.hpp>
32 using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
33
34 //------------------------------------------------------------------------------
35
36 // Report a failure
37 void
38 fail(beast::error_code ec, char const* what)
39 {
40 std::cerr << what << ": " << ec.message() << "\n";
41 }
42
43 // Echoes back all received WebSocket messages
44 void
45 do_session(
46 websocket::stream<beast::tcp_stream>& ws,
47 net::yield_context yield)
48 {
49 beast::error_code ec;
50
51 // Set suggested timeout settings for the websocket
52 ws.set_option(
53 websocket::stream_base::timeout::suggested(
54 beast::role_type::server));
55
56 // Set a decorator to change the Server of the handshake
57 ws.set_option(websocket::stream_base::decorator(
58 [](websocket::response_type& res)
59 {
60 res.set(http::field::server,
61 std::string(BOOST_BEAST_VERSION_STRING) +
62 " websocket-server-coro");
63 }));
64
65 // Accept the websocket handshake
66 ws.async_accept(yield[ec]);
67 if(ec)
68 return fail(ec, "accept");
69
70 for(;;)
71 {
72 // This buffer will hold the incoming message
73 beast::flat_buffer buffer;
74
75 // Read a message
76 ws.async_read(buffer, yield[ec]);
77
78 // This indicates that the session was closed
79 if(ec == websocket::error::closed)
80 break;
81
82 if(ec)
83 return fail(ec, "read");
84
85 // Echo the message back
86 ws.text(ws.got_text());
87 ws.async_write(buffer.data(), yield[ec]);
88 if(ec)
89 return fail(ec, "write");
90 }
91 }
92
93 //------------------------------------------------------------------------------
94
95 // Accepts incoming connections and launches the sessions
96 void
97 do_listen(
98 net::io_context& ioc,
99 tcp::endpoint endpoint,
100 net::yield_context yield)
101 {
102 beast::error_code ec;
103
104 // Open the acceptor
105 tcp::acceptor acceptor(ioc);
106 acceptor.open(endpoint.protocol(), ec);
107 if(ec)
108 return fail(ec, "open");
109
110 // Allow address reuse
111 acceptor.set_option(net::socket_base::reuse_address(true), ec);
112 if(ec)
113 return fail(ec, "set_option");
114
115 // Bind to the server address
116 acceptor.bind(endpoint, ec);
117 if(ec)
118 return fail(ec, "bind");
119
120 // Start listening for connections
121 acceptor.listen(net::socket_base::max_listen_connections, ec);
122 if(ec)
123 return fail(ec, "listen");
124
125 for(;;)
126 {
127 tcp::socket socket(ioc);
128 acceptor.async_accept(socket, yield[ec]);
129 if(ec)
130 fail(ec, "accept");
131 else
132 boost::asio::spawn(
133 acceptor.get_executor(),
134 std::bind(
135 &do_session,
136 websocket::stream<
137 beast::tcp_stream>(std::move(socket)),
138 std::placeholders::_1));
139 }
140 }
141
142 int main(int argc, char* argv[])
143 {
144 // Check command line arguments.
145 if (argc != 4)
146 {
147 std::cerr <<
148 "Usage: websocket-server-coro <address> <port> <threads>\n" <<
149 "Example:\n" <<
150 " websocket-server-coro 0.0.0.0 8080 1\n";
151 return EXIT_FAILURE;
152 }
153 auto const address = net::ip::make_address(argv[1]);
154 auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
155 auto const threads = std::max<int>(1, std::atoi(argv[3]));
156
157 // The io_context is required for all I/O
158 net::io_context ioc(threads);
159
160 // Spawn a listening port
161 boost::asio::spawn(ioc,
162 std::bind(
163 &do_listen,
164 std::ref(ioc),
165 tcp::endpoint{address, port},
166 std::placeholders::_1));
167
168 // Run the I/O service on the requested number of threads
169 std::vector<std::thread> v;
170 v.reserve(threads - 1);
171 for(auto i = threads - 1; i > 0; --i)
172 v.emplace_back(
173 [&ioc]
174 {
175 ioc.run();
176 });
177 ioc.run();
178
179 return EXIT_SUCCESS;
180 }