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 }