]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/beast/example/websocket/client/async/websocket_client_async.cpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / libs / beast / example / websocket / client / async / websocket_client_async.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 client, asynchronous
13 //
14 //------------------------------------------------------------------------------
15
16 #include <boost/beast/core.hpp>
17 #include <boost/beast/websocket.hpp>
18 #include <boost/asio/strand.hpp>
19 #include <cstdlib>
20 #include <functional>
21 #include <iostream>
22 #include <memory>
23 #include <string>
24
25 namespace beast = boost::beast; // from <boost/beast.hpp>
26 namespace http = beast::http; // from <boost/beast/http.hpp>
27 namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
28 namespace net = boost::asio; // from <boost/asio.hpp>
29 using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
30
31 //------------------------------------------------------------------------------
32
33 // Report a failure
34 void
35 fail(beast::error_code ec, char const* what)
36 {
37 std::cerr << what << ": " << ec.message() << "\n";
38 }
39
40 // Sends a WebSocket message and prints the response
41 class session : public std::enable_shared_from_this<session>
42 {
43 tcp::resolver resolver_;
44 websocket::stream<beast::tcp_stream> ws_;
45 beast::flat_buffer buffer_;
46 std::string host_;
47 std::string text_;
48
49 public:
50 // Resolver and socket require an io_context
51 explicit
52 session(net::io_context& ioc)
53 : resolver_(net::make_strand(ioc))
54 , ws_(net::make_strand(ioc))
55 {
56 }
57
58 // Start the asynchronous operation
59 void
60 run(
61 char const* host,
62 char const* port,
63 char const* text)
64 {
65 // Save these for later
66 host_ = host;
67 text_ = text;
68
69 // Look up the domain name
70 resolver_.async_resolve(
71 host,
72 port,
73 beast::bind_front_handler(
74 &session::on_resolve,
75 shared_from_this()));
76 }
77
78 void
79 on_resolve(
80 beast::error_code ec,
81 tcp::resolver::results_type results)
82 {
83 if(ec)
84 return fail(ec, "resolve");
85
86 // Set the timeout for the operation
87 beast::get_lowest_layer(ws_).expires_after(std::chrono::seconds(30));
88
89 // Make the connection on the IP address we get from a lookup
90 beast::get_lowest_layer(ws_).async_connect(
91 results,
92 beast::bind_front_handler(
93 &session::on_connect,
94 shared_from_this()));
95 }
96
97 void
98 on_connect(beast::error_code ec, tcp::resolver::results_type::endpoint_type)
99 {
100 if(ec)
101 return fail(ec, "connect");
102
103 // Turn off the timeout on the tcp_stream, because
104 // the websocket stream has its own timeout system.
105 beast::get_lowest_layer(ws_).expires_never();
106
107 // Set suggested timeout settings for the websocket
108 ws_.set_option(
109 websocket::stream_base::timeout::suggested(
110 beast::role_type::client));
111
112 // Set a decorator to change the User-Agent of the handshake
113 ws_.set_option(websocket::stream_base::decorator(
114 [](websocket::request_type& req)
115 {
116 req.set(http::field::user_agent,
117 std::string(BOOST_BEAST_VERSION_STRING) +
118 " websocket-client-async");
119 }));
120
121 // Perform the websocket handshake
122 ws_.async_handshake(host_, "/",
123 beast::bind_front_handler(
124 &session::on_handshake,
125 shared_from_this()));
126 }
127
128 void
129 on_handshake(beast::error_code ec)
130 {
131 if(ec)
132 return fail(ec, "handshake");
133
134 // Send the message
135 ws_.async_write(
136 net::buffer(text_),
137 beast::bind_front_handler(
138 &session::on_write,
139 shared_from_this()));
140 }
141
142 void
143 on_write(
144 beast::error_code ec,
145 std::size_t bytes_transferred)
146 {
147 boost::ignore_unused(bytes_transferred);
148
149 if(ec)
150 return fail(ec, "write");
151
152 // Read a message into our buffer
153 ws_.async_read(
154 buffer_,
155 beast::bind_front_handler(
156 &session::on_read,
157 shared_from_this()));
158 }
159
160 void
161 on_read(
162 beast::error_code ec,
163 std::size_t bytes_transferred)
164 {
165 boost::ignore_unused(bytes_transferred);
166
167 if(ec)
168 return fail(ec, "read");
169
170 // Close the WebSocket connection
171 ws_.async_close(websocket::close_code::normal,
172 beast::bind_front_handler(
173 &session::on_close,
174 shared_from_this()));
175 }
176
177 void
178 on_close(beast::error_code ec)
179 {
180 if(ec)
181 return fail(ec, "close");
182
183 // If we get here then the connection is closed gracefully
184
185 // The make_printable() function helps print a ConstBufferSequence
186 std::cout << beast::make_printable(buffer_.data()) << std::endl;
187 }
188 };
189
190 //------------------------------------------------------------------------------
191
192 int main(int argc, char** argv)
193 {
194 // Check command line arguments.
195 if(argc != 4)
196 {
197 std::cerr <<
198 "Usage: websocket-client-async <host> <port> <text>\n" <<
199 "Example:\n" <<
200 " websocket-client-async echo.websocket.org 80 \"Hello, world!\"\n";
201 return EXIT_FAILURE;
202 }
203 auto const host = argv[1];
204 auto const port = argv[2];
205 auto const text = argv[3];
206
207 // The io_context is required for all I/O
208 net::io_context ioc;
209
210 // Launch the asynchronous operation
211 std::make_shared<session>(ioc)->run(host, port, text);
212
213 // Run the I/O service. The call will return when
214 // the socket is closed.
215 ioc.run();
216
217 return EXIT_SUCCESS;
218 }