Skip to content

How to set SNI & connect to wss:// ? #71

@davidtwomey

Description

@davidtwomey

Hi @chronoxor,

Really liking the design of CppServer!....however, unfortunately, I am running into issues attempting to connect to a wss:// endpoint.

In general, I am unable to get a simple example of connecting working so any help explaining how to correctly resolve and connect to a websocket endpoint specified by a wss:// uri would be greatly appreciated!

For example to connect to wss://ws.okx.com:8443/ws/v5/public (taken from here) I attempted the following based on the wss client example:

 // ...int main() {

  // Create a new Asio service
  auto service = std::make_shared<AsioService>();
  service->Start();


  // Create and prepare a new SSL client context
  auto context = std::make_shared<CppServer::Asio::SSLContext>(asio::ssl::context::tlsv12);
  context->set_default_verify_paths();
  context->set_root_certs();
  context->set_verify_mode(asio::ssl::verify_peer | asio::ssl::verify_fail_if_no_peer_cert);
  context->load_verify_file("../external/CppServer/tools/certificates/ca.pem");

  // Use TCPResolver to lookup DNS
  // See: https://github.com/chronoxor/CppServer/issues/55
  auto resolver = std::make_shared<CppServer::Asio::TCPResolver>(service);

 // @NOTE ClientWebsocket is a child class of `public CppServer::WS::WSSClient`
  auto ws = std::make_shared<ClientWebsocket>(service, context, "ws.okx.com", 8443);
  ws->Connect(resolver);

and the upgrade request attempt:

class ClientWebsocket : public CppServer::WS::WSSClient
{
public:
  using CppServer::WS::WSSClient::WSSClient;
protected:
  void onWSConnecting(CppServer::HTTP::HTTPRequest &request) override
  {
    request.SetBegin("GET", "/ws/v5/public", "HTTP/2");
    request.SetHeader("Host", address() + ":8443"); // @todo
    request.SetHeader("Upgrade", "websocket");
    request.SetHeader("Connection", "upgrade");
    request.SetHeader("Sec-WebSocket-Key", CppCommon::Encoding::Base64Encode(ws_nonce()));
    request.SetHeader("Accept", "/");
    // request.SetHeader("Sec-WebSocket-Version", "13");
    request.SetHeader("User-Agent", "beast.v1");
  }

This did not work, and my comments are:

(1) Do I need to set SNI somewhere on the stream native handle (using SSL_set_tlsext_host_name)
(2) Why (once SNI is set) the upgrade request is not working? If you have any experience with this.


NOTE: something like this seemed to get round initial SSL v3 handshake errors

bool SSLClient::Connect(const std::shared_ptr<TCPResolver>& resolver) {
 // ...

    std::cout << "Setting SNI Hostname: " << _address << std::endl;
    if(SSL_set_tlsext_host_name(_stream.native_handle(), _address.c_str())) {
        std::cout << "Success!" << std::endl;
    }
    else {
        std::cout << "Failed!" << std::endl;
    }
// ...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions