1//go:build (linux || darwin || windows) && !tinygo
2
3package sysfs
4
5import (
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
15func (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
34func (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
43func (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.
65func 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}