From bc0ab93e44fc57c751e470ff9a9e788bf3d61c88 Mon Sep 17 00:00:00 2001 From: Michael Insel Date: Thu, 16 May 2019 19:39:06 +0200 Subject: [PATCH] Use new I/O engine in GelfWriter --- lib/perfdata/gelfwriter.cpp | 81 ++++++++++++++++++++++++------------- lib/perfdata/gelfwriter.hpp | 2 +- 2 files changed, 53 insertions(+), 30 deletions(-) diff --git a/lib/perfdata/gelfwriter.cpp b/lib/perfdata/gelfwriter.cpp index 9623cbe87..ce6774ddf 100644 --- a/lib/perfdata/gelfwriter.cpp +++ b/lib/perfdata/gelfwriter.cpp @@ -22,6 +22,11 @@ #include "base/statsfunction.hpp" #include #include +#include "base/io-engine.hpp" +#include +#include +#include +#include using namespace icinga; @@ -126,11 +131,7 @@ void GelfWriter::ExceptionHandler(boost::exception_ptr exp) Log(LogDebug, "GelfWriter") << "Exception during Graylog Gelf operation: " << DiagnosticInformation(std::move(exp)); - if (GetConnected()) { - m_Stream->Close(); - - SetConnected(false); - } + DisconnectInternal(); } void GelfWriter::Reconnect() @@ -156,43 +157,46 @@ void GelfWriter::ReconnectInternal() if (GetConnected()) return; - TcpSocket::Ptr socket = new TcpSocket(); - Log(LogNotice, "GelfWriter") << "Reconnecting to Graylog Gelf on host '" << GetHost() << "' port '" << GetPort() << "'."; - try { - socket->Connect(GetHost(), GetPort()); - } catch (const std::exception& ex) { - Log(LogCritical, "GelfWriter") - << "Can't connect to Graylog Gelf on host '" << GetHost() << "' port '" << GetPort() << "'."; - throw ex; - } + bool ssl = GetEnableTls(); - if (GetEnableTls()) { - std::shared_ptr sslContext; + if (ssl) { + std::shared_ptr sslContext; - try { - sslContext = MakeSSLContext(GetCertPath(), GetKeyPath(), GetCaPath()); + try { + sslContext = MakeAsioSslContext(GetCertPath(), GetKeyPath(), GetCaPath()); } catch (const std::exception& ex) { Log(LogWarning, "GelfWriter") << "Unable to create SSL context."; - throw ex; + throw; } - TlsStream::Ptr tlsStream = new TlsStream(socket, GetHost(), RoleClient, sslContext); + m_Stream.first = std::make_shared(IoEngine::Get().GetIoService(), *sslContext, GetHost()); + } else { + m_Stream.second = std::make_shared(IoEngine::Get().GetIoService()); + } + + try { + icinga::Connect(ssl ? m_Stream.first->lowest_layer() : m_Stream.second->lowest_layer(), GetHost(), GetPort()); + } catch (const std::exception& ex) { + Log(LogWarning, "GelfWriter") + << "Can't connect to Graylog Gelf on host '" << GetHost() << "' port '" << GetPort() << ".'"; + throw; + } + + if (ssl) { + auto& tlsStream (m_Stream.first->next_layer()); try { - tlsStream->Handshake(); + tlsStream.handshake(tlsStream.client); } catch (const std::exception& ex) { Log(LogWarning, "GelfWriter") - << "TLS handshake with host'" << GetHost() << "' on port '" << GetPort() << "' failed.'"; - throw ex; + << "TLS handshake with host '" << GetHost() << " failed.'"; + throw; } - - m_Stream = tlsStream; - } else - m_Stream = new NetworkStream(socket); + } SetConnected(true); @@ -217,9 +221,22 @@ void GelfWriter::DisconnectInternal() if (!GetConnected()) return; - m_Stream->Close(); + if (m_Stream.first) { + boost::system::error_code ec; + m_Stream.first->next_layer().shutdown(ec); + + // https://stackoverflow.com/a/25703699 + // As long as the error code's category is not an SSL category, then the protocol was securely shutdown + if (ec.category() == boost::asio::error::get_ssl_category()) { + Log(LogCritical, "GelfWriter") + << "TLS shutdown with host '" << GetHost() << "' could not be done securely."; + } + } else if (m_Stream.second) { + m_Stream.second->close(); + } SetConnected(false); + } void GelfWriter::CheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr) @@ -479,7 +496,13 @@ void GelfWriter::SendLogMessage(const Checkable::Ptr& checkable, const String& g Log(LogDebug, "GelfWriter") << "Checkable '" << checkable->GetName() << "' sending message '" << log << "'."; - m_Stream->Write(log.CStr(), log.GetLength()); + if (m_Stream.first) { + boost::asio::write(*m_Stream.first, boost::asio::buffer(msgbuf.str())); + m_Stream.first->flush(); + } else { + boost::asio::write(*m_Stream.second, boost::asio::buffer(msgbuf.str())); + m_Stream.second->flush(); + } } catch (const std::exception& ex) { Log(LogCritical, "GelfWriter") << "Cannot write to TCP socket on host '" << GetHost() << "' port '" << GetPort() << "'."; diff --git a/lib/perfdata/gelfwriter.hpp b/lib/perfdata/gelfwriter.hpp index 41680cb34..f729c0c5c 100644 --- a/lib/perfdata/gelfwriter.hpp +++ b/lib/perfdata/gelfwriter.hpp @@ -33,7 +33,7 @@ protected: void Pause() override; private: - Stream::Ptr m_Stream; + OptionalTlsStream m_Stream; WorkQueue m_WorkQueue{10000000, 1}; Timer::Ptr m_ReconnectTimer;