Commit 6d817e7d authored by jan.koester's avatar jan.koester
Browse files

test

parent 62db25f9
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@

#include <cstring>
#include <vector>
#include <chrono>

#include "exception.h"
#include "socket.h"
@@ -123,10 +124,17 @@ void ssl::connect(const std::string& addr, int port, bool nonblock) {
    _tls.queueClientHello();
    _tls.hs_state = tls::HsState::CLI_FLUSH_CH;

    // For blocking connections, drive the handshake to completion.
    // For blocking connections, drive the handshake to completion
    // with a timeout to prevent indefinite hangs on dead peers.
    // For non-blocking, the caller (e.g. epoll event loop) will drive it.
    if (!nonblock) {
        auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(15);
        while (!_tls.getHandshakeDone()) {
            if (std::chrono::steady_clock::now() >= deadline) {
                NetException e;
                e[NetException::Error] << "ssl::connect: TLS handshake timeout";
                throw e;
            }
            // Flush any pending writes first
            while (_tls.hasPendingWrite()) {
                _tls.flush_out();
+51 −13
Original line number Diff line number Diff line
@@ -323,28 +323,66 @@ void netplus::tcp::connect(const std::string& addr, int port, bool nonblock)
        }

        // -------------------------------------------------------
        // 3) connect() - use WSAConnect for IOCP socket compatibility
        // 3) connect() — for blocking sockets use non-blocking
        //    connect + select with timeout to prevent indefinite
        //    hangs when the remote end is unresponsive.
        // -------------------------------------------------------
        if (::WSAConnect(_Socket, rp->ai_addr, (int)rp->ai_addrlen, nullptr, nullptr, nullptr, nullptr) == 0) {
        if (!nonblock) {
            // Temporarily set non-blocking for connect with timeout
            u_long nbMode = 1;
            ::ioctlsocket(_Socket, FIONBIO, &nbMode);
        }

        int ret = ::WSAConnect(_Socket, rp->ai_addr, (int)rp->ai_addrlen, nullptr, nullptr, nullptr, nullptr);
        if (ret == 0) {
            // connected immediately
            if (!nonblock) {
                u_long bMode = 0;
                ::ioctlsocket(_Socket, FIONBIO, &bMode);
            }
            setAddrFromAI(rp);

            ::freeaddrinfo(result);
            return;
        }

        // -------------------------------------------------------
        // 4) nonblocking in progress
        // -------------------------------------------------------
        int err = ::WSAGetLastError();
        if (nonblock && (err == WSAEWOULDBLOCK || err == WSAEINPROGRESS)) {
        if (err == WSAEWOULDBLOCK || err == WSAEINPROGRESS) {
            if (nonblock) {
                // Caller wants non-blocking — let them drive completion
                setAddrFromAI(rp);

                ::freeaddrinfo(result);

                NetException n;
                n[NetException::Note] << "tcp::connect: WSAEWOULDBLOCK";
            throw n; // caller waits for completion
                throw n;
            }

            // Blocking mode: wait for connect with 10s timeout
            fd_set wset, eset;
            FD_ZERO(&wset); FD_SET(_Socket, &wset);
            FD_ZERO(&eset); FD_SET(_Socket, &eset);
            timeval tv;
            tv.tv_sec = 10;
            tv.tv_usec = 0;

            int sr = ::select(0, nullptr, &wset, &eset, &tv);
            if (sr > 0 && FD_ISSET(_Socket, &wset) && !FD_ISSET(_Socket, &eset)) {
                // Check for actual connection success
                int optval = 0;
                int optlen = sizeof(optval);
                ::getsockopt(_Socket, SOL_SOCKET, SO_ERROR, (char*)&optval, &optlen);
                if (optval == 0) {
                    // Restore blocking mode
                    u_long bMode = 0;
                    ::ioctlsocket(_Socket, FIONBIO, &bMode);
                    setAddrFromAI(rp);
                    ::freeaddrinfo(result);
                    return;
                }
            }
            // Timeout or error — try next address
            ::closesocket(_Socket);
            _Socket = INVALID_SOCKET;
            continue;
        }

        // -------------------------------------------------------