55#include < boost/asio/detached.hpp>
66#include < boost/asio/io_context.hpp>
77#include < boost/asio/spawn.hpp>
8+ #include < boost/asio/ssl/context.hpp>
9+ #include < boost/asio/ssl/stream.hpp>
810#include < boost/asio/strand.hpp>
911#include < boost/asio/ip/tcp.hpp>
1012#include < boost/asio/version.hpp>
@@ -22,6 +24,7 @@ using boost::asio::detached;
2224using boost::asio::ip::tcp;
2325using boost::asio::make_strand;
2426using tcp_socket = boost::asio::basic_stream_socket<tcp, boost::asio::strand<boost::asio::io_context::executor_type>>;
27+ using tls_socket = boost::asio::ssl::stream<tcp_socket>;
2528using yield_context_strand = boost::asio::basic_yield_context<boost::asio::strand<boost::asio::io_context::executor_type>>;
2629using namespace std ::chrono_literals;
2730
@@ -58,24 +61,63 @@ void ws_session(std::string host, uint16_t port, std::string msg, yield_context_
5861 }
5962}
6063
64+ void ws_ssl_session (std::string host, uint16_t port, std::string msg, yield_context_strand yield)
65+ {
66+ try
67+ {
68+ // SSL
69+ boost::asio::ssl::context ssl (boost::asio::ssl::context::tlsv12_client);
70+ ssl.set_verify_callback ([](bool preverified, boost::asio::ssl::verify_context& ctx) {return true ;});
71+ ssl.set_verify_mode (boost::asio::ssl::verify_peer);
72+
73+ // Connect
74+ tls_socket sock (tcp_socket (yield.get_executor ()), ssl);
75+ tcp::resolver resolver (sock.get_executor ());
76+ std::vector<char > buf (begin (msg), end (msg));
77+ size_t ret{};
78+
79+ // Async IO
80+ boost::asio::async_connect (sock.next_layer (), resolver.async_resolve (host, std::to_string (port), yield), boost::asio::cancel_after (5s, yield));
81+ sock.async_handshake (boost::asio::ssl::stream_base::client, yield);
82+ http::async_ws_handshake (sock, host, " /ws" , yield);
83+ ret = http::async_ws_write (sock, buf, true , false , yield);
84+ ret = http::async_ws_read (sock, buf, false , yield);
85+ http::async_ws_close (sock, http::ws_going_away, false , yield);
86+ sock.async_shutdown (yield);
87+
88+ // Print echo
89+ printf (" Server echoed back\n\" %.*s\"\n " , (int )buf.size (), buf.data ());
90+ }
91+ catch (const boost::system::system_error& e)
92+ {
93+ if (e.code () != boost::asio::error::eof)
94+ fprintf (stderr, " [HTTP session] %s\n " , e.what ());
95+ }
96+ }
97+
6198int main (int argc, char * argv[])
6299{
63100 std::string host;
64101 uint16_t port;
65102 std::string msg;
103+ bool use_tls;
66104 CLI::App app{" WebSocket echo client" };
67105 try {
68106 app.add_option (" --host" , host, " Host or IP address of WebSocket server" )->required ();
69107 app.add_option (" --port" , port, " Port of WebSocket server" )->required ();
70108 app.add_option (" --msg" , msg, " Message to be echoed back by server" )->required ();
109+ app.add_flag (" --tls" , use_tls, " Use transport over TLS" );
71110 app.parse (argc, argv);
72111 } catch (const CLI::ParseError& e) {return app.exit (e);}
73112
74113 boost::asio::io_context ioc{1 };
75114
76115 try
77116 {
78- boost::asio::spawn (make_strand (ioc), bind_front (ws_session, host, port, msg), detached);
117+ if (use_tls)
118+ boost::asio::spawn (make_strand (ioc), bind_front (ws_ssl_session, host, port, msg), detached);
119+ else
120+ boost::asio::spawn (make_strand (ioc), bind_front (ws_session, host, port, msg), detached);
79121 ioc.run ();
80122 }
81123 catch (const std::exception& e)
0 commit comments