zaphoyd / websocketpp

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

Memory leak in process per connection application #569

Open altan5 opened 8 years ago

altan5 commented 8 years ago

I'm writing websocket server that starts new process on each connection. This server leaks memory. Is there error in code? Thank's!

Server code is:

#include "boost/make_shared.hpp"
#include "boost/asio/buffer.hpp"

wss_server::wss_server(unsigned short thread_pool_size) : m_thread_pool_size(thread_pool_size) {
    init_tls_context();
    m_sslPort = 11111;
    m_sslServer.init_asio();
    m_sslServer.set_reuse_addr(true);
    m_sslServer.clear_access_channels(websocketpp::log::alevel::all);
    m_sslServer.clear_error_channels(websocketpp::log::elevel::all);
    m_sslServer.set_open_handler((boost::function<void (boost::weak_ptr<void>)>)bind(&wss_server::on_tls_open,this,::_1));
    m_sslServer.set_close_handler((boost::function<void (boost::weak_ptr<void>)>)bind(&wss_server::on_close,this,::_1));
    m_sslServer.set_message_handler(bind(&wss_server::on_message,this,::_1,::_2));
    m_sslServer.set_tls_init_handler((boost::function<boost::shared_ptr<boost::asio::ssl::context> (boost::weak_ptr<void>)>)bind(&wss_server::on_tls_init, this,::_1));
}

wss_server::~wss_server() {}

void wss_server::on_tls_open(connection_hdl hdl) {
    m_sslServer.get_io_service().notify_fork(boost::asio::io_service::fork_prepare);
    if (fork() == 0) {
        m_sslServer.get_io_service().notify_fork(boost::asio::io_service::fork_child);
        session* data = new session(&m_sslServer, m_sslServer.get_con_from_hdl(hdl)->get_remote_endpoint(), hdl);
        m_connections[hdl] = data;
        m_sslServer.stop_listening();
    } else {
        m_sslServer.get_io_service().notify_fork(boost::asio::io_service::fork_parent);
        m_sslServer.get_con_from_hdl(hdl)->get_raw_socket().close();
        m_sslServer.start_accept();
    }
}

void wss_server::init_tls_context() {
    ctx = boost::make_shared<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::no_sslv3 |
                                     boost::asio::ssl::context::single_dh_use);
        ctx->set_password_callback(bind(&wss_server::get_password, this));

        std::ifstream inFile;
        std::stringstream strStream;
        inFile.open("certificate_chain_file");
        strStream << inFile.rdbuf();
        ctx->add_certificate_authority(boost::asio::buffer(strStream.str()));
        ctx->use_certificate_chain_file("certificate_file");
        ctx->use_private_key_file("private_key_file", boost::asio::ssl::context::pem);
        ctx->use_tmp_dh_file(CONFIG_STR("Server.dh_file"));

        std::string ciphers;
        ciphers = "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA";
        if (SSL_CTX_set_cipher_list(ctx->native_handle() , ciphers.c_str()) != 1) {
            std::cout << "Error setting cipher list" << std::endl;
        }
    } catch (std::exception& e) {
        std::cout << e.what() << std::endl;
    }
}

context_ptr wss_server::on_tls_init(connection_hdl hdl) {
    return ctx;
}

void wss_server::on_close(connection_hdl hdl) {
    session* data = get_data_from_hdl(hdl);
    if(data) {
        int clientId = data->get_client()->get_id();
        data->close_session();
        delete data;
        m_connections.erase(hdl);
        exit(0);
    }
}

void wss_server::on_message(connection_hdl hdl, server::message_ptr msg) {
}

session* wss_server::get_data_from_hdl(connection_hdl hdl) {
    con_list::iterator it = m_connections.find(hdl);
    if (it == m_connections.end()) {
        return 0;
    }
    return it->second;
}

void wss_server::run() {
    m_sslServer.listen(m_sslPort);
    m_sslServer.start_accept();
    signal(SIGCHLD, SIG_IGN);
    bool multithread = false;
    m_server.run();
}
altan5 commented 8 years ago

If I use empty method on_tls_open - no memory leaks...

void wss_server::on_tls_open(connection_hdl hdl) { m_sslServer.get_io_service().notify_fork(boost::asio::io_service::fork_prepare); if (fork() == 0) { m_sslServer.get_io_service().notify_fork(boost::asio::io_service::fork_child); } else { m_sslServer.get_io_service().notify_fork(boost::asio::io_service::fork_parent); } }