Commit fbf748c7 authored by jan.koester's avatar jan.koester
Browse files

test

parent cd0c8d80
Loading
Loading
Loading
Loading
+101 −78
Original line number Diff line number Diff line
@@ -93,19 +93,26 @@ namespace netplus {

    class EventWorker {
        public:
            /**
             * @brief Helper to initiate a raw overlapped read.
             * This fills the context buffer which recvDataWSA will later process.
             */
            static void start_read(client* ctx) {
                con& c = *ctx->CurCon;
                // Point the WSA buffer to our persistent context buffer
                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) {
                    // Note: For SSL, this initiates the raw TCP read into _rx_netbuf
                    static_cast<ssl*>(c.csock.get())->recvDataWSA(buf, 0);
                }
            }

            /**
             * @brief Helper to initiate a raw overlapped write.
             */
            static void start_write(client* ctx) {
                con& c = *ctx->CurCon;
                if (c.SendData.empty()) return;
@@ -115,28 +122,34 @@ namespace netplus {

                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 triggers SSL encryption then calls internal WSASend
                    static_cast<ssl*>(c.csock.get())->sendDataWSA(out, 0);
                }
            }

            /**
             * @brief The core IOCP Worker Loop
             */
            EventWorker(int tid, ULONG_PTR args, EventWorkerArgs* eargs) {
                while (event::Running) {
                    DWORD dwBytesTransfered = 0;
                    ULONG_PTR lpContext = 0;
                    OVERLAPPED* pOverlapped = nullptr;

                    // 1. Wait for completion notification from Windows Kernel
                    BOOL bReturn = GetQueuedCompletionStatus(eargs->eviocp, &dwBytesTransfered,
                                                            &lpContext, &pOverlapped, eargs->timeout);

                    // Handle timeout (eargs->timeout)
                    if (lpContext == 0 && GetLastError() == WAIT_TIMEOUT) continue;
                    if (lpContext == 0) continue;

                    client* pClientContext = reinterpret_cast<client*>(lpContext);
                    IO_CONTEXT* pIoCtx = CONTAINING_RECORD(pOverlapped, IO_CONTEXT, overlapped);
                    con& c = *pClientContext->CurCon;

                    // 2. Handle Disconnection or Socket Errors
                    if (!bReturn || (bReturn && dwBytesTransfered == 0)) {
                        eargs->event->DisconnectEvent(c, tid, (ULONG_PTR)eargs->args);
                        delete pClientContext;
@@ -149,23 +162,32 @@ namespace netplus {
                        if (pIoCtx->operation == OP_READ) {
                            if (c.csock->_Type == sockettype::SSL) {
                                ssl* sslSocket = static_cast<ssl*>(c.csock.get());
                                
                                sslSocket->_rx_netbuf.insert(
                                    sslSocket->_rx_netbuf.end(), 
                                    pIoCtx->buffer, 
                                    pIoCtx->buffer + dwBytesTransfered
                                );

                                buffer plain(BLOCKSIZE);
                            size_t decrypted = sslSocket->recvData(plain, 0);
                                size_t decrypted = sslSocket->recvDataWSA(plain, 0);

                                if (decrypted > 0) {
                                    c.RecvData.append(plain.data.buf, decrypted);
                                    eargs->event->RequestEvent(c, tid, (ULONG_PTR)eargs->args);
                                }
                            } else {
                                // Standard TCP: Raw data is the application data
                                c.RecvData.append(pIoCtx->buffer, dwBytesTransfered);
                                eargs->event->RequestEvent(c, tid, (ULONG_PTR)eargs->args);
                            }

                            // Determine next step: Write if data pending, else keep reading
                            if (!c.SendData.empty()) start_write(pClientContext);
                            else start_read(pClientContext);

                        } else if (pIoCtx->operation == OP_WRITE) {
                        // FIXED: Use iterators for erasure to prevent compiler error
                            // Update the SendData buffer based on successful wire transfer
                            if (dwBytesTransfered > 0 && dwBytesTransfered <= c.SendData.size()) {
                                c.SendData.erase(c.SendData.begin(), c.SendData.begin() + dwBytesTransfered);
                            }
@@ -178,6 +200,7 @@ namespace netplus {
                            else start_read(pClientContext);
                        }
                    } catch (NetException& e) {
                        // Ignore "Note" level exceptions, but disconnect on Errors
                        if (e.getErrorType() != NetException::Note) {
                            eargs->event->DisconnectEvent(c, tid, (ULONG_PTR)eargs->args);
                            delete pClientContext;
+1 −0
Original line number Diff line number Diff line
@@ -317,5 +317,6 @@ namespace netplus {

        friend class poll;
        friend class event;
        friend class EventWorker;
    };
};
+49 −23
Original line number Diff line number Diff line
@@ -1801,39 +1801,65 @@ size_t netplus::ssl::sendDataWSA(buffer &data, int flags) {
}

size_t netplus::ssl::recvDataWSA(buffer &data, int flags) {
    // 1. Process ciphertext that was placed in _rx_netbuf by the IOCP
    // 1. Move raw ciphertext from the network buffer (filled by IOCP) to the record processor
    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
        _rx_netbuf.clear(); // Clear to allow the next WSARecv to fill it
    }

    // 2. Attempt to decrypt a full TLS record
    if (_recv_record.size() >= 5) { // Minimum TLS Header size
    // 2. We need at least 5 bytes to read the TLS Record Header
    if (_recv_record.size() < 5) {
        return 0; 
    }

    // 3. Parse TLS Record Header
    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)) {
    // Validate TLS Major Version (Must be 3 for SSLv3/TLS 1.x)
    // This specifically prevents the "bad TLS major version" error
    if ((version >> 8) != 3) {
        NetException e;
        e[NetException::Error] << "ssl::recvDataWSA: bad TLS major version: " << (int)(version >> 8);
        throw e;
    }

    // 4. Check if the full encrypted record has arrived
    if (_recv_record.size() < (size_t)(5 + length)) {
        return 0; // Wait for more data from the next IOCP completion
    }

    // 5. Extract the fragment (ciphertext + MAC + Padding)
    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);
    // 6. Decryption Logic
    std::vector<uint8_t> plaintext;
    if (!_handshakeDone) {
        // During handshake, data is often unencrypted (ClientHello/ServerHello)
        // or uses specific handshake encryption states.
        plaintext = fragment; 
    } else {
        // Decrypt the application data using the established AES/CBC state
        plaintext = _decryptRecordCBC(type, version, fragment);
    }

            // 4. Copy decrypted plaintext to the user-provided buffer
    // 7. Copy results to the application buffer
    size_t toCopy = (std::min)(data.size, plaintext.size());
    if (toCopy > 0) {
        memcpy(data.data.buf, plaintext.data(), toCopy);
    }

            // Remove the processed record from the internal buffer
    // 8. Maintenance: Remove the processed record from the internal stream
    _recv_record.erase(_recv_record.begin(), _recv_record.begin() + 5 + length);

    // 9. If there's a protocol-level requirement (like a Handshake Finished), 
    // it should be processed here before returning to the user.

    return toCopy;
}
    }
    return 0; // No full record decrypted yet
}

#endif