github.com/metacubex/mihomo@v1.18.5/common/net/packet/packet_posix.go (about)

     1  //go:build !windows
     2  
     3  package packet
     4  
     5  import (
     6  	"net"
     7  	"strconv"
     8  	"syscall"
     9  
    10  	"github.com/metacubex/mihomo/common/pool"
    11  )
    12  
    13  type enhanceUDPConn struct {
    14  	*net.UDPConn
    15  	rawConn syscall.RawConn
    16  }
    17  
    18  func (c *enhanceUDPConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) {
    19  	if c.rawConn == nil {
    20  		c.rawConn, _ = c.UDPConn.SyscallConn()
    21  	}
    22  	var readErr error
    23  	err = c.rawConn.Read(func(fd uintptr) (done bool) {
    24  		readBuf := pool.Get(pool.UDPBufferSize)
    25  		put = func() {
    26  			_ = pool.Put(readBuf)
    27  		}
    28  		var readFrom syscall.Sockaddr
    29  		var readN int
    30  		readN, _, _, readFrom, readErr = syscall.Recvmsg(int(fd), readBuf, nil, 0)
    31  		if readN > 0 {
    32  			data = readBuf[:readN]
    33  		} else {
    34  			put()
    35  			put = nil
    36  			data = nil
    37  		}
    38  		if readErr == syscall.EAGAIN {
    39  			return false
    40  		}
    41  		if readFrom != nil {
    42  			switch from := readFrom.(type) {
    43  			case *syscall.SockaddrInet4:
    44  				ip := from.Addr // copy from.Addr; ip escapes, so this line allocates 4 bytes
    45  				addr = &net.UDPAddr{IP: ip[:], Port: from.Port}
    46  			case *syscall.SockaddrInet6:
    47  				ip := from.Addr // copy from.Addr; ip escapes, so this line allocates 16 bytes
    48  				addr = &net.UDPAddr{IP: ip[:], Port: from.Port, Zone: strconv.FormatInt(int64(from.ZoneId), 10)}
    49  			}
    50  		}
    51  		// udp should not convert readN == 0 to io.EOF
    52  		//if readN == 0 {
    53  		//	readErr = io.EOF
    54  		//}
    55  		return true
    56  	})
    57  	if err != nil {
    58  		return
    59  	}
    60  	if readErr != nil {
    61  		err = readErr
    62  		return
    63  	}
    64  	return
    65  }