I am trying to create a basic vanilla websocket client using c++ and the boost/beast library. Following the examples, I can create an unsecured ws connection. But when I try to incorporate ssl into the mix, everything falls apart. It fails during the handshake with the simple error "uninitialized"
Here is my code, it is not that long
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/beast.hpp>
#include <boost/beast/ssl.hpp>
#include <cstdlib>
#include <iostream>
#include <string>
namespace http = boost::beast::http;
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>
using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
using namespace std;
// Sends a WebSocket message and prints the response
#define SYMBOL "btcusd"
#define STREAM_NAME "wss://api.gemini.com/v2/marketdata"
int main(int argc, char** argv)
{
try
{
cout << "Starting..." << endl;
// Check command line arguments.
auto const url = "wss://api.gemini.com/v2/marketdata";
auto const host = "api.gemini.com";
auto const port = "443";
auto const text = "{\"type\": \"subscribe\",\"subscriptions\":[{\"name\":\"l2\",\"symbols\":[\"BTCUSD\"]}]}\n";
auto const rpcJson = R"({"type": "subscribe","subscriptions":[{"name":"l2","symbols":["BTCUSD"]}]})";
// The io_context is required for all I/O
net::io_context ioc;
// The SSL context is required
cout << "ssl..." << endl;
boost::asio::ssl::context ctx{boost::asio::ssl::context::tlsv12_client};
// These objects perform our I/O
tcp::resolver resolver{ioc};
websocket::stream<beast::ssl_stream<tcp::socket>> ws(ioc, ctx);
if (!SSL_set_tlsext_host_name(ws.next_layer().native_handle(), host)) {
throw boost::system::system_error(beast::error_code(
::ERR_get_error(), net::error::get_ssl_category()));
}
// Look up the domain name
auto const results = resolver.resolve(host, port,boost::asio::ip::resolver_query_base::numeric_service);
cout << "Resolved Hostname" << endl;
cout << results->endpoint() << endl;
// Make the connection on the IP address we get from a lookup
cout << "Connecting..." << endl;
net::connect(ws.next_layer().next_layer(), results.begin(), results.end());
cout << "Connected..." << endl;
cout << "Handshake..." << endl;
// Perform the websocket handshake
ws.handshake(host, "/v2/marketdata");
cout << "Handshake past" << endl;
// Send the message
ws.write(net::buffer(string(text)));
// This buffer will hold the incoming message
beast::multi_buffer buffer;
// Read a message into our buffer
ws.read(buffer);
// The make_printable() function helps print a ConstBufferSequence
cout << beast::make_printable(buffer.data()) << endl;
// If we get here then the connection is closed gracefully
// Close the WebSocket connection
ws.close(websocket::close_code::normal);
}
catch(exception const& e)
{
cerr << "Error: " << e.what() << endl;
}
return EXIT_SUCCESS;
}
and the output looks like this
g++ -o test main.cpp -L ../../boost/boost_1_82_0/stage/lib -lboost_system -L/usr/local/lib64 -lssl -lcrypto -pthread
./test
Starting...
ssl...
Resolved Hostname
52.3.237.39:443
Connecting...
Connected...
Handshake...
Error: uninitialized
I tried compiling with the -g flag and using gdb but I cant run the program in gdb because of an architecture error
/bin/bash: /home/nullptr/Documents/Trading/cryptotradingplaygound/cpp/test.o: cannot execute binary file: Exec format error
/bin/bash: /home/nullptr/Documents/Trading/cryptotradingplaygound/cpp/test.o: Success
I copied some examples (i.e. https://www.boost.org/doc/libs/master/libs/beast/example/websocket/client/sync-ssl/websocket_client_sync_ssl.cpp ) but none of the examples work on their own. Anytime I modify it, it just fails.