github.com/sagernet/sing@v0.2.6/common/bufio/vectorised_unix.go (about) 1 //go:build !windows 2 3 package bufio 4 5 import ( 6 "unsafe" 7 8 "github.com/sagernet/sing/common/buf" 9 M "github.com/sagernet/sing/common/metadata" 10 11 "golang.org/x/sys/unix" 12 ) 13 14 func (w *SyscallVectorisedWriter) WriteVectorised(buffers []*buf.Buffer) error { 15 defer buf.ReleaseMulti(buffers) 16 iovecList := make([]unix.Iovec, 0, len(buffers)) 17 for _, buffer := range buffers { 18 var iovec unix.Iovec 19 iovec.Base = &buffer.Bytes()[0] 20 iovec.SetLen(buffer.Len()) 21 iovecList = append(iovecList, iovec) 22 } 23 var innerErr unix.Errno 24 err := w.rawConn.Write(func(fd uintptr) (done bool) { 25 //nolint:staticcheck 26 //goland:noinspection GoDeprecation 27 _, _, innerErr = unix.Syscall(unix.SYS_WRITEV, fd, uintptr(unsafe.Pointer(&iovecList[0])), uintptr(len(iovecList))) 28 return innerErr != unix.EAGAIN && innerErr != unix.EWOULDBLOCK 29 }) 30 if innerErr != 0 { 31 err = innerErr 32 } 33 return err 34 } 35 36 func (w *SyscallVectorisedPacketWriter) WriteVectorisedPacket(buffers []*buf.Buffer, destination M.Socksaddr) error { 37 defer buf.ReleaseMulti(buffers) 38 var sockaddr unix.Sockaddr 39 if destination.IsIPv4() { 40 sockaddr = &unix.SockaddrInet4{ 41 Port: int(destination.Port), 42 Addr: destination.Addr.As4(), 43 } 44 } else { 45 sockaddr = &unix.SockaddrInet6{ 46 Port: int(destination.Port), 47 Addr: destination.Addr.As16(), 48 } 49 } 50 var innerErr error 51 err := w.rawConn.Write(func(fd uintptr) (done bool) { 52 _, innerErr = unix.SendmsgBuffers(int(fd), buf.ToSliceMulti(buffers), nil, sockaddr, 0) 53 return innerErr != unix.EAGAIN && innerErr != unix.EWOULDBLOCK 54 }) 55 if innerErr != nil { 56 err = innerErr 57 } 58 return err 59 }