So I've been trying to follow the boost code for ssl websocket connections to binance, but I keep getting getting an error when trying to initiate the handshake. I've removed the load_root_certificates function btw because it was saying that the function was undefined and I've seen a post saying that you don't need as it'll load the deafault certificate in my machine. Not sure if the last statement was true though.
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/beast/core/ostream.hpp>
#include <string>
#include <utility>
#include <boost/beast/core.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/beast/ssl.hpp>
#include <boost/beast/websocket/ssl.hpp>
#include <iostream>
#include "JSONParser.hpp"
#include "data.hpp"
#define ONEHOUR_ONEMONTH 672
#define ONEMIN_ONEWEEK 10080
#define ONESEC_ONEDAY 86400
std::string create_subscription_message() {
boost::property_tree::ptree message;
message.put("method", "SUBSCRIBE");
std::vector<std::string> streams = {"btcusdt@kline_1m"};
boost::property_tree::ptree params;
for(auto& stream: streams)
params.push_back(std::make_pair("", boost::property_tree::ptree(stream)));
message.add_child("params", params);
message.put("id", 1);
std::stringstream ss;
boost::property_tree::write_json(ss, message);
return ss.str();
}
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;
int main() {
try {
cData candlesticks(ONEMIN_ONEWEEK);
std::string s = "{\n \"e\": \"kline\",\n \"E\": 123456789,\n \"s\": \"BNBBTC\",\n \"k\": {\n \"t\": 123400000,\n \"T\": 123460000,\n \"s\": \"BNBBTC\",\n \"i\": \"1m\",\n \"f\": 100,\n \"L\": 200,\n \"o\": \"0.0010\",\n \"c\": \"0.0020\",\n \"h\": \"0.0025\",\n \"l\": \"0.0015\",\n \"v\": \"1000\",\n \"n\": 100,\n \"x\": false,\n \"q\": \"1.0000\",\n \"V\": \"500\",\n \"Q\": \"0.500\",\n \"B\": \"123456\"\n }\n}";
candlesticks.addCandlestick(s);
candlesticks.printCandlestick(candlesticks.accessDataAtIndex(0));
// WebSocket endpoint
std::string host = "wss://stream.binance.com";
std::string port = "443";
// Create the I/O context
boost::asio::io_context ioc;
// Creates SSL context and holds certificate
ssl::context ctx{ssl::context::tlsv12_client};
tcp::resolver resolver(ioc);
// Create the WebSocket stream
websocket::stream<beast::ssl_stream<tcp::socket>> ws{ioc, ctx};
// Resolve the hostname
auto endpoints = resolver.resolve(host, port);
// Connect to the first endpoint in the list
auto ep = net::connect(get_lowest_layer(ws), endpoints);
if(! SSL_set_tlsext_host_name(ws.next_layer().native_handle(), host.c_str()))
throw beast::system_error(
beast::error_code(
static_cast<int>(::ERR_get_error()),
net::error::get_ssl_category()),
"Failed to set SNI Hostname");
host += ':' + std::to_string(ep.port());
ws.next_layer().handshake(ssl::stream_base::client);
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");
}));
boost::beast::error_code ec;
ws.handshake(host, "/ws/ethusdt@kline_5m", ec);
if(ec) {
std::cerr << "Error: " << ec.message() << std::endl;
return EXIT_FAILURE;
}
//subscription message
std::string subscription_message = create_subscription_message();
// Send the subscription message
ws.write(boost::asio::buffer(subscription_message));
// Receive messages
for (;;) {
boost::beast::multi_buffer buffer;
ws.read(buffer);
std::cout << boost::beast::make_printable(buffer.data()) << std::endl;
if (buffer.size() == 0) {
break;
}
auto message = boost::beast::buffers_to_string(buffer.data());
if (message == "ping") {
buffer.consume(buffer.size());
ws.write(boost::asio::buffer("pong"));
}
}
}
catch (std::exception const& e)
{
std::cerr << "Error: " << e.what() << std::endl;
return EXIT_FAILURE;
}
}
Error: The WebSocket handshake was declined by the remote peer
The entire problem would seem to be that the host is malformed:
That's a url, not a FQDN or valid IP address. The remainder assumed FQDN (as it is being used for TCP address resolution, SNI and HTTP Host header). Instead I'd expect:
Indeed, with that change, the error changes from
Into
Which is excellent, because it implies that the connection is accepted, and only your request is invalid. That's the next thing for you to look at.
Tested Code
Made self contained as: Coliru
Local output: