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

bsd support



Co-authored-by: default avatarCopilot <copilot@github.com>
parent fe80af5c
Loading
Loading
Loading
Loading
+45 −2
Original line number Diff line number Diff line
@@ -39,9 +39,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <fcntl.h>
#include <sys/un.h>
#include <sys/uio.h>       // iovec, sendmmsg, recvmmsg
#include <netinet/udp.h>   // SOL_UDP
#include <netinet/udp.h>   // SOL_UDP / IPPROTO_UDP

// Linux-specific: constants may be missing in old kernel headers
// FreeBSD uses IPPROTO_UDP where Linux uses SOL_UDP
#ifndef SOL_UDP
#define SOL_UDP IPPROTO_UDP
#endif

// Linux-specific: constants may be missing in old kernel headers or on FreeBSD.
// probeGSOGRO() will fail gracefully — setsockopt returns ENOPROTOOPT.
#ifndef UDP_SEGMENT
#define UDP_SEGMENT 103
#endif
@@ -49,6 +55,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define UDP_GRO 104
#endif

// macOS lacks sendmmsg/recvmmsg; FreeBSD 11+ and Linux have them.
#if defined(__APPLE__)
#define NETPLUS_NO_MMSG 1
#endif

namespace netplus {

udp::udp() : socket() {
@@ -413,6 +424,21 @@ ssize_t udp::sendBatch(
    }

    // --- sendmmsg path ---
#ifdef NETPLUS_NO_MMSG
    // Fallback: sendto loop for platforms without sendmmsg
    int sent = 0;
    for (size_t i = 0; i < count; ++i) {
        ssize_t r;
        if (dest) {
            r = ::sendto(_Socket, datagrams[i].first, datagrams[i].second,
                         MSG_DONTWAIT, reinterpret_cast<sockaddr*>(dest), dest_len);
        } else {
            r = ::send(_Socket, datagrams[i].first, datagrams[i].second, MSG_DONTWAIT);
        }
        if (r < 0) break;
        ++sent;
    }
#else
    std::vector<struct iovec> iovecs(count);
    std::vector<struct mmsghdr> msgs(count);
    std::memset(msgs.data(), 0, sizeof(struct mmsghdr) * count);
@@ -430,6 +456,7 @@ ssize_t udp::sendBatch(

    int sent = ::sendmmsg(_Socket, msgs.data(),
                          static_cast<unsigned int>(count), MSG_DONTWAIT);
#endif
    return sent;
}

@@ -451,6 +478,21 @@ size_t udp::recvBatchAddr(std::vector<std::vector<uint8_t>>& out,

    const int batch = std::min(max_count, 64);

#ifdef NETPLUS_NO_MMSG
    // Fallback: recvfrom loop for platforms without recvmmsg
    static thread_local std::vector<uint8_t> recv_buf(65535);
    for (int i = 0; i < batch; ++i) {
        sockaddr_storage peer{};
        socklen_t peer_len = sizeof(peer);
        ssize_t n = ::recvfrom(_Socket, recv_buf.data(), recv_buf.size(),
                               MSG_DONTWAIT,
                               reinterpret_cast<sockaddr*>(&peer), &peer_len);
        if (n <= 0) break;
        out.emplace_back(recv_buf.data(), recv_buf.data() + n);
        addrs.push_back(peer);
    }
    return out.size();
#else
    // Use thread_local static buffers to avoid 64×65KB heap allocation per call.
    // These are reused across calls on the same thread.
    static constexpr int MAX_BATCH = 64;
@@ -517,6 +559,7 @@ size_t udp::recvBatchAddr(std::vector<std::vector<uint8_t>>& out,
    }

    return out.size();
#endif // NETPLUS_NO_MMSG
}

} // namespace netplus