Signed-off-by: gram <git@orsinium.dev> Signed-off-by: Edoardo Vacchi <evacchi@users.noreply.github.com> Co-authored-by: Edoardo Vacchi <evacchi@users.noreply.github.com>
78 lines
2.5 KiB
Go
78 lines
2.5 KiB
Go
//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
|
|
}
|