diff --git a/lib/base/stream.cpp b/lib/base/stream.cpp index 1e6b9baf1..72ca82c1a 100644 --- a/lib/base/stream.cpp +++ b/lib/base/stream.cpp @@ -60,7 +60,7 @@ void Stream::SignalDataAvailable() } } -bool Stream::WaitForData(int timeout) +bool Stream::WaitForData() { if (!SupportsWaiting()) BOOST_THROW_EXCEPTION(std::runtime_error("Stream does not support waiting.")); @@ -68,10 +68,25 @@ bool Stream::WaitForData(int timeout) boost::mutex::scoped_lock lock(m_Mutex); while (!IsDataAvailable() && !IsEof()) - if (timeout < 0) - m_CV.wait(lock); - else - m_CV.timed_wait(lock, boost::posix_time::milliseconds(timeout * 1000)); + m_CV.wait(lock); + + return IsDataAvailable() || IsEof(); +} + +bool Stream::WaitForData(int timeout) +{ + if (!SupportsWaiting()) + BOOST_THROW_EXCEPTION(std::runtime_error("Stream does not support waiting.")); + + if (timeout < 0) + BOOST_THROW_EXCEPTION(std::runtime_error("Timeout can't be negative")); + + boost::system_time const point_of_timeout = boost::get_system_time() + boost::posix_time::seconds(timeout); + + boost::mutex::scoped_lock lock(m_Mutex); + + while (!IsDataAvailable() && !IsEof() && point_of_timeout > boost::get_system_time()) + m_CV.timed_wait(lock, point_of_timeout); return IsDataAvailable() || IsEof(); } diff --git a/lib/base/stream.hpp b/lib/base/stream.hpp index 58569246c..8a140a586 100644 --- a/lib/base/stream.hpp +++ b/lib/base/stream.hpp @@ -122,8 +122,10 @@ public: /** * Waits until data can be read from the stream. + * Optionally with a timeout. */ - bool WaitForData(int timeout = -1); + bool WaitForData(); + bool WaitForData(int timeout); virtual bool SupportsWaiting() const; diff --git a/lib/base/tlsstream.cpp b/lib/base/tlsstream.cpp index 029c9b446..e97f68b60 100644 --- a/lib/base/tlsstream.cpp +++ b/lib/base/tlsstream.cpp @@ -27,6 +27,9 @@ # include #endif /* _WIN32 */ +#define TLS_TIMEOUT_SECONDS 10 +#define TLS_TIMEOUT_STEP_SECONDS 1 + using namespace icinga; int TlsStream::m_SSLIndex; @@ -285,8 +288,14 @@ void TlsStream::Handshake() m_CurrentAction = TlsActionHandshake; ChangeEvents(POLLOUT); - while (!m_HandshakeOK && !m_ErrorOccurred && !m_Eof) - m_CV.wait(lock); + boost::system_time const timeout = boost::get_system_time() + boost::posix_time::seconds(TLS_TIMEOUT_SECONDS); + + while (!m_HandshakeOK && !m_ErrorOccurred && !m_Eof && timeout > boost::get_system_time()) + m_CV.timed_wait(lock, timeout); + + // We should _NOT_ (underline, bold, itallic and wordart) throw an exception for a timeout. + if (timeout < boost::get_system_time()) + BOOST_THROW_EXCEPTION(std::runtime_error("Timeout during handshake.")); if (m_Eof) BOOST_THROW_EXCEPTION(std::runtime_error("Socket was closed during TLS handshake.")); diff --git a/lib/remote/apilistener.cpp b/lib/remote/apilistener.cpp index 251aff791..bc0df4449 100644 --- a/lib/remote/apilistener.cpp +++ b/lib/remote/apilistener.cpp @@ -512,11 +512,17 @@ void ApiListener::NewClientHandlerInternal(const Socket::Ptr& client, const Stri JsonRpc::SendMessage(tlsStream, message); ctype = ClientJsonRpc; } else { - tlsStream->WaitForData(5); + tlsStream->WaitForData(10); if (!tlsStream->IsDataAvailable()) { - Log(LogWarning, "ApiListener") - << "No data received on new API connection for identity '" << identity << "'. Ensure that the remote endpoints are properly configured in a cluster setup."; + if (identity.IsEmpty()) + Log(LogInformation, "ApiListener") + << "No data received on new API connection. " + << "Ensure that the remote endpoints are properly configured in a cluster setup."; + else + Log(LogWarning, "ApiListener") + << "No data received on new API connection for identity '" << identity << "'. " + << "Ensure that the remote endpoints are properly configured in a cluster setup."; return; } diff --git a/lib/remote/httpserverconnection.cpp b/lib/remote/httpserverconnection.cpp index c22f0ee15..7c86f9be9 100644 --- a/lib/remote/httpserverconnection.cpp +++ b/lib/remote/httpserverconnection.cpp @@ -52,7 +52,7 @@ void HttpServerConnection::StaticInitialize() { l_HttpServerConnectionTimeoutTimer = new Timer(); l_HttpServerConnectionTimeoutTimer->OnTimerExpired.connect(std::bind(&HttpServerConnection::TimeoutTimerHandler)); - l_HttpServerConnectionTimeoutTimer->SetInterval(15); + l_HttpServerConnectionTimeoutTimer->SetInterval(5); l_HttpServerConnectionTimeoutTimer->Start(); } @@ -76,6 +76,12 @@ TlsStream::Ptr HttpServerConnection::GetStream() const void HttpServerConnection::Disconnect() { + boost::mutex::scoped_try_lock lock(m_DataHandlerMutex); + if (!lock.owns_lock()) { + Log(LogInformation, "HttpServerConnection", "Unable to disconnect Http client, I/O thread busy"); + return; + } + Log(LogDebug, "HttpServerConnection", "Http client disconnected"); ApiListener::Ptr listener = ApiListener::GetInstance(); diff --git a/lib/remote/pkiutility.cpp b/lib/remote/pkiutility.cpp index 6b896dab1..20d9ca6c2 100644 --- a/lib/remote/pkiutility.cpp +++ b/lib/remote/pkiutility.cpp @@ -121,8 +121,10 @@ std::shared_ptr PkiUtility::FetchCert(const String& host, const String& po try { stream->Handshake(); - } catch (...) { - + } catch (const std::exception& ex) { + Log(LogCritical, "pki") + << "Client TLS handshake failed. (" << ex.what() << ")"; + return std::shared_ptr(); } return stream->GetPeerCertificate();