I am building a C++ native module to be used in an Electron application. The native module is responsible for communicating with a WebSocket server. I am using the WebSocketPP library and the following sample code:
index.cc
#include <websocketpp/config/asio_client.hpp> // TLS
#include <websocketpp/client.hpp>
typedef websocketpp::client<websocketpp::config::asio_tls_client> client;
typedef websocketpp::config::asio_client::message_type::ptr message_ptr;
typedef websocketpp::lib::shared_ptr<boost::asio::ssl::context> context_ptr;
using websocketpp::lib::bind;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
//
...
//
class WebSocketHandler
{
public:
void set(const std::string &url, const std::string &token)
{
ws_url = url;
authorizationHeader = "Bearer " + token;
// Initialize ASIO
_webSocket.init_asio();
// Set logging to be pretty verbose (everything except message payloads)
_webSocket.set_access_channels(websocketpp::log::alevel::all);
_webSocket.clear_access_channels(websocketpp::log::alevel::frame_payload);
// Set open handler
_webSocket.set_open_handler(bind(&WebSocketHandler::on_open, this, std::placeholders::_1));
// Set close handler
_webSocket.set_close_handler(bind(&WebSocketHandler::on_close, this, std::placeholders::_1));
// Set fail handler
_webSocket.set_fail_handler(bind(&WebSocketHandler::on_fail, this, std::placeholders::_1));
// Set message handler
_webSocket.set_message_handler(bind(&WebSocketHandler::on_message, this, std::placeholders::_1, std::placeholders::_2));
// Set TLS handler
_webSocket.set_tls_init_handler(bind(&WebSocketHandler::on_tls_init, this, std::placeholders::_1));
}
void start()
{
websocketpp::lib::error_code ec;
client::connection_ptr con = _webSocket.get_connection(ws_url, ec);
if (ec)
{
std::cout << "Could not create connection because: " << ec.message() << std::endl;
return;
}
// Set the authorization header
con->replace_header("Authorization", authorizationHeader);
// Connect to server
_webSocket.connect(con);
// Start the ASIO io_service run loop
_thread.reset(new websocketpp::lib::thread(&client::run, &_webSocket));
}
void stop()
{
_webSocket.stop();
if (_thread && _thread->joinable())
{
_thread->join();
}
}
private:
context_ptr on_tls_init(websocketpp::connection_hdl hdl)
{
context_ptr ctx = websocketpp::lib::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::sslv23); // crash at this line
try {
// Simplified SSL options for testing
ctx->set_options(boost::asio::ssl::context::default_workarounds |
boost::asio::ssl::context::no_sslv2 |
boost::asio::ssl::context::no_sslv3 |
boost::asio::ssl::context::single_dh_use);
std::cout << "SSL options set successfully" << std::endl;
} catch (std::exception &e) {
std::cout << "Exception during set_options: " << e.what() << std::endl;
}
return ctx;
}
void on_open(websocketpp::connection_hdl hdl)
{
std::cout << "connection opened" << std::endl;
}
void on_close(websocketpp::connection_hdl hdl)
{
std::cout << "connection closed" << std::endl;
}
void on_fail(websocketpp::connection_hdl hdl)
{
std::cout << "connection failed" << std::endl;
}
void on_message(websocketpp::connection_hdl hdl, client::message_ptr msg)
{
std::cout << "message arrived" << std::endl;
}
client _webSocket;
std::string ws_url;
std::string authorizationHeader;
};
//
...
//
WebSocketHandler handler;
handler.set("wss://echo.websocket.org/", "Token_xxxx");
handler.start();
....
handler.stop();
binding.gyp
{
"targets": [
{
"target_name": "binding",
"include_dirs": [
"<!@(node -p \"require('node-addon-api').include\")",
"<(module_root_dir)/include"
],
"conditions": [
['OS=="win"', {
"sources": [
"./src/index.cc"
],
"configurations": {
"Debug": {
"msvs_settings": {
"VCCLCompilerTool": {
"RuntimeLibrary": "0",
"ExceptionHandling": "1"
},
},
},
"Release": {
"msvs_settings": {
"VCCLCompilerTool": {
"RuntimeLibrary": "0",
"ExceptionHandling": "1"
},
},
},
},
"libraries": [
"-lws2_32",
"-lShlwapi"
]
}]
]
}
],
}
Test Script
const engine = require("../bin/binding.node");
const test = async () => {
try {
engine.startConnection();
} catch (err) {
console.log("Error occurred", err);
}
};
test();
Problem The module works correctly in a JavaScript test script but crashes in Electron at this line:
context_ptr ctx = websocketpp::lib::make_sharedboost::asio::ssl::context(boost::asio::ssl::context::sslv23);
I suspect the issue might be related to the way SSL libraries are linked. I feel linking SSL libraries statically might resolve the issue, but I am unsure how to achieve this. I tested with other several libraries based in boost but the result was same. It keeps crahsed in ssl context creation part only in electron application.
Environment
C++14/17
Electron v23(version upgrade doesn't help)
WebSocketPP 0.8.2
Node 16.14.2/18.x.x
Dependencies installed using vcpkg: OpenSSL, WebSocketPP, Boost
Question
How can I link SSL libraries statically in my project to potentially fix this issue? Are there any other possible solutions or insights regarding this problem?
Thank you for your assistance!
Top comments (0)