Commit 351f81d2 authored by jan.koester's avatar jan.koester
Browse files

win working

parent 353cbe23
Loading
Loading
Loading
Loading

curl.exe

0 → 100644
+3.58 MiB

File added.

No diff preview for this file type.

+0 −0

File changed.

Preview suppressed by a .gitattributes entry or the file's encoding is unsupported.

+1 −0
Original line number Diff line number Diff line
@@ -172,6 +172,7 @@ namespace netplus {
            size_t SendOff = 0;

            std::atomic_bool WritePending{ false };
            std::atomic_bool ReadPending{ false };  // Prevent multiple simultaneous READ processing

            int DebugId=0;

+158 −33
Original line number Diff line number Diff line
@@ -51,6 +51,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define BLOCKSIZE 16384
#endif

// Set to 1 to enable debug logging
#define IOCP_DEBUG 0

#if IOCP_DEBUG
#define IOCP_LOG(x) std::cerr << x << std::endl
#else
#define IOCP_LOG(x) ((void)0)
#endif

namespace netplus {

    // -------------------------------------------------------------------------
@@ -185,10 +194,12 @@ namespace netplus {

    static AcceptCtx* pop_accept(EventState* st, OVERLAPPED* pov) {
        std::lock_guard<std::mutex> lk(st->accMutex);
#if IOCP_DEBUG
        std::cerr << "[IOCP] pop_accept: looking for pov=" << pov << " in " << st->acceptByOv.size() << " entries" << std::endl;
        for (auto& kv : st->acceptByOv) {
            std::cerr << "[IOCP]   stored ov=" << kv.first << std::endl;
        }
#endif
        auto it = st->acceptByOv.find(pov);
        if (it == st->acceptByOv.end()) return nullptr;
        AcceptCtx* ctx = it->second;
@@ -241,9 +252,18 @@ namespace netplus {
    }

    // -------------------------------------------------------------------------
    // Post receive for a connection
    // Post receive for a connection (only if not already pending)
    // -------------------------------------------------------------------------
    static void post_recv(EventState* st, con& c) {
        // Only post recv if not already pending
        bool expected = false;
        if (!c.ReadPending.compare_exchange_strong(expected, true)) {
#if IOCP_DEBUG
            std::cerr << "[IOCP] post_recv: recv already pending for fd=" << c.csock->fd() << ", skipping" << std::endl;
#endif
            return;
        }
        
        buffer* b = ensure_recv_buffer(st, c);
        std::memset(&b->overlapped, 0, sizeof(WSAOVERLAPPED));
        b->operation = OP_READ;
@@ -383,7 +403,9 @@ namespace netplus {

                // register mapping
                register_con(st, accepted, c);
#if IOCP_DEBUG
                std::cerr << "[IOCP] Registered connection: socket=" << accepted << " csock->fd()=" << c->csock->fd() << std::endl;
#endif

                // connect callback
                ev->ConnectEvent(*c, tid, 0);
@@ -407,7 +429,9 @@ namespace netplus {
            // 2) Normal I/O completion (recv/send)
            socket* sockObj = reinterpret_cast<socket*>(key);
            if (!sockObj) {
#if IOCP_DEBUG
                std::cerr << "[IOCP] sockObj is null, skipping" << std::endl;
#endif
                continue;
            }

@@ -420,17 +444,23 @@ namespace netplus {
                );
            }
            if (!buf) {
#if IOCP_DEBUG
                std::cerr << "[IOCP] buf calculation failed, pov=" << pov << std::endl;
#endif
                continue;
            }

            // Look up connection by socket fd (key is the socket*)
            SOCKET cs = (SOCKET)sockObj->fd();
#if IOCP_DEBUG
            std::cerr << "[IOCP] Looking up connection for socket fd=" << cs << std::endl;
#endif
            std::shared_ptr<con> conPtr = find_con(st, cs);
            if (!conPtr) {
                // Connection was already removed, ignore this completion
#if IOCP_DEBUG
                std::cerr << "[IOCP] Connection not found for fd=" << cs << ", ignoring" << std::endl;
#endif
                if (buf->operation == OP_WRITE) {
                    // Internal send buffer (owned by socket)
                    // Do not delete!
@@ -438,10 +468,17 @@ namespace netplus {
                continue;
            }
            con* owner = conPtr.get();
#if IOCP_DEBUG
            std::cerr << "[IOCP] Found connection, operation=" << (buf->operation == OP_READ ? "READ" : "WRITE") << " bytes=" << bytes << " InternalHigh=" << buf->overlapped.InternalHigh << std::endl;
#endif

            if (buf->operation == OP_READ && buf->overlapped.InternalHigh == 0 && bytes > 0) {
                 std::cerr << "[IOCP] Fixup: setting InternalHigh to " << bytes << std::endl;
            // Always use the bytes value from IOCP completion - InternalHigh may be stale
            if (buf->operation == OP_READ && bytes > 0) {
#if IOCP_DEBUG
                 if (buf->overlapped.InternalHigh != bytes) {
                     std::cerr << "[IOCP] Fixup: setting InternalHigh from " << buf->overlapped.InternalHigh << " to " << bytes << std::endl;
                 }
#endif
                 buf->overlapped.InternalHigh = bytes;
            }

@@ -459,6 +496,7 @@ namespace netplus {
            if (buf->operation == OP_READ) {
                if (bytes == 0) {
                    // closed
                    owner->ReadPending.store(false);
                    ev->DisconnectEvent(*owner, tid, 0);
                    remove_con(st, cs);
                    try { owner->csock->close(); } catch (...) {}
@@ -466,52 +504,74 @@ namespace netplus {
                }

                // For SSL: need to handle handshake and decryption
#if IOCP_DEBUG
                std::cerr << "[IOCP] handshakeDone=" << owner->csock->getHandshakeDone() << std::endl;
#endif

                // Check if handshake is done
                if (!owner->csock->getHandshakeDone()) {
#if IOCP_DEBUG
                    std::cerr << "[IOCP] Starting handshake_after_accept (fd=" << owner->csock->fd() << ")..." << std::endl;
                    std::cerr.flush();
#endif
                    std::lock_guard<std::mutex> hsLock(owner->event_mutex);
                    try {
                        // Process handshake from internal buffer
                        owner->csock->handshake_after_accept();
#if IOCP_DEBUG
                        std::cerr << "[IOCP] handshake_after_accept returned OK, hasPendingWrite=" << owner->csock->hasPendingWrite() << std::endl;
                        std::cerr.flush();
#endif
                        
                    } catch (NetException& e) {
#if IOCP_DEBUG
                        std::cerr << "[IOCP] handshake_after_accept threw NetException type=" << e.getErrorType() << " msg=" << e.what() << std::endl;
                        std::cerr.flush();
#endif
                        if (e.getErrorType() == NetException::Note) {
                            // Need more data - but first check if we have data to send
                            if (owner->csock->hasPendingWrite()) {
#if IOCP_DEBUG
                                std::cerr << "[IOCP] Note but hasPendingWrite - flushing first..." << std::endl;
#endif
                                try {
                                    owner->csock->flush_out();
                                } catch (...) {
#if IOCP_DEBUG
                                    std::cerr << "[IOCP] flush_out failed during Note handling" << std::endl;
#endif
                                }
                            }
                            // Repost recv for more handshake data
#if IOCP_DEBUG
                            std::cerr << "[IOCP] Reposting recv for more handshake data (fd=" << owner->csock->fd() << ")" << std::endl;
#endif
                            owner->ReadPending.store(false);  // Allow new READ processing
                            try {
                                post_recv(st, *owner);
                            } catch (...) {}
                            continue;
                        }
                        // Real error - disconnect
#if IOCP_DEBUG
                        std::cerr << "[IOCP] Non-Note error - disconnecting" << std::endl;
#endif
                        owner->ReadPending.store(false);
                        ev->DisconnectEvent(*owner, tid, 0);
                        remove_con(st, cs);
                        try { owner->csock->close(); } catch (...) {}
                        continue;
                    } catch (std::exception& e) {
#if IOCP_DEBUG
                        std::cerr << "[IOCP] handshake_after_accept threw std::exception: " << e.what() << std::endl;
#endif
                        owner->ReadPending.store(false);
                        ev->DisconnectEvent(*owner, tid, 0);
                        remove_con(st, cs);
                        try { owner->csock->close(); } catch (...) {}
                        continue;
                    } catch (...) {
#if IOCP_DEBUG
                        std::cerr << "[IOCP] handshake_after_accept threw unknown exception" << std::endl;
#endif
                        owner->ReadPending.store(false);
                        ev->DisconnectEvent(*owner, tid, 0);
                        remove_con(st, cs);
                        try { owner->csock->close(); } catch (...) {}
@@ -523,10 +583,15 @@ namespace netplus {
                    // Just check if handshake is done, otherwise repost recv for more data.
                    
                    bool handshakeDone = owner->csock->getHandshakeDone();
#if IOCP_DEBUG
                    std::cerr << "[IOCP] After handshake_after_accept: handshakeDone=" << handshakeDone << " hasPendingWrite=" << (int)owner->csock->hasPendingWrite() << std::endl;
#endif
                    
                    if (!handshakeDone) {
#if IOCP_DEBUG
                        std::cerr << "[IOCP] Handshake not done yet, reposting recv for more data" << std::endl;
#endif
                        owner->ReadPending.store(false);  // Allow new READ processing
                        try {
                            post_recv(st, *owner);
                        } catch (...) {}
@@ -541,15 +606,21 @@ namespace netplus {
                        size_t decLen = owner->csock->recvData(decrypted, 0);
                        
                        if (decLen == 0) break;
                        
#if IOCP_DEBUG
                        std::cerr << "[IOCP] Received " << decLen << " bytes of application data" << std::endl;
#endif
                        owner->RecvData.append(decrypted.data.buf, decLen);
                        ev->RequestEvent(*owner, tid, (ULONG_PTR)decLen);
#if IOCP_DEBUG
                        std::cerr << "[IOCP] RequestEvent returned, SendData.size()=" << owner->SendData.size() << std::endl;
#endif
                    }
                } catch (NetException& e) {
                    if (e.getErrorType() != NetException::Note) {
#if IOCP_DEBUG
                        std::cerr << "[IOCP] Application data recvData threw NetException: " << e.what() << std::endl;
#endif
                        owner->ReadPending.store(false);
                        ev->DisconnectEvent(*owner, tid, 0);
                        remove_con(st, cs);
                        try { owner->csock->close(); } catch (...) {}
@@ -560,17 +631,27 @@ namespace netplus {

                // if user filled SendData -> try send
                try {
#if IOCP_DEBUG
                    std::cerr << "[IOCP] Calling try_post_send, SendData.size()=" << owner->SendData.size() << std::endl;
#endif
                    try_post_send(ev, st, *owner, tid);
#if IOCP_DEBUG
                    std::cerr << "[IOCP] try_post_send completed" << std::endl;
#endif
                } catch (std::exception& ex) {
#if IOCP_DEBUG
                    std::cerr << "[IOCP] try_post_send threw: " << ex.what() << std::endl;
#endif
                    owner->ReadPending.store(false);
                    ev->DisconnectEvent(*owner, tid, 0);
                    remove_con(st, cs);
                    try { owner->csock->close(); } catch (...) {}
                    continue;
                } catch (...) {
#if IOCP_DEBUG
                    std::cerr << "[IOCP] try_post_send threw unknown exception" << std::endl;
#endif
                    owner->ReadPending.store(false);
                    ev->DisconnectEvent(*owner, tid, 0);
                    remove_con(st, cs);
                    try { owner->csock->close(); } catch (...) {}
@@ -578,6 +659,7 @@ namespace netplus {
                }

                // repost recv (IOCP rearm)
                owner->ReadPending.store(false);  // Allow new READ processing
                try {
                    post_recv(st, *owner);
                } catch (...) {
@@ -588,13 +670,26 @@ namespace netplus {
                }
            }
            else if (buf->operation == OP_WRITE) {
                // Check for write errors/connection close
                if (bytes == 0 && !ok) {
#if IOCP_DEBUG
                    std::cerr << "[IOCP] Write completion with bytes=0 and error, disconnecting" << std::endl;
#endif
                    ev->DisconnectEvent(*owner, tid, 0);
                    remove_con(st, cs);
                    try { owner->csock->close(); } catch (...) {}
                    continue;
                }
                
                // For SSL, the send encrypts all pending data at once
                // So we clear SendData entirely on completion
                bool isSSL = (owner->csock->getSocketType() == sockettype::SSL);
                
                // CRITICAL: Clear the pending IOCP write flag
                owner->csock->setPendingWrite(false);
                std::cerr << "[IOCP] Write completed, cleared _pendingIocpWrite, isSSL=" << isSSL << std::endl;
#if IOCP_DEBUG
                std::cerr << "[IOCP] Write completed, bytes=" << bytes << " cleared _pendingIocpWrite, isSSL=" << isSSL << std::endl;
#endif
                
                if (isSSL) {
                    // SSL: all data was encrypted and sent
@@ -613,34 +708,64 @@ namespace netplus {

                // If handshake not done, need to continue it
                if (!owner->csock->getHandshakeDone()) {
                    std::cerr << "[IOCP] Write completed during handshake, checking for more queued data..." << std::endl;
#if IOCP_DEBUG
                    std::cerr << "[IOCP] Write completed during handshake, continuing handshake state machine..." << std::endl;
#endif
                    
                    // Check if there's more queued handshake data to send
                    if (owner->csock->hasPendingWrite()) {
                        std::cerr << "[IOCP] More handshake data queued, flushing..." << std::endl;
                    // Clear the pending write flag BEFORE calling handshake_after_accept
                    owner->csock->setPendingWrite(false);
                    owner->WritePending.store(false);
                    
                    std::lock_guard<std::mutex> hsLock(owner->event_mutex);
                    try {
                            owner->csock->flush_out();
                        } catch (NetException& flushEx) {
                            if (flushEx.getErrorType() != NetException::Note) {
                                std::cerr << "[IOCP] flush_out error: " << flushEx.what() << std::endl;
                                throw;
                        // Continue the handshake state machine
                        owner->csock->handshake_after_accept();
#if IOCP_DEBUG
                        std::cerr << "[IOCP] handshake_after_accept completed, handshakeDone=" << owner->csock->getHandshakeDone() << " hasPendingWrite=" << owner->csock->hasPendingWrite() << std::endl;
#endif
                        
                        // If handshake is done, post recv for application data
                        if (owner->csock->getHandshakeDone()) {
                            try {
                                post_recv(st, *owner);
                            } catch (...) {}
                        }
                            std::cerr << "[IOCP] flush_out returned Note" << std::endl;
                        // If there's a new pending write, the state machine has already called flush_out()
                        // and we'll get another WRITE completion
                        // If handshake needs more data from client, post recv
                        else if (!owner->csock->hasPendingWrite()) {
                            try {
                                post_recv(st, *owner);
                            } catch (...) {}
                        }
                        // Continue with next WRITE completion
                        owner->WritePending.store(false);
                        continue;
                    } else {
                        // No more queued data. Post recv to wait for client's next message.
                        // Do NOT call handshake_after_accept() - it will be called from READ handler
                        // when client data arrives.
                        std::cerr << "[IOCP] No more queued data, posting recv for client message" << std::endl;
                    } catch (NetException& e) {
                        if (e.getErrorType() == NetException::Note) {
                            // Need more data from client
#if IOCP_DEBUG
                            std::cerr << "[IOCP] handshake_after_accept returned Note, posting recv" << std::endl;
#endif
                            try {
                                post_recv(st, *owner);
                            } catch (...) {}
                        owner->WritePending.store(false);
                        continue;
                        } else {
                            // Error 10053 = WSAECONNABORTED - connection was aborted
                            // This can happen if client closed connection during handshake
#if IOCP_DEBUG
                            std::cerr << "[IOCP] handshake_after_accept error: " << e.what() << std::endl;
#endif
                            ev->DisconnectEvent(*owner, tid, 0);
                            remove_con(st, cs);
                            try { owner->csock->close(); } catch (...) {}
                        }
                    } catch (...) {
#if IOCP_DEBUG
                        std::cerr << "[IOCP] handshake_after_accept unknown error" << std::endl;
#endif
                        ev->DisconnectEvent(*owner, tid, 0);
                        remove_con(st, cs);
                        try { owner->csock->close(); } catch (...) {}
                    }
                    continue;
                }

                owner->WritePending.store(false);

src/event/iocp_new.cpp

0 → 100644
+809 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading