Commit 3a2d70d8 authored by jan.koester's avatar jan.koester
Browse files

test

parent 1cc5c7a1
Loading
Loading
Loading
Loading
+180 −23
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/

#include <iostream>
#include <iomanip>
#include <algorithm>
#include <chrono>
#include <mutex>
@@ -212,70 +213,226 @@ namespace netplus {

                if (!ov) continue;

                // --------------------------------------------------------------------
                // 1) AcceptEx completions arrive on the IOCP with key == listenerKey
                //    DO NOT cast key to client* in that case.
                // --------------------------------------------------------------------
                if (key == eargs->listenerKey) {
                    std::unique_ptr<socket> accepted;
                    {
                        std::lock_guard<std::mutex> lk(ACCEPT_MTX);
                        auto it = ACCEPT_PENDING.find(ov);
                        if (it != ACCEPT_PENDING.end()) {
                            accepted = std::move(it->second);
                            ACCEPT_PENDING.erase(it);
                        }
                    }

                    if (!accepted) {
                        std::cerr << "[IOCP] AcceptEx completion: no pending entry for ov=" << ov << "\n";
                        continue;
                    }

                    SOCKET accSock = (SOCKET)accepted->fd();
                    std::cerr << "[IOCP] AcceptEx completion: accepted fd=" << accSock
                        << " ov=" << ov << " bytes=" << bytes << "\n";

                    setsockopt(accSock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
                        (char*)&eargs->listenSock, sizeof(eargs->listenSock));

                    // Build client connection
                    client* pClient = new client(eargs->event);
                    pClient->CurCon->csock = std::move(accepted);

                    // Associate accepted socket with IOCP using key = pClient
                    HANDLE h = CreateIoCompletionPort(
                        (HANDLE)(uintptr_t)pClient->CurCon->csock->fd(),
                        eargs->eviocp,
                        (ULONG_PTR)pClient,
                        0);

                    if (!h) {
                        std::cerr << "[IOCP] CreateIoCompletionPort(accepted) failed fd="
                            << pClient->CurCon->csock->fd()
                            << " err=" << GetLastError() << "\n";
                        eargs->event->DisconnectEvent(*pClient->CurCon, tid, (ULONG_PTR)eargs->args);
                        delete pClient;
                    }
                    else {
                        std::cerr << "[IOCP] calling ConnectEvent for fd="
                            << pClient->CurCon->csock->fd() << "\n";
                        eargs->event->ConnectEvent(*pClient->CurCon, tid, (ULONG_PTR)eargs->args);

                        // Start reading raw bytes immediately (TLS handshake will be stepped from OP_READ)
                        start_read(pClient);
                    }

                    // Re-post AcceptEx
                    try {
                        std::unique_ptr<socket> nextSock;
                        static_cast<ssl*>(eargs->ssocket)->accept(eargs->lpfnAcceptEx, nextSock);
                        {
                            std::lock_guard<std::mutex> lk(ACCEPT_MTX);
                            ACCEPT_PENDING.emplace(&nextSock->_Overlapped, std::move(nextSock));
                            std::cerr << "[IOCP] Re-posted AcceptEx; pending_count=" << ACCEPT_PENDING.size() << "\n";
                        }
                    }
                    catch (NetException& e) {
                        std::cerr << "AcceptEx repost error: " << e.what() << "\n";
                    }

                    continue;
                }

                // --------------------------------------------------------------------
                // 2) Normal client completions: key is client*
                // --------------------------------------------------------------------
                client* ctx = reinterpret_cast<client*>(key);
                if (!ctx || !ctx->CurCon || !ctx->CurCon->csock) {
                    std::cerr << "[IOCP] ERROR: invalid client key=" << (void*)key
                        << " ov=" << ov << "\n";
                    continue;
                }

                IO_CONTEXT* io = CONTAINING_RECORD(ov, IO_CONTEXT, overlapped);
                con& c = *ctx->CurCon;

                if (!ok || bytes == 0) {
                    eargs->event->DisconnectEvent(c, tid, args);
                    std::cerr << "[IOCP] closed/error fd=" << c.csock->fd()
                        << " ok=" << ok << " bytes=" << bytes
                        << " err=" << GetLastError() << "\n";
                    eargs->event->DisconnectEvent(c, tid, (ULONG_PTR)eargs->args);
                    delete ctx;
                    continue;
                }

                try {
                    std::lock_guard<std::mutex> lock(ctx->cltmtx);
                    std::lock_guard<std::mutex> guard(ctx->cltmtx);

                    if (io->operation == OP_READ) {

                        if (c.csock->_Type == sockettype::SSL) {
                            ssl* s = static_cast<ssl*>(c.csock.get());

                            // 🔴 FIX: append bytes FIRST
                            s->_rx_netbuf.insert(
                                s->_rx_netbuf.end(),
                                io->buffer,
                                io->buffer + bytes
                            );
                            // Debug header for "bad TLS version"
                            if (bytes >= 5) {
                                const unsigned char* p = (const unsigned char*)io->buffer;
                                std::cerr << "[IOCP][SSL] RX bytes=" << bytes
                                    << " hdr: "
                                    << std::hex
                                    << (int)p[0] << " " << (int)p[1] << " " << (int)p[2] << " "
                                    << (int)p[3] << " " << (int)p[4]
                                    << std::dec << "\n";
                            }
                            else {
                                std::cerr << "[IOCP][SSL] RX bytes=" << bytes << " (<5)\n";
                            }

                            // 🔴 THEN handshake
                            if (!s->_handshakeDone) {
                                while (s->handshakeStepIOCP()) {}
                            // Append ciphertext into SSL net buffer first (handshakeStepIOCP expects it there)
                            s->_rx_netbuf.insert(s->_rx_netbuf.end(),
                                (unsigned char*)io->buffer,
                                (unsigned char*)io->buffer + bytes);

                                if (!s->_hs_tx.empty())
                                    start_write(ctx);
                            // --- Handshake phase (IOCP stepped) ---
                            if (!s->_handshakeDone) {
                                bool progressed = false;
                                for (;;) {
                                    bool step = s->handshakeStepIOCP(); // consumes at most one record per call
                                    if (!step) break;
                                    progressed = true;
                                }

                                // If handshake produced outbound bytes, send them using overlapped write
                                if (!s->_hs_tx.empty() && s->_hs_tx_off < s->_hs_tx.size()) {
                                    // Kick a WSASend of handshake bytes.
                                    // Use ctx->writeCtx.overlapped, not some undefined "ctx".
                                    buffer out(
                                        (const char*)s->_hs_tx.data() + s->_hs_tx_off,
                                        (int)(s->_hs_tx.size() - s->_hs_tx_off)
                                    );
                                    s->tcp::sendDataWSA(out, &ctx->writeCtx.overlapped, 0);
                                }

                                // Always post next read while handshaking
                                start_read(ctx);
                                continue;
                            }

                            // decrypt application data
                            // --- Application phase ---
                            buffer plain(BLOCKSIZE);
                            size_t n = 0;
                            while ((n = s->recvDataWSA(plain, nullptr, 0)) > 0) {
                                c.RecvData.append(plain.data.buf, n);
                                eargs->event->RequestEvent(c, tid, args);
                            size_t decrypted = 0;
                            while ((decrypted = s->recvDataWSA(plain, nullptr, 0)) > 0) {
                                c.RecvData.append(plain.data.buf, decrypted);
                                std::cerr << "[IOCP] RequestEvent (SSL) fd=" << c.csock->fd()
                                    << " +" << decrypted << " total=" << c.RecvData.size() << "\n";
                                eargs->event->RequestEvent(c, tid, (ULONG_PTR)eargs->args);
                            }
                        }
                        else {
                            // TCP
                            c.RecvData.append(io->buffer, bytes);
                            eargs->event->RequestEvent(c, tid, args);
                            std::cerr << "[IOCP] RequestEvent (TCP) fd=" << c.csock->fd()
                                << " +" << bytes << " total=" << c.RecvData.size() << "\n";
                            eargs->event->RequestEvent(c, tid, (ULONG_PTR)eargs->args);
                        }

                        // Continue I/O
                        if (!c.SendData.empty()) start_write(ctx);
                        else start_read(ctx);
                    }

                    else if (io->operation == OP_WRITE) {

                        if (c.csock->_Type == sockettype::SSL) {
                            ssl* s = static_cast<ssl*>(c.csock.get());

                            // Handshake TX in progress?
                            if (!s->_handshakeDone && !s->_hs_tx.empty()) {
                                s->_hs_tx_off += bytes;

                                if (s->_hs_tx_off < s->_hs_tx.size()) {
                                    buffer out(
                                        (const char*)s->_hs_tx.data() + s->_hs_tx_off,
                                        (int)(s->_hs_tx.size() - s->_hs_tx_off)
                                    );
                                    s->tcp::sendDataWSA(out, &ctx->writeCtx.overlapped, 0);
                                    continue;
                                }

                                // handshake flight fully sent
                                s->_hs_tx.clear();
                                s->_hs_tx_off = 0;

                                // keep reading to continue handshake
                                start_read(ctx);
                                continue;
                            }

                            // Normal encrypted record send bookkeeping
                            s->_send_off += bytes;
                            if (s->_send_off >= s->_send_record.size()) {
                                s->_send_record.clear();
                                s->_send_off = 0;
                            }
                        }

                        if (c.SendData.empty()) {
                            std::cerr << "[IOCP] ResponseEvent fd=" << c.csock->fd() << " send_queue_empty\n";
                            eargs->event->ResponseEvent(c, tid, (ULONG_PTR)eargs->args);
                        }

                        if (!c.SendData.empty()) start_write(ctx);
                        else start_read(ctx);
                    }
                }
                catch (NetException& e) {
                    eargs->event->DisconnectEvent(c, tid, args);
                    std::cerr << "[IOCP] NetException fd=" << c.csock->fd() << ": " << e.what() << "\n";
                    if (e.getErrorType() != NetException::Note) {
                        eargs->event->DisconnectEvent(c, tid, (ULONG_PTR)eargs->args);
                        delete ctx;
                    }
                }
            }
        }
    };

    void eventapi::CreateConnection(std::shared_ptr<con>& res) {
+26 −0
Original line number Diff line number Diff line
@@ -2196,6 +2196,17 @@ bool netplus::ssl::handshakeStepIOCP()
        }
        };

    auto hexDump =[](const uint8_t* p, size_t n) {
        std::ostringstream oss;
        oss << std::hex << std::setfill('0');
        for (size_t i = 0; i < n; ++i) {
            oss << std::setw(2) << (unsigned)p[i];
            if (i + 1 != n) oss << ' ';
        }
        return oss.str();
    };


    // ---- consume one TLS record per call (keeps IOCP stepping simple) --------
    std::vector<uint8_t> rec;
    if (!tryPopTlsRecord(rec)) return false; // need more ciphertext
