2 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
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)
7 // Official repository: https://github.com/boostorg/beast
10 //------------------------------------------------------------------------------
12 // Example: WebSocket SSL client, coroutine
14 //------------------------------------------------------------------------------
16 #include "example/common/root_certificates.hpp"
18 #include <boost/beast/core.hpp>
19 #include <boost/beast/ssl.hpp>
20 #include <boost/beast/websocket.hpp>
21 #include <boost/beast/websocket/ssl.hpp>
22 #include <boost/asio/spawn.hpp>
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 namespace ssl
= boost::asio::ssl
; // from <boost/asio/ssl.hpp>
33 using tcp
= boost::asio::ip::tcp
; // from <boost/asio/ip/tcp.hpp>
35 //------------------------------------------------------------------------------
39 fail(beast::error_code ec
, char const* what
)
41 std::cerr
<< what
<< ": " << ec
.message() << "\n";
44 // Sends a WebSocket message and prints the response
47 std::string
const& host
,
48 std::string
const& port
,
49 std::string
const& text
,
52 net::yield_context yield
)
56 // These objects perform our I/O
57 tcp::resolver
resolver(ioc
);
59 beast::ssl_stream
<beast::tcp_stream
>> ws(ioc
, ctx
);
61 // Look up the domain name
62 auto const results
= resolver
.async_resolve(host
, port
, yield
[ec
]);
64 return fail(ec
, "resolve");
66 // Set a timeout on the operation
67 beast::get_lowest_layer(ws
).expires_after(std::chrono::seconds(30));
69 // Make the connection on the IP address we get from a lookup
70 beast::get_lowest_layer(ws
).async_connect(results
, yield
[ec
]);
72 return fail(ec
, "connect");
74 // Set a timeout on the operation
75 beast::get_lowest_layer(ws
).expires_after(std::chrono::seconds(30));
77 // Set a decorator to change the User-Agent of the handshake
78 ws
.set_option(websocket::stream_base::decorator(
79 [](websocket::request_type
& req
)
81 req
.set(http::field::user_agent
,
82 std::string(BOOST_BEAST_VERSION_STRING
) +
83 " websocket-client-coro");
86 // Perform the SSL handshake
87 ws
.next_layer().async_handshake(ssl::stream_base::client
, yield
[ec
]);
89 return fail(ec
, "ssl_handshake");
91 // Turn off the timeout on the tcp_stream, because
92 // the websocket stream has its own timeout system.
93 beast::get_lowest_layer(ws
).expires_never();
95 // Set suggested timeout settings for the websocket
97 websocket::stream_base::timeout::suggested(
98 beast::role_type::client
));
100 // Perform the websocket handshake
101 ws
.async_handshake(host
, "/", yield
[ec
]);
103 return fail(ec
, "handshake");
106 ws
.async_write(net::buffer(std::string(text
)), yield
[ec
]);
108 return fail(ec
, "write");
110 // This buffer will hold the incoming message
111 beast::flat_buffer buffer
;
113 // Read a message into our buffer
114 ws
.async_read(buffer
, yield
[ec
]);
116 return fail(ec
, "read");
118 // Close the WebSocket connection
119 ws
.async_close(websocket::close_code::normal
, yield
[ec
]);
121 return fail(ec
, "close");
123 // If we get here then the connection is closed gracefully
125 // The make_printable() function helps print a ConstBufferSequence
126 std::cout
<< beast::make_printable(buffer
.data()) << std::endl
;
129 //------------------------------------------------------------------------------
131 int main(int argc
, char** argv
)
133 // Check command line arguments.
137 "Usage: websocket-client-coro-ssl <host> <port> <text>\n" <<
139 " websocket-client-coro-ssl echo.websocket.org 443 \"Hello, world!\"\n";
142 auto const host
= argv
[1];
143 auto const port
= argv
[2];
144 auto const text
= argv
[3];
146 // The io_context is required for all I/O
149 // The SSL context is required, and holds certificates
150 ssl::context ctx
{ssl::context::tlsv12_client
};
152 // This holds the root certificate used for verification
153 load_root_certificates(ctx
);
155 // Launch the asynchronous operation
156 boost::asio::spawn(ioc
, std::bind(
163 std::placeholders::_1
));
165 // Run the I/O service. The call will return when
166 // the socket is closed.