Loading src/event/iocp.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -261,6 +261,8 @@ namespace netplus { continue; } c->slots[0].csock->setIocpAssociated(true); register_con(st, accepted, c); ev->ConnectEvent(*c, 0, 0); Loading src/socket.h +6 −0 Original line number Diff line number Diff line Loading @@ -242,8 +242,14 @@ namespace netplus { bool _Bound = false; bool _Listening = false; // Mark this socket as associated with an IOCP handle. // Only IOCP-bound sockets should use overlapped WSASend/WSARecv. void setIocpAssociated(bool v) { _iocpAssociated = v; } bool isIocpAssociated() const { return _iocpAssociated; } protected: std::atomic<bool> _pendingIocpWrite{false}; bool _iocpAssociated = false; // ✅ legacy helper still available void copyAddrInfo(ULONG_PTR* dest, ULONG_PTR src, size_t srclen); Loading src/windows/tcp.cpp +30 −15 Original line number Diff line number Diff line Loading @@ -152,9 +152,35 @@ void tcp::accept(std::unique_ptr<socket>& csock, bool nonblock) { } size_t tcp::sendData(buffer& data, int flags) { // Copy data to _SendBuffer for async WSASend size_t sendlen = data.size; // Client sockets (not IOCP-bound): use synchronous WSASend if (!isIocpAssociated()) { WSABUF wsaBuf; wsaBuf.buf = data.data.buf; wsaBuf.len = (ULONG)sendlen; DWORD bytesSent = 0; DWORD dwFlags = (DWORD)flags; int ret = ::WSASend(_Socket, &wsaBuf, 1, &bytesSent, dwFlags, nullptr, nullptr); if (ret == 0) { return (size_t)bytesSent; } int err = ::WSAGetLastError(); if (err == WSAEWOULDBLOCK) { NetException e; e[NetException::Note] << "tcp::sendData: would block"; throw e; } NetException e; e[NetException::Error] << "tcp::sendData WSASend failed: " << err; throw e; } // IOCP-bound server sockets: use overlapped WSASend if (!_SendBuffer) { _SendBuffer = std::make_unique<buffer>(sendlen); } Loading Loading @@ -190,19 +216,12 @@ size_t tcp::sendData(buffer& data, int flags) { } size_t tcp::recvData(buffer& data, int flags) { // First check if we have data from a completed IOCP read std::cerr << "[TCP] recvData: _ReadBuffer=" << (_ReadBuffer ? "yes" : "no"); if (_ReadBuffer) { std::cerr << " InternalHigh=" << _ReadBuffer->overlapped.InternalHigh; } std::cerr << std::endl; if (_ReadBuffer && _ReadBuffer->overlapped.InternalHigh > 0) { // IOCP-bound sockets: check if we have data from a completed IOCP read if (isIocpAssociated() && _ReadBuffer && _ReadBuffer->overlapped.InternalHigh > 0) { size_t r = (size_t)_ReadBuffer->overlapped.InternalHigh; if (r > data.size) r = data.size; std::copy(_ReadBuffer->data.buf, _ReadBuffer->data.buf + r, data.data.buf); std::cerr << "[TCP] recvData: returning " << r << " bytes from InternalHigh, resetting to 0" << std::endl; _ReadBuffer->overlapped.InternalHigh = 0; return r; } Loading @@ -220,11 +239,9 @@ size_t tcp::recvData(buffer& data, int flags) { if (ret == 0) { // Success if (bytesRecv > 0) { std::cerr << "[TCP] recvData: WSARecv returned " << bytesRecv << " bytes" << std::endl; return (size_t)bytesRecv; } // bytesRecv == 0 means connection closed std::cerr << "[TCP] recvData: connection closed" << std::endl; NetException e; e[NetException::Error] << "tcp::recvData: connection closed"; throw e; Loading @@ -233,13 +250,11 @@ size_t tcp::recvData(buffer& data, int flags) { int err = ::WSAGetLastError(); if (err == WSAEWOULDBLOCK) { // Non-blocking socket with no data - throw Note std::cerr << "[TCP] recvData: WSAEWOULDBLOCK, throwing Note" << std::endl; NetException e; e[NetException::Note] << "tcp::recvData: no data available"; throw e; } std::cerr << "[TCP] recvData: WSARecv error " << err << std::endl; NetException e; e[NetException::Error] << "tcp::recvData: WSARecv failed with error " << err; throw e; Loading src/windows/udp.cpp +29 −1 Original line number Diff line number Diff line Loading @@ -131,6 +131,33 @@ void udp::accept(std::unique_ptr<socket>& csock, bool nonblock) { size_t udp::sendData(buffer& data, int flags) { size_t sendlen = data.size; // Client sockets (not IOCP-bound): use synchronous WSASend if (!isIocpAssociated()) { WSABUF wsaBuf; wsaBuf.buf = data.data.buf; wsaBuf.len = (ULONG)sendlen; DWORD bytesSent = 0; DWORD dwFlags = (DWORD)flags; int ret = ::WSASend(_Socket, &wsaBuf, 1, &bytesSent, dwFlags, nullptr, nullptr); if (ret == 0) { return (size_t)bytesSent; } int err = ::WSAGetLastError(); if (err == WSAEWOULDBLOCK) { NetException e; e[NetException::Note] << "udp::sendData: would block"; throw e; } NetException e; e[NetException::Error] << "udp::sendData WSASend failed: " << err; throw e; } // IOCP-bound server sockets: use overlapped WSASend if (!_SendBuffer) { _SendBuffer = std::make_unique<buffer>(sendlen); } Loading Loading @@ -184,7 +211,8 @@ size_t udp::sendTo(buffer& data, int flags) { } size_t udp::recvData(buffer& data, int flags) { if (_ReadBuffer && _ReadBuffer->overlapped.InternalHigh > 0) { // IOCP-bound sockets: check completed IOCP read first if (isIocpAssociated() && _ReadBuffer && _ReadBuffer->overlapped.InternalHigh > 0) { size_t r = (size_t)_ReadBuffer->overlapped.InternalHigh; if (r > data.size) r = data.size; Loading Loading
src/event/iocp.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -261,6 +261,8 @@ namespace netplus { continue; } c->slots[0].csock->setIocpAssociated(true); register_con(st, accepted, c); ev->ConnectEvent(*c, 0, 0); Loading
src/socket.h +6 −0 Original line number Diff line number Diff line Loading @@ -242,8 +242,14 @@ namespace netplus { bool _Bound = false; bool _Listening = false; // Mark this socket as associated with an IOCP handle. // Only IOCP-bound sockets should use overlapped WSASend/WSARecv. void setIocpAssociated(bool v) { _iocpAssociated = v; } bool isIocpAssociated() const { return _iocpAssociated; } protected: std::atomic<bool> _pendingIocpWrite{false}; bool _iocpAssociated = false; // ✅ legacy helper still available void copyAddrInfo(ULONG_PTR* dest, ULONG_PTR src, size_t srclen); Loading
src/windows/tcp.cpp +30 −15 Original line number Diff line number Diff line Loading @@ -152,9 +152,35 @@ void tcp::accept(std::unique_ptr<socket>& csock, bool nonblock) { } size_t tcp::sendData(buffer& data, int flags) { // Copy data to _SendBuffer for async WSASend size_t sendlen = data.size; // Client sockets (not IOCP-bound): use synchronous WSASend if (!isIocpAssociated()) { WSABUF wsaBuf; wsaBuf.buf = data.data.buf; wsaBuf.len = (ULONG)sendlen; DWORD bytesSent = 0; DWORD dwFlags = (DWORD)flags; int ret = ::WSASend(_Socket, &wsaBuf, 1, &bytesSent, dwFlags, nullptr, nullptr); if (ret == 0) { return (size_t)bytesSent; } int err = ::WSAGetLastError(); if (err == WSAEWOULDBLOCK) { NetException e; e[NetException::Note] << "tcp::sendData: would block"; throw e; } NetException e; e[NetException::Error] << "tcp::sendData WSASend failed: " << err; throw e; } // IOCP-bound server sockets: use overlapped WSASend if (!_SendBuffer) { _SendBuffer = std::make_unique<buffer>(sendlen); } Loading Loading @@ -190,19 +216,12 @@ size_t tcp::sendData(buffer& data, int flags) { } size_t tcp::recvData(buffer& data, int flags) { // First check if we have data from a completed IOCP read std::cerr << "[TCP] recvData: _ReadBuffer=" << (_ReadBuffer ? "yes" : "no"); if (_ReadBuffer) { std::cerr << " InternalHigh=" << _ReadBuffer->overlapped.InternalHigh; } std::cerr << std::endl; if (_ReadBuffer && _ReadBuffer->overlapped.InternalHigh > 0) { // IOCP-bound sockets: check if we have data from a completed IOCP read if (isIocpAssociated() && _ReadBuffer && _ReadBuffer->overlapped.InternalHigh > 0) { size_t r = (size_t)_ReadBuffer->overlapped.InternalHigh; if (r > data.size) r = data.size; std::copy(_ReadBuffer->data.buf, _ReadBuffer->data.buf + r, data.data.buf); std::cerr << "[TCP] recvData: returning " << r << " bytes from InternalHigh, resetting to 0" << std::endl; _ReadBuffer->overlapped.InternalHigh = 0; return r; } Loading @@ -220,11 +239,9 @@ size_t tcp::recvData(buffer& data, int flags) { if (ret == 0) { // Success if (bytesRecv > 0) { std::cerr << "[TCP] recvData: WSARecv returned " << bytesRecv << " bytes" << std::endl; return (size_t)bytesRecv; } // bytesRecv == 0 means connection closed std::cerr << "[TCP] recvData: connection closed" << std::endl; NetException e; e[NetException::Error] << "tcp::recvData: connection closed"; throw e; Loading @@ -233,13 +250,11 @@ size_t tcp::recvData(buffer& data, int flags) { int err = ::WSAGetLastError(); if (err == WSAEWOULDBLOCK) { // Non-blocking socket with no data - throw Note std::cerr << "[TCP] recvData: WSAEWOULDBLOCK, throwing Note" << std::endl; NetException e; e[NetException::Note] << "tcp::recvData: no data available"; throw e; } std::cerr << "[TCP] recvData: WSARecv error " << err << std::endl; NetException e; e[NetException::Error] << "tcp::recvData: WSARecv failed with error " << err; throw e; Loading
src/windows/udp.cpp +29 −1 Original line number Diff line number Diff line Loading @@ -131,6 +131,33 @@ void udp::accept(std::unique_ptr<socket>& csock, bool nonblock) { size_t udp::sendData(buffer& data, int flags) { size_t sendlen = data.size; // Client sockets (not IOCP-bound): use synchronous WSASend if (!isIocpAssociated()) { WSABUF wsaBuf; wsaBuf.buf = data.data.buf; wsaBuf.len = (ULONG)sendlen; DWORD bytesSent = 0; DWORD dwFlags = (DWORD)flags; int ret = ::WSASend(_Socket, &wsaBuf, 1, &bytesSent, dwFlags, nullptr, nullptr); if (ret == 0) { return (size_t)bytesSent; } int err = ::WSAGetLastError(); if (err == WSAEWOULDBLOCK) { NetException e; e[NetException::Note] << "udp::sendData: would block"; throw e; } NetException e; e[NetException::Error] << "udp::sendData WSASend failed: " << err; throw e; } // IOCP-bound server sockets: use overlapped WSASend if (!_SendBuffer) { _SendBuffer = std::make_unique<buffer>(sendlen); } Loading Loading @@ -184,7 +211,8 @@ size_t udp::sendTo(buffer& data, int flags) { } size_t udp::recvData(buffer& data, int flags) { if (_ReadBuffer && _ReadBuffer->overlapped.InternalHigh > 0) { // IOCP-bound sockets: check completed IOCP read first if (isIocpAssociated() && _ReadBuffer && _ReadBuffer->overlapped.InternalHigh > 0) { size_t r = (size_t)_ReadBuffer->overlapped.InternalHigh; if (r > data.size) r = data.size; Loading