Reputation: 11
The following code throws an uninitialized exception in the ws.handshake(url, "/") call... I am new to Beast, but this was mostly copied from working example code. Does anyone know why this is happening??? I would really appreciate any help in figuring this out! :)
std::string cert =
"# MPU5 Radio - Serial #35409\n"
"-----BEGIN CERTIFICATE-----\n"
"MIIBXzCB5QIJAIXhtL/+cBGIMAoGCCqGSM49BAMDMB0xGzAZBgNVBAMMEldhdmUg\n"
"UmVsYXkgU2VsZi1DQTAeFw03MDAxMDEwMDAwMjJaFw03MTAxMDEwMDAwMjJaMBUx\n"
"EzARBgNVBAMMCldhdmUgUmVsYXkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATHCIq1\n"
"YHbWl7rJ3w/6ekiGYq5+tb1ip1Tkm4sX7yPW62QZ5rZQp05I+B8p1u6dtjsj/EvJ\n"
"YDvqqrezL0oWIgfL3X/MHSvOMiLcXzf7ooXZgkc/t19WnmdfoyS1+UPQTt0wCgYI\n"
"KoZIzj0EAwMDaQAwZgIxANjEbIEOmrNG+M8mwT0/cx9A2JldSOz87G7N5f0aB8iF\n"
"gMok+H4D/Rmeje6+MakDNAIxALYeNUw4++hyLDRTxWu37QZOoK0PprdaRQiGOsER\n"
"T+1di9sgMZ+8aQjGlgTSeKdmUg==\n"
"-----END CERTIFICATE-----";
static std::string response = "ERROR!"; // pessimistic start
boost::system::error_code ec;
std::string url = "wss://" + ip_addr ;
try
{
ssl::context ctx{ssl::context::tlsv12};
ctx.set_options(boost::asio::ssl::context::default_workarounds |
boost::asio::ssl::context::no_sslv2 |
boost::asio::ssl::context::single_dh_use);
ctx.set_verify_mode(boost::asio::ssl::context::verify_peer | boost::asio::ssl::context::verify_fail_if_no_peer_cert);
ctx.load_verify_file("/root/catkin_ws/src/radio_bridge/certs/35409.pem");
// The io_context is required for all I/O
net::io_context ioc;
// These objects perform our I/O
tcp::resolver resolver{ioc};
websocket::stream<beast::ssl_stream<beast::tcp_stream>> ws{ioc, ctx};
// Look up the domain name
auto const results = resolver.resolve(ip_addr, "443");
// Make the connection on the IP address we get from a lookup
auto ep = beast::get_lowest_layer(ws).connect(results);
url += std::string(":443");
// Set a decorator to change the User-Agent of the handshake
ws.set_option(websocket::stream_base::decorator([](websocket::request_type& req)
{
req.set(http::field::user_agent, std::string(BOOST_BEAST_VERSION_STRING) + " websocket-client-coro");
}));
// Perform the websocket handshake
std::cout << "URL: " << url << std::endl;
ROS_INFO("before handshake");
ws.handshake(url, "/");
ROS_INFO("after handshake");
// Send the message
ws.write(net::buffer(std::string(request)));
// This buffer will hold the incoming message
beast::flat_buffer buffer;
// Read a message into our buffer
ws.read(buffer);
// Close the WebSocket connection
sleep(10);
ws.close(websocket::close_code::normal);
// 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;
}
catch(std::exception const& e)
{
std::cerr << "Error: " << e.what() << std::endl;
}
return response;
Like I said, I am new to Beast, and this code is for the most part copied/pasted from existing examples. I just don't understand what further initialization should occur...
Upvotes: 1
Views: 84
Reputation: 392979
You're connecting the TCP stream:
beast::tcp_stream& ll = beast::get_lowest_layer(ws);
auto ep = ll.connect(results);
This doesn't initialize an SSL session. You're missing the SSL handshake, e.g.
ws.next_layer().handshake(ssl::stream_base::handshake_type::client);
This is my self-contained sketch for reference. Note I cannot test this because I don't own the "Wave Relay Self-CA" or any certificate signed by it. But it might help you connect some dots:
#include <boost/beast.hpp>
#include <boost/beast/ssl.hpp>
#include <iostream>
void ROS_INFO(auto const& msg) {
std::cerr << "ROS_INFO: " << msg << std::endl;
}
auto foo(std::string ip_addr, std::string const& request) {
namespace beast = boost::beast;
namespace net = boost::asio;
namespace websocket = beast::websocket;
namespace http = beast::http;
namespace ssl = net::ssl;
using net::ip::tcp;
std::string cert = "# MPU5 Radio - Serial #35409\n"
"-----BEGIN CERTIFICATE-----\n"
"MIIBXzCB5QIJAIXhtL/+cBGIMAoGCCqGSM49BAMDMB0xGzAZBgNVBAMMEldhdmUg\n"
"UmVsYXkgU2VsZi1DQTAeFw03MDAxMDEwMDAwMjJaFw03MTAxMDEwMDAwMjJaMBUx\n"
"EzARBgNVBAMMCldhdmUgUmVsYXkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATHCIq1\n"
"YHbWl7rJ3w/6ekiGYq5+tb1ip1Tkm4sX7yPW62QZ5rZQp05I+B8p1u6dtjsj/EvJ\n"
"YDvqqrezL0oWIgfL3X/MHSvOMiLcXzf7ooXZgkc/t19WnmdfoyS1+UPQTt0wCgYI\n"
"KoZIzj0EAwMDaQAwZgIxANjEbIEOmrNG+M8mwT0/cx9A2JldSOz87G7N5f0aB8iF\n"
"gMok+H4D/Rmeje6+MakDNAIxALYeNUw4++hyLDRTxWu37QZOoK0PprdaRQiGOsER\n"
"T+1di9sgMZ+8aQjGlgTSeKdmUg==\n"
"-----END CERTIFICATE-----";
static std::string response = "ERROR!"; // pessimistic start
boost::system::error_code ec;
std::string url = "wss://" + ip_addr;
try {
ssl::context ctx{ssl::context::tlsv12};
ctx.set_options(boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 |
boost::asio::ssl::context::single_dh_use);
ctx.set_verify_mode(boost::asio::ssl::context::verify_peer |
boost::asio::ssl::context::verify_fail_if_no_peer_cert);
ctx.load_verify_file("/root/catkin_ws/src/radio_bridge/certs/35409.pem");
// The io_context is required for all I/O
net::io_context ioc;
// These objects perform our I/O
tcp::resolver resolver{ioc};
websocket::stream<beast::ssl_stream<beast::tcp_stream>> ws{ioc, ctx};
// Look up the domain name
auto results = resolver.resolve(ip_addr, "443");
// Make the connection on the IP address we get from a lookup
beast::tcp_stream& ll = beast::get_lowest_layer(ws);
auto ep = ll.connect(results);
ws.next_layer().handshake(ssl::stream_base::handshake_type::client);
url += std::string(":443");
// Set a decorator to change the User-Agent of the handshake
ws.set_option(websocket::stream_base::decorator([](websocket::request_type& req) {
req.set(http::field::user_agent, std::string(BOOST_BEAST_VERSION_STRING) + " websocket-client-coro");
}));
// Perform the websocket handshake
std::cout << "URL: " << url << std::endl;
ROS_INFO("before handshake");
ws.handshake(url, "/");
ROS_INFO("after handshake");
// Send the message
ws.write(net::buffer(std::string(request)));
// This buffer will hold the incoming message
beast::flat_buffer buffer;
// Read a message into our buffer
ws.read(buffer);
// Close the WebSocket connection
sleep(10);
ws.close(websocket::close_code::normal);
// 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;
}
catch(std::exception const& e)
{
std::cerr << "Error: " << e.what() << std::endl;
}
return response;
}
int main() {
foo("127.0.0.1", "test hello world");
}
Upvotes: 0