Websocket improvements:

* Log on_close/on_fail/on_open calls.
* Ping out connections.
* Improve ping logic.
* On websocket ping out, close abnormally.
* Avoid deadlock when shutting down websocket endpoint
This commit is contained in:
David Schwartz
2013-12-11 11:49:02 -08:00
committed by JoelKatz
parent deead04a6a
commit de92ac9e0b
3 changed files with 70 additions and 20 deletions

View File

@@ -160,10 +160,8 @@ public:
bool onPingTimer (std::string&)
{
#ifdef DISCONNECT_ON_WEBSOCKET_PING_TIMEOUTS
if (m_sentPing)
return true; // causes connection to close
#endif
m_sentPing = true;
setPingTimer ();

View File

@@ -74,7 +74,7 @@ private:
{
ScopedLockType lock (m_endpointLock, __FILE__, __LINE__);
m_endpoint = new websocketpp::server_multitls (handler);
m_endpoint = boost::make_shared<websocketpp::server_multitls> (handler);
}
// Call the main-event-loop of the websocket server.
@@ -107,7 +107,7 @@ private:
{
ScopedLockType lock (m_endpointLock, __FILE__, __LINE__);
m_endpoint = nullptr;
m_endpoint.reset();
}
stopped ();
@@ -115,16 +115,20 @@ private:
void onStop ()
{
boost::shared_ptr<websocketpp::server_multitls> endpoint;
{
ScopedLockType lock (m_endpointLock, __FILE__, __LINE__);
// VFALCO NOTE we probably dont want to block here
// but websocketpp is deficient and broken.
//
if (m_endpoint != nullptr)
m_endpoint->stop ();
endpoint = m_endpoint;
}
// VFALCO NOTE we probably dont want to block here
// but websocketpp is deficient and broken.
//
if (endpoint)
endpoint->stop ();
signalThreadShouldExit ();
}
@@ -137,7 +141,7 @@ private:
boost::asio::ssl::context& m_ssl_context;
LockType m_endpointLock;
ScopedPointer <websocketpp::server_multitls> m_endpoint;
boost::shared_ptr<websocketpp::server_multitls> m_endpoint;
bool mPublic;
bool mProxy;
std::string mIp;

View File

@@ -69,8 +69,9 @@ private:
protected:
// For each connection maintain an associated object to track subscriptions.
boost::unordered_map <connection_ptr,
boost::shared_ptr <WSConnectionType <endpoint_type> > > mMap;
typedef boost::unordered_map <connection_ptr,
boost::shared_ptr <WSConnectionType <endpoint_type> > > MapType;
MapType mMap;
bool const mPublic;
bool const mProxy;
@@ -154,8 +155,15 @@ public:
if (ptr->onPingTimer (data))
{
WriteLog (lsWARNING, WSServerHandlerLog) << "Connection pings out";
cpClient->close (websocketpp::close::status::PROTOCOL_ERROR, "ping timeout");
cpClient->terminate (false);
try
{
WriteLog (lsDEBUG, WSServerHandlerLog) <<
"Ws:: ping_out(" << cpClient->get_socket ().remote_endpoint ().to_string () << ")";
}
catch (...)
{
}
}
else
cpClient->ping (data);
@@ -183,11 +191,13 @@ public:
try
{
mMap [cpClient] = boost::make_shared <
WSConnectionType <endpoint_type>
> (boost::ref(m_resourceManager),
boost::ref (m_source),
boost::ref(*this), boost::cref(cpClient));
std::pair <typename MapType::iterator, bool> const result (
mMap.emplace (cpClient,
boost::make_shared < WSConnectionType <endpoint_type> > (boost::ref(m_resourceManager),
boost::ref (m_source), boost::ref(*this), boost::cref(cpClient))));
check_postcondition (result.second);
WriteLog (lsDEBUG, WSServerHandlerLog) <<
"Ws:: on_open(" << cpClient->get_socket ().remote_endpoint ().to_string () << ")";
}
catch (...)
{
@@ -206,10 +216,28 @@ public:
ptr = it->second;
}
try
{
WriteLog (lsDEBUG, WSServerHandlerLog) <<
"Ws:: on_pong(" << cpClient->get_socket ().remote_endpoint ().to_string () << ")";
}
catch (...)
{
}
ptr->onPong (data);
}
void on_close (connection_ptr cpClient)
{
doClose (cpClient, "on_close");
}
void on_fail (connection_ptr cpClient)
{
doClose (cpClient, "on_fail");
}
void doClose (connection_ptr const& cpClient, char const* reason)
{
// we cannot destroy the connection while holding the map lock or we deadlock with pubLedger
wsc_ptr ptr;
@@ -218,12 +246,32 @@ public:
typename boost::unordered_map<connection_ptr, wsc_ptr>::iterator it = mMap.find (cpClient);
if (it == mMap.end ())
{
try
{
WriteLog (lsDEBUG, WSServerHandlerLog) <<
"Ws:: " << reason << "(" <<
cpClient->get_socket ().remote_endpoint ().to_string () << ") not found";
}
catch (...)
{
}
return;
}
ptr = it->second; // prevent the WSConnection from being destroyed until we release the lock
mMap.erase (it);
}
ptr->preDestroy (); // Must be done before we return
try
{
WriteLog (lsDEBUG, WSServerHandlerLog) <<
"Ws:: " << reason << "(" <<
cpClient->get_socket ().remote_endpoint ().to_string () << ") found";
}
catch (...)
{
}
// Must be done without holding the websocket send lock
getApp().getJobQueue ().addJob (jtCLIENT, "WSClient::destroy",
@@ -335,7 +383,7 @@ public:
{
std::string cmd = jvRequest["command"].asString ();
job.rename (std::string ("WSClient::") + cmd);
}
}
send (cpClient, conn->invokeCommand (jvRequest), false);
}