icinga2/lib/remote
Julian Brost 3302c9b0a8 Fix that NewClientHandler() could hang indefinitely, preventing new connection attempts
There is some race condition when the `async_write()`/`async_flush()` operation
for the `icinga::Hello` message fails (connection reset by peer for example)
around the same time the connect timeout fires and calls `cancel()` on the
stream, the following call to `async_shutdown()` may block indefinitely. If
that happens, the endpoint remains in the connecting state and no new
connection attemps are initiated.

This commit fixes the issue by removing the `Defer` containing the
`async_shutdown()`. The purpose of `async_shutdown()` is to signal a clean
termination of the connection to the peer, which really isn't something that
makes sense to to in a `Defer` block that is also executed in case of errors.
For the one situation where doing a clean TLS shutdown makes some sense
(closing anonymous client connections), a call to GracefulShutdown() is added
to that specific code path.

A large part of the change is just changing the indentation of the code, given
that a now unnecessary `try`/`catch` block is removed.

The following Go code creates a TLS server that can be used to demonstrate the
issue. Note that given that a race condition is involved, this is not reliable
and the sleep duration may need some fine-tuning. For this to work,
`ApiListener.tls_handshake_timeout` needs to be set to a large-enough value
like 60s to disable the timeout for `async_handshake()` itself so that the
overall connect timeout is the one that fires. However, changing the timeout is
not a prerequisite for the problem, it just makes it easier to reproduce. The
error can also happen with the default timeouts if the TCP connect takes long
enough so that the handshake is started late enough that its timeout expires
after the connect timeout.

    package main

    import (
        "crypto/tls"
        "log"
        "net"
        "time"
    )

    func main() {
        cert, err := tls.LoadX509KeyPair("bad-agent.crt", "bad-agent.key")
        if err != nil {
            panic(err)
        }

        listener, err := tls.Listen("tcp", ":1337", &tls.Config{
            Certificates: []tls.Certificate{cert},
        })
        if err != nil {
            panic(err)
        }

        log.Println("Listening on", listener.Addr())

        for {
            conn, err := listener.Accept()
            if err != nil {
                panic(err)
            }

            go handle(conn.(*tls.Conn))
        }
    }

    func handle(conn *tls.Conn) {
        addr := conn.RemoteAddr().String()
        log.Println(addr, "new connection")

        time.Sleep(15*time.Second - 10*time.Millisecond)

        log.Println(addr, "SetLinger(0)", conn.NetConn().(*net.TCPConn).SetLinger(0))
        log.Println(addr, "Handshake()", conn.Handshake())
        log.Println(addr, "conn.NetConn().Close()", conn.NetConn().Close())
    }

With additional logging in the `catch` block for `boost::system::system_error`
and `Defer shutdownSslConn` (both removed by this commit), this showed the
following. Note that in particular, `async_shutdown()` never returned,
indicating that it hangs in there.

    [2026-04-24 17:32:56 +0200] information/ApiListener: Reconnecting to endpoint 'bad-agent' via host 'host.docker.internal' and port '1337'
    [2026-04-24 17:33:11 +0200] critical/ApiListener: Timeout while reconnecting to endpoint 'bad-agent' via host 'host.docker.internal' and port '1337', cancelling attempt
    [2026-04-24 17:33:11 +0200] information/ApiListener: New client connection for identity 'bad-agent' to [172.17.0.1]:1337
    [2026-04-24 17:33:12 +0200] information/ApiListener: rethrowing for bad-agent: Error: Connection reset by peer [system:104 at /usr/include/boost/asio/detail/reactive_socket_send_op.hpp:137 in function 'do_complete']
    [2026-04-24 17:33:12 +0200] information/ApiListener: doing async_shutdown for bad-agent
