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