Reputation: 87
I`m trying to connect to Kraken websocket API.But i got "The WebSocket handshake was declined by the remote peer" error.
I`ve wrote a wrapper class for websocket and rest api client of exchanges.It works well with Binance websocket APIs,but Kraken websocket connection was unsuccessful.
I have tried diffrent type of tls(ssl::context ctx_webSocket{ ssl::context::tlsv13_client };) verions too, but the result was same.
class Exchange {
public:
Exchange(std::string name, const std::string& http_host) :m_name(std::move(name)) {
init_http(http_host);
}
void init_http(std::string const& host) {
const auto results{ resolver.resolve(host,"443") };
get_lowest_layer(stream).connect(results);
if (!SSL_set_tlsext_host_name(stream.native_handle(), host.c_str()))
{
boost::system::error_code ec{ static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category() };
throw boost::system::system_error{ ec };
}
stream.handshake(ssl::stream_base::client);
}
void init_webSocket(std::string const& host, std::string const& port, std::string const& target) {
auto const results = resolver_webSocket.resolve(host, port);
net::connect(ws.next_layer().next_layer(), results.begin(), results.end());
ws.next_layer().handshake(ssl::stream_base::client);
// 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");
}));
ws.handshake(host, target.c_str());
}
void read_Socket() {
ws.read(buffer);
}
void write_Socket(const std::string& text) {
ws.write(net::buffer(text));
}
std::string get_socket_data() {
return beast::buffers_to_string(buffer.data());
}
void buffer_clear() {
buffer.clear();
}
void webSocket_close() {
ws.close(websocket::close_code::none);
}
private:
// HTTP REQUEST SET //
std::string m_name;
net::io_context ioc;
ssl::context ctx{ ssl::context::tlsv12_client };
tcp::resolver resolver{ ioc };
Stream stream{ ioc, ctx };
// WEB SOCKET SET //
std::string m_web_socket_host;
std::string m_web_socket_port;
beast::flat_buffer buffer;
net::io_context ioc_webSocket;
ssl::context ctx_webSocket{ ssl::context::tlsv13_client };
tcp::resolver resolver_webSocket{ ioc_webSocket };
websocket::stream<beast::ssl_stream<tcp::socket>> ws{ ioc_webSocket, ctx_webSocket };
};
int main()
{
Exchange kraken{ "kraken","api.kraken.com" };
try
{
kraken.init_webSocket("ws.kraken.com", "443", "/");
while (true)
{
kraken.read_Socket();
std::cout << kraken.get_socket_data();
return 1;
kraken.buffer_clear();
}
kraken.webSocket_close();
}
catch (std::exception const& e)
{
std::cerr << "Error: " << e.what() << std::endl;
}
}
Upvotes: 2
Views: 4055
Reputation: 1
Have you ever come across the same error you have posted about, but on the last line in this code block?
ws.next_layer().handshake(ssl::stream_base::client);
// 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");
}));
ws.handshake(host, target.c_str());
For bitfinex I had to meddle with host and target until the arguments worked, but I'm currently trying to set this up for Deribit and I can't get anything to work. I would have thought that
ws.handshake("deribit.com", "/ws/api/v2");
would have worked but nothing so far. I've also tried setting SNI Hostname before this argument as well as the first time around.
Upvotes: 0
Reputation: 87
SOLVED. I have found out where the problem is. Before websocket handshake, have to set the SNI host name, here below is the working test code.
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/beast.hpp>
#include <boost/beast/ssl.hpp>
#include <iostream>
namespace net = boost::asio;
namespace ssl = net::ssl;
namespace beast = boost::beast;
namespace http = beast::http;
namespace websocket = beast::websocket;
using tcp = net::ip::tcp;
using Request = http::request<http::string_body>;
using Stream = beast::ssl_stream<beast::tcp_stream>;
using Response = http::response<http::dynamic_body>;
class Exchange {
public:
Exchange(std::string name, const std::string& http_host)
: m_name(std::move(name))
{
init_http(http_host);
}
void init_http(std::string const& host)
{
const auto results{resolver.resolve(host, "443")};
get_lowest_layer(stream).connect(results);
// Set SNI Hostname (many hosts need this to handshake successfully)
if (!SSL_set_tlsext_host_name(stream.native_handle(), host.c_str())) {
boost::system::error_code ec{
static_cast<int>(::ERR_get_error()),
boost::asio::error::get_ssl_category()};
throw boost::system::system_error{ec};
}
stream.handshake(ssl::stream_base::client);
}
void init_webSocket(std::string const& host, std::string const& port,
const char* p = "")
{
// Set SNI Hostname (many hosts need this to handshake successfully)
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");
auto const results = resolver_webSocket.resolve(host, port);
net::connect(ws.next_layer().next_layer(), results.begin(),
results.end());
ws.next_layer().handshake(ssl::stream_base::client);
ws.handshake(host, p);
}
void read_Socket() { ws.read(buffer); }
bool is_socket_open()
{
if (ws.is_open())
return true;
return false;
}
void write_Socket(const std::string& text) { ws.write(net::buffer(text)); }
std::string get_socket_data()
{
return beast::buffers_to_string(buffer.data());
}
void buffer_clear() { buffer.clear(); }
void webSocket_close() { ws.close(websocket::close_code::none); }
private:
// HTTP REQUEST SET //
std::string m_name;
net::io_context ioc;
ssl::context ctx{ssl::context::tlsv12_client};
tcp::resolver resolver{ioc};
Stream stream{ioc, ctx};
// WEB SOCKET SET //
std::string m_web_socket_host;
std::string m_web_socket_port;
beast::flat_buffer buffer;
net::io_context ioc_webSocket;
ssl::context ctx_webSocket{ssl::context::tlsv12_client};
tcp::resolver resolver_webSocket{ioc_webSocket};
websocket::stream<beast::ssl_stream<tcp::socket>> ws{ioc_webSocket,
ctx_webSocket};
};
int main()
{
Exchange kraken{"kraken", "ws.kraken.com"};
try {
kraken.init_webSocket("ws.kraken.com", "443", "/");
if (kraken.is_socket_open())
kraken.write_Socket(
R"({"event": "subscribe","pair": ["MINA/USD"],"subscription": {"name": "spread"}})");
while (true) {
kraken.read_Socket();
std::cout << kraken.get_socket_data();
kraken.buffer_clear();
}
kraken.webSocket_close();
} catch (std::exception const& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
}
Upvotes: 3