github.com/tetratelabs/wazero@v1.7.3-0.20240513003603-48f702e154b5/internal/sysfs/sock_supported.go (about)

     1  //go:build (linux || darwin || windows) && !tinygo
     2  
     3  package sysfs
     4  
     5  import (
     6  	"net"
     7  	"syscall"
     8  
     9  	experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
    10  	"github.com/tetratelabs/wazero/internal/fsapi"
    11  	socketapi "github.com/tetratelabs/wazero/internal/sock"
    12  )
    13  
    14  // Accept implements the same method as documented on socketapi.TCPSock
    15  func (f *tcpListenerFile) Accept() (socketapi.TCPConn, experimentalsys.Errno) {
    16  	// Ensure we have an incoming connection, otherwise return immediately.
    17  	if f.nonblock {
    18  		if ready, errno := _pollSock(f.tl, fsapi.POLLIN, 0); !ready || errno != 0 {
    19  			return nil, experimentalsys.EAGAIN
    20  		}
    21  	}
    22  
    23  	// Accept normally blocks goroutines, but we
    24  	// made sure that we have an incoming connection,
    25  	// so we should be safe.
    26  	if conn, err := f.tl.Accept(); err != nil {
    27  		return nil, experimentalsys.UnwrapOSError(err)
    28  	} else {
    29  		return newTcpConn(conn.(*net.TCPConn)), 0
    30  	}
    31  }
    32  
    33  // SetNonblock implements the same method as documented on fsapi.File
    34  func (f *tcpListenerFile) SetNonblock(enabled bool) (errno experimentalsys.Errno) {
    35  	f.nonblock = enabled
    36  	_, errno = syscallConnControl(f.tl, func(fd uintptr) (int, experimentalsys.Errno) {
    37  		return 0, setNonblockSocket(fd, enabled)
    38  	})
    39  	return
    40  }
    41  
    42  // Shutdown implements the same method as documented on experimentalsys.Conn
    43  func (f *tcpConnFile) Shutdown(how int) experimentalsys.Errno {
    44  	// FIXME: can userland shutdown listeners?
    45  	var err error
    46  	switch how {
    47  	case socketapi.SHUT_RD:
    48  		err = f.tc.CloseRead()
    49  	case socketapi.SHUT_WR:
    50  		err = f.tc.CloseWrite()
    51  	case socketapi.SHUT_RDWR:
    52  		return f.close()
    53  	default:
    54  		return experimentalsys.EINVAL
    55  	}
    56  	return experimentalsys.UnwrapOSError(err)
    57  }
    58  
    59  // syscallConnControl extracts a syscall.RawConn from the given syscall.Conn and applies
    60  // the given fn to a file descriptor, returning an integer or a nonzero syscall.Errno on failure.
    61  //
    62  // syscallConnControl streamlines the pattern of extracting the syscall.Rawconn,
    63  // invoking its syscall.RawConn.Control method, then handling properly the errors that may occur
    64  // within fn or returned by syscall.RawConn.Control itself.
    65  func syscallConnControl(conn syscall.Conn, fn func(fd uintptr) (int, experimentalsys.Errno)) (n int, errno experimentalsys.Errno) {
    66  	syscallConn, err := conn.SyscallConn()
    67  	if err != nil {
    68  		return 0, experimentalsys.UnwrapOSError(err)
    69  	}
    70  	// Prioritize the inner errno over Control
    71  	if controlErr := syscallConn.Control(func(fd uintptr) {
    72  		n, errno = fn(fd)
    73  	}); errno == 0 {
    74  		errno = experimentalsys.UnwrapOSError(controlErr)
    75  	}
    76  	return
    77  }