]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/beast/example/websocket/server/coro-ssl/websocket_server_coro_ssl.cpp
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / boost / libs / beast / example / websocket / server / coro-ssl / websocket_server_coro_ssl.cpp
CommitLineData
b32b8144
FG
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
33using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
34namespace ssl = boost::asio::ssl; // from <boost/asio/ssl.hpp>
35namespace websocket = boost::beast::websocket; // from <boost/beast/websocket.hpp>
36
37//------------------------------------------------------------------------------
38
39// Report a failure
40void
41fail(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
47void
48do_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
94void
95do_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");
11fdf7f2
TL
108
109 // Allow address reuse
110 acceptor.set_option(boost::asio::socket_base::reuse_address(true));
111 if(ec)
112 return fail(ec, "set_option");
b32b8144
FG
113
114 // Bind to the server address
115 acceptor.bind(endpoint, ec);
116 if(ec)
117 return fail(ec, "bind");
118
119 // Start listening for connections
120 acceptor.listen(boost::asio::socket_base::max_listen_connections, ec);
121 if(ec)
122 return fail(ec, "listen");
123
124 for(;;)
125 {
126 tcp::socket socket(ioc);
127 acceptor.async_accept(socket, yield[ec]);
128 if(ec)
129 fail(ec, "accept");
130 else
131 boost::asio::spawn(
132 acceptor.get_executor().context(),
133 std::bind(
134 &do_session,
135 std::move(socket),
136 std::ref(ctx),
137 std::placeholders::_1));
138 }
139}
140
141int main(int argc, char* argv[])
142{
143 // Check command line arguments.
144 if (argc != 4)
145 {
146 std::cerr <<
147 "Usage: websocket-server-coro-ssl <address> <port> <threads>\n" <<
148 "Example:\n" <<
149 " websocket-server-coro-ssl 0.0.0.0 8080 1\n";
150 return EXIT_FAILURE;
151 }
152 auto const address = boost::asio::ip::make_address(argv[1]);
153 auto const port = static_cast<unsigned short>(std::atoi(argv[2]));
154 auto const threads = std::max<int>(1, std::atoi(argv[3]));
155
156 // The io_context is required for all I/O
157 boost::asio::io_context ioc{threads};
158
159 // The SSL context is required, and holds certificates
160 ssl::context ctx{ssl::context::sslv23};
161
162 // This holds the self-signed certificate used by the server
163 load_server_certificate(ctx);
164
165 // Spawn a listening port
166 boost::asio::spawn(ioc,
167 std::bind(
168 &do_listen,
169 std::ref(ioc),
170 std::ref(ctx),
171 tcp::endpoint{address, port},
172 std::placeholders::_1));
173
174 // Run the I/O service on the requested number of threads
175 std::vector<std::thread> v;
176 v.reserve(threads - 1);
177 for(auto i = threads - 1; i > 0; --i)
178 v.emplace_back(
179 [&ioc]
180 {
181 ioc.run();
182 });
183 ioc.run();
184
185 return EXIT_SUCCESS;
186}