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 }