| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | //
 | 
					
						
							|  |  |  | // Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Distributed under the Boost Software License, Version 1.0. (See accompanying
 | 
					
						
							|  |  |  | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Official repository: https://github.com/boostorg/beast
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //------------------------------------------------------------------------------
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Example: WebSocket SSL client, asynchronous
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //------------------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "example/common/root_certificates.hpp"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <boost/beast/core.hpp>
 | 
					
						
							|  |  |  | #include <boost/beast/websocket.hpp>
 | 
					
						
							|  |  |  | #include <boost/beast/websocket/ssl.hpp>
 | 
					
						
							|  |  |  | #include <boost/asio/connect.hpp>
 | 
					
						
							|  |  |  | #include <boost/asio/ip/tcp.hpp>
 | 
					
						
							|  |  |  | #include <boost/asio/ssl/stream.hpp>
 | 
					
						
							|  |  |  | #include <cstdlib>
 | 
					
						
							|  |  |  | #include <functional>
 | 
					
						
							|  |  |  | #include <iostream>
 | 
					
						
							|  |  |  | #include <memory>
 | 
					
						
							|  |  |  | #include <string>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  | namespace beast = boost::beast;         // from <boost/beast.hpp>
 | 
					
						
							|  |  |  | namespace http = beast::http;           // from <boost/beast/http.hpp>
 | 
					
						
							|  |  |  | namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
 | 
					
						
							|  |  |  | namespace net = boost::asio;            // from <boost/asio.hpp>
 | 
					
						
							|  |  |  | namespace ssl = boost::asio::ssl;       // from <boost/asio/ssl.hpp>
 | 
					
						
							|  |  |  | using tcp = boost::asio::ip::tcp;       // from <boost/asio/ip/tcp.hpp>
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | //------------------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Report a failure
 | 
					
						
							|  |  |  | void | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  | fail(beast::error_code ec, char const* what) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | { | 
					
						
							|  |  |  |     std::cerr << what << ": " << ec.message() << "\n"; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Sends a WebSocket message and prints the response
 | 
					
						
							|  |  |  | class session : public std::enable_shared_from_this<session> | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     tcp::resolver resolver_; | 
					
						
							|  |  |  |     websocket::stream<ssl::stream<tcp::socket>> ws_; | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |     beast::multi_buffer buffer_; | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     std::string host_; | 
					
						
							|  |  |  |     std::string text_; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2017-09-07 07:39:52 -07:00
										 |  |  |     // Resolver and socket require an io_context
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     explicit | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |     session(net::io_context& ioc, ssl::context& ctx) | 
					
						
							| 
									
										
										
										
											2017-09-07 07:39:52 -07:00
										 |  |  |         : resolver_(ioc) | 
					
						
							|  |  |  |         , ws_(ioc, ctx) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Start the asynchronous operation
 | 
					
						
							|  |  |  |     void | 
					
						
							|  |  |  |     run( | 
					
						
							|  |  |  |         char const* host, | 
					
						
							|  |  |  |         char const* port, | 
					
						
							|  |  |  |         char const* text) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // Save these for later
 | 
					
						
							|  |  |  |         host_ = host; | 
					
						
							|  |  |  |         text_ = text; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Look up the domain name
 | 
					
						
							| 
									
										
										
										
											2017-09-07 07:39:52 -07:00
										 |  |  |         resolver_.async_resolve( | 
					
						
							|  |  |  |             host, | 
					
						
							|  |  |  |             port, | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |             std::bind( | 
					
						
							|  |  |  |                 &session::on_resolve, | 
					
						
							|  |  |  |                 shared_from_this(), | 
					
						
							|  |  |  |                 std::placeholders::_1, | 
					
						
							|  |  |  |                 std::placeholders::_2)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void | 
					
						
							|  |  |  |     on_resolve( | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |         beast::error_code ec, | 
					
						
							| 
									
										
										
										
											2017-09-07 07:39:52 -07:00
										 |  |  |         tcp::resolver::results_type results) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     { | 
					
						
							|  |  |  |         if(ec) | 
					
						
							|  |  |  |             return fail(ec, "resolve"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Make the connection on the IP address we get from a lookup
 | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |         net::async_connect( | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |             ws_.next_layer().next_layer(), | 
					
						
							| 
									
										
										
										
											2017-09-07 07:39:52 -07:00
										 |  |  |             results.begin(), | 
					
						
							|  |  |  |             results.end(), | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |             std::bind( | 
					
						
							|  |  |  |                 &session::on_connect, | 
					
						
							|  |  |  |                 shared_from_this(), | 
					
						
							|  |  |  |                 std::placeholders::_1)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |     on_connect(beast::error_code ec) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     { | 
					
						
							|  |  |  |         if(ec) | 
					
						
							|  |  |  |             return fail(ec, "connect"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Perform the SSL handshake
 | 
					
						
							|  |  |  |         ws_.next_layer().async_handshake( | 
					
						
							|  |  |  |             ssl::stream_base::client, | 
					
						
							|  |  |  |             std::bind( | 
					
						
							|  |  |  |                 &session::on_ssl_handshake, | 
					
						
							|  |  |  |                 shared_from_this(), | 
					
						
							|  |  |  |                 std::placeholders::_1)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |     on_ssl_handshake(beast::error_code ec) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     { | 
					
						
							|  |  |  |         if(ec) | 
					
						
							|  |  |  |             return fail(ec, "ssl_handshake"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Perform the websocket handshake
 | 
					
						
							|  |  |  |         ws_.async_handshake(host_, "/", | 
					
						
							|  |  |  |             std::bind( | 
					
						
							|  |  |  |                 &session::on_handshake, | 
					
						
							|  |  |  |                 shared_from_this(), | 
					
						
							|  |  |  |                 std::placeholders::_1)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |     on_handshake(beast::error_code ec) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     { | 
					
						
							|  |  |  |         if(ec) | 
					
						
							|  |  |  |             return fail(ec, "handshake"); | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         // Send the message
 | 
					
						
							|  |  |  |         ws_.async_write( | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |             net::buffer(text_), | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |             std::bind( | 
					
						
							|  |  |  |                 &session::on_write, | 
					
						
							|  |  |  |                 shared_from_this(), | 
					
						
							| 
									
										
										
										
											2017-09-03 06:18:07 -07:00
										 |  |  |                 std::placeholders::_1, | 
					
						
							|  |  |  |                 std::placeholders::_2)); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void | 
					
						
							| 
									
										
										
										
											2017-09-03 06:18:07 -07:00
										 |  |  |     on_write( | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |         beast::error_code ec, | 
					
						
							| 
									
										
										
										
											2017-09-03 06:18:07 -07:00
										 |  |  |         std::size_t bytes_transferred) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-09-03 06:18:07 -07:00
										 |  |  |         boost::ignore_unused(bytes_transferred); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         if(ec) | 
					
						
							|  |  |  |             return fail(ec, "write"); | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         // Read a message into our buffer
 | 
					
						
							|  |  |  |         ws_.async_read( | 
					
						
							|  |  |  |             buffer_, | 
					
						
							|  |  |  |             std::bind( | 
					
						
							|  |  |  |                 &session::on_read, | 
					
						
							|  |  |  |                 shared_from_this(), | 
					
						
							| 
									
										
										
										
											2017-09-03 06:18:07 -07:00
										 |  |  |                 std::placeholders::_1, | 
					
						
							|  |  |  |                 std::placeholders::_2)); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void | 
					
						
							| 
									
										
										
										
											2017-09-03 06:18:07 -07:00
										 |  |  |     on_read( | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |         beast::error_code ec, | 
					
						
							| 
									
										
										
										
											2017-09-03 06:18:07 -07:00
										 |  |  |         std::size_t bytes_transferred) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-09-03 06:18:07 -07:00
										 |  |  |         boost::ignore_unused(bytes_transferred); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |         if(ec) | 
					
						
							|  |  |  |             return fail(ec, "read"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Close the WebSocket connection
 | 
					
						
							|  |  |  |         ws_.async_close(websocket::close_code::normal, | 
					
						
							|  |  |  |             std::bind( | 
					
						
							|  |  |  |                 &session::on_close, | 
					
						
							|  |  |  |                 shared_from_this(), | 
					
						
							|  |  |  |                 std::placeholders::_1)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |     on_close(beast::error_code ec) | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     { | 
					
						
							|  |  |  |         if(ec) | 
					
						
							|  |  |  |             return fail(ec, "close"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // If we get here then the connection is closed gracefully
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-16 14:36:17 -08:00
										 |  |  |         // The make_printable() function helps print a ConstBufferSequence
 | 
					
						
							|  |  |  |         std::cout << beast::make_printable(buffer_.data()) << std::endl; | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //------------------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int main(int argc, char** argv) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Check command line arguments.
 | 
					
						
							|  |  |  |     if(argc != 4) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         std::cerr << | 
					
						
							|  |  |  |             "Usage: websocket-client-async-ssl <host> <port> <text>\n" << | 
					
						
							|  |  |  |             "Example:\n" << | 
					
						
							|  |  |  |             "    websocket-client-async-ssl echo.websocket.org 443 \"Hello, world!\"\n"; | 
					
						
							|  |  |  |         return EXIT_FAILURE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     auto const host = argv[1]; | 
					
						
							|  |  |  |     auto const port = argv[2]; | 
					
						
							|  |  |  |     auto const text = argv[3]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-07 07:39:52 -07:00
										 |  |  |     // The io_context is required for all I/O
 | 
					
						
							| 
									
										
										
										
											2018-11-30 14:58:38 -08:00
										 |  |  |     net::io_context ioc; | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // The SSL context is required, and holds certificates
 | 
					
						
							|  |  |  |     ssl::context ctx{ssl::context::sslv23_client}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // This holds the root certificate used for verification
 | 
					
						
							|  |  |  |     load_root_certificates(ctx); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Launch the asynchronous operation
 | 
					
						
							| 
									
										
										
										
											2017-09-07 07:39:52 -07:00
										 |  |  |     std::make_shared<session>(ioc, ctx)->run(host, port, text); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Run the I/O service. The call will return when
 | 
					
						
							| 
									
										
										
										
											2018-02-20 03:33:02 -08:00
										 |  |  |     // the socket is closed.
 | 
					
						
							| 
									
										
										
										
											2017-09-07 07:39:52 -07:00
										 |  |  |     ioc.run(); | 
					
						
							| 
									
										
										
										
											2017-08-04 19:55:28 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return EXIT_SUCCESS; | 
					
						
							|  |  |  | } |