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

epoll rescue

parent e4fb3b8f
Loading
Loading
Loading
Loading
+130 −41
Original line number Original line Diff line number Diff line
@@ -171,11 +171,20 @@ namespace netplus {
            ev.data.fd = fd;
            ev.data.fd = fd;


            if (epoll_ctl(_pollFD, EPOLL_CTL_MOD, fd, &ev) < 0) {
            if (epoll_ctl(_pollFD, EPOLL_CTL_MOD, fd, &ev) < 0) {
                // If FD doesn't exist in epoll, add it instead
                if (errno == ENOENT) {
                    if (epoll_ctl(_pollFD, EPOLL_CTL_ADD, fd, &ev) < 0) {
                        NetException except;
                        except[NetException::Error] << "setpollEventsFd: epoll_ctl ADD failed: " << strerror(errno);
                        throw except;
                    }
                } else {
                    NetException except;
                    NetException except;
                    except[NetException::Error] << "setpollEventsFd: epoll_ctl MOD failed: " << strerror(errno);
                    except[NetException::Error] << "setpollEventsFd: epoll_ctl MOD failed: " << strerror(errno);
                    throw except;
                    throw except;
                }
                }
            }
            }
        }


        int pollState(int pos) override {
        int pollState(int pos) override {
            if (_Events[pos].data.fd == _ServerSocket->fd())
            if (_Events[pos].data.fd == _ServerSocket->fd())
@@ -244,8 +253,12 @@ namespace netplus {
        // IO handling (NO DEADLOCK!)
        // IO handling (NO DEADLOCK!)
        // ------------------------------------------------------------
        // ------------------------------------------------------------
        void IoEventHandler(int fd, int events, const int tid, ULONG_PTR args) override {
        void IoEventHandler(int fd, int events, const int tid, ULONG_PTR args) override {
            std::cerr << "[EPOLL] ===== IoEventHandler called! fd=" << fd << " events=" << events << " EPOLLIN=" << (events & EPOLLIN) << std::endl;
            std::shared_ptr<con> c = getConByFd(fd);
            std::shared_ptr<con> c = getConByFd(fd);
            if (!c || !c->csock) return;
            if (!c || !c->csock) {
                std::cerr << "[EPOLL] No connection found!" << std::endl;
                return;
            }


            EpollArmGuard rearm(fd, c, this);
            EpollArmGuard rearm(fd, c, this);


@@ -264,20 +277,58 @@ namespace netplus {
                        needClose = true;
                        needClose = true;
                    }
                    }
                    else {
                    else {
                        std::cerr << "[EPOLL] Event: events=" << events << " EPOLLIN=" << (events & EPOLLIN) 
                                  << " handshakeDone=" << c->csock->getHandshakeDone() << std::endl;
                        
                        // Step 1: If handshake not done and EPOLLIN, read raw TCP data into TLS buffer
                        if ((events & EPOLLIN) && !c->csock->getHandshakeDone() && !needClose) {
                            buffer buf(BLOCKSIZE);
                            size_t rcv = 0;

                            std::cerr << "[EPOLL] Attempting to read raw TCP data..." << std::endl;
                            try {
                                // Read raw TCP data (don't use recvData which tries to decrypt)
                                rcv = ((netplus::tcp&)*c->csock).tcp::recvData(buf, 0);
                                std::cerr << "[EPOLL] Read " << rcv << " bytes from socket" << std::endl;
                            } catch (NetException& e) {
                                if (e.getErrorType() == NetException::Note){
                                    std::cerr << "[EPOLL] tcp::recvData threw Note (EAGAIN/EWOULDBLOCK)" << std::endl;
                                    // No data available right now - just continue to handshake
                                    // (it will re-arm socket when needed)
                                    rcv = 0;
                                } else {
                                    throw;
                                }
                            }


                        // 1) TLS handshake - loop until no more buffered data
                            if (rcv == 0) {
                        while (!c->csock->getHandshakeDone()) {
                                std::cerr << "[EPOLL] No TCP data available (would block or EOF)" << std::endl;
                            std::cerr << "[EPOLL] Calling handshake_after_accept()" << std::endl;
                            } else {
                                std::cerr << "[EPOLL] Received " << rcv << " raw TCP bytes for handshake" << std::endl;
                                // Put raw TLS data into _rx_tcp_buf via pushReceivedData()
                                c->csock->pushReceivedData((const uint8_t*)buf.data.buf, rcv);
                            }
                        }

                        // Step 2: Try handshake (with buffered TLS data)
                        if (!c->csock->getHandshakeDone() && !needClose) {
                            std::cerr << "[EPOLL] BEFORE handshake_after_accept: handshakeDone=" << c->csock->getHandshakeDone() << std::endl;
                            try {
                                c->csock->handshake_after_accept();
                                c->csock->handshake_after_accept();
                            std::cerr << "[EPOLL] handshake_after_accept() returned" << std::endl;
                            } catch (NetException& e) {
                                if (e.getErrorType() != NetException::Note) throw;
                                std::cerr << "[EPOLL] handshake_after_accept returned Note" << std::endl;
                            }
                            std::cerr << "[EPOLL] AFTER handshake_after_accept: handshakeDone=" << c->csock->getHandshakeDone() << std::endl;


                            // Flush any pending write data
                            if (c->csock->hasPendingWrite()) {
                            if (c->csock->hasPendingWrite()) {
                                std::cerr << "[EPOLL] Flushing pending write data" << std::endl;
                                std::cerr << "[EPOLL] Flushing pending write data" << std::endl;
                                try {
                                try {
                                    c->csock->flush_out();
                                    c->csock->flush_out();
                                } catch (NetException& e) {
                                } catch (NetException& e) {
                                    if (e.getErrorType() == NetException::Note) {
                                    if (e.getErrorType() == NetException::Note) {
                                        std::cerr << "[EPOLL] flush_out threw Note" << std::endl;
                                        std::cerr << "[EPOLL] flush_out threw Note, re-arming for write" << std::endl;
                                        setpollEventsFd(fd, EPOLLOUT | EPOLLRDHUP | EPOLLONESHOT);
                                        setpollEventsFd(fd, EPOLLOUT | EPOLLRDHUP | EPOLLONESHOT);
                                    } else {
                                    } else {
                                        throw;
                                        throw;
@@ -285,32 +336,67 @@ namespace netplus {
                                }
                                }
                            }
                            }


                            // Process any buffered TLS data left in socket buffer
                            while (!c->csock->getHandshakeDone() && c->csock->hasBufferedData()) {
                                std::cerr << "[EPOLL] Processing buffered TLS data" << std::endl;
                                try {
                                    c->csock->handshake_after_accept();
                                } catch (NetException& e) {
                                    if (e.getErrorType() != NetException::Note) throw;
                                }

                                if (c->csock->hasPendingWrite()) {
                                    try {
                                        c->csock->flush_out();
                                    } catch (NetException& e) {
                                        if (e.getErrorType() != NetException::Note) throw;
                                        setpollEventsFd(fd, EPOLLOUT | EPOLLRDHUP | EPOLLONESHOT);
                                        break;
                                    }
                                }
                            }

                            // If handshake still not done, re-arm for more data
                            if (!c->csock->getHandshakeDone()) {
                            if (!c->csock->getHandshakeDone()) {
                                // still waiting
                                std::cerr << "[EPOLL] Handshake not done, re-arming socket" << std::endl;
                                // Check if there's buffered data to process first!
                                if (!c->csock->hasBufferedData()) {
                                    // No buffered data, re-arm socket for more events
                                    std::cerr << "[EPOLL] Handshake not done, re-arming socket for more events" << std::endl;
                                int ev = EPOLLIN | EPOLLRDHUP | EPOLLONESHOT;
                                int ev = EPOLLIN | EPOLLRDHUP | EPOLLONESHOT;
                                if (c->csock->hasPendingWrite())
                                if (c->csock->hasPendingWrite())
                                    ev |= EPOLLOUT;
                                    ev |= EPOLLOUT;
                                setpollEventsFd(fd, ev);
                                setpollEventsFd(fd, ev);
                                    break; // Exit handshake loop, return to event handler
                            }
                            }
                                // else: has buffered data, loop again to process it
                                std::cerr << "[EPOLL] Buffered data available, continuing handshake" << std::endl;
                        }
                        }

                        // Step 3: Handle application data (only after handshake)
                        if ((events & EPOLLIN) && c->csock->getHandshakeDone() && !needClose) {
                            // First, read raw TCP data into TLS buffer
                            std::cerr << "[EPOLL] Application data phase: reading raw TCP data..." << std::endl;
                            try {
                                buffer buf(BLOCKSIZE);
                                size_t rcv = ((netplus::tcp&)*c->csock).tcp::recvData(buf, 0);
                                std::cerr << "[EPOLL] Read " << rcv << " raw TCP bytes for application data" << std::endl;
                                if (rcv > 0) {
                                    c->csock->pushReceivedData((const uint8_t*)buf.data.buf, rcv);
                                }
                            } catch (NetException& e) {
                                if (e.getErrorType() != NetException::Note) {
                                    throw;
                                }
                                std::cerr << "[EPOLL] No more TCP data available (would block)" << std::endl;
                            }
                            }


                        // 2) EPOLLIN: recv one chunk
                            // Now try to decrypt application data from the TLS buffer
                        if (events & EPOLLIN) {
                            if (c->csock->hasBufferedData()) {
                                buffer buf(BLOCKSIZE);
                                buffer buf(BLOCKSIZE);
                                size_t rcv = 0;
                                size_t rcv = 0;
                                std::cerr << "[EPOLL] Calling recvData for decrypted application data" << std::endl;


                                try {
                                try {
                                    rcv = c->csock->recvData(buf, 0);
                                    rcv = c->csock->recvData(buf, 0);
                                    std::cerr << "[EPOLL] recvData returned " << rcv << " decrypted bytes" << std::endl;
                                } catch (NetException& e) {
                                } catch (NetException& e) {
                                    std::cerr << "[EPOLL] recvData threw exception type=" << e.getErrorType() << " msg=" << e.what() << std::endl;
                                    if (e.getErrorType() == NetException::Note){
                                    if (e.getErrorType() == NetException::Note){
                                        std::cerr << "[EPOLL] Not ready for data, re-arming" << std::endl;
                                        rearm.disarm();
                                        rearm.disarm();
                                        setpollEventsFd(fd, EPOLLIN | EPOLLRDHUP | EPOLLONESHOT);
                                        setpollEventsFd(fd, EPOLLIN | EPOLLRDHUP | EPOLLONESHOT);
                                        return;
                                        return;
@@ -319,14 +405,17 @@ namespace netplus {
                                }
                                }


                                if (rcv == 0) {
                                if (rcv == 0) {
                                    std::cerr << "[EPOLL] recvData returned 0, peer closed" << std::endl;
                                    needClose = true;
                                    needClose = true;
                                } else {
                                } else {
                                    std::cerr << "[EPOLL] Appending " << rcv << " bytes to RecvData" << std::endl;
                                    c->RecvData.append(buf.data.buf, rcv);
                                    c->RecvData.append(buf.data.buf, rcv);
                                    evconnection->RequestEvent(*c, tid, args);
                                    evconnection->RequestEvent(*c, tid, args);
                                }
                                }
                            }
                            }
                        }


                        // 3) EPOLLOUT: flush + send one chunk
                        // Step 4: EPOLLOUT: flush + send one chunk
                        if ((events & EPOLLOUT) && !needClose) {
                        if ((events & EPOLLOUT) && !needClose) {


                            if (c->csock->hasPendingWrite()) {
                            if (c->csock->hasPendingWrite()) {
+78 −68
Original line number Original line Diff line number Diff line
@@ -575,7 +575,11 @@ namespace netplus {
                std::cerr << "[IOCP] handshakeDone=" << owner->csock->getHandshakeDone() << std::endl;
                std::cerr << "[IOCP] handshakeDone=" << owner->csock->getHandshakeDone() << std::endl;
#endif
#endif


handshake_continue:
                // Process handshake with buffered data loop
                bool continueHandshake = true;
                while (continueHandshake && !owner->csock->getHandshakeDone()) {
                    continueHandshake = false;

                    // Check if handshake is done
                    // Check if handshake is done
                    if (!owner->csock->getHandshakeDone()) {
                    if (!owner->csock->getHandshakeDone()) {
#if IOCP_DEBUG
#if IOCP_DEBUG
@@ -615,29 +619,30 @@ handshake_continue:
                                try {
                                try {
                                    post_recv(st, *owner);
                                    post_recv(st, *owner);
                                } catch (...) {}
                                } catch (...) {}
                            continue;
                                continueHandshake = false;  // Exit loop, wait for more data
                        }
                            } else {
                                // Real error - disconnect
                                // Real error - disconnect
#if IOCP_DEBUG
#if IOCP_DEBUG
                                std::cerr << "[IOCP] Non-Note error - disconnecting" << std::endl;
                                std::cerr << "[IOCP] Non-Note error - disconnecting" << std::endl;
#endif
#endif
                                owner->ReadPending.store(false);
                                owner->ReadPending.store(false);
                                try_cleanup_con(ev, st, owner, cs, tid);
                                try_cleanup_con(ev, st, owner, cs, tid);
                        continue;
                                continueHandshake = false;  // Exit loop
                            }
                        } catch (std::exception& e) {
                        } catch (std::exception& e) {
#if IOCP_DEBUG
#if IOCP_DEBUG
                            std::cerr << "[IOCP] handshake_after_accept threw std::exception: " << e.what() << std::endl;
                            std::cerr << "[IOCP] handshake_after_accept threw std::exception: " << e.what() << std::endl;
#endif
#endif
                            owner->ReadPending.store(false);
                            owner->ReadPending.store(false);
                            try_cleanup_con(ev, st, owner, cs, tid);
                            try_cleanup_con(ev, st, owner, cs, tid);
                        continue;
                            continueHandshake = false;  // Exit loop
                        } catch (...) {
                        } catch (...) {
#if IOCP_DEBUG
#if IOCP_DEBUG
                            std::cerr << "[IOCP] handshake_after_accept threw unknown exception" << std::endl;
                            std::cerr << "[IOCP] handshake_after_accept threw unknown exception" << std::endl;
#endif
#endif
                            owner->ReadPending.store(false);
                            owner->ReadPending.store(false);
                            try_cleanup_con(ev, st, owner, cs, tid);
                            try_cleanup_con(ev, st, owner, cs, tid);
                        continue;
                            continueHandshake = false;  // Exit loop
                        }
                        }
                        
                        
                        // CRITICAL: handshake_after_accept() has ALREADY called flush_out() internally!
                        // CRITICAL: handshake_after_accept() has ALREADY called flush_out() internally!
@@ -657,9 +662,8 @@ handshake_continue:
                                std::cerr << "[IOCP] Buffered data available, continuing handshake loop" << std::endl;
                                std::cerr << "[IOCP] Buffered data available, continuing handshake loop" << std::endl;
#endif
#endif
                                // Continue processing without reposting recv
                                // Continue processing without reposting recv
                            // We need to call handshake_after_accept again
                                continueHandshake = true;  // Loop again
                            goto handshake_continue;
                            } else {
                        }
#if IOCP_DEBUG
#if IOCP_DEBUG
                                std::cerr << "[IOCP] Handshake not done, no buffered data, reposting recv" << std::endl;
                                std::cerr << "[IOCP] Handshake not done, no buffered data, reposting recv" << std::endl;
#endif
#endif
@@ -667,6 +671,12 @@ handshake_continue:
                                try {
                                try {
                                    post_recv(st, *owner);
                                    post_recv(st, *owner);
                                } catch (...) {}
                                } catch (...) {}
                            }
                        }
                    }
                }

                // Handshake is done or error occurred, continue main loop
                continue;
                continue;
                    }
                    }
                }
                }
+7 −6
Original line number Original line Diff line number Diff line
@@ -678,12 +678,7 @@ namespace netplus {
			IDLE
			IDLE
		};
		};


		HsState _hs_state = HsState::READ_CLIENT_HELLO;
	HsState _hs_state = HsState::IDLE;

		std::vector<uint8_t> _masterSecret;
		std::vector<uint8_t> _tls12_transcript_before_client_finished;  // Saved for server Finished PRF
		std::vector<uint8_t> _handshake_transcript;
		std::vector<uint8_t> _clientHelloRawBytes;


		bool _handshakeDone = false;
		bool _handshakeDone = false;
		bool _is_server = true;
		bool _is_server = true;
@@ -691,6 +686,12 @@ namespace netplus {
		bool hasTLS13SV = false;
		bool hasTLS13SV = false;
		bool hasTLS13KS = false;
		bool hasTLS13KS = false;


		// TLS handshake state members
		std::vector<uint8_t> _handshake_transcript;
		std::vector<uint8_t> _masterSecret;
		std::vector<uint8_t> _clientHelloRawBytes;
		std::vector<uint8_t> _tls12_transcript_before_client_finished;

		friend class poll;
		friend class poll;
		friend class event;
		friend class event;
		friend class EventWorker;
		friend class EventWorker;
+9 −1
Original line number Original line Diff line number Diff line
@@ -1628,9 +1628,11 @@ void netplus::ssl::handshake_after_accept(){
    // Note: Caller (IOCP layer) must hold con::event_mutex to prevent concurrent access
    // Note: Caller (IOCP layer) must hold con::event_mutex to prevent concurrent access


#if SSL_DEBUG
#if SSL_DEBUG
    std::cerr << "[SSL] ===== handshake_after_accept ENTER state=" << (int)_hs_state << std::endl;
    std::cerr << "[SSL] ===== handshake_after_accept ENTER state=" << (int)_hs_state << " _handshakeDone=" << _handshakeDone << std::endl;
    std::cerr.flush();
    std::cerr.flush();
#endif
#endif
    std::cerr << "[SSL] ===== handshake_after_accept ENTER state=" << (int)_hs_state << " _handshakeDone=" << _handshakeDone << std::endl;
    std::cerr.flush();


    auto throwSSL = [&](int type, const std::string& msg) {
    auto throwSSL = [&](int type, const std::string& msg) {
        netplus::NetException e;
        netplus::NetException e;
@@ -1675,6 +1677,7 @@ void netplus::ssl::handshake_after_accept(){


    // If already done -> nothing
    // If already done -> nothing
    if (_hs_state == HsState::DONE) {
    if (_hs_state == HsState::DONE) {
        std::cerr << "[SSL] handshake_after_accept: state already DONE, setting _handshakeDone=true" << std::endl;
        // sicherstellen: alles raus
        // sicherstellen: alles raus
        if (hasPendingWrite()) {
        if (hasPendingWrite()) {
            flush_out();   // darf Note werfen -> caller rearm EPOLLOUT
            flush_out();   // darf Note werfen -> caller rearm EPOLLOUT
@@ -2343,6 +2346,7 @@ void netplus::ssl::handshake_after_accept(){


            // 3) erst wenn wirklich alles raus ist -> DONE
            // 3) erst wenn wirklich alles raus ist -> DONE
            if (!hasPendingWrite()) {
            if (!hasPendingWrite()) {
                std::cerr << "[SSL] SEND_CCS_FIN: all data flushed, setting _handshakeDone=true and state=DONE" << std::endl;
                _handshakeDone = true;
                _handshakeDone = true;
                _hs_state = HsState::DONE;
                _hs_state = HsState::DONE;
                return;
                return;
@@ -2528,6 +2532,7 @@ void netplus::ssl::handshake_after_accept(){
            // after server Finished was added to transcript (but before client Finished).
            // after server Finished was added to transcript (but before client Finished).
            // Calling it again here would use wrong transcript (includes client Finished).
            // Calling it again here would use wrong transcript (includes client Finished).


            std::cerr << "[SSL] TLS13_WAIT_CLIENT_FINISHED: client finished verified, setting _handshakeDone=true" << std::endl;
            _handshakeDone = true;
            _handshakeDone = true;
            _hs_state = HsState::ESTABLISHED;
            _hs_state = HsState::ESTABLISHED;
            return;
            return;
@@ -4431,6 +4436,7 @@ void netplus::ssl::_tls13_send_record(uint8_t inner_type,
}
}


void netplus::ssl::resetTLS() {
void netplus::ssl::resetTLS() {
    std::cerr << "[SSL] resetTLS ENTER: fd=" << this->fd() << std::endl;


    // MUST be false so next handshake is treated as fresh
    // MUST be false so next handshake is treated as fresh
    _handshakeStarted = false;
    _handshakeStarted = false;
@@ -4450,6 +4456,8 @@ void netplus::ssl::resetTLS() {
    _recv_seq = 0;
    _recv_seq = 0;
    _handshakeDone = false;
    _handshakeDone = false;
    
    
    std::cerr << "[SSL] resetTLS: after reset, _handshakeDone=" << _handshakeDone << " _hs_state=" << (int)_hs_state << std::endl;

    _handshake_transcript.clear();
    _handshake_transcript.clear();
    _clientRandom.clear();
    _clientRandom.clear();
    _serverRandom.clear();
    _serverRandom.clear();