From: Alexander A. Klimov Date: Wed, 20 Feb 2019 13:56:12 +0000 (+0100) Subject: Re-add HttpServerConnection#Disconnect() X-Git-Tag: v2.11.0-rc1~174^2~27 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f029fd48847c797cee32d8068745b4a1e6fe0f08;p=icinga2 Re-add HttpServerConnection#Disconnect() --- diff --git a/lib/remote/httpserverconnection.cpp b/lib/remote/httpserverconnection.cpp index a37b3a0b1..2419eb595 100644 --- a/lib/remote/httpserverconnection.cpp +++ b/lib/remote/httpserverconnection.cpp @@ -12,7 +12,6 @@ #include "base/configtype.hpp" #include "base/defer.hpp" #include "base/exception.hpp" -#include "base/io-engine.hpp" #include "base/logger.hpp" #include "base/objectlock.hpp" #include "base/timer.hpp" @@ -31,7 +30,7 @@ using namespace icinga; auto const l_ServerHeader ("Icinga/" + Application::GetAppVersion()); HttpServerConnection::HttpServerConnection(const String& identity, bool authenticated, const std::shared_ptr& stream) - : m_Stream(stream) + : m_Stream(stream), m_IoStrand(stream->get_io_service()), m_ShuttingDown(false) { if (authenticated) { m_ApiUser = ApiUser::GetByClientCN(identity); @@ -51,7 +50,43 @@ void HttpServerConnection::Start() { namespace asio = boost::asio; - asio::spawn(IoEngine::Get().GetIoService(), [this](asio::yield_context yc) { ProcessMessages(yc); }); + HttpServerConnection::Ptr preventGc (this); + + asio::spawn(m_IoStrand, [this, preventGc](asio::yield_context yc) { ProcessMessages(yc); }); +} + +void HttpServerConnection::Disconnect() +{ + namespace asio = boost::asio; + + HttpServerConnection::Ptr preventGc (this); + + asio::spawn(m_IoStrand, [this, preventGc](asio::yield_context yc) { + if (!m_ShuttingDown) { + m_ShuttingDown = true; + + Log(LogInformation, "HttpServerConnection") + << "HTTP client disconnected (from " << m_PeerAddress << ")"; + + try { + m_Stream->next_layer().async_shutdown(yc); + } catch (...) { + } + + try { + m_Stream->lowest_layer().shutdown(m_Stream->lowest_layer().shutdown_both); + } catch (...) { + } + + auto listener (ApiListener::GetInstance()); + + if (listener) { + CpuBoundWork removeHttpClient (yc); + + listener->RemoveHttpClient(this); + } + } + }); } static inline @@ -357,23 +392,7 @@ void HttpServerConnection::ProcessMessages(boost::asio::yield_context yc) namespace beast = boost::beast; namespace http = beast::http; - Defer removeHttpClient ([this, &yc]() { - auto listener (ApiListener::GetInstance()); - - if (listener) { - CpuBoundWork removeHttpClient (yc); - - listener->RemoveHttpClient(this); - } - }); - - Defer shutdown ([this, &yc]() { - try { - m_Stream->next_layer().async_shutdown(yc); - } catch (...) { - // https://stackoverflow.com/questions/130117/throwing-exceptions-out-of-a-destructor - } - }); + Defer disconnect ([this]() { Disconnect(); }); try { beast::flat_buffer buf; @@ -440,7 +459,9 @@ void HttpServerConnection::ProcessMessages(boost::asio::yield_context yc) } } } catch (const std::exception& ex) { - Log(LogCritical, "HttpServerConnection") - << "Unhandled exception while processing HTTP request: " << DiagnosticInformation(ex); + if (!m_ShuttingDown) { + Log(LogCritical, "HttpServerConnection") + << "Unhandled exception while processing HTTP request: " << DiagnosticInformation(ex); + } } } diff --git a/lib/remote/httpserverconnection.hpp b/lib/remote/httpserverconnection.hpp index 3fdbeef50..bb3291991 100644 --- a/lib/remote/httpserverconnection.hpp +++ b/lib/remote/httpserverconnection.hpp @@ -7,6 +7,7 @@ #include "base/string.hpp" #include "base/tlsstream.hpp" #include +#include #include namespace icinga @@ -25,11 +26,14 @@ public: HttpServerConnection(const String& identity, bool authenticated, const std::shared_ptr& stream); void Start(); + void Disconnect(); private: ApiUser::Ptr m_ApiUser; std::shared_ptr m_Stream; String m_PeerAddress; + boost::asio::io_service::strand m_IoStrand; + bool m_ShuttingDown; void ProcessMessages(boost::asio::yield_context yc); };