forked from boostorg/beast
		
	* The function buffers is deprecated, use the new function make_printable as the replacement. Actions Required: * Replace call sites to use make_printable instead of buffers, and also include make_printable.hpp instead of ostream.hpp.
		
			
				
	
	
		
			236 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			236 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| //
 | |
| // 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>
 | |
| 
 | |
| 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>
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| // Report a failure
 | |
| void
 | |
| fail(beast::error_code ec, char const* what)
 | |
| {
 | |
|     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_;
 | |
|     beast::multi_buffer buffer_;
 | |
|     std::string host_;
 | |
|     std::string text_;
 | |
| 
 | |
| public:
 | |
|     // Resolver and socket require an io_context
 | |
|     explicit
 | |
|     session(net::io_context& ioc, ssl::context& ctx)
 | |
|         : resolver_(ioc)
 | |
|         , ws_(ioc, ctx)
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     // 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
 | |
|         resolver_.async_resolve(
 | |
|             host,
 | |
|             port,
 | |
|             std::bind(
 | |
|                 &session::on_resolve,
 | |
|                 shared_from_this(),
 | |
|                 std::placeholders::_1,
 | |
|                 std::placeholders::_2));
 | |
|     }
 | |
| 
 | |
|     void
 | |
|     on_resolve(
 | |
|         beast::error_code ec,
 | |
|         tcp::resolver::results_type results)
 | |
|     {
 | |
|         if(ec)
 | |
|             return fail(ec, "resolve");
 | |
| 
 | |
|         // Make the connection on the IP address we get from a lookup
 | |
|         net::async_connect(
 | |
|             ws_.next_layer().next_layer(),
 | |
|             results.begin(),
 | |
|             results.end(),
 | |
|             std::bind(
 | |
|                 &session::on_connect,
 | |
|                 shared_from_this(),
 | |
|                 std::placeholders::_1));
 | |
|     }
 | |
| 
 | |
|     void
 | |
|     on_connect(beast::error_code ec)
 | |
|     {
 | |
|         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
 | |
|     on_ssl_handshake(beast::error_code ec)
 | |
|     {
 | |
|         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
 | |
|     on_handshake(beast::error_code ec)
 | |
|     {
 | |
|         if(ec)
 | |
|             return fail(ec, "handshake");
 | |
|         
 | |
|         // Send the message
 | |
|         ws_.async_write(
 | |
|             net::buffer(text_),
 | |
|             std::bind(
 | |
|                 &session::on_write,
 | |
|                 shared_from_this(),
 | |
|                 std::placeholders::_1,
 | |
|                 std::placeholders::_2));
 | |
|     }
 | |
| 
 | |
|     void
 | |
|     on_write(
 | |
|         beast::error_code ec,
 | |
|         std::size_t bytes_transferred)
 | |
|     {
 | |
|         boost::ignore_unused(bytes_transferred);
 | |
| 
 | |
|         if(ec)
 | |
|             return fail(ec, "write");
 | |
|         
 | |
|         // Read a message into our buffer
 | |
|         ws_.async_read(
 | |
|             buffer_,
 | |
|             std::bind(
 | |
|                 &session::on_read,
 | |
|                 shared_from_this(),
 | |
|                 std::placeholders::_1,
 | |
|                 std::placeholders::_2));
 | |
|     }
 | |
| 
 | |
|     void
 | |
|     on_read(
 | |
|         beast::error_code ec,
 | |
|         std::size_t bytes_transferred)
 | |
|     {
 | |
|         boost::ignore_unused(bytes_transferred);
 | |
| 
 | |
|         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
 | |
|     on_close(beast::error_code ec)
 | |
|     {
 | |
|         if(ec)
 | |
|             return fail(ec, "close");
 | |
| 
 | |
|         // If we get here then the connection is closed gracefully
 | |
| 
 | |
|         // The make_printable() function helps print a ConstBufferSequence
 | |
|         std::cout << beast::make_printable(buffer_.data()) << std::endl;
 | |
|     }
 | |
| };
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| 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];
 | |
| 
 | |
|     // The io_context is required for all I/O
 | |
|     net::io_context ioc;
 | |
| 
 | |
|     // 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
 | |
|     std::make_shared<session>(ioc, ctx)->run(host, port, text);
 | |
| 
 | |
|     // Run the I/O service. The call will return when
 | |
|     // the socket is closed.
 | |
|     ioc.run();
 | |
| 
 | |
|     return EXIT_SUCCESS;
 | |
| }
 |