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

test

parent 2c19a22c
Loading
Loading
Loading
Loading
+28 −10
Original line number Diff line number Diff line
@@ -56,16 +56,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define UDP_GRO 104
#endif

// macOS lacks sendmmsg/recvmmsg entirely, so do OpenBSD, NetBSD and
// DragonFly BSD -- calling them there doesn't compile. FreeBSD 11+ does
// have the symbols, but sendmmsg() to an explicit (unconnected) peer
// address has been observed there to fail a QUIC server's Retry/handshake
// sends with EINVAL, even though the identical arguments work fine via
// plain sendto() -- not something a Linux dev box can repro (it accepts
// this call shape fine). Rather than special-case that one FreeBSD failure
// mode, only Linux -- where this path is actually exercised and trusted --
// gets the real sendmmsg/recvmmsg path; every other platform, FreeBSD
// included, uses the sendto/recvfrom fallback below.
// macOS lacks sendmmsg/recvmmsg entirely, as do OpenBSD (pre-7.x), NetBSD
// and DragonFly BSD -- calling them there doesn't compile. OpenBSD 7.9 and
// FreeBSD 11+ do have the symbols, but the batch send/recv path here has
// only ever been exercised end-to-end on Linux; a real BSD bug once
// mistaken for an mmsg quirk turned out to be an unrelated msg_namelen
// mismatch (see sockaddrLen() below), not anything wrong with sendmmsg()
// itself. Until the mmsg path is specifically verified on a BSD, only
// Linux gets it; everyone else uses the plain sendto/recvfrom fallback
// below, which is simpler and has been the one actually proven correct
// cross-platform.
#if !defined(__linux__)
#define NETPLUS_NO_MMSG 1
#endif
@@ -396,6 +396,24 @@ void udp::probeGSOGRO(uint16_t segment_size) {
    }
}

// The real wire length of a peer address, by family — NOT
// sizeof(sockaddr_storage). Linux's sendto()/sendmsg() tolerate an
// oversized msg_namelen/addrlen (it just reads sizeof(sockaddr_in{,6})
// worth of bytes based on ss_family and ignores the rest), so passing
// sizeof(sockaddr_storage) there silently "worked" by accident. BSD socket
// implementations (confirmed on OpenBSD 7.9) validate the length strictly
// against the address family and reject the mismatch with EINVAL — not
// kqueue itself, which has nothing to do with sockaddr validation, but the
// send()/sendmsg() syscall path underneath it. This was breaking every
// send to a peer (QUIC Retry, handshake flight, and all post-handshake
// application data via quic::flushBatch()'s _AddrLen) on BSD, while
// epoll/Linux masked it completely.
socklen_t sockaddrLen(const sockaddr_storage& addr) {
    if (addr.ss_family == AF_INET) return sizeof(struct sockaddr_in);
    if (addr.ss_family == AF_INET6) return sizeof(struct sockaddr_in6);
    return sizeof(sockaddr_storage);
}

// ============================================================================
// UDP Batched Send: sendmmsg + GSO when available
// ============================================================================
+0 −16
Original line number Diff line number Diff line
@@ -967,22 +967,6 @@ bool constantTimeEqual(const uint8_t* a, const uint8_t* b, size_t len) {
    return diff == 0;
}

// The real wire length of a peer address, by family — NOT
// sizeof(sockaddr_storage). Linux's sendto()/sendmsg() tolerate an
// oversized msg_namelen/addrlen (it just reads sizeof(sockaddr_in{,6})
// worth of bytes based on ss_family and ignores the rest), so passing
// sizeof(sockaddr_storage) there silently "worked" by accident. FreeBSD's
// kqueue-backed stack validates the length strictly and rejects the
// mismatch with EINVAL — this was breaking every send to a peer (Retry,
// handshake flight, and all post-handshake application data via
// flushBatch()'s _AddrLen) on kqueue platforms, while epoll/Linux masked
// it completely.
socklen_t sockaddrLen(const sockaddr_storage& addr) {
    if (addr.ss_family == AF_INET) return sizeof(struct sockaddr_in);
    if (addr.ss_family == AF_INET6) return sizeof(struct sockaddr_in6);
    return sizeof(sockaddr_storage);
}

} // namespace

std::array<uint8_t, 16> quic::computeRetryIntegrityTag(
+5 −0
Original line number Diff line number Diff line
@@ -324,6 +324,11 @@ namespace netplus {
		std::string _UxPath;
	};

	// The real wire length of a peer address, by family — NOT
	// sizeof(sockaddr_storage). See udp.cpp's implementation for the full
	// cross-platform rationale.
	socklen_t sockaddrLen(const sockaddr_storage& addr);

	class udp : public socket {
	public:
		udp();
+11 −0
Original line number Diff line number Diff line
@@ -427,6 +427,17 @@ void udp::getAddress(std::string& addr) {
    }
}

// The real wire length of a peer address, by family — NOT
// sizeof(sockaddr_storage). See posix/udp.cpp's implementation for the
// full cross-platform rationale (a BSD sendto()/sendmsg() EINVAL this
// fixed on the POSIX side); ws2tcpip.h provides the same sockaddr_in{,6}
// layouts here, so the identical family switch applies.
socklen_t sockaddrLen(const sockaddr_storage& addr) {
    if (addr.ss_family == AF_INET) return sizeof(struct sockaddr_in);
    if (addr.ss_family == AF_INET6) return sizeof(struct sockaddr_in6);
    return sizeof(sockaddr_storage);
}

// --- GSO/GRO stubs (not supported on Windows) ---

void udp::probeGSOGRO(uint16_t segment_size) {