Loading src/ssl.cpp +9 −1 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include <cstring> #include <vector> #include <chrono> #include "exception.h" #include "socket.h" Loading Loading @@ -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(); Loading src/windows/tcp.cpp +51 −13 Original line number Diff line number Diff line Loading @@ -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; } // ------------------------------------------------------- Loading Loading
src/ssl.cpp +9 −1 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include <cstring> #include <vector> #include <chrono> #include "exception.h" #include "socket.h" Loading Loading @@ -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(); Loading
src/windows/tcp.cpp +51 −13 Original line number Diff line number Diff line Loading @@ -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; } // ------------------------------------------------------- Loading