Loading src/posix/udp.cpp +19 −0 Original line number Diff line number Diff line Loading @@ -198,6 +198,25 @@ size_t udp::sendData(buffer& data, int flags) { return (size_t)s; } size_t udp::sendTo(buffer& data, int flags) { const char* p = data.ptr ? data.data.ptr : data.data.buf; ssize_t s = ::sendto(_Socket, p, data.size, flags, reinterpret_cast<const sockaddr*>(&_Addr), _AddrLen); if (s < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) { NetException e; e[NetException::Note] << "udp::sendTo would block"; throw e; } NetException e; e[NetException::Error] << "udp::sendTo failed: " << strerror(errno); throw e; } return (size_t)s; } size_t udp::recvData(buffer& data, int flags) { sockaddr_storage peer{}; socklen_t peerLen = sizeof(peer); Loading src/quic.cpp +27 −15 Original line number Diff line number Diff line Loading @@ -204,7 +204,7 @@ void quic::generateConnectionId(std::vector<uint8_t>& cid, size_t len) { } // ============================================================================ // Helper: Send packet to peer (uses sendto with stored peer address) // Helper: Send packet to peer (uses udp class methods) // ============================================================================ ssize_t quic::sendPacket(const uint8_t* data, size_t len) { Loading @@ -212,21 +212,26 @@ ssize_t quic::sendPacket(const uint8_t* data, size_t len) { return -1; } // Use sendto for child connections (shared unconnected parent socket), // send() for everything else (client sockets that called connect()). // FreeBSD returns EISCONN if sendto() is used on a connected socket. ssize_t sent; buffer send_buf(reinterpret_cast<const char*>(data), len); try { size_t sent; if (_parent != nullptr) { sent = ::sendto(_Socket, reinterpret_cast<const char*>(data), len, MSG_DONTWAIT, reinterpret_cast<const sockaddr*>(&_Addr), _AddrLen); // Child connection: shared unconnected parent socket, send to stored peer address sent = udp::sendTo(send_buf, MSG_DONTWAIT); } else { sent = ::send(_Socket, reinterpret_cast<const char*>(data), len, MSG_DONTWAIT); // Client connection: connected socket sent = udp::sendData(send_buf, MSG_DONTWAIT); } if (sent > 0) { _last_activity = std::chrono::steady_clock::now(); } return sent; return static_cast<ssize_t>(sent); } catch (NetException&) { // EAGAIN/EWOULDBLOCK or other send failure return -1; } } // ============================================================================ Loading Loading @@ -2353,6 +2358,8 @@ void quic::completeHandshake() { // Receive and process packets until handshake is complete or timeout const auto start = std::chrono::steady_clock::now(); const auto timeout = std::chrono::milliseconds(1500); int recv_attempts = 0; int recv_got = 0; while (!_handshake_complete) { // Bail out if the connection was closed while we were waiting Loading @@ -2365,8 +2372,11 @@ void quic::completeHandshake() { try { buffer recv_buf_wrapper(65535); recv_attempts++; size_t recv_len = udp::recvData(recv_buf_wrapper, MSG_DONTWAIT); if (recv_len > 0) { recv_got++; std::cerr << "[QUIC-client] recv " << recv_len << " bytes (attempt " << recv_attempts << ")" << std::endl; processIncomingPacket(reinterpret_cast<const uint8_t*>(recv_buf_wrapper.data.buf), recv_len); } Loading @@ -2381,6 +2391,8 @@ void quic::completeHandshake() { } if (std::chrono::steady_clock::now() - start > timeout) { std::cerr << "[QUIC-client] handshake timeout: " << recv_attempts << " attempts, " << recv_got << " packets received, fd=" << _Socket << std::endl; NetException e; e[NetException::Error] << "quic::completeHandshake: handshake timed out"; throw e; Loading src/socket.h +3 −0 Original line number Diff line number Diff line Loading @@ -324,6 +324,9 @@ namespace netplus { size_t sendData(buffer& data, int flags = 0) override; size_t recvData(buffer& data, int flags = 0) override; // Send to stored _Addr destination (for unconnected sockets) size_t sendTo(buffer& data, int flags = 0); void connect(const std::string& addr, int port, bool nonblock = false) override; void getAddress(std::string& addr) override; Loading src/windows/udp.cpp +20 −0 Original line number Diff line number Diff line Loading @@ -163,6 +163,26 @@ size_t udp::sendData(buffer& data, int flags) { return sendlen; } size_t udp::sendTo(buffer& data, int flags) { const char* p = data.data.buf; int s = ::sendto(_Socket, p, (int)data.size, flags, reinterpret_cast<const sockaddr*>(&_Addr), _AddrLen); if (s == SOCKET_ERROR) { int err = ::WSAGetLastError(); if (err == WSAEWOULDBLOCK) { NetException e; e[NetException::Note] << "udp::sendTo would block"; throw e; } NetException e; e[NetException::Error] << "udp::sendTo WSASendTo failed: " << err; throw e; } return (size_t)s; } size_t udp::recvData(buffer& data, int flags) { if (_ReadBuffer && _ReadBuffer->overlapped.InternalHigh > 0) { size_t r = (size_t)_ReadBuffer->overlapped.InternalHigh; Loading Loading
src/posix/udp.cpp +19 −0 Original line number Diff line number Diff line Loading @@ -198,6 +198,25 @@ size_t udp::sendData(buffer& data, int flags) { return (size_t)s; } size_t udp::sendTo(buffer& data, int flags) { const char* p = data.ptr ? data.data.ptr : data.data.buf; ssize_t s = ::sendto(_Socket, p, data.size, flags, reinterpret_cast<const sockaddr*>(&_Addr), _AddrLen); if (s < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) { NetException e; e[NetException::Note] << "udp::sendTo would block"; throw e; } NetException e; e[NetException::Error] << "udp::sendTo failed: " << strerror(errno); throw e; } return (size_t)s; } size_t udp::recvData(buffer& data, int flags) { sockaddr_storage peer{}; socklen_t peerLen = sizeof(peer); Loading
src/quic.cpp +27 −15 Original line number Diff line number Diff line Loading @@ -204,7 +204,7 @@ void quic::generateConnectionId(std::vector<uint8_t>& cid, size_t len) { } // ============================================================================ // Helper: Send packet to peer (uses sendto with stored peer address) // Helper: Send packet to peer (uses udp class methods) // ============================================================================ ssize_t quic::sendPacket(const uint8_t* data, size_t len) { Loading @@ -212,21 +212,26 @@ ssize_t quic::sendPacket(const uint8_t* data, size_t len) { return -1; } // Use sendto for child connections (shared unconnected parent socket), // send() for everything else (client sockets that called connect()). // FreeBSD returns EISCONN if sendto() is used on a connected socket. ssize_t sent; buffer send_buf(reinterpret_cast<const char*>(data), len); try { size_t sent; if (_parent != nullptr) { sent = ::sendto(_Socket, reinterpret_cast<const char*>(data), len, MSG_DONTWAIT, reinterpret_cast<const sockaddr*>(&_Addr), _AddrLen); // Child connection: shared unconnected parent socket, send to stored peer address sent = udp::sendTo(send_buf, MSG_DONTWAIT); } else { sent = ::send(_Socket, reinterpret_cast<const char*>(data), len, MSG_DONTWAIT); // Client connection: connected socket sent = udp::sendData(send_buf, MSG_DONTWAIT); } if (sent > 0) { _last_activity = std::chrono::steady_clock::now(); } return sent; return static_cast<ssize_t>(sent); } catch (NetException&) { // EAGAIN/EWOULDBLOCK or other send failure return -1; } } // ============================================================================ Loading Loading @@ -2353,6 +2358,8 @@ void quic::completeHandshake() { // Receive and process packets until handshake is complete or timeout const auto start = std::chrono::steady_clock::now(); const auto timeout = std::chrono::milliseconds(1500); int recv_attempts = 0; int recv_got = 0; while (!_handshake_complete) { // Bail out if the connection was closed while we were waiting Loading @@ -2365,8 +2372,11 @@ void quic::completeHandshake() { try { buffer recv_buf_wrapper(65535); recv_attempts++; size_t recv_len = udp::recvData(recv_buf_wrapper, MSG_DONTWAIT); if (recv_len > 0) { recv_got++; std::cerr << "[QUIC-client] recv " << recv_len << " bytes (attempt " << recv_attempts << ")" << std::endl; processIncomingPacket(reinterpret_cast<const uint8_t*>(recv_buf_wrapper.data.buf), recv_len); } Loading @@ -2381,6 +2391,8 @@ void quic::completeHandshake() { } if (std::chrono::steady_clock::now() - start > timeout) { std::cerr << "[QUIC-client] handshake timeout: " << recv_attempts << " attempts, " << recv_got << " packets received, fd=" << _Socket << std::endl; NetException e; e[NetException::Error] << "quic::completeHandshake: handshake timed out"; throw e; Loading
src/socket.h +3 −0 Original line number Diff line number Diff line Loading @@ -324,6 +324,9 @@ namespace netplus { size_t sendData(buffer& data, int flags = 0) override; size_t recvData(buffer& data, int flags = 0) override; // Send to stored _Addr destination (for unconnected sockets) size_t sendTo(buffer& data, int flags = 0); void connect(const std::string& addr, int port, bool nonblock = false) override; void getAddress(std::string& addr) override; Loading
src/windows/udp.cpp +20 −0 Original line number Diff line number Diff line Loading @@ -163,6 +163,26 @@ size_t udp::sendData(buffer& data, int flags) { return sendlen; } size_t udp::sendTo(buffer& data, int flags) { const char* p = data.data.buf; int s = ::sendto(_Socket, p, (int)data.size, flags, reinterpret_cast<const sockaddr*>(&_Addr), _AddrLen); if (s == SOCKET_ERROR) { int err = ::WSAGetLastError(); if (err == WSAEWOULDBLOCK) { NetException e; e[NetException::Note] << "udp::sendTo would block"; throw e; } NetException e; e[NetException::Error] << "udp::sendTo WSASendTo failed: " << err; throw e; } return (size_t)s; } size_t udp::recvData(buffer& data, int flags) { if (_ReadBuffer && _ReadBuffer->overlapped.InternalHigh > 0) { size_t r = (size_t)_ReadBuffer->overlapped.InternalHigh; Loading