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  }