Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a dedicated method for disconnecting TLS connections #10005

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions lib/base/netstring.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ size_t NetString::WriteStringToStream(const Stream::Ptr& stream, const String& s
* @exception invalid_argument The input stream is invalid.
* @see https://github.com/PeterScott/netstring-c/blob/master/netstring.c
*/
String NetString::ReadStringFromStream(const Shared<AsioTlsStream>::Ptr& stream,
String NetString::ReadStringFromStream(const AsioTlsStream::Ptr& stream,
ssize_t maxMessageLength)
{
namespace asio = boost::asio;
Expand Down Expand Up @@ -205,7 +205,7 @@ String NetString::ReadStringFromStream(const Shared<AsioTlsStream>::Ptr& stream,
* @exception invalid_argument The input stream is invalid.
* @see https://github.com/PeterScott/netstring-c/blob/master/netstring.c
*/
String NetString::ReadStringFromStream(const Shared<AsioTlsStream>::Ptr& stream,
String NetString::ReadStringFromStream(const AsioTlsStream::Ptr& stream,
boost::asio::yield_context yc, ssize_t maxMessageLength)
{
namespace asio = boost::asio;
Expand Down Expand Up @@ -284,7 +284,7 @@ String NetString::ReadStringFromStream(const Shared<AsioTlsStream>::Ptr& stream,
*
* @return The amount of bytes written.
*/
size_t NetString::WriteStringToStream(const Shared<AsioTlsStream>::Ptr& stream, const String& str)
size_t NetString::WriteStringToStream(const AsioTlsStream::Ptr& stream, const String& str)
{
namespace asio = boost::asio;

Expand All @@ -307,7 +307,7 @@ size_t NetString::WriteStringToStream(const Shared<AsioTlsStream>::Ptr& stream,
*
* @return The amount of bytes written.
*/
size_t NetString::WriteStringToStream(const Shared<AsioTlsStream>::Ptr& stream, const String& str, boost::asio::yield_context yc)
size_t NetString::WriteStringToStream(const AsioTlsStream::Ptr& stream, const String& str, boost::asio::yield_context yc)
{
namespace asio = boost::asio;

Expand Down
8 changes: 4 additions & 4 deletions lib/base/netstring.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ class NetString
public:
static StreamReadStatus ReadStringFromStream(const Stream::Ptr& stream, String *message, StreamReadContext& context,
bool may_wait = false, ssize_t maxMessageLength = -1);
static String ReadStringFromStream(const Shared<AsioTlsStream>::Ptr& stream, ssize_t maxMessageLength = -1);
static String ReadStringFromStream(const Shared<AsioTlsStream>::Ptr& stream,
static String ReadStringFromStream(const AsioTlsStream::Ptr& stream, ssize_t maxMessageLength = -1);
static String ReadStringFromStream(const AsioTlsStream::Ptr& stream,
boost::asio::yield_context yc, ssize_t maxMessageLength = -1);
static size_t WriteStringToStream(const Stream::Ptr& stream, const String& message);
static size_t WriteStringToStream(const Shared<AsioTlsStream>::Ptr& stream, const String& message);
static size_t WriteStringToStream(const Shared<AsioTlsStream>::Ptr& stream, const String& message, boost::asio::yield_context yc);
static size_t WriteStringToStream(const AsioTlsStream::Ptr& stream, const String& message);
static size_t WriteStringToStream(const AsioTlsStream::Ptr& stream, const String& message, boost::asio::yield_context yc);
static void WriteStringToStream(std::ostream& stream, const String& message);

private:
Expand Down
25 changes: 25 additions & 0 deletions lib/base/tlsstream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "base/logger.hpp"
#include "base/configuration.hpp"
#include "base/convert.hpp"
#include "base/io-engine.hpp"
#include <boost/asio/ssl/context.hpp>
#include <boost/asio/ssl/verify_context.hpp>
#include <boost/asio/ssl/verify_mode.hpp>
Expand Down Expand Up @@ -69,3 +70,27 @@ void UnbufferedAsioTlsStream::BeforeHandshake(handshake_type type)
}
#endif /* SSL_CTRL_SET_TLSEXT_HOSTNAME */
}

void AsioTlsStream::ForceDisconnect()
{
boost::system::error_code ec;
lowest_layer().shutdown(lowest_layer_type::shutdown_both, ec);
}

void AsioTlsStream::GracefulDisconnect(boost::asio::io_context::strand strand, boost::asio::yield_context yc)
{
boost::system::error_code ec;

lowest_layer().cancel(ec);

Timeout::Ptr shutdownTimeout(new Timeout(strand.context(), strand, boost::posix_time::seconds(10),
[this, keepAlive = AsioTlsStream::Ptr(this)](boost::asio::yield_context yc) {
boost::system::error_code ec;
lowest_layer().cancel(ec);
}
));
next_layer().async_shutdown(yc[ec]);
shutdownTimeout->Cancel();

ForceDisconnect();
}
16 changes: 13 additions & 3 deletions lib/base/tlsstream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#define TLSSTREAM_H

#include "base/i2-base.hpp"
#include "base/shared.hpp"
#include "base/shared-object.hpp"
#include "base/socket.hpp"
#include "base/stream.hpp"
#include "base/tlsutility.hpp"
Expand Down Expand Up @@ -104,15 +104,25 @@ class UnbufferedAsioTlsStream : public AsioTcpTlsStream
void BeforeHandshake(handshake_type type);
};

class AsioTlsStream : public boost::asio::buffered_stream<UnbufferedAsioTlsStream>
class AsioTlsStream : public SharedObject, public boost::asio::buffered_stream<UnbufferedAsioTlsStream>
{
public:
DECLARE_PTR_TYPEDEFS(AsioTlsStream);

inline
AsioTlsStream(boost::asio::io_context& ioContext, boost::asio::ssl::context& sslContext, const String& hostname = String())
: AsioTlsStream(UnbufferedAsioTlsStreamParams{ioContext, sslContext, hostname})
{
}

static AsioTlsStream::Ptr Make(boost::asio::io_context& ioContext, boost::asio::ssl::context& sslContext, const String& hostname = String())
{
return new AsioTlsStream(ioContext, sslContext, hostname);
}

void ForceDisconnect();
void GracefulDisconnect(boost::asio::io_context::strand strand, boost::asio::yield_context yc);

private:
inline
AsioTlsStream(UnbufferedAsioTlsStreamParams init)
Expand All @@ -122,7 +132,7 @@ class AsioTlsStream : public boost::asio::buffered_stream<UnbufferedAsioTlsStrea
};

typedef boost::asio::buffered_stream<boost::asio::ip::tcp::socket> AsioTcpStream;
typedef std::pair<Shared<AsioTlsStream>::Ptr, Shared<AsioTcpStream>::Ptr> OptionalTlsStream;
typedef std::pair<AsioTlsStream::Ptr, Shared<AsioTcpStream>::Ptr> OptionalTlsStream;

}

Expand Down
6 changes: 3 additions & 3 deletions lib/cli/consolecommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ namespace po = boost::program_options;

static ScriptFrame *l_ScriptFrame;
static Url::Ptr l_Url;
static Shared<AsioTlsStream>::Ptr l_TlsStream;
static AsioTlsStream::Ptr l_TlsStream;
static String l_Session;

REGISTER_CLICOMMAND("console", ConsoleCommand);
Expand Down Expand Up @@ -522,7 +522,7 @@ int ConsoleCommand::RunScriptConsole(ScriptFrame& scriptFrame, const String& con
*
* @returns AsioTlsStream pointer for future HTTP connections.
*/
Shared<AsioTlsStream>::Ptr ConsoleCommand::Connect()
AsioTlsStream::Ptr ConsoleCommand::Connect()
{
Shared<boost::asio::ssl::context>::Ptr sslContext;

Expand All @@ -537,7 +537,7 @@ Shared<AsioTlsStream>::Ptr ConsoleCommand::Connect()
String host = l_Url->GetHost();
String port = l_Url->GetPort();

Shared<AsioTlsStream>::Ptr stream = Shared<AsioTlsStream>::Make(IoEngine::Get().GetIoContext(), *sslContext, host);
AsioTlsStream::Ptr stream = AsioTlsStream::Make(IoEngine::Get().GetIoContext(), *sslContext, host);

try {
icinga::Connect(stream->lowest_layer(), host, port);
Expand Down
2 changes: 1 addition & 1 deletion lib/cli/consolecommand.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class ConsoleCommand final : public CLICommand
mutable std::mutex m_Mutex;
mutable std::condition_variable m_CV;

static Shared<AsioTlsStream>::Ptr Connect();
static AsioTlsStream::Ptr Connect();

static Value ExecuteScript(const String& session, const String& command, bool sandboxed);
static Array::Ptr AutoCompleteScript(const String& session, const String& command, bool sandboxed);
Expand Down
2 changes: 1 addition & 1 deletion lib/icingadb/redisconnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ void RedisConnection::Connect(asio::yield_context& yc)
Log(m_Parent ? LogNotice : LogInformation, "IcingaDB")
<< "Trying to connect to Redis server (async, TLS) on host '" << m_Host << ":" << m_Port << "'";

auto conn (Shared<AsioTlsStream>::Make(m_Strand.context(), *m_TLSContext, m_Host));
auto conn (AsioTlsStream::Make(m_Strand.context(), *m_TLSContext, m_Host));
auto& tlsConn (conn->next_layer());
auto connectTimeout (MakeTimeout(conn));
Defer cancelTimeout ([&connectTimeout]() { connectTimeout->Cancel(); });
Expand Down
2 changes: 1 addition & 1 deletion lib/icingadb/redisconnection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ namespace icinga
boost::asio::io_context::strand m_Strand;
Shared<TcpConn>::Ptr m_TcpConn;
Shared<UnixConn>::Ptr m_UnixConn;
Shared<AsioTlsStream>::Ptr m_TlsConn;
AsioTlsStream::Ptr m_TlsConn;
Atomic<bool> m_Connecting, m_Connected, m_Started;

struct {
Expand Down
25 changes: 11 additions & 14 deletions lib/methods/ifwapichecktask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,9 @@ static const char* GetUnderstandableError(const std::exception& ex)
}

static void DoIfwNetIo(
boost::asio::yield_context yc, const Checkable::Ptr& checkable, const Array::Ptr& cmdLine,
boost::asio::yield_context yc, boost::asio::io_context::strand& strand, const Checkable::Ptr& checkable, const Array::Ptr& cmdLine,
const CheckResult::Ptr& cr, const String& psCommand, const String& psHost, const String& san, const String& psPort,
AsioTlsStream& conn, boost::beast::http::request<boost::beast::http::string_body>& req, double start
const AsioTlsStream::Ptr& conn, boost::beast::http::request<boost::beast::http::string_body>& req, double start
)
{
namespace http = boost::beast::http;
Expand All @@ -105,7 +105,7 @@ static void DoIfwNetIo(
http::response<http::string_body> resp;

try {
Connect(conn.lowest_layer(), psHost, psPort, yc);
Connect(conn->lowest_layer(), psHost, psPort, yc);
} catch (const std::exception& ex) {
ReportIfwCheckResult(
yc, checkable, cmdLine, cr,
Expand All @@ -115,10 +115,10 @@ static void DoIfwNetIo(
return;
}

auto& sslConn (conn.next_layer());
auto& sslConn (conn->next_layer());

try {
sslConn.async_handshake(conn.next_layer().client, yc);
sslConn.async_handshake(conn->next_layer().client, yc);
} catch (const std::exception& ex) {
ReportIfwCheckResult(
yc, checkable, cmdLine, cr,
Expand Down Expand Up @@ -148,8 +148,8 @@ static void DoIfwNetIo(
}

try {
http::async_write(conn, req, yc);
conn.async_flush(yc);
http::async_write(*conn, req, yc);
conn->async_flush(yc);
} catch (const std::exception& ex) {
ReportIfwCheckResult(
yc, checkable, cmdLine, cr,
Expand All @@ -160,7 +160,7 @@ static void DoIfwNetIo(
}

try {
http::async_read(conn, buf, resp, yc);
http::async_read(*conn, buf, resp, yc);
} catch (const std::exception& ex) {
ReportIfwCheckResult(
yc, checkable, cmdLine, cr,
Expand All @@ -172,10 +172,7 @@ static void DoIfwNetIo(

double end = Utility::GetTime();

{
boost::system::error_code ec;
sslConn.async_shutdown(yc[ec]);
}
conn->GracefulDisconnect(strand, yc);

CpuBoundWork cbw (yc);
Value jsonRoot;
Expand Down Expand Up @@ -507,7 +504,7 @@ void IfwApiCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes
return;
}

auto conn (Shared<AsioTlsStream>::Make(io, *ctx, expectedSan));
auto conn (AsioTlsStream::Make(io, *ctx, expectedSan));

IoEngine::SpawnCoroutine(
*strand,
Expand All @@ -525,7 +522,7 @@ void IfwApiCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes

Defer cancelTimeout ([&timeout]() { timeout->Cancel(); });

DoIfwNetIo(yc, checkable, cmdLine, cr, psCommand, psHost, expectedSan, psPort, *conn, *req, start);
DoIfwNetIo(yc, *strand, checkable, cmdLine, cr, psCommand, psHost, expectedSan, psPort, conn, *req, start);
}
);
}
2 changes: 1 addition & 1 deletion lib/perfdata/elasticsearchwriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,7 @@ OptionalTlsStream ElasticsearchWriter::Connect()
throw;
}

stream.first = Shared<AsioTlsStream>::Make(IoEngine::Get().GetIoContext(), *sslContext, GetHost());
stream.first = AsioTlsStream::Make(IoEngine::Get().GetIoContext(), *sslContext, GetHost());

} else {
stream.second = Shared<AsioTcpStream>::Make(IoEngine::Get().GetIoContext());
Expand Down
2 changes: 1 addition & 1 deletion lib/perfdata/gelfwriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ void GelfWriter::ReconnectInternal()
throw;
}

m_Stream.first = Shared<AsioTlsStream>::Make(IoEngine::Get().GetIoContext(), *sslContext, GetHost());
m_Stream.first = AsioTlsStream::Make(IoEngine::Get().GetIoContext(), *sslContext, GetHost());

} else {
m_Stream.second = Shared<AsioTcpStream>::Make(IoEngine::Get().GetIoContext());
Expand Down
2 changes: 1 addition & 1 deletion lib/perfdata/influxdbcommonwriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ OptionalTlsStream InfluxdbCommonWriter::Connect()
throw;
}

stream.first = Shared<AsioTlsStream>::Make(IoEngine::Get().GetIoContext(), *sslContext, GetHost());
stream.first = AsioTlsStream::Make(IoEngine::Get().GetIoContext(), *sslContext, GetHost());

} else {
stream.second = Shared<AsioTcpStream>::Make(IoEngine::Get().GetIoContext());
Expand Down
15 changes: 6 additions & 9 deletions lib/remote/apilistener.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,7 @@ void ApiListener::ListenerCoroutineProc(boost::asio::yield_context yc, const Sha
}

boost::shared_lock<decltype(m_SSLContextMutex)> lock (m_SSLContextMutex);
auto sslConn (Shared<AsioTlsStream>::Make(io, *m_SSLContext));
auto sslConn (AsioTlsStream::Make(io, *m_SSLContext));

lock.unlock();
sslConn->lowest_layer() = std::move(socket);
Expand Down Expand Up @@ -580,7 +580,7 @@ void ApiListener::AddConnection(const Endpoint::Ptr& endpoint)

try {
boost::shared_lock<decltype(m_SSLContextMutex)> lock (m_SSLContextMutex);
auto sslConn (Shared<AsioTlsStream>::Make(io, *m_SSLContext, endpoint->GetName()));
auto sslConn (AsioTlsStream::Make(io, *m_SSLContext, endpoint->GetName()));

lock.unlock();

Expand Down Expand Up @@ -614,7 +614,7 @@ void ApiListener::AddConnection(const Endpoint::Ptr& endpoint)

void ApiListener::NewClientHandler(
boost::asio::yield_context yc, const Shared<boost::asio::io_context::strand>::Ptr& strand,
const Shared<AsioTlsStream>::Ptr& client, const String& hostname, ConnectionRole role
const AsioTlsStream::Ptr& client, const String& hostname, ConnectionRole role
)
{
try {
Expand Down Expand Up @@ -653,7 +653,7 @@ static const auto l_MyCapabilities (
*/
void ApiListener::NewClientHandlerInternal(
boost::asio::yield_context yc, const Shared<boost::asio::io_context::strand>::Ptr& strand,
const Shared<AsioTlsStream>::Ptr& client, const String& hostname, ConnectionRole role
const AsioTlsStream::Ptr& client, const String& hostname, ConnectionRole role
)
{
namespace asio = boost::asio;
Expand Down Expand Up @@ -713,12 +713,9 @@ void ApiListener::NewClientHandlerInternal(

bool willBeShutDown = false;

Defer shutDownIfNeeded ([&sslConn, &willBeShutDown, &yc]() {
Defer shutDownIfNeeded ([&client, &strand, &willBeShutDown, &yc]() {
if (!willBeShutDown) {
// Ignore the error, but do not throw an exception being swallowed at all cost.
// https://github.com/Icinga/icinga2/issues/7351
boost::system::error_code ec;
sslConn.async_shutdown(yc[ec]);
client->GracefulDisconnect(*strand, yc);
}
});

Expand Down
4 changes: 2 additions & 2 deletions lib/remote/apilistener.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,11 +191,11 @@ class ApiListener final : public ObjectImpl<ApiListener>

void NewClientHandler(
boost::asio::yield_context yc, const Shared<boost::asio::io_context::strand>::Ptr& strand,
const Shared<AsioTlsStream>::Ptr& client, const String& hostname, ConnectionRole role
const AsioTlsStream::Ptr& client, const String& hostname, ConnectionRole role
);
void NewClientHandlerInternal(
boost::asio::yield_context yc, const Shared<boost::asio::io_context::strand>::Ptr& strand,
const Shared<AsioTlsStream>::Ptr& client, const String& hostname, ConnectionRole role
const AsioTlsStream::Ptr& client, const String& hostname, ConnectionRole role
);
void ListenerCoroutineProc(boost::asio::yield_context yc, const Shared<boost::asio::ip::tcp::acceptor>::Ptr& server);

Expand Down
8 changes: 3 additions & 5 deletions lib/remote/httpserverconnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ using namespace icinga;

auto const l_ServerHeader ("Icinga/" + Application::GetAppVersion());

HttpServerConnection::HttpServerConnection(const String& identity, bool authenticated, const Shared<AsioTlsStream>::Ptr& stream)
HttpServerConnection::HttpServerConnection(const String& identity, bool authenticated, const AsioTlsStream::Ptr& stream)
: HttpServerConnection(identity, authenticated, stream, IoEngine::Get().GetIoContext())
{
}

HttpServerConnection::HttpServerConnection(const String& identity, bool authenticated, const Shared<AsioTlsStream>::Ptr& stream, boost::asio::io_context& io)
HttpServerConnection::HttpServerConnection(const String& identity, bool authenticated, const AsioTlsStream::Ptr& stream, boost::asio::io_context& io)
: m_Stream(stream), m_Seen(Utility::GetTime()), m_IoStrand(io), m_ShuttingDown(false), m_HasStartedStreaming(false),
m_CheckLivenessTimer(io)
{
Expand Down Expand Up @@ -95,9 +95,7 @@ void HttpServerConnection::Disconnect()

m_Stream->lowest_layer().cancel(ec);

m_Stream->next_layer().async_shutdown(yc[ec]);

m_Stream->lowest_layer().shutdown(m_Stream->lowest_layer().shutdown_both, ec);
m_Stream->GracefulDisconnect(m_IoStrand, yc);

auto listener (ApiListener::GetInstance());

Expand Down
Loading
Loading