"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "lib/remote/apilistener.cpp" between
icinga2-2.11.5.tar.gz and icinga2-2.12.0.tar.gz

About: Icinga 2 is an enterprise grade monitoring system which keeps watch over networks and any conceivable network resource.

apilistener.cpp  (icinga2-2.11.5):apilistener.cpp  (icinga2-2.12.0)
skipping to change at line 27 skipping to change at line 27
#include "base/logger.hpp" #include "base/logger.hpp"
#include "base/objectlock.hpp" #include "base/objectlock.hpp"
#include "base/stdiostream.hpp" #include "base/stdiostream.hpp"
#include "base/perfdatavalue.hpp" #include "base/perfdatavalue.hpp"
#include "base/application.hpp" #include "base/application.hpp"
#include "base/context.hpp" #include "base/context.hpp"
#include "base/statsfunction.hpp" #include "base/statsfunction.hpp"
#include "base/exception.hpp" #include "base/exception.hpp"
#include "base/tcpsocket.hpp" #include "base/tcpsocket.hpp"
#include <boost/asio/buffer.hpp> #include <boost/asio/buffer.hpp>
#include <boost/asio/io_context_strand.hpp>
#include <boost/asio/ip/tcp.hpp> #include <boost/asio/ip/tcp.hpp>
#include <boost/asio/spawn.hpp> #include <boost/asio/spawn.hpp>
#include <boost/asio/ssl/context.hpp> #include <boost/asio/ssl/context.hpp>
#include <boost/date_time/posix_time/posix_time_duration.hpp>
#include <boost/system/error_code.hpp> #include <boost/system/error_code.hpp>
#include <climits> #include <climits>
#include <cstdint>
#include <fstream> #include <fstream>
#include <memory> #include <memory>
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <openssl/tls1.h> #include <openssl/tls1.h>
#include <openssl/x509.h> #include <openssl/x509.h>
#include <sstream> #include <sstream>
#include <utility> #include <utility>
using namespace icinga; using namespace icinga;
skipping to change at line 181 skipping to change at line 184
Log(LogInformation, "ApiListener") Log(LogInformation, "ApiListener")
<< "My API identity: " << GetIdentity(); << "My API identity: " << GetIdentity();
UpdateSSLContext(); UpdateSSLContext();
} }
void ApiListener::UpdateSSLContext() void ApiListener::UpdateSSLContext()
{ {
namespace ssl = boost::asio::ssl; namespace ssl = boost::asio::ssl;
std::shared_ptr<ssl::context> context; Shared<ssl::context>::Ptr context;
try { try {
context = MakeAsioSslContext(GetDefaultCertPath(), GetDefaultKeyP ath(), GetDefaultCaPath()); context = MakeAsioSslContext(GetDefaultCertPath(), GetDefaultKeyP ath(), GetDefaultCaPath());
} catch (const std::exception&) { } catch (const std::exception&) {
BOOST_THROW_EXCEPTION(ScriptError("Cannot make SSL context for ce rt path: '" BOOST_THROW_EXCEPTION(ScriptError("Cannot make SSL context for ce rt path: '"
+ GetDefaultCertPath() + "' key path: '" + GetDefaultKeyP ath() + "' ca path: '" + GetDefaultCaPath() + "'.", GetDebugInfo())); + GetDefaultCertPath() + "' key path: '" + GetDefaultKeyP ath() + "' ca path: '" + GetDefaultCaPath() + "'.", GetDebugInfo()));
} }
if (!GetCrlPath().IsEmpty()) { if (!GetCrlPath().IsEmpty()) {
try { try {
skipping to change at line 359 skipping to change at line 362
* @param service The port to listen on. * @param service The port to listen on.
*/ */
bool ApiListener::AddListener(const String& node, const String& service) bool ApiListener::AddListener(const String& node, const String& service)
{ {
namespace asio = boost::asio; namespace asio = boost::asio;
namespace ip = asio::ip; namespace ip = asio::ip;
using ip::tcp; using ip::tcp;
ObjectLock olock(this); ObjectLock olock(this);
auto sslContext (m_SSLContext); if (!m_SSLContext) {
if (!sslContext) {
Log(LogCritical, "ApiListener", "SSL context is required for AddL istener()"); Log(LogCritical, "ApiListener", "SSL context is required for AddL istener()");
return false; return false;
} }
auto& io (IoEngine::Get().GetIoContext()); auto& io (IoEngine::Get().GetIoContext());
auto acceptor (std::make_shared<tcp::acceptor>(io)); auto acceptor (Shared<tcp::acceptor>::Make(io));
try { try {
tcp::resolver resolver (io); tcp::resolver resolver (io);
tcp::resolver::query query (node, service, tcp::resolver::query:: passive); tcp::resolver::query query (node, service, tcp::resolver::query:: passive);
auto result (resolver.resolve(query)); auto result (resolver.resolve(query));
auto current (result.begin()); auto current (result.begin());
for (;;) { for (;;) {
try { try {
skipping to change at line 419 skipping to change at line 420
return false; return false;
} }
acceptor->listen(INT_MAX); acceptor->listen(INT_MAX);
auto localEndpoint (acceptor->local_endpoint()); auto localEndpoint (acceptor->local_endpoint());
Log(LogInformation, "ApiListener") Log(LogInformation, "ApiListener")
<< "Started new listener on '[" << localEndpoint.address() << "]: " << localEndpoint.port() << "'"; << "Started new listener on '[" << localEndpoint.address() << "]: " << localEndpoint.port() << "'";
IoEngine::SpawnCoroutine(io, [this, acceptor, sslContext](asio::yield_con text yc) { ListenerCoroutineProc(yc, acceptor, sslContext); }); IoEngine::SpawnCoroutine(io, [this, acceptor](asio::yield_context yc) { L istenerCoroutineProc(yc, acceptor, m_SSLContext); });
UpdateStatusFile(localEndpoint); UpdateStatusFile(localEndpoint);
return true; return true;
} }
void ApiListener::ListenerCoroutineProc(boost::asio::yield_context yc, const std ::shared_ptr<boost::asio::ip::tcp::acceptor>& server, const std::shared_ptr<boos t::asio::ssl::context>& sslContext) void ApiListener::ListenerCoroutineProc(boost::asio::yield_context yc, const Sha red<boost::asio::ip::tcp::acceptor>::Ptr& server, const Shared<boost::asio::ssl: :context>::Ptr& sslContext)
{ {
namespace asio = boost::asio; namespace asio = boost::asio;
auto& io (IoEngine::Get().GetIoContext()); auto& io (IoEngine::Get().GetIoContext());
for (;;) { for (;;) {
try { try {
auto sslConn (std::make_shared<AsioTlsStream>(io, *sslCon text)); auto sslConn (Shared<AsioTlsStream>::Make(io, *sslContext ));
server->async_accept(sslConn->lowest_layer(), yc); server->async_accept(sslConn->lowest_layer(), yc);
IoEngine::SpawnCoroutine(io, [this, sslConn](asio::yield_ auto strand (Shared<asio::io_context::strand>::Make(io));
context yc) { NewClientHandler(yc, sslConn, String(), RoleServer); });
IoEngine::SpawnCoroutine(*strand, [this, strand, sslConn]
(asio::yield_context yc) { NewClientHandler(yc, strand, sslConn, String(), RoleS
erver); });
} catch (const std::exception& ex) { } catch (const std::exception& ex) {
Log(LogCritical, "ApiListener") Log(LogCritical, "ApiListener")
<< "Cannot accept new connection: " << ex.what(); << "Cannot accept new connection: " << ex.what();
} }
} }
} }
/** /**
* Creates a new JSON-RPC client and connects to the specified endpoint. * Creates a new JSON-RPC client and connects to the specified endpoint.
* *
* @param endpoint The endpoint. * @param endpoint The endpoint.
*/ */
void ApiListener::AddConnection(const Endpoint::Ptr& endpoint) void ApiListener::AddConnection(const Endpoint::Ptr& endpoint)
{ {
namespace asio = boost::asio; namespace asio = boost::asio;
using asio::ip::tcp; using asio::ip::tcp;
auto sslContext (m_SSLContext); if (!m_SSLContext) {
if (!sslContext) {
Log(LogCritical, "ApiListener", "SSL context is required for AddC onnection()"); Log(LogCritical, "ApiListener", "SSL context is required for AddC onnection()");
return; return;
} }
auto& io (IoEngine::Get().GetIoContext()); auto& io (IoEngine::Get().GetIoContext());
auto strand (Shared<asio::io_context::strand>::Make(io));
IoEngine::SpawnCoroutine(io, [this, endpoint, &io, sslContext](asio::yiel d_context yc) { IoEngine::SpawnCoroutine(*strand, [this, strand, endpoint, &io](asio::yie ld_context yc) {
String host = endpoint->GetHost(); String host = endpoint->GetHost();
String port = endpoint->GetPort(); String port = endpoint->GetPort();
Log(LogInformation, "ApiListener") Log(LogInformation, "ApiListener")
<< "Reconnecting to endpoint '" << endpoint->GetName() << "' via host '" << host << "' and port '" << port << "'"; << "Reconnecting to endpoint '" << endpoint->GetName() << "' via host '" << host << "' and port '" << port << "'";
try { try {
auto sslConn (std::make_shared<AsioTlsStream>(io, *sslCon text, endpoint->GetName())); auto sslConn (Shared<AsioTlsStream>::Make(io, *m_SSLConte xt, endpoint->GetName()));
Connect(sslConn->lowest_layer(), host, port, yc); Connect(sslConn->lowest_layer(), host, port, yc);
NewClientHandler(yc, sslConn, endpoint->GetName(), RoleCl ient); NewClientHandler(yc, strand, sslConn, endpoint->GetName() , RoleClient);
endpoint->SetConnecting(false); endpoint->SetConnecting(false);
Log(LogInformation, "ApiListener") Log(LogInformation, "ApiListener")
<< "Finished reconnecting to endpoint '" << endpo int->GetName() << "' via host '" << host << "' and port '" << port << "'"; << "Finished reconnecting to endpoint '" << endpo int->GetName() << "' via host '" << host << "' and port '" << port << "'";
} catch (const std::exception& ex) { } catch (const std::exception& ex) {
endpoint->SetConnecting(false); endpoint->SetConnecting(false);
Log(LogCritical, "ApiListener") Log(LogCritical, "ApiListener")
<< "Cannot connect to host '" << host << "' on po rt '" << port << "': " << ex.what(); << "Cannot connect to host '" << host << "' on po rt '" << port << "': " << ex.what();
} }
}); });
} }
void ApiListener::NewClientHandler(boost::asio::yield_context yc, const std::sha void ApiListener::NewClientHandler(
red_ptr<AsioTlsStream>& client, const String& hostname, ConnectionRole role) boost::asio::yield_context yc, const Shared<boost::asio::io_context::stra
nd>::Ptr& strand,
const Shared<AsioTlsStream>::Ptr& client, const String& hostname, Connect
ionRole role
)
{ {
try { try {
NewClientHandlerInternal(yc, client, hostname, role); NewClientHandlerInternal(yc, strand, client, hostname, role);
} catch (const std::exception& ex) { } catch (const std::exception& ex) {
Log(LogCritical, "ApiListener") Log(LogCritical, "ApiListener")
<< "Exception while handling new API client connection: " << DiagnosticInformation(ex, false); << "Exception while handling new API client connection: " << DiagnosticInformation(ex, false);
Log(LogDebug, "ApiListener") Log(LogDebug, "ApiListener")
<< "Exception while handling new API client connection: " << DiagnosticInformation(ex); << "Exception while handling new API client connection: " << DiagnosticInformation(ex);
} }
} }
/** /**
* Processes a new client connection. * Processes a new client connection.
* *
* @param client The new client. * @param client The new client.
*/ */
void ApiListener::NewClientHandlerInternal(boost::asio::yield_context yc, const void ApiListener::NewClientHandlerInternal(
std::shared_ptr<AsioTlsStream>& client, const String& hostname, ConnectionRole r boost::asio::yield_context yc, const Shared<boost::asio::io_context::stra
ole) nd>::Ptr& strand,
const Shared<AsioTlsStream>::Ptr& client, const String& hostname, Connect
ionRole role
)
{ {
namespace asio = boost::asio; namespace asio = boost::asio;
namespace ssl = asio::ssl; namespace ssl = asio::ssl;
String conninfo; String conninfo;
{ {
std::ostringstream conninfo_; std::ostringstream conninfo_;
if (role == RoleClient) { if (role == RoleClient) {
skipping to change at line 536 skipping to change at line 544
conninfo_ << " [" << endpoint.address() << "]:" << endpoint.port( ); conninfo_ << " [" << endpoint.address() << "]:" << endpoint.port( );
conninfo = conninfo_.str(); conninfo = conninfo_.str();
} }
auto& sslConn (client->next_layer()); auto& sslConn (client->next_layer());
boost::system::error_code ec; boost::system::error_code ec;
sslConn.async_handshake(role == RoleClient ? sslConn.client : sslConn.ser {
ver, yc[ec]); struct DoneHandshake
{
bool Done = false;
};
auto doneHandshake (Shared<DoneHandshake>::Make());
IoEngine::SpawnCoroutine(*strand, [strand, client, doneHandshake]
(asio::yield_context yc) {
namespace sys = boost::system;
{
boost::asio::deadline_timer timer (strand->contex
t());
timer.expires_from_now(boost::posix_time::microse
conds(intmax_t(Configuration::TlsHandshakeTimeout * 1000000)));
sys::error_code ec;
timer.async_wait(yc[ec]);
}
if (!doneHandshake->Done) {
sys::error_code ec;
client->lowest_layer().cancel(ec);
}
});
sslConn.async_handshake(role == RoleClient ? sslConn.client : ssl
Conn.server, yc[ec]);
doneHandshake->Done = true;
}
if (ec) { if (ec) {
// https://github.com/boostorg/beast/issues/915 // https://github.com/boostorg/beast/issues/915
// Google Chrome 73+ seems not close the connection properly, htt ps://stackoverflow.com/questions/56272906/how-to-fix-certificate-unknown-error-f rom-chrome-v73 // Google Chrome 73+ seems not close the connection properly, htt ps://stackoverflow.com/questions/56272906/how-to-fix-certificate-unknown-error-f rom-chrome-v73
if (ec == asio::ssl::error::stream_truncated) { if (ec == asio::ssl::error::stream_truncated) {
Log(LogNotice, "ApiListener") Log(LogNotice, "ApiListener")
<< "TLS stream was truncated, ignoring connection from " << conninfo; << "TLS stream was truncated, ignoring connection from " << conninfo;
return; return;
} }
skipping to change at line 1200 skipping to change at line 1235
if (ts == 0) if (ts == 0)
ts = Utility::GetTime(); ts = Utility::GetTime();
String oldpath = GetApiDir() + "log/current"; String oldpath = GetApiDir() + "log/current";
String newpath = GetApiDir() + "log/" + Convert::ToString(static_cast<int >(ts)+1); String newpath = GetApiDir() + "log/" + Convert::ToString(static_cast<int >(ts)+1);
// If the log is being rotated more than once per second, // If the log is being rotated more than once per second,
// don't overwrite the previous one, but silently deny rotation. // don't overwrite the previous one, but silently deny rotation.
if (!Utility::PathExists(newpath)) { if (!Utility::PathExists(newpath)) {
(void) rename(oldpath.CStr(), newpath.CStr()); try {
Utility::RenameFile(oldpath, newpath);
} catch (const std::exception& ex) {
Log(LogCritical, "ApiListener")
<< "Cannot rotate replay log file from '" << oldp
ath << "' to '"
<< newpath << "': " << ex.what();
}
} }
} }
void ApiListener::LogGlobHandler(std::vector<int>& files, const String& file) void ApiListener::LogGlobHandler(std::vector<int>& files, const String& file)
{ {
String name = Utility::BaseName(file); String name = Utility::BaseName(file);
if (name == "current") if (name == "current")
return; return;
 End of changes. 20 change blocks. 
25 lines changed or deleted 72 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)