Commit 794ffc67 authored by jan.koester's avatar jan.koester
Browse files

test

parent d40c7a5f
Loading
Loading
Loading
Loading
+11 −1
Original line number Diff line number Diff line
@@ -8,3 +8,13 @@ build/
.vscode/
test/
build_ninja/
install/
curl_out.txt
test_https_ps.ps1
patch_ssl_accept_run.py
patch_ssl_accept.py
refactor_ssl_key.py
reproduce_issue.cpp
silence_logs.py
test_openssl.sh
test_tls_client.py
+31 −8
Original line number Diff line number Diff line
@@ -135,6 +135,12 @@ namespace netplus {
            throw e;
        }

        if (serverSock->fd() == INVALID_SOCKET) {
             NetException e;
             e[NetException::Critical] << "init_state: Server socket is INVALID_SOCKET (closed?). Object lifetime issue?";
             throw e;
        }

        // bind listening socket
        HANDLE h = CreateIoCompletionPort((HANDLE)serverSock->fd(),
                                          st->iocp,
@@ -161,7 +167,12 @@ namespace netplus {
        try {
            // Uses the virtual accept which uses internal buffer
            serverSock->accept(st->fnAcceptEx, ctx->csock);
        } catch (NetException& e) {
            std::cerr << "[IOCP] post_accept failed (NetException): " << e.what() << std::endl;
            delete ctx;
            return;
        } catch (...) {
            std::cerr << "[IOCP] post_accept failed (unknown exception)" << std::endl;
            delete ctx;
            return;
        }
@@ -315,8 +326,9 @@ namespace netplus {
        void operator()(event* ev, socket* serverSock, int tid) {
        EventState* st = ST(ev);
        
        try {
            while (event::Running) {
            std::cerr << "[IOCP] Worker " << tid << " waiting..." << std::endl;
            // std::cerr << "[IOCP] Worker " << tid << " waiting..." << std::endl;

            DWORD bytes = 0;
            ULONG_PTR key = 0;
@@ -324,15 +336,15 @@ namespace netplus {

            BOOL ok = GetQueuedCompletionStatus(st->iocp, &bytes, &key, &pov, INFINITE);
            DWORD lastErr = GetLastError();
            std::cerr << "[IOCP] Worker " << tid << " got completion: ok=" << ok << " bytes=" << bytes << " key=" << key << " pov=" << pov << " err=" << lastErr << std::endl;
            // std::cerr << "[IOCP] Worker " << tid << " got completion: ok=" << ok << " bytes=" << bytes << " key=" << key << " pov=" << pov << " err=" << lastErr << std::endl;
            if (!event::Running) break;

            if (!pov && key == 0) continue; // wake packet

            // 1) Accept completion?
            std::cerr << "[IOCP] Checking if AcceptEx completion, pov=" << pov << std::endl;
            // std::cerr << "[IOCP] Checking if AcceptEx completion, pov=" << pov << std::endl;
            if (AcceptCtx* actx = pop_accept(st, pov)) {
                std::cerr << "[IOCP] AcceptEx completion detected!" << std::endl;
                // std::cerr << "[IOCP] AcceptEx completion detected!" << std::endl;

                // Take ownership of the accepted socket
                std::unique_ptr<socket> acceptedSock = std::move(actx->csock);
@@ -421,7 +433,12 @@ namespace netplus {
                continue;
            }
            con* owner = conPtr.get();
            std::cerr << "[IOCP] Found connection, operation=" << (buf->operation == OP_READ ? "READ" : "WRITE") << " bytes=" << bytes << std::endl;
            std::cerr << "[IOCP] Found connection, operation=" << (buf->operation == OP_READ ? "READ" : "WRITE") << " bytes=" << bytes << " InternalHigh=" << buf->overlapped.InternalHigh << std::endl;

            if (buf->operation == OP_READ && buf->overlapped.InternalHigh == 0 && bytes > 0) {
                 std::cerr << "[IOCP] Fixup: setting InternalHigh to " << bytes << std::endl;
                 buf->overlapped.InternalHigh = bytes;
            }

            if (!ok) {
                // error -> disconnect
@@ -645,6 +662,12 @@ namespace netplus {
                // if (buf) delete buf;
            }
        }
        
        } catch (std::exception& e) {
             std::cerr << "[IOCP] EventWorker thread exception: " << e.what() << std::endl;
        } catch (...) {
             std::cerr << "[IOCP] EventWorker thread unknown exception" << std::endl;
        }
    }
};

@@ -704,7 +727,7 @@ namespace netplus {
        _pollFD = (int)(intptr_t)st->iocp;

        Running = true;
        std::cerr << "[IOCP] XXXXX Starting event loop, Running=" << Running.load() << " threads=" << st->threads << std::endl; std::cerr.flush();
        std::cerr << "[IOCP] runEventloop: Starting " << st->threads << " threads." << std::endl;

        // Pre-post accepts (like "listen ready")
        // recommended: 2*threads AcceptEx in flight
+1 −0
Original line number Diff line number Diff line
@@ -331,6 +331,7 @@ namespace netplus {
#endif

		bool loadServerPrivateKeyDer(const std::string& keyDerPath);
		bool loadServerPrivateKey(const std::vector<uint8_t>& keyData);

		bool hasPendingWrite() const override {
			return (!_send_queue.empty()) || (_send_off < _send_record.size());
+27 −63
Original line number Diff line number Diff line
@@ -357,9 +357,9 @@ std::vector<uint8_t> netplus::ssl::readTlsRecordAsync()
        throw e;
    };

    // ------------------------------------------------------------
    // -------- --------------------------------------------------------
    // 1) ensure we have at least TLS record header (5 bytes)
    // ------------------------------------------------------------
    // ----------------------------------------------------------------
#ifdef Windows
    while (_rx_tcp_buf.size() < 5) {
        buffer tmpBuf(4096);
@@ -407,7 +407,6 @@ std::vector<uint8_t> netplus::ssl::readTlsRecordAsync()
    // ------------------------------------------------------------
    uint16_t recLen = (uint16_t(_rx_tcp_buf[3]) << 8) | uint16_t(_rx_tcp_buf[4]);
    size_t total = 5 + recLen;

    // ------------------------------------------------------------
    // 3) read until full record present
    // ------------------------------------------------------------
@@ -1553,6 +1552,7 @@ void netplus::ssl::_tls13_send_finished(bool handshake_keys){


void netplus::ssl::handshake_after_accept(){
    std::cerr << "[SSL] handshake_after_accept called, _handshakeDone=" << _handshakeDone << " _hs_tx.size()=" << _hs_tx.size() << std::endl;
    auto throwSSL = [&](int type, const std::string& msg) {
        netplus::NetException e;
        e[type] << "ssl::accept: " << msg;
@@ -2669,68 +2669,29 @@ void netplus::ssl::flush_out(){

#ifdef Windows
void netplus::ssl::accept(LPFN_ACCEPTEX lpfnAcceptEx, std::unique_ptr<socket>& csock) {
    NetException exception;

    // Create the SSL socket if it doesn't exist
    if (!csock) {
        if(this->_cert)
        csock = std::make_unique<netplus::ssl>(*this->_cert);
        else{
            exception[NetException::Error] << "ssl::accept: no certificate";
            throw exception;
    }

    ssl* cssock = dynamic_cast<ssl*>(csock.get());
    if (!cssock) {
        NetException e;
        e[NetException::Critical] << "ssl::accept: csock is not ssl";
        throw e;
    }

    ssl* cssock = static_cast<ssl*>(csock.get());
    // Reset TLS state for new connection
    cssock->resetTLS();

    // SSL-Status zurücksetzen
    cssock->_handshakeDone = false;
    cssock->_hs_tx.clear();
    cssock->_rx_tcp_buf.clear();
    // Share cert/rsa/ec key from server socket
    cssock->_cert = this->_cert;
    cssock->_rsa  = this->_rsa;
    std::memcpy(cssock->_ec_priv, this->_ec_priv, 32);
    cssock->_has_ec_key = this->_has_ec_key;

    const addrinfo* ai = reinterpret_cast<const addrinfo*>(this->_SocketInfo);

    // Socket erstellen
    cssock->_Socket = WSASocketW(ai->ai_family, ai->ai_socktype, ai->ai_protocol, nullptr, 0, WSA_FLAG_OVERLAPPED);

    if (cssock->_Socket == INVALID_SOCKET) {
        exception[NetException::Error] << "AcceptEx (SSL): WSASocket failed: " << WSAGetLastError();
        throw exception;
    }

    if (!csock->_ReadBuffer)
        csock->_ReadBuffer.reset(new buffer);

    buffer* buf = csock->_ReadBuffer.get();

    // WICHTIG: Verwende die Overlapped-Struktur aus dem übergebenen Buffer-Objekt
    // Nur so kann der EventWorker via CONTAINING_RECORD das buffer-Objekt finden!
    std::memset(&buf->overlapped, 0, sizeof(WSAOVERLAPPED));
    buf->operation = OP_ACCEPT; // Markiere die Operation für den Worker

    DWORD dwbytes = 0;

    // AcceptEx Aufruf
    const BOOL ok = lpfnAcceptEx(
        (SOCKET)this->_Socket,
        (SOCKET)cssock->_Socket,
        buf->data.buf,           
        0,                       // 0 = Return sofort bei Verbindung (TCP Handshake)
        sizeof(SOCKADDR_STORAGE) + 16,
        sizeof(SOCKADDR_STORAGE) + 16,
        &dwbytes,
        &buf->overlapped         // <--- Entscheidend für den Worker
    );

    if (!ok && WSAGetLastError() != WSA_IO_PENDING) {
        closesocket((SOCKET)cssock->_Socket);
        cssock->_Socket = INVALID_SOCKET;
        exception[NetException::Error] << "AcceptEx (SSL) failed: " << WSAGetLastError();
        throw exception;
    }
    // Call parent tcp::accept() to handle AcceptEx and socket creation
    tcp::accept(lpfnAcceptEx, csock);
}
#endif

@@ -3885,13 +3846,16 @@ static bool isOidEcPublicKey(const uint8_t* oid, size_t len) {
}

bool netplus::ssl::loadServerPrivateKeyDer(const std::string& keyDerPath) {
    std::cerr << "[SSL] *** loadServerPrivateKeyDer CALLED ***" << std::endl;
    std::cerr << "[SSL] keyDerPath=" << keyDerPath << std::endl;
    std::cerr.flush();
    try {
        std::vector<uint8_t> der = readFileBytesDer(keyDerPath);
        std::cerr << "[SSL] Read " << der.size() << " bytes from key file" << std::endl;
        std::cerr.flush();
        return loadServerPrivateKey(der);
    } catch (...) {
        throw;
    }
}

bool netplus::ssl::loadServerPrivateKey(const std::vector<uint8_t>& der) {
    try {

        netplus::ASN1Node root;
        size_t used = _cert->parseInternal(der.data(), der.size(), root); // reuse parser
+9 −2
Original line number Diff line number Diff line
@@ -69,7 +69,7 @@ tcp::tcp(const std::string& addr, int port, int maxconnections, int sockopts)
    }

    for (addrinfo* rp = result; rp; rp = rp->ai_next) {
        _Socket = ::socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
        _Socket = ::WSASocketA(rp->ai_family, rp->ai_socktype, rp->ai_protocol, nullptr, 0, WSA_FLAG_OVERLAPPED);
        if (_Socket == INVALID_SOCKET)
            continue;

@@ -228,7 +228,7 @@ void netplus::tcp::connect(const std::string& addr, int port, bool nonblock)
        }

        if (_Socket == INVALID_SOCKET) {
            _Socket = ::socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
            _Socket = ::WSASocketA(rp->ai_family, rp->ai_socktype, rp->ai_protocol, nullptr, 0, WSA_FLAG_OVERLAPPED);
            if (_Socket == INVALID_SOCKET)
                continue;
        }
@@ -296,6 +296,9 @@ void tcp::setBlock() {
}

void tcp::accept(LPFN_ACCEPTEX lpfnAcceptEx, std::unique_ptr<socket>& csock) {
    if (!csock) {
        csock = std::make_unique<tcp>();
    }
    // Create accept socket
    SOCKET acceptSock = ::WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, nullptr, 0, WSA_FLAG_OVERLAPPED);
    if (acceptSock == INVALID_SOCKET) {
@@ -304,6 +307,10 @@ void tcp::accept(LPFN_ACCEPTEX lpfnAcceptEx, std::unique_ptr<socket>& csock) {
        throw e;
    }

    // IOCP sockets should be non-blocking to prevent accidental blocking in recv/send
    u_long mode = 1;
    ::ioctlsocket(acceptSock, FIONBIO, &mode);

    if (!csock->_ReadBuffer)
        csock->_ReadBuffer.reset(new buffer);

Loading