]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/beast/example/websocket/server/coro/websocket_server_coro.cpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / libs / beast / example / websocket / server / coro / websocket_server_coro.cpp
1 //
2 // Copyright (c) 2016-2017 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/ip/tcp.hpp>
19 #include <boost/asio/spawn.hpp>
20 #include <algorithm>
21 #include <cstdlib>
22 #include <functional>
23 #include <iostream>
24 #include <memory>
25 #include <string>
26 #include <thread>
27 #include <vector>
28
29 using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
30 namespace websocket = boost::beast::websocket; // from <boost/beast/websocket.hpp>
31
32 //------------------------------------------------------------------------------
33
34 // Report a failure
35 void
36 fail(boost::system::error_code ec, char const* what)
37 {
38 std::cerr << what << ": " << ec.message() << "\n";
39 }
40
41 // Echoes back all received WebSocket messages
42 void
43 do_session(tcp::socket& socket, boost::asio::yield_context yield)
44 {
45 boost::system::error_code ec;
46
47 // Construct the stream by moving in the socket
48 websocket::stream<tcp::socket> ws{std::move(socket)};
49
50 // Accept the websocket handshake
51 ws.async_accept(yield[ec]);
52 if(ec)
53 return fail(ec, "accept");
54
55 for(;;)
56 {
57 // This buffer will hold the incoming message
58 boost::beast::multi_buffer buffer;
59
60 // Read a message
61 ws.async_read(buffer, yield[ec]);
62
63 // This indicates that the session was closed
64 if(ec == websocket::error::closed)
65 break;
66
67 if(ec)
68 return fail(ec, "read");
69
70 // Echo the message back
71 ws.text(ws.got_text());
72 ws.async_write(buffer.data(), yield[ec]);
73 if(ec)
74 return fail(ec, "write");
75 }
76 }
77
78 //------------------------------------------------------------------------------
79
80 // Accepts incoming connections and launches the sessions
81 void
82 do_listen(
83 boost::asio::io_context& ioc,
84 tcp::endpoint endpoint,
85 boost::asio::yield_context yield)
86 {
87 boost::system::error_code ec;
88
89 // Open the acceptor
90 tcp::acceptor acceptor(ioc);
91 acceptor.open(endpoint.protocol(), ec);
92 if(ec)
93 return fail(ec, "open");
94
95 // Bind to the server address
96 acceptor.bind(endpoint, ec);
97 if(ec)
98 return fail(ec, "bind");
99
100 // Start listening for connections
101 acceptor.listen(boost::asio::socket_base::max_listen_connections, ec);
102 if(ec)
103 return fail(ec, "listen");
104
105 for(;;)
106 {
107 tcp::socket socket(ioc);
108 acceptor.async_accept(socket, yield[ec]);
109 if(ec)
110 fail(ec, "accept");
111 else
112 boost::asio::spawn(
113 acceptor.get_executor().context(),
114 std::bind(
115 &do_session,
116 std::move(socket),
117 std::placeholders::_1));
118 }
119 }
120
121 int main(int argc, char* argv[])
122 {
123 // Check command line arguments.
124 if (argc != 4)
125 {
126 std::cerr <<
127 "Usage: websocket-server-coro <address> <port> <threads>\n" <<
128 "Example:\n" <<
129 " websocket-server-coro 0.0.0.0 8080 1\n";
130 return EXIT_FAILURE;
131 }
132 auto const address = boost::asio::ip::make_address(argv[1]);
133 auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
134 auto const threads = std::max<int>(1, std::atoi(argv[3]));
135
136 // The io_context is required for all I/O
137 boost::asio::io_context ioc{threads};
138
139 // Spawn a listening port
140 boost::asio::spawn(ioc,
141 std::bind(
142 &do_listen,
143 std::ref(ioc),
144 tcp::endpoint{address, port},
145 std::placeholders::_1));
146
147 // Run the I/O service on the requested number of threads
148 std::vector<std::thread> v;
149 v.reserve(threads - 1);
150 for(auto i = threads - 1; i > 0; --i)
151 v.emplace_back(
152 [&ioc]
153 {
154 ioc.run();
155 });
156 ioc.run();
157
158 return EXIT_SUCCESS;
159 }