mirror of
https://gitclone.com/github.com/MetaCubeX/Clash.Meta
synced 2024-11-16 06:01:21 +08:00
65 lines
1.3 KiB
Go
65 lines
1.3 KiB
Go
|
//go:build !windows
|
||
|
|
||
|
package net
|
||
|
|
||
|
import (
|
||
|
"io"
|
||
|
"net"
|
||
|
"strconv"
|
||
|
"syscall"
|
||
|
|
||
|
"github.com/Dreamacro/clash/common/pool"
|
||
|
)
|
||
|
|
||
|
type enhanceUDPConn struct {
|
||
|
*net.UDPConn
|
||
|
rawConn syscall.RawConn
|
||
|
}
|
||
|
|
||
|
func (c *enhanceUDPConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) {
|
||
|
if c.rawConn == nil {
|
||
|
c.rawConn, _ = c.UDPConn.SyscallConn()
|
||
|
}
|
||
|
var readErr error
|
||
|
err = c.rawConn.Read(func(fd uintptr) (done bool) {
|
||
|
readBuf := pool.Get(pool.UDPBufferSize)
|
||
|
put = func() {
|
||
|
_ = pool.Put(readBuf)
|
||
|
}
|
||
|
var readFrom syscall.Sockaddr
|
||
|
var readN int
|
||
|
readN, _, _, readFrom, readErr = syscall.Recvmsg(int(fd), readBuf, nil, 0)
|
||
|
if readN > 0 {
|
||
|
data = readBuf[:readN]
|
||
|
} else {
|
||
|
put()
|
||
|
put = nil
|
||
|
}
|
||
|
if readErr == syscall.EAGAIN {
|
||
|
return false
|
||
|
}
|
||
|
if readFrom != nil {
|
||
|
switch from := readFrom.(type) {
|
||
|
case *syscall.SockaddrInet4:
|
||
|
ip := from.Addr // copy from.Addr; ip escapes, so this line allocates 4 bytes
|
||
|
addr = &net.UDPAddr{IP: ip[:], Port: from.Port}
|
||
|
case *syscall.SockaddrInet6:
|
||
|
ip := from.Addr // copy from.Addr; ip escapes, so this line allocates 16 bytes
|
||
|
addr = &net.UDPAddr{IP: ip[:], Port: from.Port, Zone: strconv.FormatInt(int64(from.ZoneId), 10)}
|
||
|
}
|
||
|
}
|
||
|
if readN == 0 {
|
||
|
readErr = io.EOF
|
||
|
}
|
||
|
return true
|
||
|
})
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
if readErr != nil {
|
||
|
err = readErr
|
||
|
return
|
||
|
}
|
||
|
return
|
||
|
}
|