From 15887237355a51567d92c003d6ad023c7b3008c0 Mon Sep 17 00:00:00 2001 From: Edoardo Vacchi Date: Fri, 9 Jun 2023 15:21:32 +0200 Subject: [PATCH] wip Signed-off-by: Edoardo Vacchi --- internal/sysfs/sock.go | 2 + internal/sysfs/sock_windows.go | 146 +++++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+) diff --git a/internal/sysfs/sock.go b/internal/sysfs/sock.go index 6a23f155..8c102e40 100644 --- a/internal/sysfs/sock.go +++ b/internal/sysfs/sock.go @@ -1,3 +1,5 @@ +//go:build !windows + package sysfs import ( diff --git a/internal/sysfs/sock_windows.go b/internal/sysfs/sock_windows.go index 1ff680c6..9e75b0a8 100644 --- a/internal/sysfs/sock_windows.go +++ b/internal/sysfs/sock_windows.go @@ -3,7 +3,10 @@ package sysfs import ( + "github.com/tetratelabs/wazero/internal/fsapi" + socketapi "github.com/tetratelabs/wazero/internal/sock" "net" + "os" "syscall" "unsafe" @@ -61,3 +64,146 @@ func recvfrom(s syscall.Handle, buf []byte, flags int32) (n int, errno syscall.E 0) // fromlen *int (optional) return int(r0), e1 } + +func NewTCPListenerFile(tl *net.TCPListener) socketapi.TCPSock { + return &winTcpListenerFile{tl: tl} +} + +var _ socketapi.TCPSock = (*winTcpListenerFile)(nil) + +type winTcpListenerFile struct { + fsapi.UnimplementedFile + + tl *net.TCPListener +} + +// Accept implements the same method as documented on socketapi.TCPSock +func (f *winTcpListenerFile) Accept() (socketapi.TCPConn, syscall.Errno) { + conn, err := f.tl.Accept() + if err != nil { + return nil, platform.UnwrapOSError(err) + } + return &winTcpConnFile{tc: conn.(*net.TCPConn)}, 0 +} + +// IsDir implements the same method as documented on File.IsDir +func (*winTcpListenerFile) IsDir() (bool, syscall.Errno) { + // We need to override this method because WASI-libc prestats the FD + // and the default impl returns ENOSYS otherwise. + return false, 0 +} + +// Stat implements the same method as documented on File.Stat +func (f *winTcpListenerFile) Stat() (fs fsapi.Stat_t, errno syscall.Errno) { + // The mode is not really important, but it should be neither a regular file nor a directory. + fs.Mode = os.ModeIrregular + return +} + +// Close implements the same method as documented on fsapi.File +func (f *winTcpListenerFile) Close() syscall.Errno { + return platform.UnwrapOSError(f.tl.Close()) +} + +// Addr is exposed for testing. +func (f *winTcpListenerFile) Addr() *net.TCPAddr { + return f.tl.Addr().(*net.TCPAddr) +} + +var _ socketapi.TCPConn = (*winTcpConnFile)(nil) + +type winTcpConnFile struct { + fsapi.UnimplementedFile + + tc *net.TCPConn + + // closed is true when closed was called. This ensures proper syscall.EBADF + closed bool +} + +// IsDir implements the same method as documented on File.IsDir +func (*winTcpConnFile) IsDir() (bool, syscall.Errno) { + // We need to override this method because WASI-libc prestats the FD + // and the default impl returns ENOSYS otherwise. + return false, 0 +} + +// Stat implements the same method as documented on File.Stat +func (f *winTcpConnFile) Stat() (fs fsapi.Stat_t, errno syscall.Errno) { + // The mode is not really important, but it should be neither a regular file nor a directory. + fs.Mode = os.ModeIrregular + return +} + +// SetNonblock implements the same method as documented on fsapi.File +func (f *winTcpConnFile) SetNonblock(enabled bool) (errno syscall.Errno) { + syscallConn, err := f.tc.SyscallConn() + if err != nil { + return platform.UnwrapOSError(err) + } + + // Prioritize the error from setNonblock over Control + if controlErr := syscallConn.Control(func(fd uintptr) { + errno = platform.UnwrapOSError(setNonblock(fd, enabled)) + }); errno == 0 { + errno = platform.UnwrapOSError(controlErr) + } + return +} + +// Read implements the same method as documented on fsapi.File +func (f *winTcpConnFile) Read(buf []byte) (n int, errno syscall.Errno) { + if n, errno = read(f.tc, buf); errno != 0 { + // Defer validation overhead until we've already had an error. + errno = fileError(f, f.closed, errno) + } + return +} + +// Write implements the same method as documented on fsapi.File +func (f *winTcpConnFile) Write(buf []byte) (n int, errno syscall.Errno) { + if n, errno = write(f.tc, buf); errno != 0 { + // Defer validation overhead until we've alwritey had an error. + errno = fileError(f, f.closed, errno) + } + return +} + +// Recvfrom implements the same method as documented on socketapi.TCPConn +func (f *winTcpConnFile) Recvfrom(p []byte, flags int) (n int, errno syscall.Errno) { + if flags != MSG_PEEK { + errno = syscall.EINVAL + return + } + return recvfromPeek(f.tc, p) +} + +// Shutdown implements the same method as documented on fsapi.Conn +func (f *winTcpConnFile) Shutdown(how int) syscall.Errno { + // FIXME: can userland shutdown listeners? + var err error + switch how { + case syscall.SHUT_RD: + err = f.tc.CloseRead() + case syscall.SHUT_WR: + err = f.tc.CloseWrite() + case syscall.SHUT_RDWR: + return f.close() + default: + return syscall.EINVAL + } + return platform.UnwrapOSError(err) +} + +// Close implements the same method as documented on fsapi.File +func (f *winTcpConnFile) Close() syscall.Errno { + return f.close() +} + +func (f *winTcpConnFile) close() syscall.Errno { + if f.closed { + return 0 + } + f.closed = true + return f.Shutdown(syscall.SHUT_RDWR) +}