2026-05-06 09:54:21 +02:00
..
actionshandler.cpp Merge pull request #10716 from Icinga/drop-thread-local-variable-apiuser 2026-02-13 14:43:36 +01:00
actionshandler.hpp Remove AuthenticatedApiUser thread-local variable & pass it as param instead 2026-02-11 11:39:57 +01:00
apiaction.cpp Remove AuthenticatedApiUser thread-local variable & pass it as param instead 2026-02-11 11:39:57 +01:00
apiaction.hpp Remove AuthenticatedApiUser thread-local variable & pass it as param instead 2026-02-11 11:39:57 +01:00
apifunction.cpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
apifunction.hpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
apilistener-authority.cpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
apilistener-configsync.cpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
apilistener-filesync.cpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
apilistener.cpp Fix that NewClientHandler() could hang indefinitely, preventing new connection attempts 2026-05-06 09:54:21 +02:00
apilistener.hpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
apilistener.ti Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
apiuser.cpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
apiuser.hpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
apiuser.ti Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
CMakeLists.txt Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
configfileshandler.cpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
configfileshandler.hpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
configobjectslock.cpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
configobjectslock.hpp HTTP: stream responses where appropriate 2026-02-11 09:47:39 +01:00
configobjectutility.cpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
configobjectutility.hpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
configpackageshandler.cpp HTTP: stream responses where appropriate 2026-02-11 09:47:39 +01:00
configpackageshandler.hpp HTTP: stream responses where appropriate 2026-02-11 09:47:39 +01:00
configpackageutility.cpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
configpackageutility.hpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
configstageshandler.cpp HTTP: stream responses where appropriate 2026-02-11 09:47:39 +01:00
configstageshandler.hpp HTTP: stream responses where appropriate 2026-02-11 09:47:39 +01:00
consolehandler.cpp /v1/console: prevent concurrent use of the same session by multiple requests 2026-03-03 11:32:39 +01:00
consolehandler.hpp /v1/console: prevent concurrent use of the same session by multiple requests 2026-03-03 11:32:39 +01:00
createobjecthandler.cpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
createobjecthandler.hpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
deleteobjecthandler.cpp HTTP: stream responses where appropriate 2026-02-11 09:47:39 +01:00
deleteobjecthandler.hpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
endpoint.cpp Endpoint: warn if endpoint name exceeds 64 characters 2026-03-26 13:58:57 +01:00
endpoint.hpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
endpoint.ti Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
eventqueue.cpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
eventqueue.hpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
eventshandler.cpp OutgoingHttpMessage#Flush(): release CpuBoundWork slot 2026-03-19 14:51:19 +01:00
eventshandler.hpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
filterutility.cpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
filterutility.hpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
httphandler.cpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
httphandler.hpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
httpmessage.cpp Add common OTel type/lib 2026-04-01 12:18:21 +02:00
httpmessage.hpp Add common OTel type/lib 2026-04-01 12:18:21 +02:00
httpserverconnection.cpp OutgoingHttpMessage: don't use shared_ptr for m_CpuBoundWork 2026-03-26 11:47:45 +01:00
httpserverconnection.hpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
httputility.cpp HTTP: stream responses where appropriate 2026-02-11 09:47:39 +01:00
httputility.hpp HTTP: stream responses where appropriate 2026-02-11 09:47:39 +01:00
i2-remote.hpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
infohandler.cpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
infohandler.hpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
jsonrpc.cpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
jsonrpc.hpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
jsonrpcconnection-heartbeat.cpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
jsonrpcconnection-pki.cpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
jsonrpcconnection.cpp [Refactor] CpuBoundWork#CpuBoundWork(): require an io_context::strand 2026-03-19 14:53:29 +01:00
jsonrpcconnection.hpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
mallocinfohandler.cpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
mallocinfohandler.hpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
messageorigin.cpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
messageorigin.hpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
modifyobjecthandler.cpp HTTP: stream responses where appropriate 2026-02-11 09:47:39 +01:00
modifyobjecthandler.hpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
objectqueryhandler.cpp HTTP: stream responses where appropriate 2026-02-11 09:47:39 +01:00
objectqueryhandler.hpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
pkiutility.cpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
pkiutility.hpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
statushandler.cpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
statushandler.hpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
templatequeryhandler.cpp HTTP: stream responses where appropriate 2026-02-11 09:47:39 +01:00
templatequeryhandler.hpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
typequeryhandler.cpp HTTP: stream responses where appropriate 2026-02-11 09:47:39 +01:00
typequeryhandler.hpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
url-characters.hpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
url.cpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
url.hpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
variablequeryhandler.cpp HTTP: stream responses where appropriate 2026-02-11 09:47:39 +01:00
variablequeryhandler.hpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
zone.cpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
zone.hpp Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00
zone.ti Replace all existing copyright headers with SPDX headers 2026-02-04 14:00:05 +01:00