summaryrefslogtreecommitdiff
path: root/vendor/github.com/tetratelabs/wazero/internal/sysfs/sock_supported.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/tetratelabs/wazero/internal/sysfs/sock_supported.go')
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/sysfs/sock_supported.go77
1 files changed, 77 insertions, 0 deletions
diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/sock_supported.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/sock_supported.go
new file mode 100644
index 000000000..6c976fb86
--- /dev/null
+++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/sock_supported.go
@@ -0,0 +1,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
+}