Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix websocket client crash on quit #136

Merged
merged 3 commits into from
May 27, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 16 additions & 69 deletions src/network/http/websocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ namespace fc { namespace http {
:_ws_connection(con){
}

~websocket_connection_impl()
virtual ~websocket_connection_impl()
{
}

Expand Down Expand Up @@ -432,16 +432,16 @@ namespace fc { namespace http {
typedef websocket_tls_client_type::connection_ptr websocket_tls_client_connection_type;
using websocketpp::connection_hdl;

class websocket_client_impl
template<typename T>
class generic_websocket_client_impl
{
public:
typedef websocket_client_type::message_ptr message_ptr;

websocket_client_impl()
generic_websocket_client_impl()
:_client_thread( fc::thread::current() )
{
_client.clear_access_channels( websocketpp::log::alevel::all );
_client.set_message_handler( [&]( connection_hdl hdl, message_ptr msg ){
_client.set_message_handler( [&]( connection_hdl hdl,
typename websocketpp::client<T>::message_ptr msg ){
_client_thread.async( [&](){
wdump((msg->get_payload()));
//std::cerr<<"recv: "<<msg->get_payload()<<"\n";
Expand Down Expand Up @@ -469,74 +469,38 @@ namespace fc { namespace http {

_client.init_asio( &fc::asio::default_io_service() );
}
~websocket_client_impl()
virtual ~generic_websocket_client_impl()
{
if(_connection )
if( _connection )
{
_connection->close(0, "client closed");
_connection.reset();
_closed->wait();
}
if( _closed )
_closed->wait();
}
fc::promise<void>::ptr _connected;
fc::promise<void>::ptr _closed;
fc::thread& _client_thread;
websocket_client_type _client;
websocketpp::client<T> _client;
websocket_connection_ptr _connection;
std::string _uri;
fc::optional<connection_hdl> _hdl;
};

class websocket_client_impl : public generic_websocket_client_impl<asio_with_stub_log>
{};


class websocket_tls_client_impl
class websocket_tls_client_impl : public generic_websocket_client_impl<asio_tls_stub_log>
{
public:
typedef websocket_tls_client_type::message_ptr message_ptr;

websocket_tls_client_impl( const std::string& ca_filename )
:_client_thread( fc::thread::current() )
: generic_websocket_client_impl()
{
// ca_filename has special values:
// "_none" disables cert checking (potentially insecure!)
// "_default" uses default CA's provided by OS

_client.clear_access_channels( websocketpp::log::alevel::all );
_client.set_message_handler( [&]( connection_hdl hdl, message_ptr msg ){
_client_thread.async( [&](){
wdump((msg->get_payload()));
_connection->on_message( msg->get_payload() );
}).wait();
});
_client.set_close_handler( [=]( connection_hdl hdl ){
if( _connection )
{
try {
_client_thread.async( [&](){
wlog(". ${p}", ("p",uint64_t(_connection.get())));
if( !_shutting_down && !_closed && _connection )
_connection->closed();
_connection.reset();
} ).wait();
} catch ( const fc::exception& e )
{
if( _closed ) _closed->set_exception( e.dynamic_copy_exception() );
}
if( _closed ) _closed->set_value();
}
});
_client.set_fail_handler( [=]( connection_hdl hdl ){
elog( "." );
auto con = _client.get_con_from_hdl(hdl);
auto message = con->get_ec().message();
if( _connection )
_client_thread.async( [&](){ if( _connection ) _connection->closed(); _connection.reset(); } ).wait();
if( _connected && !_connected->ready() )
_connected->set_exception( exception_ptr( new FC_EXCEPTION( exception, "${message}", ("message",message)) ) );
if( _closed )
_closed->set_value();
});

//
// We need ca_filename to be copied into the closure, as the referenced object might be destroyed by the caller by the time
// tls_init_handler() is called. According to [1], capture-by-value results in the desired behavior (i.e. creation of
Expand Down Expand Up @@ -569,18 +533,8 @@ namespace fc { namespace http {
return ctx;
});

_client.init_asio( &fc::asio::default_io_service() );
}
~websocket_tls_client_impl()
{
if(_connection )
{
wlog(".");
_shutting_down = true;
_connection->close(0, "client closed");
_closed->wait();
}
}
virtual ~websocket_tls_client_impl() {}

std::string get_host()const
{
Expand All @@ -600,13 +554,6 @@ namespace fc { namespace http {
ctx->set_verify_callback( boost::asio::ssl::rfc2818_verification( get_host() ) );
}

bool _shutting_down = false;
fc::promise<void>::ptr _connected;
fc::promise<void>::ptr _closed;
fc::thread& _client_thread;
websocket_tls_client_type _client;
websocket_connection_ptr _connection;
std::string _uri;
};


Expand Down