zaphoyd / websocketpp

C++ websocket client/server library
http://www.zaphoyd.com/websocketpp
Other
6.86k stars 1.94k forks source link

Secured Client leaking memory in Tizen #782

Open hossainimtiaz opened 5 years ago

hossainimtiaz commented 5 years ago

Hi,

I am trying to develop a Stomp-Ws client using WebsocketPP. The client is working fine in Ubuntu but leaking memory in Tizen.

Unfortunately, Tizen 3.0 doesn't support valgrind so I am unable to pinpoint the leak in Tizen. While trying to check step-by step I have found that "WebsocketEndpoint::send(std::string message)" is leaking memory over time.

Interestingly a non-secured endpoint doesn't leak memory.

I am now confused if it is a OpenSSL related bug (if so, what is the work around) or it is my implementation mistake.

`#include

include

include

include

include

include

include

include <openssl/ssl.h>

include <curl/curl.h>

//Tizen

include "Utility.h"

include "StompClient.h"

include "StompFrame.h"

include "StompFrameHandler.h"

include "ResponseCode.h"

using websocketpp::lib::placeholders::_1; using websocketpp::lib::placeholders::_2; using websocketpp::lib::bind;

// pull out the type of messages sent by our config

void ConnectionMetadata::on_open_listener(client *c, websocketpp::connection_hdl hdl) { m_status = "Open"; DLOG("on_open called"); client::connection_ptr con = c->get_con_from_hdl(hdl); m_server = con->get_response_header("Server"); m_worker_is_done = true; m_condition_variable.notify_one(); }

void ConnectionMetadata::on_fail_listener(client *c, websocketpp::connection_hdl hdl) { m_status = "Failed"; DLOG("on_fail called"); client::connection_ptr con = c->get_con_from_hdl(hdl); m_server = con->get_response_header("Server"); m_error_reason = con->get_ec().message(); m_worker_is_done = true; m_condition_variable.notify_one();

}

void ConnectionMetadata::on_close_listener(client *c, websocketpp::connection_hdl hdl) { DLOG("on_close called"); m_status = "Closed"; client::connection_ptr con = c->get_con_from_hdl(hdl); std::stringstream s; s << "close code: " << con->get_remote_close_code() << " (" << websocketpp::close::status::get_string(con->get_remote_close_code()) << "), close reason: " << con->get_remote_close_reason(); m_error_reason = s.str();

ResponseCode responseCode = ResponseCode::NORMAL_CLOSE;

int close_code = con->get_remote_close_code();

switch(close_code) {
    case 1000:
        responseCode = ResponseCode::NORMAL_CLOSE;
    case 1002:
        responseCode = ResponseCode::PROTOCOL_ERROR;
        break;
    default:
    responseCode = ResponseCode::UNEXPECTED_CLOSE;

}

m_server_response_listener(responseCode, m_error_reason);
DLOG("%s", m_error_reason.c_str());

}

void ConnectionMetadata::on_message_listener(websocketpp::connection_hdl, client::message_ptr msg) { DLOG("on_message called"); std::string payload = msg->get_payload(); std::stringstream ss(payload); std::string response; std::getline(ss, response, '\n'); std::string connected = "Connected"; StompFrame stompFrame;

if (msg->get_opcode() == websocketpp::frame::opcode::text) {
    m_messages.push_back("<< " + payload);
    DLOG("Payload Len: %d", payload.length());

    if (payload.compare("\n") == 0) {
        DLOG("Frame: %s", "Pong");
        return;
    }

    DLOG("Payload : %s", payload.c_str());
    stompFrame = StompFrameHandler::unmarshall(payload);
    DLOG("Frame: %s", StompFrameHandler::marshall(stompFrame).c_str());

} else {
    m_messages.push_back("<< " + websocketpp::utility::to_hex(payload));
}

//std::cout << response << std::endl;
if (boost::iequals(response, connected)) {
    m_status = connected;

} else {
    string tempMsg = payload;
    boost::replace_all(tempMsg, "\n", "<br>");
    m_server_response_listener(ResponseCode::MESSAGE, payload);
}

m_worker_is_done = true;
m_condition_variable.notify_one();

}

websocketpp::connection_hdl ConnectionMetadata::get_hdl() const { return m_hdl; }

std::string ConnectionMetadata::get_status() const { return m_status; }

void ConnectionMetadata::record_sent_message(std::string message) { m_messages.push_back(">> " + message); }

std::ostream &operator<< (std::ostream &out, ConnectionMetadata const &data) { out << "> URI: " << data.m_uri << "\n" << "> Status: " << data.m_status << "\n" << "> Remote Server: " << (data.m_server.empty() ? "None Specified" : data.m_server) << "\n" << "> Error/close reason: " << (data.m_error_reason.empty() ? "N/A" : data.m_error_reason) << "\n"; out << "> Messages Processed: (" << data.m_messages.size() << ") \n";

std::vector<std::string>::const_iterator it;

for (it = data.m_messages.begin(); it != data.m_messages.end(); ++it) {
    out << *it << "\n";
}

return out;

}

WebsocketEndpoint::WebsocketEndpoint (std::string id) : m_id (id) { DLOG("WebsocketEndpoint IN"); m_client_endpoint.clear_access_channels(websocketpp::log::alevel::all); m_client_endpoint.clear_error_channels(websocketpp::log::elevel::all);

m_client_endpoint.init_asio();
m_client_endpoint.start_perpetual();

m_client_endpoint.set_socket_init_handler(bind(&WebsocketEndpoint::on_socket_init, this, ::_1));
m_client_endpoint.set_tls_init_handler(bind(&WebsocketEndpoint::on_tls_init, this, ::_1));

m_thread = websocketpp::lib::make_shared<websocketpp::lib::thread>(&client::run,
             &m_client_endpoint);
DLOG("WebsocketEndpoint OUT");

}

WebsocketEndpoint::~WebsocketEndpoint() {

DLOG("WebsocketEndpoint Destructor IN");
m_client_endpoint.stop_perpetual();

DLOG("WebsocketEndpoint Status IN");

if (m_connection && (m_connection->get_status() == "Open" || m_connection->get_status() == "Connected")) {
    DLOG("WebsocketEndpoint Status IN");

    websocketpp::lib::error_code ec;
    m_client_endpoint.close(m_connection->get_hdl(), websocketpp::close::status::going_away, "", ec);

    if (ec) {
        std::cout << "> Error closing connection " << ": "
                  << ec.message() << std::endl;
    }
}

m_thread->join();
DLOG("WebsocketEndpoint Destructor OUT");

}

bool WebsocketEndpoint::connect(std::string const &uri, int connection_waiting_timeout, std::function<void(ResponseCode, std::string)> server_reponse_listener) {

DLOG("WebsocketEndpoint::connect IN");
websocketpp::lib::error_code ec;

client::connection_ptr con = m_client_endpoint.get_connection(uri, ec);

if (ec) {
    std::cout << "> Connect initialization error: " << ec.message() << std::endl;
    return false;
}

//ConnectionMetadata::ptr m_connection = websocketpp::lib::make_shared<ConnectionMetadata>
//                                       (con->get_handle(), uri, server_reponse_listener);
//m_connection = metadata_ptr;

m_connection = websocketpp::lib::make_shared<ConnectionMetadata>
                    (con->get_handle(), uri, server_reponse_listener);
con->set_open_handler(websocketpp::lib::bind(
                          &ConnectionMetadata::on_open_listener,
                          m_connection,
                          &m_client_endpoint,
                          websocketpp::lib::placeholders::_1
                      ));

con->set_fail_handler(websocketpp::lib::bind(
                          &ConnectionMetadata::on_fail_listener,
                          m_connection,
                          &m_client_endpoint,
                          websocketpp::lib::placeholders::_1
                      ));
con->set_close_handler(websocketpp::lib::bind(
                           &ConnectionMetadata::on_close_listener,
                           m_connection,
                           &m_client_endpoint,
                           websocketpp::lib::placeholders::_1
                       ));
con->set_message_handler(websocketpp::lib::bind(
                             &ConnectionMetadata::on_message_listener,
                             m_connection,
                             websocketpp::lib::placeholders::_1,
                             websocketpp::lib::placeholders::_2
                         ));

boost::system_time const timeout = boost::get_system_time() + boost::posix_time::milliseconds(
                                       connection_waiting_timeout);
boost::mutex io_mutex;
boost::mutex::scoped_lock lock(io_mutex);

m_client_endpoint.connect(con);
try {
    while (!m_connection->m_worker_is_done) {
        DLOG("Wait Loop");

        if (!m_connection->m_condition_variable.timed_wait(lock, timeout)) {
            DLOG("Timed Out");
            return false;
        }
    } 
} catch(...) {
    DLOG("Exception Occured");
    return false;
}

DLOG("WebsocketEndpoint::connect OUT");
return boost::iequals(m_connection->get_status(), "Open");

}

void WebsocketEndpoint::close(websocketpp::close::status::value code, std::string reason) { DLOG("WebsocketEndpoint::close IN");
websocketpp::lib::error_code ec;

m_client_endpoint.close(m_connection->get_hdl(), code, reason, ec);

if (ec) {
    std::cout << "> Error initiating close: " << ec.message() << std::endl;
}
DLOG("WebsocketEndpoint::close OUT");  

}

void WebsocketEndpoint::send(std::string message) { //DLOG("WebsocketEndpoint::send IN");

if(m_connection ) {
    websocketpp::lib::error_code ec;
    m_client_endpoint.send(m_connection->get_hdl(), message, websocketpp::frame::opcode::text, ec);

    if (ec) {
        std::cout << "> Error sending message: " << ec.message() << " for Stomp Client ID " << m_id <<
                  std::endl;
        std::cout << "Payload : " << message <<  std::endl;
        //DLOG("WebsocketEndpoint::send OUT");  
        return;
    }

    m_connection->record_sent_message(message);
    //curl_global_cleanup();
    //SSL_COMP_free_compression_methods();
}

//DLOG("WebsocketEndpoint::send OUT");  

}

void WebsocketEndpoint::on_socket_init(websocketpp::connection_hdl hdl) { (void) hdl; std::cout << "on_socket_init called" << std::endl; m_socket_init = std::chrono::high_resolution_clock::now(); }

context_ptr WebsocketEndpoint::on_tls_init(websocketpp::connection_hdl hdl) { std::cout << "on_tls_init called" << std::endl; (void) hdl; m_tls_init = std::chrono::high_resolution_clock::now(); context_ptr ctx(new boost::asio::ssl::context(boost::asio::ssl::context::tlsv1));

try {
    ctx->set_options(boost::asio::ssl::context::default_workarounds |
                     boost::asio::ssl::context::no_sslv2 |
                     boost::asio::ssl::context::single_dh_use);

} catch (std::exception &e) {
    std::cout << e.what() << std::endl;
}

return ctx;

}

ConnectionMetadata::ptr WebsocketEndpoint::getMetadata() const { return m_connection; }`

sterryxue commented 4 years ago

I also have the problem

13272438611 commented 4 years ago

Have same problem in Windows

tonybarba commented 3 years ago

Has this ever been resolved? I am using version 0.81 and I still see the problem

free-wind-0 commented 3 years ago

I am using version 0.82 and I still see the problem, os is centos 7

zhouhuirun2015 commented 1 month ago

server on arm device leak memory too