-
Notifications
You must be signed in to change notification settings - Fork 578
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
base: master
Are you sure you want to change the base?
Conversation
By now, I'm pretty sure the answer is yes. Evidence: Take two connected Icinga 2 nodes and break individual connections by dropping the packets specific to that connection in a firewall. Both nodes will detect that no messages were received and reconnect, however, the old connection remains in an established state:
That implies that there's probably a resource leak in that scenario (until the kernel decides that the connection is actually dead and returns an error for the socket operations). Unverified theory of what might happen: icinga2/lib/remote/jsonrpcconnection.cpp Line 226 in 9a8620d
Which waits for icinga2/lib/remote/jsonrpcconnection.cpp Lines 112 to 120 in 9a8620d
|
Thing to consider
|
e90acc5
to
3a72a6f
Compare
I resolved conflicts and started implementing |
All usages of `AsioTlsStream` were already using `Shared<AsioTlsStream>` to keep a reference-counted instance. This commit moves the reference counting to `AsioTlsStream` itself by inheriting from `SharedObject`. This will allow to implement methods making use of the fact that these objects are reference-counted. The changes outside of `lib/base/tlsstream.hpp` are merely replacing `Shared<AsioTlsStream>::Ptr` with `AsioTlsStream::Ptr` everywhere.
Calling `AsioTlsStream::async_shutdown()` performs a TLS shutdown which exchanges messages (that's why it takes a `yield_context`) and thus has the potential to block the coroutine. Therefore, it should be protected with a timeout. As `async_shutdown()` doesn't simply take a timeout, this has to be implemented using a timer. So far, these timers are scattered throughout the codebase with some places missing them entirely. This commit adds helper functions to properly shutdown a TLS connection with a single function call.
This new helper functions allows deduplicating the timeout handling for `async_shutdown()`.
This new helper function has proper timeout handling which was missing here.
The reason for introducing AsioTlsStream::GracefulDisconnect() was to handle the TLS shutdown properly with a timeout since it involves a timeout. However, the implementation of this timeout involves spwaning coroutines which are redundant in some cases. This commit adds comments to the remaining calls of async_shutdown() stating why calling it is safe in these places.
3a72a6f
to
9d67c26
Compare
While continuing that work, I figured that this might become a bigger rework of This PR on it's own should already be enough of an improvement on its own, after all it even fixes a problem in the HTTP connection handling.
In that regard, I figured that adding comments to these calls why they are fine is good enough, especially when compared that was needed just to add a redundant timeout and spawn a pointless coroutine (e90acc5). I'm leaving the PR in a draft state for the moment because I still want to answer a few detail questions regarding the two new disconnect methods (I removed a |
Properly closing a TLS connection involves sending some shutdown messages so that both ends know that the connection wasn't truncated maliciously. Exchanging those messages can stall for a long time if the underlying TCP connection is broken. The HTTP connection handling was missing any kind of timeout for the TLS shutdown so that dead connections could hang around for a long time.
This PR introduces two new methods on
AsioTlsStream
, namelyForceDisconnect()
which just wraps the call for closing the TCP connection andGracefulShutdown()
which performs the TLS shutdown with a timeout similar to it was done inJsonRpcConnection::Disconnect()
before.As the lambda passed to
Timeout
has to keep the connection object alive,AsioTlsStream
is changed to inherit fromSharedObject
, adding reference counting to it directly. Previously, it was already created asShared<AsioTlsStream>
everywhere. Thus, a good part of the first commit is changing that type across multiple files.fixes #9986