Loading src/event/iocp.cpp +54 −62 Original line number Diff line number Diff line Loading @@ -154,29 +154,6 @@ namespace netplus { class EventWorker { public: // Inside the IOCP Worker logic void EventWorker::start_read(client* ctx) { con& c = *ctx->CurCon; buffer buf(ctx->readCtx.buffer, BLOCKSIZE); if (c.csock->_Type == sockettype::UDP) { // Cast to UDP to access the WSA-specific methods static_cast<udp*>(c.csock.get())->recvDataWSA(buf, 0); } } void EventWorker::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::UDP) { static_cast<udp*>(c.csock.get())->sendDataWSA(out, 0); } } EventWorker(int tid, ULONG_PTR args, EventWorkerArgs* eargs) { while (event::Running) { DWORD dwBytesTransfered = 0; Loading @@ -201,44 +178,59 @@ namespace netplus { try { std::lock_guard<std::mutex> guard(pClientContext->cltmtx); if (pIoCtx->operation == OP_READ) { // SSL vs Plaintext Decryption Logic if (c.csock->_Type == sockettype::SSL) { // Feed encrypted data to SSL engine; recvData should return plaintext buffer enc(pIoCtx->buffer, dwBytesTransfered); c.csock->recvData(enc, 0); } else { c.RecvData.append(pIoCtx->buffer, dwBytesTransfered); } // CAST required because recvData in SSL class handles the decryption state ssl* sslSocket = static_cast<ssl*>(c.csock.get()); // Notify Protocol Layer eargs->event->RequestEvent(c, tid, args); // 1. Prepare a buffer for the plaintext buffer plain(BLOCKSIZE); // Decide next step: Write if data queued, else keep reading if (!c.SendData.empty()) { start_write(pClientContext); } else { start_read(pClientContext); // 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); } } else if (pIoCtx->operation == OP_WRITE) { // For SSL, we track plaintext consumed, but IOCP tells us bytes sent on wire. // We erase based on the application layer's queue management. if (c.csock->_Type == sockettype::SSL) { // SSL layers handle SendData erasure internally or via return codes // 3. Request more ciphertext from the wire sslSocket->recvDataWSA(c.RecvData, 0); } else { c.SendData.erase(c.SendData.begin(), c.SendData.begin() + dwBytesTransfered); // Standard TCP: Direct append and re-read c.RecvData.append(pIoCtx->buffer, dwBytesTransfered); eargs->event->RequestEvent(c, tid, args); static_cast<tcp*>(c.csock.get())->recvDataWSA(c.RecvData, 0); } } 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. 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, args); eargs->event->ResponseEvent(c, tid, (ULONG_PTR)eargs->args); } // 3. Continue the write loop if there is remaining data if (!c.SendData.empty()) { start_write(pClientContext); // 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 { start_read(pClientContext); // If nothing left to write, switch back to listening for data EventWorker::start_read(pClientContext); } } } catch (NetException& e) { Loading src/socket.h +4 −1 Original line number Diff line number Diff line Loading @@ -221,7 +221,10 @@ namespace netplus { size_t sendData(buffer &data, int flags = 0) override; size_t recvData(buffer &data, int flags = 0) override; #ifdef Windows size_t sendDataWSA(buffer &data, int flags = 0); size_t recvDataWSA(buffer &data, int flags = 0); #endif bool loadServerPrivateKeyDer(const std::string& keyDerPath); bool hasPendingWrite() const override { Loading src/ssl.cpp +63 −0 Original line number Diff line number Diff line Loading @@ -1774,3 +1774,66 @@ std::vector<uint8_t> netplus::ssl::_decryptRecordCBC(uint8_t recType, } bool loadServerPrivateKeyDer(const std::string& keyDerPath); #ifdef Windows size_t netplus::ssl::sendDataWSA(buffer &data, int flags) { if (!_handshakeDone) { // Handshake logic usually handled via standard sendData // until the secure channel is established. return 0; } // 1. Encrypt the plaintext data into a TLS Record // This utilizes your existing internal encryption logic std::vector<uint8_t> plaintext( data.ptr ? data.data.ptr : data.data.buf, (data.ptr ? data.data.ptr : data.data.buf) + data.size ); // This internal helper should append the encrypted record to _send_record _sendEncryptedRecord(this, 23, plaintext); // 23 = Application Data // 2. Prepare the encrypted buffer for the WSA call buffer wsa_out((char*)_send_record.data() + _send_off, _send_record.size() - _send_off); // 3. Call the parent tcp implementation to initiate the IOCP write return tcp::sendDataWSA(wsa_out, flags); } size_t netplus::ssl::recvData(buffer &data, int flags) { // 1. Process ciphertext that was placed in _rx_netbuf by the IOCP if (!_rx_netbuf.empty()) { // Append new network data to our decryption record buffer _recv_record.insert(_recv_record.end(), _rx_netbuf.begin(), _rx_netbuf.end()); _rx_netbuf.clear(); // Clear for next WSA request } // 2. Attempt to decrypt a full TLS record if (_recv_record.size() >= 5) { // Minimum TLS Header size uint8_t type = _recv_record[0]; uint16_t version = (_recv_record[1] << 8) | _recv_record[2]; uint16_t length = (_recv_record[3] << 8) | _recv_record[4]; if (_recv_record.size() >= (size_t)(5 + length)) { std::vector<uint8_t> fragment( _recv_record.begin() + 5, _recv_record.begin() + 5 + length ); // 3. Decrypt the fragment using your CBC helper std::vector<uint8_t> plaintext = _decryptRecordCBC(type, version, fragment); // 4. Copy decrypted plaintext to the user-provided buffer size_t toCopy = std::min(data.size, plaintext.size()); memcpy(data.data.buf, plaintext.data(), toCopy); // Remove the processed record from the internal buffer _recv_record.erase(_recv_record.begin(), _recv_record.begin() + 5 + length); return toCopy; } } return 0; // No full record decrypted yet } #endif Loading
src/event/iocp.cpp +54 −62 Original line number Diff line number Diff line Loading @@ -154,29 +154,6 @@ namespace netplus { class EventWorker { public: // Inside the IOCP Worker logic void EventWorker::start_read(client* ctx) { con& c = *ctx->CurCon; buffer buf(ctx->readCtx.buffer, BLOCKSIZE); if (c.csock->_Type == sockettype::UDP) { // Cast to UDP to access the WSA-specific methods static_cast<udp*>(c.csock.get())->recvDataWSA(buf, 0); } } void EventWorker::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::UDP) { static_cast<udp*>(c.csock.get())->sendDataWSA(out, 0); } } EventWorker(int tid, ULONG_PTR args, EventWorkerArgs* eargs) { while (event::Running) { DWORD dwBytesTransfered = 0; Loading @@ -201,44 +178,59 @@ namespace netplus { try { std::lock_guard<std::mutex> guard(pClientContext->cltmtx); if (pIoCtx->operation == OP_READ) { // SSL vs Plaintext Decryption Logic if (c.csock->_Type == sockettype::SSL) { // Feed encrypted data to SSL engine; recvData should return plaintext buffer enc(pIoCtx->buffer, dwBytesTransfered); c.csock->recvData(enc, 0); } else { c.RecvData.append(pIoCtx->buffer, dwBytesTransfered); } // CAST required because recvData in SSL class handles the decryption state ssl* sslSocket = static_cast<ssl*>(c.csock.get()); // Notify Protocol Layer eargs->event->RequestEvent(c, tid, args); // 1. Prepare a buffer for the plaintext buffer plain(BLOCKSIZE); // Decide next step: Write if data queued, else keep reading if (!c.SendData.empty()) { start_write(pClientContext); } else { start_read(pClientContext); // 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); } } else if (pIoCtx->operation == OP_WRITE) { // For SSL, we track plaintext consumed, but IOCP tells us bytes sent on wire. // We erase based on the application layer's queue management. if (c.csock->_Type == sockettype::SSL) { // SSL layers handle SendData erasure internally or via return codes // 3. Request more ciphertext from the wire sslSocket->recvDataWSA(c.RecvData, 0); } else { c.SendData.erase(c.SendData.begin(), c.SendData.begin() + dwBytesTransfered); // Standard TCP: Direct append and re-read c.RecvData.append(pIoCtx->buffer, dwBytesTransfered); eargs->event->RequestEvent(c, tid, args); static_cast<tcp*>(c.csock.get())->recvDataWSA(c.RecvData, 0); } } 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. 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, args); eargs->event->ResponseEvent(c, tid, (ULONG_PTR)eargs->args); } // 3. Continue the write loop if there is remaining data if (!c.SendData.empty()) { start_write(pClientContext); // 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 { start_read(pClientContext); // If nothing left to write, switch back to listening for data EventWorker::start_read(pClientContext); } } } catch (NetException& e) { Loading
src/socket.h +4 −1 Original line number Diff line number Diff line Loading @@ -221,7 +221,10 @@ namespace netplus { size_t sendData(buffer &data, int flags = 0) override; size_t recvData(buffer &data, int flags = 0) override; #ifdef Windows size_t sendDataWSA(buffer &data, int flags = 0); size_t recvDataWSA(buffer &data, int flags = 0); #endif bool loadServerPrivateKeyDer(const std::string& keyDerPath); bool hasPendingWrite() const override { Loading
src/ssl.cpp +63 −0 Original line number Diff line number Diff line Loading @@ -1774,3 +1774,66 @@ std::vector<uint8_t> netplus::ssl::_decryptRecordCBC(uint8_t recType, } bool loadServerPrivateKeyDer(const std::string& keyDerPath); #ifdef Windows size_t netplus::ssl::sendDataWSA(buffer &data, int flags) { if (!_handshakeDone) { // Handshake logic usually handled via standard sendData // until the secure channel is established. return 0; } // 1. Encrypt the plaintext data into a TLS Record // This utilizes your existing internal encryption logic std::vector<uint8_t> plaintext( data.ptr ? data.data.ptr : data.data.buf, (data.ptr ? data.data.ptr : data.data.buf) + data.size ); // This internal helper should append the encrypted record to _send_record _sendEncryptedRecord(this, 23, plaintext); // 23 = Application Data // 2. Prepare the encrypted buffer for the WSA call buffer wsa_out((char*)_send_record.data() + _send_off, _send_record.size() - _send_off); // 3. Call the parent tcp implementation to initiate the IOCP write return tcp::sendDataWSA(wsa_out, flags); } size_t netplus::ssl::recvData(buffer &data, int flags) { // 1. Process ciphertext that was placed in _rx_netbuf by the IOCP if (!_rx_netbuf.empty()) { // Append new network data to our decryption record buffer _recv_record.insert(_recv_record.end(), _rx_netbuf.begin(), _rx_netbuf.end()); _rx_netbuf.clear(); // Clear for next WSA request } // 2. Attempt to decrypt a full TLS record if (_recv_record.size() >= 5) { // Minimum TLS Header size uint8_t type = _recv_record[0]; uint16_t version = (_recv_record[1] << 8) | _recv_record[2]; uint16_t length = (_recv_record[3] << 8) | _recv_record[4]; if (_recv_record.size() >= (size_t)(5 + length)) { std::vector<uint8_t> fragment( _recv_record.begin() + 5, _recv_record.begin() + 5 + length ); // 3. Decrypt the fragment using your CBC helper std::vector<uint8_t> plaintext = _decryptRecordCBC(type, version, fragment); // 4. Copy decrypted plaintext to the user-provided buffer size_t toCopy = std::min(data.size, plaintext.size()); memcpy(data.data.buf, plaintext.data(), toCopy); // Remove the processed record from the internal buffer _recv_record.erase(_recv_record.begin(), _recv_record.begin() + 5 + length); return toCopy; } } return 0; // No full record decrypted yet } #endif