@@ -2207,8 +2218,23 @@ bool netplus::ssl::handshakeStepIOCP()
    const uint16_t len = (uint16_t(rec[3]) << 8) | uint16_t(rec[4]);

    if (ver != 0x0303) {
        // rec includes the popped TLS record (5+len bytes)
        const size_t showRec = (std::min<size_t>)(rec.size(), 32);
        std::cerr << "[TLS-HS] bad ver=" << std::hex << ver << std::dec
            << " ct=" << (int)ct
            << " len=" << len
            << " rec[0..]=" << hexDump(rec.data(), showRec)
            << "\n";

        // also show current remaining buffered ciphertext after popping this record
        const size_t showBuf = (std::min<size_t>)(_rx_netbuf.size(), (size_t)32);
        std::cerr << "[TLS-HS] rx_netbuf(rem)=" << _rx_netbuf.size()
            << " bytes: " << (showBuf ? hexDump(_rx_netbuf.data(), showBuf) : std::string("(empty)"))
            << "\n";

        throwSSL(netplus::NetException::Error, "bad TLS version during handshake");
    }

    if (rec.size() != size_t(5 + len)) {
        throwSSL(netplus::NetException::Error, "TLS record length mismatch");
    }
+19 −7
Original line number Diff line number Diff line
@@ -282,31 +282,43 @@ namespace netplus {

    // ---- TLS record reader ---------------------------------------------------
    std::vector<uint8_t> readTlsRecord(netplus::ssl* s) {
        uint8_t hdr[5] = { 0xAA,0xAA,0xAA,0xAA,0xAA };

        uint8_t hdr[5] = { 0 };
        readExactRaw(*s, hdr, 5);

        if (hdr[1] != 0x0303) {
        const uint8_t  type = hdr[0];
        const uint16_t ver = (uint16_t(hdr[1]) << 8) | uint16_t(hdr[2]);
        const uint16_t len = (uint16_t(hdr[3]) << 8) | uint16_t(hdr[4]);

        // TLS/SSLv3 record major must be 0x03
        if (hdr[1] != 0x03) {
            netplus::NetException e;
            e[netplus::NetException::Error] << "ssl::accept: bad TLS major version";
            e[netplus::NetException::Error] << "ssl::accept: bad TLS major byte: 0x"
                << std::hex << int(hdr[1]);
            throw e;
        }

        size_t len = (size_t(hdr[3]) << 8) | size_t(hdr[4]);
        // Accept legacy record-layer versions (very common: 0x0301 even for TLS1.2 ClientHello)
        // Allow: TLS1.0..TLS1.2 record versions
        if (ver < 0x0301 || ver > 0x0303) {
            netplus::NetException e;
            e[netplus::NetException::Error] << "ssl::accept: unsupported TLS record version: 0x"
                << std::hex << ver;
            throw e;
        }

        // sanity on len (keep your existing limits)
        static constexpr size_t TLS_MAX_PLAINTEXT = 16384;
        static constexpr size_t TLS_MAX_CBC_OVERHEAD = 2048;
        static constexpr size_t TLS_MAX_RECORD = TLS_MAX_PLAINTEXT + TLS_MAX_CBC_OVERHEAD;

        if (len == 0 || len > TLS_MAX_RECORD) {
            netplus::NetException e;
            e[netplus::NetException::Error] << "ssl::accept: invalid TLS record length " << len;
            e[netplus::NetException::Error] << "ssl::accept: invalid TLS record length " << std::dec << len;
            throw e;
        }

        std::vector<uint8_t> rec(5 + len);
        std::memcpy(rec.data(), hdr, 5);

        readExactRaw(*s, rec.data() + 5, len);
        return rec;
    }