Loading src/event/iocp.cpp +4 −2 Original line number Diff line number Diff line Loading @@ -329,8 +329,10 @@ namespace netplus { // attach accepted socket to con::csock if(serverSock->_Type==sockettype::TCP) c->csock = std::make_unique<tcp>(accepted); else if(serverSock->_Type==sockettype::SSL) c->csock = std::make_unique<ssl>( static_cast<ssl*>(serverSock)->_cert,accepted); else if(serverSock->_Type==sockettype::SSL) { ssl* sslServer = static_cast<ssl*>(serverSock); c->csock = std::make_unique<ssl>(sslServer->getCert(), accepted); } else continue; Loading src/socket.h +3 −1 Original line number Diff line number Diff line Loading @@ -57,7 +57,6 @@ #include <WinSock2.h> #include <ws2tcpip.h> #include <mswsock.h> typedef unsigned long ULONG_PTR; #endif namespace netplus { Loading Loading @@ -352,6 +351,9 @@ namespace netplus { void resetTLS(); // Public accessor for certificate (used by event loop for SSL accept) std::shared_ptr<netplus::x509cert> getCert() const { return _cert; } private: // --- crypto helpers --- std::vector<uint8_t> _sha1_hash(const std::vector<uint8_t>& input); Loading src/ssl.cpp +51 −125 Original line number Diff line number Diff line Loading @@ -361,27 +361,24 @@ std::vector<uint8_t> netplus::ssl::readTlsRecordAsync() // 1) ensure we have at least TLS record header (5 bytes) // ------------------------------------------------------------ while (_rx_tcp_buf.size() < 5) { uint8_t tmp[4096]; buffer tmpBuf(4096); ssize_t r = ::recv(fd(), tmp, sizeof(tmp), 0); try { size_t r = tcp::recvData(tmpBuf, 0); if (r > 0) { _rx_tcp_buf.insert(_rx_tcp_buf.end(), tmp, tmp + r); _rx_tcp_buf.insert(_rx_tcp_buf.end(), tmpBuf.data.buf, tmpBuf.data.buf + r); continue; } if (r == 0) { // peer closed // r == 0 means peer closed return {}; } if (errno == EAGAIN || errno == EWOULDBLOCK) { } catch (NetException& e) { if (e.getErrorType() == NetException::Note) { NetException n; n[NetException::Note] << "ssl: record incomplete (need header)"; throw n; } throwSSL(NetException::Error, std::string("recv failed: ") + strerror(errno)); throw; } } // ------------------------------------------------------------ Loading @@ -394,27 +391,24 @@ std::vector<uint8_t> netplus::ssl::readTlsRecordAsync() // 3) read until full record present // ------------------------------------------------------------ while (_rx_tcp_buf.size() < total) { uint8_t tmp[4096]; buffer tmpBuf(4096); ssize_t r = ::recv(fd(), tmp, sizeof(tmp), 0); try { size_t r = tcp::recvData(tmpBuf, 0); if (r > 0) { _rx_tcp_buf.insert(_rx_tcp_buf.end(), tmp, tmp + r); _rx_tcp_buf.insert(_rx_tcp_buf.end(), tmpBuf.data.buf, tmpBuf.data.buf + r); continue; } if (r == 0) { // peer closed mid-record return {}; } if (errno == EAGAIN || errno == EWOULDBLOCK) { } catch (NetException& e) { if (e.getErrorType() == NetException::Note) { NetException n; n[NetException::Note] << "ssl: record incomplete"; throw n; // ✅ critical: must be Note! throw n; } throw; } throwSSL(NetException::Error, std::string("recv failed: ") + strerror(errno)); } // ------------------------------------------------------------ Loading Loading @@ -1679,7 +1673,7 @@ void netplus::ssl::handshake_after_accept(){ size_t vend = vp + vlen; while (vp + 1 < vend) { uint16_t v = (uint16_t(ch[vp]) << 8) | ch[vp+1]; if (v == 0x0304) offeredTLS13 = true; if (v == 0x0304) return true; // TLS 1.3 vp += 2; } } Loading Loading @@ -2506,18 +2500,17 @@ void netplus::ssl::flush_out(){ _send_record.size() - _send_off ); ssize_t s=0; size_t s = 0; try { s = tcp::sendData(dat, 0); } catch (NetException &e) { if (e.getErrorType() == NetException::Note) { NetException n; if(e.getErrorType()==NetException::Error){ n[NetException::Note] << "ssl::flush_out: would block"; throw n; } n[NetException::Error] << "ssl::flush_out send() failed: " << strerror(errno); throw n; throw; } if (s == 0) { Loading @@ -2526,7 +2519,7 @@ void netplus::ssl::flush_out(){ throw n; } _send_off += (size_t)s; _send_off += s; // record fully sent? if (_send_off >= _send_record.size()) { Loading Loading @@ -2554,7 +2547,7 @@ void netplus::ssl::accept(LPFN_ACCEPTEX lpfnAcceptEx, std::unique_ptr<socket>& c // SSL-Status zurücksetzen cssock->_handshakeDone = false; cssock->_hs_tx.clear(); cssock->_rx_netbuf.clear(); cssock->_rx_tcp_buf.clear(); cssock->_cert = this->_cert; cssock->_rsa = this->_rsa; Loading Loading @@ -3518,7 +3511,7 @@ size_t netplus::ssl::sendData(buffer& data, int flags) { throw n; } const char* p = data.ptr ? data.data.ptr : data.data.buf; // <-- VERIFY with your buffer layout const char* p = data.data.buf; if (!p || data.size == 0) return 0; static constexpr size_t TLS_MAX_PLAINTEXT = 16384; Loading Loading @@ -4150,14 +4143,6 @@ std::vector<uint8_t> netplus::ssl::_rsa_pss_sha256_sign(const std::vector<uint8_ #ifdef Windows void netplus::ssl::accept(LPFN_ACCEPTEX lpfnAcceptEx, std::unique_ptr<socket>& csock, buffer& data){ // This accept is already implemented above at line ~2545 // This stub should not be reached - the other implementation handles it NetException e; e[NetException::Error] << "ssl::accept(LPFN_ACCEPTEX): wrong overload called"; throw e; } void netplus::ssl::sendDataWSA(buffer& data, int flags) { // For SSL, we need to encrypt the data before sending // The data in buffer is plaintext - encrypt it and queue for sending Loading @@ -4171,84 +4156,25 @@ void netplus::ssl::sendDataWSA(buffer& data, int flags) { std::vector<uint8_t> plain(p, p + data.size); if (_is_tls13) { // TLS 1.3: Use application keys - this queues to _hs_tx _tls13_send_record(plain, 0x17, false); // 0x17 = application_data // TLS 1.3: Use application keys _tls13_send_record(0x17, plain, false); // 0x17 = application_data } else { // TLS 1.2: Use CBC encryption std::vector<uint8_t> rec = _buildAppDataRecord(plain); queueRaw(rec); _sendTLS12Record(0x17, plain); } } // Now post the actual WSASend with the encrypted data from _hs_tx if (_hs_tx.empty()) return; // Now post the actual send using tcp method flush_out(); // Copy encrypted data to the buffer's memory for WSASend // Resize buffer if needed size_t encSize = _hs_tx.size(); if (encSize > data.size) { // Reallocate buffer data delete[] data.data.buf; data.data.buf = new char[encSize]; data.size = encSize; } std::memcpy(data.data.buf, _hs_tx.data(), encSize); data.data.len = static_cast<ULONG>(encSize); // Clear send queue now that we've copied it _hs_tx.clear(); DWORD bytesSent = 0; DWORD sendFlags = 0; int result = WSASend( _Socket, &data.data, // WSABUF 1, &bytesSent, sendFlags, &data.overlapped, nullptr ); if (result == SOCKET_ERROR) { int err = WSAGetLastError(); if (err != WSA_IO_PENDING) { NetException e; e[NetException::Error] << "ssl::sendDataWSA: WSASend failed: " << err; throw e; } } // Use tcp::sendDataWSA for the underlying send tcp::sendDataWSA(data, flags); } void netplus::ssl::recvDataWSA(buffer& data, int flags) { // Post an overlapped receive operation // Post an overlapped receive operation using tcp method // The received data will be ciphertext that needs decryption data.wsaBuf.buf = data.data.buf; data.wsaBuf.len = static_cast<ULONG>(data.size); DWORD bytesRecv = 0; DWORD recvFlags = 0; int result = WSARecv( _Socket, &data.wsaBuf, 1, &bytesRecv, &recvFlags, &data.overlapped, nullptr ); if (result == SOCKET_ERROR) { int err = WSAGetLastError(); if (err != WSA_IO_PENDING) { NetException e; e[NetException::Error] << "ssl::recvDataWSA: WSARecv failed: " << err; throw e; } } tcp::recvDataWSA(data, flags); } void netplus::ssl::prime_read(buffer& data) { Loading @@ -4256,8 +4182,8 @@ void netplus::ssl::prime_read(buffer& data) { std::memset(&data.overlapped, 0, sizeof(WSAOVERLAPPED)); data.operation = OP_READ; // Post the async receive recvDataWSA(data, 0); // Post the async receive using tcp method tcp::prime_read(data); } #endif src/windows/tcp.cpp +183 −8 Original line number Diff line number Diff line Loading @@ -146,9 +146,7 @@ void tcp::accept(std::unique_ptr<socket>& csock, bool nonblock) { } size_t tcp::sendData(buffer& data, int flags) { const char* p = data.ptr ? data.data.ptr : data.data.buf; int s = ::send(_Socket, p, (int)data.size, flags); int s = ::send(_Socket, data.data.buf, (int)data.size, flags); if (s == SOCKET_ERROR) { NetException e; e[NetException::Error] << "tcp::sendData failed"; Loading @@ -166,15 +164,192 @@ size_t tcp::recvData(buffer& data, int flags) { return 0; } void tcp::connect(std::unique_ptr<socket>& srvsock) { if (::connect(_Socket, reinterpret_cast<sockaddr*>(&srvsock->_Addr), srvsock->_AddrLen) == SOCKET_ERROR) { void netplus::tcp::connect(const std::string& addr, int port, bool nonblock) { NetException exception; addrinfo hints{}; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; addrinfo* result = nullptr; char serv[32]; std::snprintf(serv, sizeof(serv), "%d", port); int gai = ::getaddrinfo(addr.c_str(), serv, &hints, &result); if (gai != 0) { exception[NetException::Error] << "tcp::connect: getaddrinfo failed: " << gai_strerrorA(gai); throw exception; } for (addrinfo* rp = result; rp; rp = rp->ai_next) { // ------------------------------------------------------- // 1) ensure socket exists and matches family // ------------------------------------------------------- if (_Socket != INVALID_SOCKET) { // if family mismatch, close and recreate sockaddr_storage tmp{}; int tmpLen = sizeof(tmp); if (::getsockname(_Socket, (sockaddr*)&tmp, &tmpLen) == 0) { if (tmp.ss_family != rp->ai_family) { ::closesocket(_Socket); _Socket = INVALID_SOCKET; } } } if (_Socket == INVALID_SOCKET) { _Socket = ::socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (_Socket == INVALID_SOCKET) continue; } // ------------------------------------------------------- // 2) set nonblock BEFORE connect() if requested // ------------------------------------------------------- if (nonblock) { try { setNonBlock(); } catch (...) { ::closesocket(_Socket); _Socket = INVALID_SOCKET; continue; } } // ------------------------------------------------------- // 3) connect() // ------------------------------------------------------- if (::connect(_Socket, rp->ai_addr, (int)rp->ai_addrlen) == 0) { // connected immediately setAddrFromAI(rp); ::freeaddrinfo(result); return; } // ------------------------------------------------------- // 4) nonblocking in progress // ------------------------------------------------------- int err = ::WSAGetLastError(); if (nonblock && (err == WSAEWOULDBLOCK || err == WSAEINPROGRESS)) { setAddrFromAI(rp); ::freeaddrinfo(result); NetException n; n[NetException::Note] << "tcp::connect: WSAEWOULDBLOCK"; throw n; // caller waits for completion } // ------------------------------------------------------- // 5) fatal error -> try next addrinfo // ------------------------------------------------------- ::closesocket(_Socket); _Socket = INVALID_SOCKET; } ::freeaddrinfo(result); exception[NetException::Error] << "tcp::connect: could not connect to " << addr << ":" << port; throw exception; } void tcp::setBlock() { u_long mode = 0; if (::ioctlsocket(_Socket, FIONBIO, &mode) == SOCKET_ERROR) { NetException e; e[NetException::Error] << "tcp::setBlock failed"; throw e; } } void tcp::accept(LPFN_ACCEPTEX lpfnAcceptEx, std::unique_ptr<socket>& csock, buffer& data) { // Create accept socket SOCKET acceptSock = ::WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, nullptr, 0, WSA_FLAG_OVERLAPPED); if (acceptSock == INVALID_SOCKET) { NetException e; e[NetException::Error] << "tcp::accept WSASocket failed"; throw e; } std::memset(&data.overlapped, 0, sizeof(WSAOVERLAPPED)); data.operation = OP_ACCEPT; DWORD bytesReceived = 0; BOOL result = lpfnAcceptEx( _Socket, acceptSock, data.data.buf, 0, sizeof(SOCKADDR_STORAGE) + 16, sizeof(SOCKADDR_STORAGE) + 16, &bytesReceived, &data.overlapped ); if (!result) { int err = ::WSAGetLastError(); if (err != WSA_IO_PENDING) { ::closesocket(acceptSock); NetException e; e[NetException::Error] << "tcp::accept AcceptEx failed: " << err; throw e; } } // Store the accept socket for later retrieval *csock = acceptSock; } void tcp::sendDataWSA(buffer& data, int flags) { DWORD bytesSent = 0; std::memset(&data.overlapped, 0, sizeof(WSAOVERLAPPED)); data.operation = OP_WRITE; int ret = ::WSASend(_Socket, &data.data, 1, &bytesSent, (DWORD)flags, &data.overlapped, nullptr); if (ret == SOCKET_ERROR) { int err = ::WSAGetLastError(); if (err != WSA_IO_PENDING) { NetException e; e[NetException::Error] << "tcp::sendDataWSA failed: " << err; throw e; } } } void tcp::recvDataWSA(buffer& data, int flags) { DWORD bytesRecv = 0; DWORD dwFlags = (DWORD)flags; std::memset(&data.overlapped, 0, sizeof(WSAOVERLAPPED)); data.operation = OP_READ; int ret = ::WSARecv(_Socket, &data.data, 1, &bytesRecv, &dwFlags, &data.overlapped, nullptr); if (ret == SOCKET_ERROR) { int err = ::WSAGetLastError(); if (err != WSA_IO_PENDING) { NetException e; e[NetException::Error] << "tcp::connect failed"; e[NetException::Error] << "tcp::recvDataWSA failed: " << err; throw e; } } } void tcp::prime_read(buffer& data) { recvDataWSA(data, 0); } void tcp::getAddress(std::string& addr) { char buf[INET6_ADDRSTRLEN]{}; Loading src/windows/udp.cpp +155 −8 Original line number Diff line number Diff line Loading @@ -129,10 +129,7 @@ void udp::accept(std::unique_ptr<socket>& csock, bool nonblock) { } size_t udp::sendData(buffer& data, int flags) { const char* p = data.ptr ? data.data.ptr : data.data.buf; int s = ::sendto(_Socket, p, (int)data.size, flags, reinterpret_cast<sockaddr*>(&_Addr), _AddrLen); int s = ::send(_Socket,data.data.buf,data.data.len, flags); if (s == SOCKET_ERROR) { NetException e; Loading @@ -156,10 +153,160 @@ size_t udp::recvData(buffer& data, int flags) { return 0; } void udp::connect(std::unique_ptr<socket>& srvsock) { ::connect(_Socket, reinterpret_cast<sockaddr*>(&srvsock->_Addr), srvsock->_AddrLen); void udp::setBlock() { u_long mode = 0; if (::ioctlsocket(_Socket, FIONBIO, &mode) == SOCKET_ERROR) { NetException e; e[NetException::Error] << "udp::setBlock failed"; throw e; } } void udp::accept(LPFN_ACCEPTEX lpfnAcceptEx, std::unique_ptr<socket>& csock, buffer& data) { // UDP does not use AcceptEx - this is a no-op (void)lpfnAcceptEx; (void)csock; (void)data; } void udp::sendDataWSA(buffer& data, int flags) { DWORD bytesSent = 0; std::memset(&data.overlapped, 0, sizeof(WSAOVERLAPPED)); data.operation = OP_WRITE; int ret = ::WSASend(_Socket, &data.data, 1, &bytesSent, (DWORD)flags, &data.overlapped, nullptr); if (ret == SOCKET_ERROR) { int err = ::WSAGetLastError(); if (err != WSA_IO_PENDING) { NetException e; e[NetException::Error] << "udp::sendDataWSA failed: " << err; throw e; } } } void udp::recvDataWSA(buffer& data, int flags) { DWORD bytesRecv = 0; DWORD dwFlags = (DWORD)flags; std::memset(&data.overlapped, 0, sizeof(WSAOVERLAPPED)); data.operation = OP_READ; int ret = ::WSARecv(_Socket, &data.data, 1, &bytesRecv, &dwFlags, &data.overlapped, nullptr); if (ret == SOCKET_ERROR) { int err = ::WSAGetLastError(); if (err != WSA_IO_PENDING) { NetException e; e[NetException::Error] << "udp::recvDataWSA failed: " << err; throw e; } } } void udp::prime_read(buffer& data) { recvDataWSA(data, 0); } void udp::connect(const std::string& addr, int port, bool nonblock) { NetException exception; addrinfo hints{}; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; addrinfo* result = nullptr; char serv[32]; std::snprintf(serv, sizeof(serv), "%d", port); int gai = ::getaddrinfo(addr.c_str(), serv, &hints, &result); if (gai != 0) { exception[NetException::Error] << "udp::connect: getaddrinfo failed: " << gai_strerrorA(gai); throw exception; } for (addrinfo* rp = result; rp; rp = rp->ai_next) { // ------------------------------------------------------- // 1) ensure socket exists and matches family // ------------------------------------------------------- if (_Socket != INVALID_SOCKET) { // if family mismatch, close and recreate sockaddr_storage tmp{}; int tmpLen = sizeof(tmp); if (::getsockname(_Socket, (sockaddr*)&tmp, &tmpLen) == 0) { if (tmp.ss_family != rp->ai_family) { ::closesocket(_Socket); _Socket = INVALID_SOCKET; } } } if (_Socket == INVALID_SOCKET) { _Socket = ::socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (_Socket == INVALID_SOCKET) continue; } // ------------------------------------------------------- // 2) set nonblock BEFORE connect() if requested // ------------------------------------------------------- if (nonblock) { try { setNonBlock(); } catch (...) { ::closesocket(_Socket); _Socket = INVALID_SOCKET; continue; } } // ------------------------------------------------------- // 3) connect() // ------------------------------------------------------- if (::connect(_Socket, rp->ai_addr, (int)rp->ai_addrlen) == 0) { // connected immediately setAddrFromAI(rp); ::freeaddrinfo(result); return; } // ------------------------------------------------------- // 4) nonblocking in progress // ------------------------------------------------------- int err = ::WSAGetLastError(); if (nonblock && (err == WSAEWOULDBLOCK || err == WSAEINPROGRESS)) { setAddrFromAI(rp); ::freeaddrinfo(result); NetException n; n[NetException::Note] << "udp::connect: WSAEWOULDBLOCK"; throw n; // caller waits for completion } // ------------------------------------------------------- // 5) fatal error -> try next addrinfo // ------------------------------------------------------- ::closesocket(_Socket); _Socket = INVALID_SOCKET; } ::freeaddrinfo(result); exception[NetException::Error] << "udp::connect: could not connect to " << addr << ":" << port; throw exception; } void udp::getAddress(std::string& addr) { Loading Loading
src/event/iocp.cpp +4 −2 Original line number Diff line number Diff line Loading @@ -329,8 +329,10 @@ namespace netplus { // attach accepted socket to con::csock if(serverSock->_Type==sockettype::TCP) c->csock = std::make_unique<tcp>(accepted); else if(serverSock->_Type==sockettype::SSL) c->csock = std::make_unique<ssl>( static_cast<ssl*>(serverSock)->_cert,accepted); else if(serverSock->_Type==sockettype::SSL) { ssl* sslServer = static_cast<ssl*>(serverSock); c->csock = std::make_unique<ssl>(sslServer->getCert(), accepted); } else continue; Loading
src/socket.h +3 −1 Original line number Diff line number Diff line Loading @@ -57,7 +57,6 @@ #include <WinSock2.h> #include <ws2tcpip.h> #include <mswsock.h> typedef unsigned long ULONG_PTR; #endif namespace netplus { Loading Loading @@ -352,6 +351,9 @@ namespace netplus { void resetTLS(); // Public accessor for certificate (used by event loop for SSL accept) std::shared_ptr<netplus::x509cert> getCert() const { return _cert; } private: // --- crypto helpers --- std::vector<uint8_t> _sha1_hash(const std::vector<uint8_t>& input); Loading
src/ssl.cpp +51 −125 Original line number Diff line number Diff line Loading @@ -361,27 +361,24 @@ std::vector<uint8_t> netplus::ssl::readTlsRecordAsync() // 1) ensure we have at least TLS record header (5 bytes) // ------------------------------------------------------------ while (_rx_tcp_buf.size() < 5) { uint8_t tmp[4096]; buffer tmpBuf(4096); ssize_t r = ::recv(fd(), tmp, sizeof(tmp), 0); try { size_t r = tcp::recvData(tmpBuf, 0); if (r > 0) { _rx_tcp_buf.insert(_rx_tcp_buf.end(), tmp, tmp + r); _rx_tcp_buf.insert(_rx_tcp_buf.end(), tmpBuf.data.buf, tmpBuf.data.buf + r); continue; } if (r == 0) { // peer closed // r == 0 means peer closed return {}; } if (errno == EAGAIN || errno == EWOULDBLOCK) { } catch (NetException& e) { if (e.getErrorType() == NetException::Note) { NetException n; n[NetException::Note] << "ssl: record incomplete (need header)"; throw n; } throwSSL(NetException::Error, std::string("recv failed: ") + strerror(errno)); throw; } } // ------------------------------------------------------------ Loading @@ -394,27 +391,24 @@ std::vector<uint8_t> netplus::ssl::readTlsRecordAsync() // 3) read until full record present // ------------------------------------------------------------ while (_rx_tcp_buf.size() < total) { uint8_t tmp[4096]; buffer tmpBuf(4096); ssize_t r = ::recv(fd(), tmp, sizeof(tmp), 0); try { size_t r = tcp::recvData(tmpBuf, 0); if (r > 0) { _rx_tcp_buf.insert(_rx_tcp_buf.end(), tmp, tmp + r); _rx_tcp_buf.insert(_rx_tcp_buf.end(), tmpBuf.data.buf, tmpBuf.data.buf + r); continue; } if (r == 0) { // peer closed mid-record return {}; } if (errno == EAGAIN || errno == EWOULDBLOCK) { } catch (NetException& e) { if (e.getErrorType() == NetException::Note) { NetException n; n[NetException::Note] << "ssl: record incomplete"; throw n; // ✅ critical: must be Note! throw n; } throw; } throwSSL(NetException::Error, std::string("recv failed: ") + strerror(errno)); } // ------------------------------------------------------------ Loading Loading @@ -1679,7 +1673,7 @@ void netplus::ssl::handshake_after_accept(){ size_t vend = vp + vlen; while (vp + 1 < vend) { uint16_t v = (uint16_t(ch[vp]) << 8) | ch[vp+1]; if (v == 0x0304) offeredTLS13 = true; if (v == 0x0304) return true; // TLS 1.3 vp += 2; } } Loading Loading @@ -2506,18 +2500,17 @@ void netplus::ssl::flush_out(){ _send_record.size() - _send_off ); ssize_t s=0; size_t s = 0; try { s = tcp::sendData(dat, 0); } catch (NetException &e) { if (e.getErrorType() == NetException::Note) { NetException n; if(e.getErrorType()==NetException::Error){ n[NetException::Note] << "ssl::flush_out: would block"; throw n; } n[NetException::Error] << "ssl::flush_out send() failed: " << strerror(errno); throw n; throw; } if (s == 0) { Loading @@ -2526,7 +2519,7 @@ void netplus::ssl::flush_out(){ throw n; } _send_off += (size_t)s; _send_off += s; // record fully sent? if (_send_off >= _send_record.size()) { Loading Loading @@ -2554,7 +2547,7 @@ void netplus::ssl::accept(LPFN_ACCEPTEX lpfnAcceptEx, std::unique_ptr<socket>& c // SSL-Status zurücksetzen cssock->_handshakeDone = false; cssock->_hs_tx.clear(); cssock->_rx_netbuf.clear(); cssock->_rx_tcp_buf.clear(); cssock->_cert = this->_cert; cssock->_rsa = this->_rsa; Loading Loading @@ -3518,7 +3511,7 @@ size_t netplus::ssl::sendData(buffer& data, int flags) { throw n; } const char* p = data.ptr ? data.data.ptr : data.data.buf; // <-- VERIFY with your buffer layout const char* p = data.data.buf; if (!p || data.size == 0) return 0; static constexpr size_t TLS_MAX_PLAINTEXT = 16384; Loading Loading @@ -4150,14 +4143,6 @@ std::vector<uint8_t> netplus::ssl::_rsa_pss_sha256_sign(const std::vector<uint8_ #ifdef Windows void netplus::ssl::accept(LPFN_ACCEPTEX lpfnAcceptEx, std::unique_ptr<socket>& csock, buffer& data){ // This accept is already implemented above at line ~2545 // This stub should not be reached - the other implementation handles it NetException e; e[NetException::Error] << "ssl::accept(LPFN_ACCEPTEX): wrong overload called"; throw e; } void netplus::ssl::sendDataWSA(buffer& data, int flags) { // For SSL, we need to encrypt the data before sending // The data in buffer is plaintext - encrypt it and queue for sending Loading @@ -4171,84 +4156,25 @@ void netplus::ssl::sendDataWSA(buffer& data, int flags) { std::vector<uint8_t> plain(p, p + data.size); if (_is_tls13) { // TLS 1.3: Use application keys - this queues to _hs_tx _tls13_send_record(plain, 0x17, false); // 0x17 = application_data // TLS 1.3: Use application keys _tls13_send_record(0x17, plain, false); // 0x17 = application_data } else { // TLS 1.2: Use CBC encryption std::vector<uint8_t> rec = _buildAppDataRecord(plain); queueRaw(rec); _sendTLS12Record(0x17, plain); } } // Now post the actual WSASend with the encrypted data from _hs_tx if (_hs_tx.empty()) return; // Now post the actual send using tcp method flush_out(); // Copy encrypted data to the buffer's memory for WSASend // Resize buffer if needed size_t encSize = _hs_tx.size(); if (encSize > data.size) { // Reallocate buffer data delete[] data.data.buf; data.data.buf = new char[encSize]; data.size = encSize; } std::memcpy(data.data.buf, _hs_tx.data(), encSize); data.data.len = static_cast<ULONG>(encSize); // Clear send queue now that we've copied it _hs_tx.clear(); DWORD bytesSent = 0; DWORD sendFlags = 0; int result = WSASend( _Socket, &data.data, // WSABUF 1, &bytesSent, sendFlags, &data.overlapped, nullptr ); if (result == SOCKET_ERROR) { int err = WSAGetLastError(); if (err != WSA_IO_PENDING) { NetException e; e[NetException::Error] << "ssl::sendDataWSA: WSASend failed: " << err; throw e; } } // Use tcp::sendDataWSA for the underlying send tcp::sendDataWSA(data, flags); } void netplus::ssl::recvDataWSA(buffer& data, int flags) { // Post an overlapped receive operation // Post an overlapped receive operation using tcp method // The received data will be ciphertext that needs decryption data.wsaBuf.buf = data.data.buf; data.wsaBuf.len = static_cast<ULONG>(data.size); DWORD bytesRecv = 0; DWORD recvFlags = 0; int result = WSARecv( _Socket, &data.wsaBuf, 1, &bytesRecv, &recvFlags, &data.overlapped, nullptr ); if (result == SOCKET_ERROR) { int err = WSAGetLastError(); if (err != WSA_IO_PENDING) { NetException e; e[NetException::Error] << "ssl::recvDataWSA: WSARecv failed: " << err; throw e; } } tcp::recvDataWSA(data, flags); } void netplus::ssl::prime_read(buffer& data) { Loading @@ -4256,8 +4182,8 @@ void netplus::ssl::prime_read(buffer& data) { std::memset(&data.overlapped, 0, sizeof(WSAOVERLAPPED)); data.operation = OP_READ; // Post the async receive recvDataWSA(data, 0); // Post the async receive using tcp method tcp::prime_read(data); } #endif
src/windows/tcp.cpp +183 −8 Original line number Diff line number Diff line Loading @@ -146,9 +146,7 @@ void tcp::accept(std::unique_ptr<socket>& csock, bool nonblock) { } size_t tcp::sendData(buffer& data, int flags) { const char* p = data.ptr ? data.data.ptr : data.data.buf; int s = ::send(_Socket, p, (int)data.size, flags); int s = ::send(_Socket, data.data.buf, (int)data.size, flags); if (s == SOCKET_ERROR) { NetException e; e[NetException::Error] << "tcp::sendData failed"; Loading @@ -166,15 +164,192 @@ size_t tcp::recvData(buffer& data, int flags) { return 0; } void tcp::connect(std::unique_ptr<socket>& srvsock) { if (::connect(_Socket, reinterpret_cast<sockaddr*>(&srvsock->_Addr), srvsock->_AddrLen) == SOCKET_ERROR) { void netplus::tcp::connect(const std::string& addr, int port, bool nonblock) { NetException exception; addrinfo hints{}; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; addrinfo* result = nullptr; char serv[32]; std::snprintf(serv, sizeof(serv), "%d", port); int gai = ::getaddrinfo(addr.c_str(), serv, &hints, &result); if (gai != 0) { exception[NetException::Error] << "tcp::connect: getaddrinfo failed: " << gai_strerrorA(gai); throw exception; } for (addrinfo* rp = result; rp; rp = rp->ai_next) { // ------------------------------------------------------- // 1) ensure socket exists and matches family // ------------------------------------------------------- if (_Socket != INVALID_SOCKET) { // if family mismatch, close and recreate sockaddr_storage tmp{}; int tmpLen = sizeof(tmp); if (::getsockname(_Socket, (sockaddr*)&tmp, &tmpLen) == 0) { if (tmp.ss_family != rp->ai_family) { ::closesocket(_Socket); _Socket = INVALID_SOCKET; } } } if (_Socket == INVALID_SOCKET) { _Socket = ::socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (_Socket == INVALID_SOCKET) continue; } // ------------------------------------------------------- // 2) set nonblock BEFORE connect() if requested // ------------------------------------------------------- if (nonblock) { try { setNonBlock(); } catch (...) { ::closesocket(_Socket); _Socket = INVALID_SOCKET; continue; } } // ------------------------------------------------------- // 3) connect() // ------------------------------------------------------- if (::connect(_Socket, rp->ai_addr, (int)rp->ai_addrlen) == 0) { // connected immediately setAddrFromAI(rp); ::freeaddrinfo(result); return; } // ------------------------------------------------------- // 4) nonblocking in progress // ------------------------------------------------------- int err = ::WSAGetLastError(); if (nonblock && (err == WSAEWOULDBLOCK || err == WSAEINPROGRESS)) { setAddrFromAI(rp); ::freeaddrinfo(result); NetException n; n[NetException::Note] << "tcp::connect: WSAEWOULDBLOCK"; throw n; // caller waits for completion } // ------------------------------------------------------- // 5) fatal error -> try next addrinfo // ------------------------------------------------------- ::closesocket(_Socket); _Socket = INVALID_SOCKET; } ::freeaddrinfo(result); exception[NetException::Error] << "tcp::connect: could not connect to " << addr << ":" << port; throw exception; } void tcp::setBlock() { u_long mode = 0; if (::ioctlsocket(_Socket, FIONBIO, &mode) == SOCKET_ERROR) { NetException e; e[NetException::Error] << "tcp::setBlock failed"; throw e; } } void tcp::accept(LPFN_ACCEPTEX lpfnAcceptEx, std::unique_ptr<socket>& csock, buffer& data) { // Create accept socket SOCKET acceptSock = ::WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, nullptr, 0, WSA_FLAG_OVERLAPPED); if (acceptSock == INVALID_SOCKET) { NetException e; e[NetException::Error] << "tcp::accept WSASocket failed"; throw e; } std::memset(&data.overlapped, 0, sizeof(WSAOVERLAPPED)); data.operation = OP_ACCEPT; DWORD bytesReceived = 0; BOOL result = lpfnAcceptEx( _Socket, acceptSock, data.data.buf, 0, sizeof(SOCKADDR_STORAGE) + 16, sizeof(SOCKADDR_STORAGE) + 16, &bytesReceived, &data.overlapped ); if (!result) { int err = ::WSAGetLastError(); if (err != WSA_IO_PENDING) { ::closesocket(acceptSock); NetException e; e[NetException::Error] << "tcp::accept AcceptEx failed: " << err; throw e; } } // Store the accept socket for later retrieval *csock = acceptSock; } void tcp::sendDataWSA(buffer& data, int flags) { DWORD bytesSent = 0; std::memset(&data.overlapped, 0, sizeof(WSAOVERLAPPED)); data.operation = OP_WRITE; int ret = ::WSASend(_Socket, &data.data, 1, &bytesSent, (DWORD)flags, &data.overlapped, nullptr); if (ret == SOCKET_ERROR) { int err = ::WSAGetLastError(); if (err != WSA_IO_PENDING) { NetException e; e[NetException::Error] << "tcp::sendDataWSA failed: " << err; throw e; } } } void tcp::recvDataWSA(buffer& data, int flags) { DWORD bytesRecv = 0; DWORD dwFlags = (DWORD)flags; std::memset(&data.overlapped, 0, sizeof(WSAOVERLAPPED)); data.operation = OP_READ; int ret = ::WSARecv(_Socket, &data.data, 1, &bytesRecv, &dwFlags, &data.overlapped, nullptr); if (ret == SOCKET_ERROR) { int err = ::WSAGetLastError(); if (err != WSA_IO_PENDING) { NetException e; e[NetException::Error] << "tcp::connect failed"; e[NetException::Error] << "tcp::recvDataWSA failed: " << err; throw e; } } } void tcp::prime_read(buffer& data) { recvDataWSA(data, 0); } void tcp::getAddress(std::string& addr) { char buf[INET6_ADDRSTRLEN]{}; Loading
src/windows/udp.cpp +155 −8 Original line number Diff line number Diff line Loading @@ -129,10 +129,7 @@ void udp::accept(std::unique_ptr<socket>& csock, bool nonblock) { } size_t udp::sendData(buffer& data, int flags) { const char* p = data.ptr ? data.data.ptr : data.data.buf; int s = ::sendto(_Socket, p, (int)data.size, flags, reinterpret_cast<sockaddr*>(&_Addr), _AddrLen); int s = ::send(_Socket,data.data.buf,data.data.len, flags); if (s == SOCKET_ERROR) { NetException e; Loading @@ -156,10 +153,160 @@ size_t udp::recvData(buffer& data, int flags) { return 0; } void udp::connect(std::unique_ptr<socket>& srvsock) { ::connect(_Socket, reinterpret_cast<sockaddr*>(&srvsock->_Addr), srvsock->_AddrLen); void udp::setBlock() { u_long mode = 0; if (::ioctlsocket(_Socket, FIONBIO, &mode) == SOCKET_ERROR) { NetException e; e[NetException::Error] << "udp::setBlock failed"; throw e; } } void udp::accept(LPFN_ACCEPTEX lpfnAcceptEx, std::unique_ptr<socket>& csock, buffer& data) { // UDP does not use AcceptEx - this is a no-op (void)lpfnAcceptEx; (void)csock; (void)data; } void udp::sendDataWSA(buffer& data, int flags) { DWORD bytesSent = 0; std::memset(&data.overlapped, 0, sizeof(WSAOVERLAPPED)); data.operation = OP_WRITE; int ret = ::WSASend(_Socket, &data.data, 1, &bytesSent, (DWORD)flags, &data.overlapped, nullptr); if (ret == SOCKET_ERROR) { int err = ::WSAGetLastError(); if (err != WSA_IO_PENDING) { NetException e; e[NetException::Error] << "udp::sendDataWSA failed: " << err; throw e; } } } void udp::recvDataWSA(buffer& data, int flags) { DWORD bytesRecv = 0; DWORD dwFlags = (DWORD)flags; std::memset(&data.overlapped, 0, sizeof(WSAOVERLAPPED)); data.operation = OP_READ; int ret = ::WSARecv(_Socket, &data.data, 1, &bytesRecv, &dwFlags, &data.overlapped, nullptr); if (ret == SOCKET_ERROR) { int err = ::WSAGetLastError(); if (err != WSA_IO_PENDING) { NetException e; e[NetException::Error] << "udp::recvDataWSA failed: " << err; throw e; } } } void udp::prime_read(buffer& data) { recvDataWSA(data, 0); } void udp::connect(const std::string& addr, int port, bool nonblock) { NetException exception; addrinfo hints{}; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; addrinfo* result = nullptr; char serv[32]; std::snprintf(serv, sizeof(serv), "%d", port); int gai = ::getaddrinfo(addr.c_str(), serv, &hints, &result); if (gai != 0) { exception[NetException::Error] << "udp::connect: getaddrinfo failed: " << gai_strerrorA(gai); throw exception; } for (addrinfo* rp = result; rp; rp = rp->ai_next) { // ------------------------------------------------------- // 1) ensure socket exists and matches family // ------------------------------------------------------- if (_Socket != INVALID_SOCKET) { // if family mismatch, close and recreate sockaddr_storage tmp{}; int tmpLen = sizeof(tmp); if (::getsockname(_Socket, (sockaddr*)&tmp, &tmpLen) == 0) { if (tmp.ss_family != rp->ai_family) { ::closesocket(_Socket); _Socket = INVALID_SOCKET; } } } if (_Socket == INVALID_SOCKET) { _Socket = ::socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (_Socket == INVALID_SOCKET) continue; } // ------------------------------------------------------- // 2) set nonblock BEFORE connect() if requested // ------------------------------------------------------- if (nonblock) { try { setNonBlock(); } catch (...) { ::closesocket(_Socket); _Socket = INVALID_SOCKET; continue; } } // ------------------------------------------------------- // 3) connect() // ------------------------------------------------------- if (::connect(_Socket, rp->ai_addr, (int)rp->ai_addrlen) == 0) { // connected immediately setAddrFromAI(rp); ::freeaddrinfo(result); return; } // ------------------------------------------------------- // 4) nonblocking in progress // ------------------------------------------------------- int err = ::WSAGetLastError(); if (nonblock && (err == WSAEWOULDBLOCK || err == WSAEINPROGRESS)) { setAddrFromAI(rp); ::freeaddrinfo(result); NetException n; n[NetException::Note] << "udp::connect: WSAEWOULDBLOCK"; throw n; // caller waits for completion } // ------------------------------------------------------- // 5) fatal error -> try next addrinfo // ------------------------------------------------------- ::closesocket(_Socket); _Socket = INVALID_SOCKET; } ::freeaddrinfo(result); exception[NetException::Error] << "udp::connect: could not connect to " << addr << ":" << port; throw exception; } void udp::getAddress(std::string& addr) { Loading