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