Loading src/event/iocp.cpp +101 −78 Original line number Diff line number Diff line Loading @@ -154,12 +154,54 @@ namespace netplus { class EventWorker { public: class EventWorker { public: /** * @brief Initiates an asynchronous read. * Uses the specialized WSA methods to interact with the IOCP. */ static void start_read(client* ctx) { con& c = *ctx->CurCon; // Temporary buffer for the overlapped operation buffer buf(ctx->readCtx.buffer, BLOCKSIZE); if (c.csock->_Type == sockettype::TCP) { static_cast<tcp*>(c.csock.get())->recvDataWSA(buf, 0); } else if (c.csock->_Type == sockettype::UDP) { static_cast<udp*>(c.csock.get())->recvDataWSA(buf, 0); } else if (c.csock->_Type == sockettype::SSL) { // SSL recvDataWSA prepares the internal _rx_netbuf for ciphertext static_cast<ssl*>(c.csock.get())->recvDataWSA(buf, 0); } } /** * @brief Initiates an asynchronous write. * For SSL, this triggers encryption before the WSASend call. */ static void start_write(client* ctx) { con& c = *ctx->CurCon; if (c.SendData.empty()) return; size_t toSend = std::min<size_t>(BLOCKSIZE, c.SendData.size()); buffer out(c.SendData.data(), toSend); if (c.csock->_Type == sockettype::TCP) { static_cast<tcp*>(c.csock.get())->sendDataWSA(out, 0); } else if (c.csock->_Type == sockettype::UDP) { static_cast<udp*>(c.csock.get())->sendDataWSA(out, 0); } else if (c.csock->_Type == sockettype::SSL) { static_cast<ssl*>(c.csock.get())->sendDataWSA(out, 0); } } EventWorker(int tid, ULONG_PTR args, EventWorkerArgs* eargs) { while (event::Running) { DWORD dwBytesTransfered = 0; ULONG_PTR lpContext = 0; OVERLAPPED* pOverlapped = nullptr; // Wait for completion from the port BOOL bReturn = GetQueuedCompletionStatus(eargs->eviocp, &dwBytesTransfered, &lpContext, &pOverlapped, eargs->timeout); Loading @@ -169,77 +211,58 @@ namespace netplus { IO_CONTEXT* pIoCtx = CONTAINING_RECORD(pOverlapped, IO_CONTEXT, overlapped); con& c = *pClientContext->CurCon; // Handle Disconnection or Errors // Handle Disconnection or Reset (Fixes PR_CONNECT_RESET_ERROR logic) if (!bReturn || (bReturn && dwBytesTransfered == 0)) { eargs->event->DisconnectEvent(c, tid, args); eargs->event->DisconnectEvent(c, tid, (ULONG_PTR)eargs->args); delete pClientContext; continue; } try { std::lock_guard<std::mutex> guard(pClientContext->cltmtx); if (pIoCtx->operation == OP_READ) { if (c.csock->_Type == sockettype::SSL) { // CAST required because recvData in SSL class handles the decryption state ssl* sslSocket = static_cast<ssl*>(c.csock.get()); // 1. Prepare a buffer for the plaintext // Bridge: Feed ciphertext from network to SSL engine for decryption buffer plain(BLOCKSIZE); // 2. This call takes the ciphertext (automatically filled by IOCP into _rx_netbuf) // and decrypts it into our 'plain' buffer. size_t decrypted = sslSocket->recvData(plain, 0); if (decrypted > 0) { c.RecvData.append(plain.data.buf, decrypted); eargs->event->RequestEvent(c, tid, args); eargs->event->RequestEvent(c, tid, (ULONG_PTR)eargs->args); } // 3. Request more ciphertext from the wire sslSocket->recvDataWSA(c.RecvData, 0); } else { // Standard TCP: Direct append and re-read // Plaintext TCP/UDP c.RecvData.append(pIoCtx->buffer, dwBytesTransfered); eargs->event->RequestEvent(c, tid, args); static_cast<tcp*>(c.csock.get())->recvDataWSA(c.RecvData, 0); eargs->event->RequestEvent(c, tid, (ULONG_PTR)eargs->args); } // Continue Read/Write cycle if (!c.SendData.empty()) start_write(pClientContext); else start_read(pClientContext); } else if (pIoCtx->operation == OP_WRITE) { // 1. Remove the bytes that were successfully sent from the SendData buffer // For TCP/UDP, dwBytesTransfered represents the raw bytes on the wire. // For SSL, sendDataWSA handles the internal plaintext tracking. // Update buffer: for SSL, dwBytesTransfered is the encrypted wire size c.SendData.erase(0, dwBytesTransfered); // 2. Trigger ResponseEvent if the buffer is now empty to let the user add more data if (c.SendData.empty()) { eargs->event->ResponseEvent(c, tid, (ULONG_PTR)eargs->args); } // 3. Continue the write loop if there is remaining data if (!c.SendData.empty()) { // Prepare a buffer object for the next chunk size_t toSend = std::min<size_t>(BLOCKSIZE, c.SendData.size()); buffer out(c.SendData.data(), toSend); // 4. Use the specialized WSA methods based on socket type if (c.csock->_Type == sockettype::TCP) { static_cast<tcp*>(c.csock.get())->sendDataWSA(out, 0); } else if (c.csock->_Type == sockettype::UDP) { static_cast<udp*>(c.csock.get())->sendDataWSA(out, 0); } else if (c.csock->_Type == sockettype::SSL) { // This method encrypts the plaintext in c.SendData and initiates a WSASend static_cast<ssl*>(c.csock.get())->sendDataWSA(out, 0); } } else { // If nothing left to write, switch back to listening for data EventWorker::start_read(pClientContext); } if (!c.SendData.empty()) start_write(pClientContext); else start_read(pClientContext); } } catch (NetException& e) { std::cerr << "IOCP Worker Error: " << e.what() << std::endl; eargs->event->DisconnectEvent(c, tid, args); // Ignore non-critical notes, disconnect on actual errors if (e.getErrorType() != NetException::Note) { eargs->event->DisconnectEvent(c, tid, (ULONG_PTR)eargs->args); delete pClientContext; } } } } }; event::event(socket* serversocket, int timeout) : _ServerSocket(serversocket) { Loading Loading
src/event/iocp.cpp +101 −78 Original line number Diff line number Diff line Loading @@ -154,12 +154,54 @@ namespace netplus { class EventWorker { public: class EventWorker { public: /** * @brief Initiates an asynchronous read. * Uses the specialized WSA methods to interact with the IOCP. */ static void start_read(client* ctx) { con& c = *ctx->CurCon; // Temporary buffer for the overlapped operation buffer buf(ctx->readCtx.buffer, BLOCKSIZE); if (c.csock->_Type == sockettype::TCP) { static_cast<tcp*>(c.csock.get())->recvDataWSA(buf, 0); } else if (c.csock->_Type == sockettype::UDP) { static_cast<udp*>(c.csock.get())->recvDataWSA(buf, 0); } else if (c.csock->_Type == sockettype::SSL) { // SSL recvDataWSA prepares the internal _rx_netbuf for ciphertext static_cast<ssl*>(c.csock.get())->recvDataWSA(buf, 0); } } /** * @brief Initiates an asynchronous write. * For SSL, this triggers encryption before the WSASend call. */ static void start_write(client* ctx) { con& c = *ctx->CurCon; if (c.SendData.empty()) return; size_t toSend = std::min<size_t>(BLOCKSIZE, c.SendData.size()); buffer out(c.SendData.data(), toSend); if (c.csock->_Type == sockettype::TCP) { static_cast<tcp*>(c.csock.get())->sendDataWSA(out, 0); } else if (c.csock->_Type == sockettype::UDP) { static_cast<udp*>(c.csock.get())->sendDataWSA(out, 0); } else if (c.csock->_Type == sockettype::SSL) { static_cast<ssl*>(c.csock.get())->sendDataWSA(out, 0); } } EventWorker(int tid, ULONG_PTR args, EventWorkerArgs* eargs) { while (event::Running) { DWORD dwBytesTransfered = 0; ULONG_PTR lpContext = 0; OVERLAPPED* pOverlapped = nullptr; // Wait for completion from the port BOOL bReturn = GetQueuedCompletionStatus(eargs->eviocp, &dwBytesTransfered, &lpContext, &pOverlapped, eargs->timeout); Loading @@ -169,77 +211,58 @@ namespace netplus { IO_CONTEXT* pIoCtx = CONTAINING_RECORD(pOverlapped, IO_CONTEXT, overlapped); con& c = *pClientContext->CurCon; // Handle Disconnection or Errors // Handle Disconnection or Reset (Fixes PR_CONNECT_RESET_ERROR logic) if (!bReturn || (bReturn && dwBytesTransfered == 0)) { eargs->event->DisconnectEvent(c, tid, args); eargs->event->DisconnectEvent(c, tid, (ULONG_PTR)eargs->args); delete pClientContext; continue; } try { std::lock_guard<std::mutex> guard(pClientContext->cltmtx); if (pIoCtx->operation == OP_READ) { if (c.csock->_Type == sockettype::SSL) { // CAST required because recvData in SSL class handles the decryption state ssl* sslSocket = static_cast<ssl*>(c.csock.get()); // 1. Prepare a buffer for the plaintext // Bridge: Feed ciphertext from network to SSL engine for decryption buffer plain(BLOCKSIZE); // 2. This call takes the ciphertext (automatically filled by IOCP into _rx_netbuf) // and decrypts it into our 'plain' buffer. size_t decrypted = sslSocket->recvData(plain, 0); if (decrypted > 0) { c.RecvData.append(plain.data.buf, decrypted); eargs->event->RequestEvent(c, tid, args); eargs->event->RequestEvent(c, tid, (ULONG_PTR)eargs->args); } // 3. Request more ciphertext from the wire sslSocket->recvDataWSA(c.RecvData, 0); } else { // Standard TCP: Direct append and re-read // Plaintext TCP/UDP c.RecvData.append(pIoCtx->buffer, dwBytesTransfered); eargs->event->RequestEvent(c, tid, args); static_cast<tcp*>(c.csock.get())->recvDataWSA(c.RecvData, 0); eargs->event->RequestEvent(c, tid, (ULONG_PTR)eargs->args); } // Continue Read/Write cycle if (!c.SendData.empty()) start_write(pClientContext); else start_read(pClientContext); } else if (pIoCtx->operation == OP_WRITE) { // 1. Remove the bytes that were successfully sent from the SendData buffer // For TCP/UDP, dwBytesTransfered represents the raw bytes on the wire. // For SSL, sendDataWSA handles the internal plaintext tracking. // Update buffer: for SSL, dwBytesTransfered is the encrypted wire size c.SendData.erase(0, dwBytesTransfered); // 2. Trigger ResponseEvent if the buffer is now empty to let the user add more data if (c.SendData.empty()) { eargs->event->ResponseEvent(c, tid, (ULONG_PTR)eargs->args); } // 3. Continue the write loop if there is remaining data if (!c.SendData.empty()) { // Prepare a buffer object for the next chunk size_t toSend = std::min<size_t>(BLOCKSIZE, c.SendData.size()); buffer out(c.SendData.data(), toSend); // 4. Use the specialized WSA methods based on socket type if (c.csock->_Type == sockettype::TCP) { static_cast<tcp*>(c.csock.get())->sendDataWSA(out, 0); } else if (c.csock->_Type == sockettype::UDP) { static_cast<udp*>(c.csock.get())->sendDataWSA(out, 0); } else if (c.csock->_Type == sockettype::SSL) { // This method encrypts the plaintext in c.SendData and initiates a WSASend static_cast<ssl*>(c.csock.get())->sendDataWSA(out, 0); } } else { // If nothing left to write, switch back to listening for data EventWorker::start_read(pClientContext); } if (!c.SendData.empty()) start_write(pClientContext); else start_read(pClientContext); } } catch (NetException& e) { std::cerr << "IOCP Worker Error: " << e.what() << std::endl; eargs->event->DisconnectEvent(c, tid, args); // Ignore non-critical notes, disconnect on actual errors if (e.getErrorType() != NetException::Note) { eargs->event->DisconnectEvent(c, tid, (ULONG_PTR)eargs->args); delete pClientContext; } } } } }; event::event(socket* serversocket, int timeout) : _ServerSocket(serversocket) { Loading