//go:build linuxpackage quicimport ()const ( msgTypeIPTOS = unix.IP_TOS ipv4PKTINFO = unix.IP_PKTINFO)const ecnIPv4DataLen = 1const batchSize = 8// needs to smaller than MaxUint8 (otherwise the type of oobConn.readPos has to be changed)var kernelVersionMajor intfunc init() {kernelVersionMajor, _ = kernelVersion()}func forceSetReceiveBuffer( syscall.RawConn, int) error {varerrorif := .Control(func( uintptr) { = unix.SetsockoptInt(int(), unix.SOL_SOCKET, unix.SO_RCVBUFFORCE, ) }); != nil {return }return}func forceSetSendBuffer( syscall.RawConn, int) error {varerrorif := .Control(func( uintptr) { = unix.SetsockoptInt(int(), unix.SOL_SOCKET, unix.SO_SNDBUFFORCE, ) }); != nil {return }return}func parseIPv4PktInfo( []byte) ( netip.Addr, uint32, bool) {// struct in_pktinfo { // unsigned int ipi_ifindex; /* Interface index */ // struct in_addr ipi_spec_dst; /* Local address */ // struct in_addr ipi_addr; /* Header Destination address */ // };iflen() != 12 {returnnetip.Addr{}, 0, false }returnnetip.AddrFrom4(*(*[4]byte)([8:12])), binary.NativeEndian.Uint32(), true}// isGSOEnabled tests if the kernel supports GSO.// Sending with GSO might still fail later on, if the interface doesn't support it (see isGSOError).func isGSOEnabled( syscall.RawConn) bool {ifkernelVersionMajor < 5 {returnfalse } , := strconv.ParseBool(os.Getenv("QUIC_GO_DISABLE_GSO"))if == nil && {returnfalse }varerrorif := .Control(func( uintptr) { _, = unix.GetsockoptInt(int(), unix.IPPROTO_UDP, unix.UDP_SEGMENT) }); != nil {returnfalse }return == nil}func appendUDPSegmentSizeMsg( []byte, uint16) []byte { := len()const = 2// payload is a uint16 = append(, make([]byte, unix.CmsgSpace())...) := (*unix.Cmsghdr)(unsafe.Pointer(&[])) .Level = syscall.IPPROTO_UDP .Type = unix.UDP_SEGMENT .SetLen(unix.CmsgLen())// UnixRights uses the private `data` method, but I *think* this achieves the same goal. := + unix.CmsgSpace(0) *(*uint16)(unsafe.Pointer(&[])) = return}func isGSOError( error) bool {var *os.SyscallErroriferrors.As(, &) {// EIO is returned by udp_send_skb() if the device driver does not have tx checksums enabled, // which is a hard requirement of UDP_SEGMENT. See: // https://git.kernel.org/pub/scm/docs/man-pages/man-pages.git/tree/man7/udp.7?id=806eabd74910447f21005160e90957bde4db0183#n228 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/ipv4/udp.c?h=v6.2&id=c9c3395d5e3dcc6daee66c6908354d47bf98cb0c#n942return .Err == unix.EIO }returnfalse}// The first sendmsg call on a new UDP socket sometimes errors on Linux.// It's not clear why this happens.// See https://github.com/golang/go/issues/63322.func isPermissionError( error) bool {var *os.SyscallErroriferrors.As(, &) {return .Syscall == "sendmsg" && .Err == unix.EPERM }returnfalse}func isECNEnabled() bool {returnkernelVersionMajor >= 5 && !isECNDisabledUsingEnv()}// kernelVersion returns major and minor kernel version numbers, parsed from// the syscall.Uname's Release field, or 0, 0 if the version can't be obtained// or parsed.//// copied from the standard library's internal/syscall/unix/kernel_version_linux.gofunc kernelVersion() (, int) {varsyscall.Utsnameif := syscall.Uname(&); != nil {return }var ( [2]int , int )for , := range .Release {if'0' <= && <= '9' { = ( * 10) + int(-'0') } else {// Note that we're assuming N.N.N here. // If we see anything else, we are likely to mis-parse it. [] = ++if >= len() {break } = 0 } }return [0], [1]}
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.