//go:build linux

package socket

import (
	
	
	
	

	
)

// WriteMsgUDP writes a possibly segmented datagram. Direct IP destinations use
// the kernel's UDP_SEGMENT path. Other transports receive one datagram per
// segment through the ordinary magic-socket router.
func ( *MagicConn) (,  []byte,  *net.UDPAddr) (,  int,  error) {
	 := udpSegmentSize()
	if .sock.IsClosed() {
		return len(), len(), nil
	}
	 := canonicalAddrPort(.AddrPort())
	if .transports.ip == nil || (!isDefinitelyIP(.Addr()) && Classify(.Addr()) != KindIP) {
		.writeMsgSegments(, , )
		return len(), len(), nil
	}
	, ,  = .udp.WriteMsgUDPAddrPort(, , )
	if  == nil {
		for range segmentCount(len(), ) {
			.recordIPSent()
		}
		return , , nil
	}
	// EIO on a segmented write is the kernel refusing GSO, not a lost
	// datagram: the caller disables GSO and resends the batch one datagram at
	// a time, and those resends are counted on the ordinary path. Counting
	// here would count them twice.
	if  > 0 && errors.Is(, unix.EIO) {
		return , , 
	}
	.metrics.blackholed.Add(uint64(segmentCount(len(), )))
	return len(), len(), nil
}

func ( *MagicConn) ( []byte,  *net.UDPAddr,  int) {
	if  <= 0 {
		.WriteTo(, )
		return
	}
	for len() > 0 {
		 := min(len(), )
		.WriteTo([:], )
		 = [:]
	}
}

func segmentCount(,  int) int {
	if  <= 0 {
		return 1
	}
	return ( +  - 1) / 
}

func udpSegmentSize( []byte) int {
	for len() > 0 {
		, , ,  := unix.ParseOneSocketControlMessage()
		if  != nil {
			return 0
		}
		if .Level == syscall.IPPROTO_UDP && .Type == unix.UDP_SEGMENT && len() >= 2 {
			return int(binary.NativeEndian.Uint16())
		}
		 = 
	}
	return 0
}