Commit 6dd61cc9 authored by jan.koester's avatar jan.koester
Browse files

test

parent f58b8c37
Loading
Loading
Loading
Loading
+141 −120
Original line number Diff line number Diff line
@@ -261,42 +261,42 @@ namespace netplus {

        EpollArmGuard rearm(fd, c, this);

            std::lock_guard<std::mutex> lk(c->event_mutex);
            if (!c->csock) return;
        bool wantResponseCallback = false;
        bool wantRequestCallback  = false;
        bool wantClose            = false;

        try {
                // Peer already closed?
            // Peer closed?
            if (events & (EPOLLRDHUP | EPOLLHUP | EPOLLERR)) {
                    rearm.disarm();
                    CloseEventHandler(fd, tid, args);
                    return;
                wantClose = true;
            }
            else {
                // ----------- LOCK nur für IO ----------
                {
                    std::lock_guard<std::mutex> lk(c->event_mutex);

                    if (!c->csock) return;

                // -------------------------------------------------
                // 1) TLS handshake
                // -------------------------------------------------
                    // 1) TLS Handshake
                    if (!c->csock->getHandshakeDone()) {

                        c->csock->handshake_after_accept();

                    // try flush once if something queued
                        if (c->csock->hasPendingWrite()) {
                            try {
                                c->csock->flush_out();
                            } catch (NetException& e) {
                            if (e.getErrorType() == NetException::Note)
                                return; // wait EPOLLOUT
                                if (e.getErrorType() != NetException::Note)
                                    throw;
                            }
                        }

                    // still not done -> wait for next IO event
                        // handshake not done => wait for next event
                        if (!c->csock->getHandshakeDone())
                        return;
                            return; // Guard rearms IN|OUT
                    }

                // -------------------------------------------------
                // 2) EPOLLIN: receive one chunk
                // -------------------------------------------------
                    // 2) EPOLLIN: read
                    if (events & EPOLLIN) {
                        buffer buf(BLOCKSIZE);
                        size_t rcv = 0;
@@ -305,39 +305,35 @@ namespace netplus {
                            rcv = c->csock->recvData(buf, 0);
                        } catch (NetException& e) {
                            if (e.getErrorType() == NetException::Note) {
                            return;
                        }
                                rcv = 0; // nothing available
                            } else {
                                throw;
                            }
                        }

                        if (rcv == 0) {
                        rearm.disarm();
                        CloseEventHandler(fd, tid, args);
                        return;
                            // if peer closed OR no data (note) -> close only if RDHUP already seen
                            if (events & EPOLLRDHUP) {
                                wantClose = true;
                            }

                        } else {
                            c->RecvData.append(buf.data.buf, rcv);
                    evconnection->RequestEvent(*c, tid, args);
                            wantRequestCallback = true;
                        }
                    }


                // -------------------------------------------------
                // 3) EPOLLOUT: flush + send one chunk
                // -------------------------------------------------
                    // 3) EPOLLOUT: flush + send
                    if (events & EPOLLOUT) {

                    // flush pending TLS output
                        if (c->csock->hasPendingWrite()) {
                            try {
                                c->csock->flush_out();
                            } catch (NetException& e) {
                            if (e.getErrorType() == NetException::Note)
                                return;
                                if (e.getErrorType() != NetException::Note)
                                    throw;
                            }
                        }

                    // send exactly one chunk from SendData
                        if (!c->SendData.empty()) {
                            size_t sendlen = std::min((size_t)BLOCKSIZE, c->SendData.size());
                            buffer out(c->SendData.data(), sendlen);
@@ -345,77 +341,101 @@ namespace netplus {
                            size_t consumed = 0;
                            try {
                                consumed = c->csock->sendData(out, 0);

                            if (c->csock->hasPendingWrite()) {
                                c->csock->flush_out();
                            }

                            } catch (NetException& e) {
                            if (e.getErrorType() == NetException::Note)
                                return;
                                if (e.getErrorType() == NetException::Note) {
                                    consumed = 0;
                                } else {
                                    throw;
                                }
                            }

                            if (consumed > 0) {
                            c->SendData.erase(c->SendData.begin(), c->SendData.begin() + consumed);
                                c->SendData.erase(c->SendData.begin(),
                                                c->SendData.begin() + consumed);
                            }
                        }

                        if (c->SendData.empty() && !c->csock->hasPendingWrite()) {
                            wantResponseCallback = true;
                        }
                    }
                } // unlock event_mutex

                // ✅ Wenn RequestEvent Daten erzeugt, sofort OUT aktivieren
                if (wantRequestCallback) {
                    evconnection->RequestEvent(*c, tid, args);

                    if (!c->SendData.empty() || c->csock->hasPendingWrite()) {
                        setpollEventsFd(fd, EPOLLIN | EPOLLOUT | EPOLLRDHUP | EPOLLONESHOT);
                    }
                }

                if (wantResponseCallback) {
                    evconnection->ResponseEvent(*c, tid, args);
                }
            }

            } catch (NetException& e) {
                if (e.getErrorType() == NetException::Note)
                    return;
        } catch (...) {
            wantClose = true;
        }

        if (wantClose) {
            rearm.disarm();
            CloseEventHandler(fd, tid, args);
                return;
        }
    }

    void CloseEventHandler(int fd, const int tid, ULONG_PTR args){
        std::shared_ptr<con> ccon;

        // 1) Remove from global map first (so nobody else sees it anymore)
        {
            std::lock_guard<std::mutex> lock(POLL_HANDLER_MUTEX);
            auto it = CONNECTIONS.find(fd);
            if (it == CONNECTIONS.end())
                    return; // already closed
                return;

            ccon = it->second;
            CONNECTIONS.erase(it);
        }

            if (!ccon)
                return;
        if (!ccon) return;

            if (!ccon->csock) {
                return;
            }

            {
                std::lock_guard<std::mutex> conn_lock(ccon->event_mutex);
        // 2) Grab csock pointer once
        socket* rawSock = ccon->csock.get();
        if (!rawSock) return;

        // 3) Remove from epoll ASAP
        if (epoll_ctl(_pollFD, EPOLL_CTL_DEL, fd, nullptr) < 0) {
            if (errno != ENOENT && errno != EBADF) {
                std::cerr << "epoll_ctl DEL failed fd=" << fd
                        << " errno=" << errno << std::endl;
            }
        }
                if (ccon->csock) {

        // 4) Shutdown TCP immediately (prevents CLOSE_WAIT / FIN_WAIT2 issues)
        ::shutdown(fd, SHUT_RDWR);

        // 5) Close socket with lock, but DO NOT call callbacks under that lock
        {
            std::lock_guard<std::mutex> conn_lock(ccon->event_mutex);

            try {
                        ccon->csock->close();
                    } catch (...) {}
                if (ccon->csock)
                    ccon->csock->close();  // will call ::close() inside
            } catch (...) {
                // ignore
            }

            // ensure pointer cleared
            ccon->csock.reset();
        }

        // 6) Notify user callback (no locks held)
        try {
            evconnection->DisconnectEvent(*ccon, tid, args);
        } catch (...) {
                // ignore user callback failures
            // ignore
        }
    }

@@ -476,6 +496,7 @@ namespace netplus {
                        }

                        pollptr.IoEventHandler(fd, flags, tid, args);

                    }
                } catch (NetException& e) {
                    std::cerr << "Poll Error: " << e.what() << std::endl;
+50 −124
Original line number Diff line number Diff line
@@ -25,158 +25,84 @@
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *******************************************************************************/

#include <chrono>
#include <thread>
#include <cstring>
#include <atomic>
#include "socket.h"
#include "exception.h"
#include "error.h"

#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>
#include <netdb.h>
#include <string.h>
#include <pthread.h>

#include "exception.h"
#include "socket.h"
#include "error.h"
namespace netplus {

#define HIDDEN __attribute__ ((visibility ("hidden")))

netplus::socket::socket(){
    _SocketInfo=(ULONG_PTR)malloc(sizeof(struct addrinfo));
    _SocketInfoLen=sizeof(struct addrinfo);
    memset((void*)_SocketInfo,0,sizeof(struct addrinfo));
socket::socket() {
    _Socket = -1;
    _Type   = -1;
}

netplus::socket::~socket() {
    auto* ai = reinterpret_cast<addrinfo*>(_SocketInfo);
    if (!ai) return;
    _Extension = 0;

    if (ai->ai_addr) {
        std::free(ai->ai_addr);
        ai->ai_addr = nullptr;
    std::memset(&_Addr, 0, sizeof(_Addr));
    _AddrLen = sizeof(_Addr);
}
    if (ai->ai_canonname) {
        std::free(ai->ai_canonname);
        ai->ai_canonname = nullptr;

socket::~socket() {
    // no heap free needed
}
    ai->ai_addrlen = 0;
    ai->ai_next = nullptr;

    std::free(reinterpret_cast<void*>(_SocketInfo));   // ✅ WICHTIG
    _SocketInfo = 0;
SOCKET socket::fd() {
    return _Socket;
}

void netplus::socket::close() {
void socket::close() {
    if (_Socket < 0) return;

    ::shutdown(_Socket, SHUT_RDWR);
    ::close(_Socket);

    _Socket = -1;
}

void netplus::socket::setFlag(int flag,int value){
    int sockopts=fcntl(_Socket, F_GETFL, 0);
    if (fcntl(_Socket, F_SETFL, sockopts | flag) < 0) {
        NetException exception;
        exception[NetException::Error] << "Could not set ClientSocket nonblocking!";
        throw exception;
void socket::setFlag(int flag, int value) {
    int sockopts = ::fcntl(_Socket, F_GETFL, 0);
    if (sockopts < 0) {
        NetException e;
        e[NetException::Error] << "fcntl(F_GETFL) failed";
        throw e;
    }
 }

void netplus::socket::setTimeout(int usec){
    struct timeval timeout;
    timeout.tv_sec =  0;
    timeout.tv_usec =usec;
    if (setsockopt (_Socket, SOL_SOCKET, SO_RCVTIMEO, &timeout,
        sizeof timeout) < 0){

        char errstr[512];
        strerror_r_netplus(errno,errstr,512);

        NetException exception;
        exception[NetException::Error] << "Could not set ClientSocket Recv timeout"<< errstr;
        throw exception;
    }


    if (setsockopt (_Socket, SOL_SOCKET, SO_SNDTIMEO, &timeout,
        sizeof timeout) < 0){

        char errstr[512];
        strerror_r_netplus(errno,errstr,512);

        NetException exception;
        exception[NetException::Error] << "Could not set ClientSocket Send timeout" << errstr;
        throw exception;
    if (value)
        sockopts |= flag;
    else
        sockopts &= ~flag;

    if (::fcntl(_Socket, F_SETFL, sockopts) < 0) {
        NetException e;
        e[NetException::Error] << "fcntl(F_SETFL) failed";
        throw e;
    }
}

void netplus::socket::copyAddrInfo(ULONG_PTR* dest, ULONG_PTR src, size_t srclen) {
    auto* s = reinterpret_cast<addrinfo*>(src);
    auto* d = reinterpret_cast<addrinfo*>(*dest);
void socket::setTimeout(int usec) {
    timeval timeout{};
    timeout.tv_sec  = usec / 1000000;
    timeout.tv_usec = usec % 1000000;

    if (!s || !d) return;

    // ✅ free old deep fields (avoid leak)
    if (d->ai_addr) {
        std::free(d->ai_addr);
        d->ai_addr = nullptr;
    }
    if (d->ai_canonname) {
        std::free(d->ai_canonname);
        d->ai_canonname = nullptr;
    if (::setsockopt(_Socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) {
        NetException e;
        e[NetException::Error] << "setsockopt SO_RCVTIMEO failed";
        throw e;
    }

    // Ensure srclen
    if (srclen < sizeof(addrinfo)) srclen = sizeof(addrinfo);

    // Copy only POD header fields
    std::memset(d, 0, srclen);
    d->ai_family   = s->ai_family;
    d->ai_socktype = s->ai_socktype;
    d->ai_protocol = s->ai_protocol;
    d->ai_flags    = s->ai_flags;
    d->ai_next     = nullptr;

    // Canonname optional
    if (s->ai_canonname) {
        size_t n = std::strlen(s->ai_canonname);
        d->ai_canonname = static_cast<char*>(std::malloc(n + 1));
        if (d->ai_canonname) {
            std::memcpy(d->ai_canonname, s->ai_canonname, n);
            d->ai_canonname[n] = '\0';
    if (::setsockopt(_Socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) < 0) {
        NetException e;
        e[NetException::Error] << "setsockopt SO_SNDTIMEO failed";
        throw e;
    }
}

    // Deep copy sockaddr
    d->ai_addrlen = s->ai_addrlen;

    if (s->ai_addr && s->ai_addrlen > 0) {
        d->ai_addr = static_cast<sockaddr*>(std::malloc(s->ai_addrlen));
        if (!d->ai_addr) {
            d->ai_addrlen = 0;
            return;
        }
        std::memcpy(d->ai_addr, s->ai_addr, s->ai_addrlen);
    } else {
        d->ai_addr = nullptr;
        d->ai_addrlen = 0;
void socket::copyAddrInfo(ULONG_PTR* dest, ULONG_PTR src, size_t srclen) {
    // legacy (unused in new POSIX code)
    std::memcpy((void*)*dest, (void*)src, srclen);
}
}


SOCKET netplus::socket::fd() {
    return _Socket;
}
} // namespace netplus
+127 −158

File changed.

Preview size limit exceeded, changes collapsed.

+151 −190

File changed.

Preview size limit exceeded, changes collapsed.

+28 −0
Original line number Diff line number Diff line
/*******************************************************************************
 * Copyright (c) 2025, Jan Koester jan.koester@gmx.net
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 * Neither the name of the <organization> nor the
 *      names of its contributors may be used to endorse or promote products
 *      derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *******************************************************************************/

#pragma once

#include <cstdint>
#include <cstddef>
#include <vector>
Loading