mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
net: implement wasip1 FileListener and FileConn
Implements net.FileListener and net.FileConn for wasip1. net.FileListener can be used with a pre-opened socket. If the WASM module knows the file descriptor, a listener can be constructed with: l, err := net.FileListener(os.NewFile(fd, "")) If the WASM module does not know the file descriptor, but knows that at least one of the preopens is a socket, it can find the file descriptor and construct a listener like so: func findListener() (net.Listener, error) { // We start looking for pre-opened sockets at fd=3 because 0, 1, // and 2 are reserved for stdio. Pre-opened directories also // start at fd=3, so we skip fds that aren't sockets. Once we // reach EBADF we know there are no more pre-opens. for preopenFd := uintptr(3); ; preopenFd++ { l, err := net.FileListener(os.NewFile(preopenFd, "")) var se syscall.Errno switch errors.As(err, &se); se { case syscall.ENOTSOCK: continue case syscall.EBADF: err = nil } return l, err } } A similar strategy can be used with net.FileConn and pre-opened connection sockets. The wasmtime runtime supports pre-opening listener sockets: $ wasmtime --tcplisten 127.0.0.1:8080 module.wasm Change-Id: Iec6ae4ffa84b3753cce4f56a2817e150445db643 Reviewed-on: https://go-review.googlesource.com/c/go/+/493358 Reviewed-by: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Ian Lance Taylor <iant@golang.org> Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org> TryBot-Bypass: Dmitri Shuralyov <dmitshur@google.com> Reviewed-by: Johan Brandhorst-Satzkorn <johan.brandhorst@gmail.com> Auto-Submit: Johan Brandhorst-Satzkorn <johan.brandhorst@gmail.com> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
This commit is contained in:
parent
c5c2184538
commit
a17de43ef1
@ -11,10 +11,10 @@ case "$GOWASIRUNTIME" in
|
|||||||
exec wasmer run --dir=/ --env PWD="$PWD" ${GOWASIRUNTIMEARGS:-} "$1" -- "${@:2}"
|
exec wasmer run --dir=/ --env PWD="$PWD" ${GOWASIRUNTIMEARGS:-} "$1" -- "${@:2}"
|
||||||
;;
|
;;
|
||||||
"wasmtime")
|
"wasmtime")
|
||||||
exec wasmtime run --dir=/ --env PWD="$PWD" --max-wasm-stack 1048576 "$1" -- "${@:2}"
|
exec wasmtime run --dir=/ --env PWD="$PWD" --max-wasm-stack 1048576 ${GOWASIRUNTIMEARGS:-} "$1" -- "${@:2}"
|
||||||
;;
|
;;
|
||||||
"wazero" | "")
|
"wazero" | "")
|
||||||
exec wazero run -mount /:/ -env-inherit -cachedir "${TMPDIR:-/tmp}"/wazero "$1" "${@:2}"
|
exec wazero run -mount /:/ -env-inherit -cachedir "${TMPDIR:-/tmp}"/wazero ${GOWASIRUNTIMEARGS:-} "$1" "${@:2}"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Unknown Go WASI runtime specified: $GOWASIRUNTIME"
|
echo "Unknown Go WASI runtime specified: $GOWASIRUNTIME"
|
||||||
|
@ -52,6 +52,8 @@ type FD struct {
|
|||||||
// or "file".
|
// or "file".
|
||||||
// Set pollable to true if fd should be managed by runtime netpoll.
|
// Set pollable to true if fd should be managed by runtime netpoll.
|
||||||
func (fd *FD) Init(net string, pollable bool) error {
|
func (fd *FD) Init(net string, pollable bool) error {
|
||||||
|
fd.SysFile.init()
|
||||||
|
|
||||||
// We don't actually care about the various network types.
|
// We don't actually care about the various network types.
|
||||||
if net == "file" {
|
if net == "file" {
|
||||||
fd.isFile = true
|
fd.isFile = true
|
||||||
@ -76,12 +78,7 @@ func (fd *FD) destroy() error {
|
|||||||
// so this must be executed before CloseFunc.
|
// so this must be executed before CloseFunc.
|
||||||
fd.pd.close()
|
fd.pd.close()
|
||||||
|
|
||||||
// We don't use ignoringEINTR here because POSIX does not define
|
err := fd.SysFile.destroy(fd.Sysfd)
|
||||||
// whether the descriptor is closed if close returns EINTR.
|
|
||||||
// If the descriptor is indeed closed, using a loop would race
|
|
||||||
// with some other goroutine opening a new descriptor.
|
|
||||||
// (The Linux kernel guarantees that it is closed on an EINTR error.)
|
|
||||||
err := CloseFunc(fd.Sysfd)
|
|
||||||
|
|
||||||
fd.Sysfd = -1
|
fd.Sysfd = -1
|
||||||
runtime_Semrelease(&fd.csema)
|
runtime_Semrelease(&fd.csema)
|
||||||
|
@ -13,6 +13,17 @@ type SysFile struct {
|
|||||||
iovecs *[]syscall.Iovec
|
iovecs *[]syscall.Iovec
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SysFile) init() {}
|
||||||
|
|
||||||
|
func (s *SysFile) destroy(fd int) error {
|
||||||
|
// We don't use ignoringEINTR here because POSIX does not define
|
||||||
|
// whether the descriptor is closed if close returns EINTR.
|
||||||
|
// If the descriptor is indeed closed, using a loop would race
|
||||||
|
// with some other goroutine opening a new descriptor.
|
||||||
|
// (The Linux kernel guarantees that it is closed on an EINTR error.)
|
||||||
|
return CloseFunc(fd)
|
||||||
|
}
|
||||||
|
|
||||||
// dupCloseOnExecOld is the traditional way to dup an fd and
|
// dupCloseOnExecOld is the traditional way to dup an fd and
|
||||||
// set its O_CLOEXEC bit, using two system calls.
|
// set its O_CLOEXEC bit, using two system calls.
|
||||||
func dupCloseOnExecOld(fd int) (int, string, error) {
|
func dupCloseOnExecOld(fd int) (int, string, error) {
|
||||||
|
@ -11,6 +11,18 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type SysFile struct {
|
type SysFile struct {
|
||||||
|
// RefCountPtr is a pointer to the reference count of Sysfd.
|
||||||
|
//
|
||||||
|
// WASI preview 1 lacks a dup(2) system call. When the os and net packages
|
||||||
|
// need to share a file/socket, instead of duplicating the underlying file
|
||||||
|
// descriptor, we instead provide a way to copy FD instances and manage the
|
||||||
|
// underlying file descriptor with reference counting.
|
||||||
|
RefCountPtr *int32
|
||||||
|
|
||||||
|
// RefCount is the reference count of Sysfd. When a copy of an FD is made,
|
||||||
|
// it points to the reference count of the original FD instance.
|
||||||
|
RefCount int32
|
||||||
|
|
||||||
// Cache for the file type, lazily initialized when Seek is called.
|
// Cache for the file type, lazily initialized when Seek is called.
|
||||||
Filetype uint32
|
Filetype uint32
|
||||||
|
|
||||||
@ -29,6 +41,47 @@ type SysFile struct {
|
|||||||
// always set instead of being lazily initialized.
|
// always set instead of being lazily initialized.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SysFile) init() {
|
||||||
|
if s.RefCountPtr == nil {
|
||||||
|
s.RefCount = 1
|
||||||
|
s.RefCountPtr = &s.RefCount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SysFile) ref() SysFile {
|
||||||
|
atomic.AddInt32(s.RefCountPtr, +1)
|
||||||
|
return SysFile{RefCountPtr: s.RefCountPtr}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SysFile) destroy(fd int) error {
|
||||||
|
if s.RefCountPtr != nil && atomic.AddInt32(s.RefCountPtr, -1) > 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't use ignoringEINTR here because POSIX does not define
|
||||||
|
// whether the descriptor is closed if close returns EINTR.
|
||||||
|
// If the descriptor is indeed closed, using a loop would race
|
||||||
|
// with some other goroutine opening a new descriptor.
|
||||||
|
// (The Linux kernel guarantees that it is closed on an EINTR error.)
|
||||||
|
return CloseFunc(fd)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy creates a copy of the FD.
|
||||||
|
//
|
||||||
|
// The FD instance points to the same underlying file descriptor. The file
|
||||||
|
// descriptor isn't closed until all FD instances that refer to it have been
|
||||||
|
// closed/destroyed.
|
||||||
|
func (fd *FD) Copy() FD {
|
||||||
|
return FD{
|
||||||
|
Sysfd: fd.Sysfd,
|
||||||
|
SysFile: fd.SysFile.ref(),
|
||||||
|
IsStream: fd.IsStream,
|
||||||
|
ZeroReadIsEOF: fd.ZeroReadIsEOF,
|
||||||
|
isBlocking: fd.isBlocking,
|
||||||
|
isFile: fd.isFile,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// dupCloseOnExecOld always errors on wasip1 because there is no mechanism to
|
// dupCloseOnExecOld always errors on wasip1 because there is no mechanism to
|
||||||
// duplicate file descriptors.
|
// duplicate file descriptors.
|
||||||
func dupCloseOnExecOld(fd int) (int, string, error) {
|
func dupCloseOnExecOld(fd int) (int, string, error) {
|
||||||
|
168
src/net/fd_wasip1.go
Normal file
168
src/net/fd_wasip1.go
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
// Copyright 2023 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build wasip1
|
||||||
|
|
||||||
|
package net
|
||||||
|
|
||||||
|
import (
|
||||||
|
"internal/poll"
|
||||||
|
"runtime"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
readSyscallName = "fd_read"
|
||||||
|
writeSyscallName = "fd_write"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Network file descriptor.
|
||||||
|
type netFD struct {
|
||||||
|
pfd poll.FD
|
||||||
|
|
||||||
|
// immutable until Close
|
||||||
|
family int
|
||||||
|
sotype int
|
||||||
|
isConnected bool // handshake completed or use of association with peer
|
||||||
|
net string
|
||||||
|
laddr Addr
|
||||||
|
raddr Addr
|
||||||
|
|
||||||
|
// The only networking available in WASI preview 1 is the ability to
|
||||||
|
// sock_accept on an pre-opened socket, and then fd_read, fd_write,
|
||||||
|
// fd_close, and sock_shutdown on the resulting connection. We
|
||||||
|
// intercept applicable netFD calls on this instance, and then pass
|
||||||
|
// the remainder of the netFD calls to fakeNetFD.
|
||||||
|
*fakeNetFD
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFD(sysfd int) (*netFD, error) {
|
||||||
|
return newPollFD(poll.FD{
|
||||||
|
Sysfd: sysfd,
|
||||||
|
IsStream: true,
|
||||||
|
ZeroReadIsEOF: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPollFD(pfd poll.FD) (*netFD, error) {
|
||||||
|
ret := &netFD{
|
||||||
|
pfd: pfd,
|
||||||
|
net: "tcp",
|
||||||
|
laddr: unknownAddr{},
|
||||||
|
raddr: unknownAddr{},
|
||||||
|
}
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fd *netFD) init() error {
|
||||||
|
return fd.pfd.Init(fd.net, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fd *netFD) name() string {
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fd *netFD) accept() (netfd *netFD, err error) {
|
||||||
|
if fd.fakeNetFD != nil {
|
||||||
|
return fd.fakeNetFD.accept()
|
||||||
|
}
|
||||||
|
d, _, errcall, err := fd.pfd.Accept()
|
||||||
|
if err != nil {
|
||||||
|
if errcall != "" {
|
||||||
|
err = wrapSyscallError(errcall, err)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if netfd, err = newFD(d); err != nil {
|
||||||
|
poll.CloseFunc(d)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = netfd.init(); err != nil {
|
||||||
|
netfd.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return netfd, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fd *netFD) setAddr(laddr, raddr Addr) {
|
||||||
|
fd.laddr = laddr
|
||||||
|
fd.raddr = raddr
|
||||||
|
runtime.SetFinalizer(fd, (*netFD).Close)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fd *netFD) Close() error {
|
||||||
|
if fd.fakeNetFD != nil {
|
||||||
|
return fd.fakeNetFD.Close()
|
||||||
|
}
|
||||||
|
runtime.SetFinalizer(fd, nil)
|
||||||
|
return fd.pfd.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fd *netFD) shutdown(how int) error {
|
||||||
|
if fd.fakeNetFD != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err := fd.pfd.Shutdown(how)
|
||||||
|
runtime.KeepAlive(fd)
|
||||||
|
return wrapSyscallError("shutdown", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fd *netFD) closeRead() error {
|
||||||
|
if fd.fakeNetFD != nil {
|
||||||
|
return fd.fakeNetFD.closeRead()
|
||||||
|
}
|
||||||
|
return fd.shutdown(syscall.SHUT_RD)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fd *netFD) closeWrite() error {
|
||||||
|
if fd.fakeNetFD != nil {
|
||||||
|
return fd.fakeNetFD.closeWrite()
|
||||||
|
}
|
||||||
|
return fd.shutdown(syscall.SHUT_WR)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fd *netFD) Read(p []byte) (n int, err error) {
|
||||||
|
if fd.fakeNetFD != nil {
|
||||||
|
return fd.fakeNetFD.Read(p)
|
||||||
|
}
|
||||||
|
n, err = fd.pfd.Read(p)
|
||||||
|
runtime.KeepAlive(fd)
|
||||||
|
return n, wrapSyscallError(readSyscallName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fd *netFD) Write(p []byte) (nn int, err error) {
|
||||||
|
if fd.fakeNetFD != nil {
|
||||||
|
return fd.fakeNetFD.Write(p)
|
||||||
|
}
|
||||||
|
nn, err = fd.pfd.Write(p)
|
||||||
|
runtime.KeepAlive(fd)
|
||||||
|
return nn, wrapSyscallError(writeSyscallName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fd *netFD) SetDeadline(t time.Time) error {
|
||||||
|
if fd.fakeNetFD != nil {
|
||||||
|
return fd.fakeNetFD.SetDeadline(t)
|
||||||
|
}
|
||||||
|
return fd.pfd.SetDeadline(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fd *netFD) SetReadDeadline(t time.Time) error {
|
||||||
|
if fd.fakeNetFD != nil {
|
||||||
|
return fd.fakeNetFD.SetReadDeadline(t)
|
||||||
|
}
|
||||||
|
return fd.pfd.SetReadDeadline(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fd *netFD) SetWriteDeadline(t time.Time) error {
|
||||||
|
if fd.fakeNetFD != nil {
|
||||||
|
return fd.fakeNetFD.SetWriteDeadline(t)
|
||||||
|
}
|
||||||
|
return fd.pfd.SetWriteDeadline(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
type unknownAddr struct{}
|
||||||
|
|
||||||
|
func (unknownAddr) Network() string { return "unknown" }
|
||||||
|
func (unknownAddr) String() string { return "unknown" }
|
@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build (js && wasm) || wasip1
|
//go:build js && wasm
|
||||||
|
|
||||||
package net
|
package net
|
||||||
|
|
||||||
|
62
src/net/file_wasip1.go
Normal file
62
src/net/file_wasip1.go
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// Copyright 2023 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build wasip1
|
||||||
|
|
||||||
|
package net
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
_ "unsafe" // for go:linkname
|
||||||
|
)
|
||||||
|
|
||||||
|
func fileListener(f *os.File) (Listener, error) {
|
||||||
|
fd, err := newFileFD(f)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &TCPListener{fd: fd}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func fileConn(f *os.File) (Conn, error) {
|
||||||
|
fd, err := newFileFD(f)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &TCPConn{conn{fd: fd}}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func filePacketConn(f *os.File) (PacketConn, error) { return nil, syscall.ENOPROTOOPT }
|
||||||
|
|
||||||
|
func newFileFD(f *os.File) (fd *netFD, err error) {
|
||||||
|
pfd := f.PollFD().Copy()
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
pfd.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
filetype, err := fd_fdstat_get_type(pfd.Sysfd)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if filetype != syscall.FILETYPE_SOCKET_STREAM {
|
||||||
|
return nil, syscall.ENOTSOCK
|
||||||
|
}
|
||||||
|
fd, err = newPollFD(pfd)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := fd.init(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return fd, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// This helper is implemented in the syscall package. It means we don't have
|
||||||
|
// to redefine the fd_fdstat_get host import or the fdstat struct it
|
||||||
|
// populates.
|
||||||
|
//
|
||||||
|
//go:linkname fd_fdstat_get_type syscall.fd_fdstat_get_type
|
||||||
|
func fd_fdstat_get_type(fd int) (uint8, error)
|
@ -10,7 +10,6 @@ package net
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"internal/poll"
|
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
@ -33,61 +32,64 @@ func nextPort() int {
|
|||||||
return portCounter
|
return portCounter
|
||||||
}
|
}
|
||||||
|
|
||||||
// Network file descriptor.
|
type fakeNetFD struct {
|
||||||
type netFD struct {
|
listener bool
|
||||||
|
laddr Addr
|
||||||
r *bufferedPipe
|
r *bufferedPipe
|
||||||
w *bufferedPipe
|
w *bufferedPipe
|
||||||
incoming chan *netFD
|
incoming chan *netFD
|
||||||
|
|
||||||
closedMu sync.Mutex
|
closedMu sync.Mutex
|
||||||
closed bool
|
closed bool
|
||||||
|
|
||||||
// immutable until Close
|
|
||||||
listener bool
|
|
||||||
family int
|
|
||||||
sotype int
|
|
||||||
net string
|
|
||||||
laddr Addr
|
|
||||||
raddr Addr
|
|
||||||
|
|
||||||
// unused
|
|
||||||
pfd poll.FD
|
|
||||||
isConnected bool // handshake completed or use of association with peer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// socket returns a network file descriptor that is ready for
|
// socket returns a network file descriptor that is ready for
|
||||||
// asynchronous I/O using the network poller.
|
// asynchronous I/O using the network poller.
|
||||||
func socket(ctx context.Context, net string, family, sotype, proto int, ipv6only bool, laddr, raddr sockaddr, ctrlCtxFn func(context.Context, string, string, syscall.RawConn) error) (*netFD, error) {
|
func socket(ctx context.Context, net string, family, sotype, proto int, ipv6only bool, laddr, raddr sockaddr, ctrlCtxFn func(context.Context, string, string, syscall.RawConn) error) (*netFD, error) {
|
||||||
fd := &netFD{family: family, sotype: sotype, net: net}
|
fd := &netFD{family: family, sotype: sotype, net: net}
|
||||||
|
if laddr != nil && raddr == nil {
|
||||||
if laddr != nil && raddr == nil { // listener
|
return fakelistener(fd, laddr)
|
||||||
l := laddr.(*TCPAddr)
|
|
||||||
fd.laddr = &TCPAddr{
|
|
||||||
IP: l.IP,
|
|
||||||
Port: nextPort(),
|
|
||||||
Zone: l.Zone,
|
|
||||||
}
|
|
||||||
fd.listener = true
|
|
||||||
fd.incoming = make(chan *netFD, 1024)
|
|
||||||
listenersMu.Lock()
|
|
||||||
listeners[fd.laddr.(*TCPAddr).String()] = fd
|
|
||||||
listenersMu.Unlock()
|
|
||||||
return fd, nil
|
|
||||||
}
|
}
|
||||||
|
fd2 := &netFD{family: family, sotype: sotype, net: net}
|
||||||
|
return fakeconn(fd, fd2, raddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func fakelistener(fd *netFD, laddr sockaddr) (*netFD, error) {
|
||||||
|
l := laddr.(*TCPAddr)
|
||||||
|
fd.laddr = &TCPAddr{
|
||||||
|
IP: l.IP,
|
||||||
|
Port: nextPort(),
|
||||||
|
Zone: l.Zone,
|
||||||
|
}
|
||||||
|
fd.fakeNetFD = &fakeNetFD{
|
||||||
|
listener: true,
|
||||||
|
laddr: fd.laddr,
|
||||||
|
incoming: make(chan *netFD, 1024),
|
||||||
|
}
|
||||||
|
listenersMu.Lock()
|
||||||
|
listeners[fd.laddr.(*TCPAddr).String()] = fd
|
||||||
|
listenersMu.Unlock()
|
||||||
|
return fd, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func fakeconn(fd *netFD, fd2 *netFD, raddr sockaddr) (*netFD, error) {
|
||||||
fd.laddr = &TCPAddr{
|
fd.laddr = &TCPAddr{
|
||||||
IP: IPv4(127, 0, 0, 1),
|
IP: IPv4(127, 0, 0, 1),
|
||||||
Port: nextPort(),
|
Port: nextPort(),
|
||||||
}
|
}
|
||||||
fd.raddr = raddr
|
fd.raddr = raddr
|
||||||
fd.r = newBufferedPipe(65536)
|
|
||||||
fd.w = newBufferedPipe(65536)
|
|
||||||
|
|
||||||
fd2 := &netFD{family: fd.family, sotype: sotype, net: net}
|
fd.fakeNetFD = &fakeNetFD{
|
||||||
|
r: newBufferedPipe(65536),
|
||||||
|
w: newBufferedPipe(65536),
|
||||||
|
}
|
||||||
|
fd2.fakeNetFD = &fakeNetFD{
|
||||||
|
r: fd.fakeNetFD.w,
|
||||||
|
w: fd.fakeNetFD.r,
|
||||||
|
}
|
||||||
|
|
||||||
fd2.laddr = fd.raddr
|
fd2.laddr = fd.raddr
|
||||||
fd2.raddr = fd.laddr
|
fd2.raddr = fd.laddr
|
||||||
fd2.r = fd.w
|
|
||||||
fd2.w = fd.r
|
|
||||||
listenersMu.Lock()
|
listenersMu.Lock()
|
||||||
l, ok := listeners[fd.raddr.(*TCPAddr).String()]
|
l, ok := listeners[fd.raddr.(*TCPAddr).String()]
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -100,15 +102,15 @@ func socket(ctx context.Context, net string, family, sotype, proto int, ipv6only
|
|||||||
return fd, nil
|
return fd, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *netFD) Read(p []byte) (n int, err error) {
|
func (fd *fakeNetFD) Read(p []byte) (n int, err error) {
|
||||||
return fd.r.Read(p)
|
return fd.r.Read(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *netFD) Write(p []byte) (nn int, err error) {
|
func (fd *fakeNetFD) Write(p []byte) (nn int, err error) {
|
||||||
return fd.w.Write(p)
|
return fd.w.Write(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *netFD) Close() error {
|
func (fd *fakeNetFD) Close() error {
|
||||||
fd.closedMu.Lock()
|
fd.closedMu.Lock()
|
||||||
if fd.closed {
|
if fd.closed {
|
||||||
fd.closedMu.Unlock()
|
fd.closedMu.Unlock()
|
||||||
@ -131,17 +133,17 @@ func (fd *netFD) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *netFD) closeRead() error {
|
func (fd *fakeNetFD) closeRead() error {
|
||||||
fd.r.Close()
|
fd.r.Close()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *netFD) closeWrite() error {
|
func (fd *fakeNetFD) closeWrite() error {
|
||||||
fd.w.Close()
|
fd.w.Close()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *netFD) accept() (*netFD, error) {
|
func (fd *fakeNetFD) accept() (*netFD, error) {
|
||||||
c, ok := <-fd.incoming
|
c, ok := <-fd.incoming
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, syscall.EINVAL
|
return nil, syscall.EINVAL
|
||||||
@ -149,18 +151,18 @@ func (fd *netFD) accept() (*netFD, error) {
|
|||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *netFD) SetDeadline(t time.Time) error {
|
func (fd *fakeNetFD) SetDeadline(t time.Time) error {
|
||||||
fd.r.SetReadDeadline(t)
|
fd.r.SetReadDeadline(t)
|
||||||
fd.w.SetWriteDeadline(t)
|
fd.w.SetWriteDeadline(t)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *netFD) SetReadDeadline(t time.Time) error {
|
func (fd *fakeNetFD) SetReadDeadline(t time.Time) error {
|
||||||
fd.r.SetReadDeadline(t)
|
fd.r.SetReadDeadline(t)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *netFD) SetWriteDeadline(t time.Time) error {
|
func (fd *fakeNetFD) SetWriteDeadline(t time.Time) error {
|
||||||
fd.w.SetWriteDeadline(t)
|
fd.w.SetWriteDeadline(t)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -265,55 +267,59 @@ func sysSocket(family, sotype, proto int) (int, error) {
|
|||||||
return 0, syscall.ENOSYS
|
return 0, syscall.ENOSYS
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
|
func (fd *fakeNetFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (syscall.Sockaddr, error) {
|
||||||
|
return nil, syscall.ENOSYS
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fd *fakeNetFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
|
||||||
return 0, nil, syscall.ENOSYS
|
return 0, nil, syscall.ENOSYS
|
||||||
|
|
||||||
}
|
}
|
||||||
func (fd *netFD) readFromInet4(p []byte, sa *syscall.SockaddrInet4) (n int, err error) {
|
func (fd *fakeNetFD) readFromInet4(p []byte, sa *syscall.SockaddrInet4) (n int, err error) {
|
||||||
return 0, syscall.ENOSYS
|
return 0, syscall.ENOSYS
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *netFD) readFromInet6(p []byte, sa *syscall.SockaddrInet6) (n int, err error) {
|
func (fd *fakeNetFD) readFromInet6(p []byte, sa *syscall.SockaddrInet6) (n int, err error) {
|
||||||
return 0, syscall.ENOSYS
|
return 0, syscall.ENOSYS
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *netFD) readMsg(p []byte, oob []byte, flags int) (n, oobn, retflags int, sa syscall.Sockaddr, err error) {
|
func (fd *fakeNetFD) readMsg(p []byte, oob []byte, flags int) (n, oobn, retflags int, sa syscall.Sockaddr, err error) {
|
||||||
return 0, 0, 0, nil, syscall.ENOSYS
|
return 0, 0, 0, nil, syscall.ENOSYS
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *netFD) readMsgInet4(p []byte, oob []byte, flags int, sa *syscall.SockaddrInet4) (n, oobn, retflags int, err error) {
|
func (fd *fakeNetFD) readMsgInet4(p []byte, oob []byte, flags int, sa *syscall.SockaddrInet4) (n, oobn, retflags int, err error) {
|
||||||
return 0, 0, 0, syscall.ENOSYS
|
return 0, 0, 0, syscall.ENOSYS
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *netFD) readMsgInet6(p []byte, oob []byte, flags int, sa *syscall.SockaddrInet6) (n, oobn, retflags int, err error) {
|
func (fd *fakeNetFD) readMsgInet6(p []byte, oob []byte, flags int, sa *syscall.SockaddrInet6) (n, oobn, retflags int, err error) {
|
||||||
return 0, 0, 0, syscall.ENOSYS
|
return 0, 0, 0, syscall.ENOSYS
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *netFD) writeMsgInet4(p []byte, oob []byte, sa *syscall.SockaddrInet4) (n int, oobn int, err error) {
|
func (fd *fakeNetFD) writeMsgInet4(p []byte, oob []byte, sa *syscall.SockaddrInet4) (n int, oobn int, err error) {
|
||||||
return 0, 0, syscall.ENOSYS
|
return 0, 0, syscall.ENOSYS
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *netFD) writeMsgInet6(p []byte, oob []byte, sa *syscall.SockaddrInet6) (n int, oobn int, err error) {
|
func (fd *fakeNetFD) writeMsgInet6(p []byte, oob []byte, sa *syscall.SockaddrInet6) (n int, oobn int, err error) {
|
||||||
return 0, 0, syscall.ENOSYS
|
return 0, 0, syscall.ENOSYS
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
|
func (fd *fakeNetFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
|
||||||
return 0, syscall.ENOSYS
|
return 0, syscall.ENOSYS
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *netFD) writeToInet4(p []byte, sa *syscall.SockaddrInet4) (n int, err error) {
|
func (fd *fakeNetFD) writeToInet4(p []byte, sa *syscall.SockaddrInet4) (n int, err error) {
|
||||||
return 0, syscall.ENOSYS
|
return 0, syscall.ENOSYS
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *netFD) writeToInet6(p []byte, sa *syscall.SockaddrInet6) (n int, err error) {
|
func (fd *fakeNetFD) writeToInet6(p []byte, sa *syscall.SockaddrInet6) (n int, err error) {
|
||||||
return 0, syscall.ENOSYS
|
return 0, syscall.ENOSYS
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
|
func (fd *fakeNetFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
|
||||||
return 0, 0, syscall.ENOSYS
|
return 0, 0, syscall.ENOSYS
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *netFD) dup() (f *os.File, err error) {
|
func (fd *fakeNetFD) dup() (f *os.File, err error) {
|
||||||
return nil, syscall.ENOSYS
|
return nil, syscall.ENOSYS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
27
src/net/net_fake_js.go
Normal file
27
src/net/net_fake_js.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// Copyright 2023 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Fake networking for js/wasm. It is intended to allow tests of other package to pass.
|
||||||
|
|
||||||
|
//go:build js && wasm
|
||||||
|
|
||||||
|
package net
|
||||||
|
|
||||||
|
import "internal/poll"
|
||||||
|
|
||||||
|
// Network file descriptor.
|
||||||
|
type netFD struct {
|
||||||
|
*fakeNetFD
|
||||||
|
|
||||||
|
// immutable until Close
|
||||||
|
family int
|
||||||
|
sotype int
|
||||||
|
net string
|
||||||
|
laddr Addr
|
||||||
|
raddr Addr
|
||||||
|
|
||||||
|
// unused
|
||||||
|
pfd poll.FD
|
||||||
|
isConnected bool // handshake completed or use of association with peer
|
||||||
|
}
|
22
src/os/file_wasip1.go
Normal file
22
src/os/file_wasip1.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// Copyright 2023 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build wasip1
|
||||||
|
|
||||||
|
package os
|
||||||
|
|
||||||
|
import "internal/poll"
|
||||||
|
|
||||||
|
// PollFD returns the poll.FD of the file.
|
||||||
|
//
|
||||||
|
// Other packages in std that also import internal/poll (such as net)
|
||||||
|
// can use a type assertion to access this extension method so that
|
||||||
|
// they can pass the *poll.FD to functions like poll.Splice.
|
||||||
|
//
|
||||||
|
// There is an equivalent function in net.rawConn.
|
||||||
|
//
|
||||||
|
// PollFD is not intended for use outside the standard library.
|
||||||
|
func (f *file) PollFD() *poll.FD {
|
||||||
|
return &f.pfd
|
||||||
|
}
|
92
src/runtime/internal/wasitest/tcpecho_test.go
Normal file
92
src/runtime/internal/wasitest/tcpecho_test.go
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
// Copyright 2023 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package wasi_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTCPEcho(t *testing.T) {
|
||||||
|
if target != "wasip1/wasm" {
|
||||||
|
t.Skip()
|
||||||
|
}
|
||||||
|
|
||||||
|
// We're unable to pass port 0 here (let the OS choose a spare port).
|
||||||
|
// Although wasmtime accepts port 0, and testdata/main.go successfully
|
||||||
|
// listens, there's no way for this test case to query the chosen port
|
||||||
|
// so that it can connect to the WASM module. The WASM module itself
|
||||||
|
// cannot access any information about the socket due to limitations
|
||||||
|
// with WASI preview 1 networking, and wasmtime does not log the address
|
||||||
|
// when you preopen a socket. Instead, we probe for a free port here.
|
||||||
|
var host string
|
||||||
|
port := rand.Intn(10000) + 40000
|
||||||
|
for attempts := 0; attempts < 10; attempts++ {
|
||||||
|
host = fmt.Sprintf("127.0.0.1:%d", port)
|
||||||
|
l, err := net.Listen("tcp", host)
|
||||||
|
if err == nil {
|
||||||
|
l.Close()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
port++
|
||||||
|
}
|
||||||
|
|
||||||
|
subProcess := exec.Command("go", "run", "./testdata/tcpecho.go")
|
||||||
|
|
||||||
|
subProcess.Env = append(os.Environ(), "GOOS=wasip1", "GOARCH=wasm")
|
||||||
|
|
||||||
|
switch os.Getenv("GOWASIRUNTIME") {
|
||||||
|
case "wasmtime":
|
||||||
|
subProcess.Env = append(subProcess.Env, "GOWASIRUNTIMEARGS=--tcplisten="+host)
|
||||||
|
default:
|
||||||
|
t.Skip("WASI runtime does not support sockets")
|
||||||
|
}
|
||||||
|
|
||||||
|
var b bytes.Buffer
|
||||||
|
subProcess.Stdout = &b
|
||||||
|
subProcess.Stderr = &b
|
||||||
|
|
||||||
|
if err := subProcess.Start(); err != nil {
|
||||||
|
t.Log(b.String())
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer subProcess.Process.Kill()
|
||||||
|
|
||||||
|
var conn net.Conn
|
||||||
|
var err error
|
||||||
|
for attempts := 0; attempts < 5; attempts++ {
|
||||||
|
conn, err = net.Dial("tcp", host)
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
time.Sleep(500 * time.Millisecond)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Log(b.String())
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
payload := []byte("foobar")
|
||||||
|
if _, err := conn.Write(payload); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
var buf [256]byte
|
||||||
|
n, err := conn.Read(buf[:])
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if string(buf[:n]) != string(payload) {
|
||||||
|
t.Error("unexpected payload")
|
||||||
|
t.Logf("expect: %d bytes (%v)", len(payload), payload)
|
||||||
|
t.Logf("actual: %d bytes (%v)", n, buf[:n])
|
||||||
|
}
|
||||||
|
}
|
74
src/runtime/internal/wasitest/testdata/tcpecho.go
vendored
Normal file
74
src/runtime/internal/wasitest/testdata/tcpecho.go
vendored
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
// Copyright 2023 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if err := run(); err != nil {
|
||||||
|
println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func run() error {
|
||||||
|
l, err := findListener()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if l == nil {
|
||||||
|
return errors.New("no pre-opened sockets available")
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
|
||||||
|
c, err := l.Accept()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return handleConn(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleConn(c net.Conn) error {
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
var buf [128]byte
|
||||||
|
n, err := c.Read(buf[:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := c.Write(buf[:n]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := c.(*net.TCPConn).CloseWrite(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func findListener() (net.Listener, error) {
|
||||||
|
// We start looking for pre-opened sockets at fd=3 because 0, 1, and 2
|
||||||
|
// are reserved for stdio. Pre-opened directors also start at fd=3, so
|
||||||
|
// we skip fds that aren't sockets. Once we reach EBADF we know there
|
||||||
|
// are no more pre-opens.
|
||||||
|
for preopenFd := uintptr(3); ; preopenFd++ {
|
||||||
|
f := os.NewFile(preopenFd, "")
|
||||||
|
l, err := net.FileListener(f)
|
||||||
|
f.Close()
|
||||||
|
|
||||||
|
var se syscall.Errno
|
||||||
|
switch errors.As(err, &se); se {
|
||||||
|
case syscall.ENOTSOCK:
|
||||||
|
continue
|
||||||
|
case syscall.EBADF:
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
return l, err
|
||||||
|
}
|
||||||
|
}
|
@ -279,6 +279,12 @@ func fd_fdstat_get_flags(fd int) (uint32, error) {
|
|||||||
return uint32(stat.fdflags), errnoErr(errno)
|
return uint32(stat.fdflags), errnoErr(errno)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fd_fdstat_get_type(fd int) (uint8, error) {
|
||||||
|
var stat fdstat
|
||||||
|
errno := fd_fdstat_get(int32(fd), unsafe.Pointer(&stat))
|
||||||
|
return stat.filetype, errnoErr(errno)
|
||||||
|
}
|
||||||
|
|
||||||
type preopentype = uint8
|
type preopentype = uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -331,12 +337,12 @@ func init() {
|
|||||||
if errno == EBADF {
|
if errno == EBADF {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
if errno == ENOTDIR || prestat.typ != preopentypeDir {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if errno != 0 {
|
if errno != 0 {
|
||||||
panic("fd_prestat: " + errno.Error())
|
panic("fd_prestat: " + errno.Error())
|
||||||
}
|
}
|
||||||
if prestat.typ != preopentypeDir {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if int(prestat.dir.prNameLen) > len(dirNameBuf) {
|
if int(prestat.dir.prNameLen) > len(dirNameBuf) {
|
||||||
dirNameBuf = make([]byte, prestat.dir.prNameLen)
|
dirNameBuf = make([]byte, prestat.dir.prNameLen)
|
||||||
}
|
}
|
||||||
|
63
src/syscall/net_fake.go
Normal file
63
src/syscall/net_fake.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
// Copyright 2023 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Fake networking for js/wasm and wasip1/wasm.
|
||||||
|
// This file only exists to make the compiler happy.
|
||||||
|
|
||||||
|
//go:build (js && wasm) || wasip1
|
||||||
|
|
||||||
|
package syscall
|
||||||
|
|
||||||
|
const (
|
||||||
|
AF_UNSPEC = iota
|
||||||
|
AF_UNIX
|
||||||
|
AF_INET
|
||||||
|
AF_INET6
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
SOCK_STREAM = 1 + iota
|
||||||
|
SOCK_DGRAM
|
||||||
|
SOCK_RAW
|
||||||
|
SOCK_SEQPACKET
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
IPPROTO_IP = 0
|
||||||
|
IPPROTO_IPV4 = 4
|
||||||
|
IPPROTO_IPV6 = 0x29
|
||||||
|
IPPROTO_TCP = 6
|
||||||
|
IPPROTO_UDP = 0x11
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
_ = iota
|
||||||
|
IPV6_V6ONLY
|
||||||
|
SOMAXCONN
|
||||||
|
SO_ERROR
|
||||||
|
)
|
||||||
|
|
||||||
|
// Misc constants expected by package net but not supported.
|
||||||
|
const (
|
||||||
|
_ = iota
|
||||||
|
F_DUPFD_CLOEXEC
|
||||||
|
SYS_FCNTL = 500 // unsupported
|
||||||
|
)
|
||||||
|
|
||||||
|
type Sockaddr any
|
||||||
|
|
||||||
|
type SockaddrInet4 struct {
|
||||||
|
Port int
|
||||||
|
Addr [4]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type SockaddrInet6 struct {
|
||||||
|
Port int
|
||||||
|
ZoneId uint32
|
||||||
|
Addr [16]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type SockaddrUnix struct {
|
||||||
|
Name string
|
||||||
|
}
|
@ -2,66 +2,10 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// js/wasm uses fake networking directly implemented in the net package.
|
|
||||||
// This file only exists to make the compiler happy.
|
|
||||||
|
|
||||||
//go:build js && wasm
|
//go:build js && wasm
|
||||||
|
|
||||||
package syscall
|
package syscall
|
||||||
|
|
||||||
const (
|
|
||||||
AF_UNSPEC = iota
|
|
||||||
AF_UNIX
|
|
||||||
AF_INET
|
|
||||||
AF_INET6
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
SOCK_STREAM = 1 + iota
|
|
||||||
SOCK_DGRAM
|
|
||||||
SOCK_RAW
|
|
||||||
SOCK_SEQPACKET
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
IPPROTO_IP = 0
|
|
||||||
IPPROTO_IPV4 = 4
|
|
||||||
IPPROTO_IPV6 = 0x29
|
|
||||||
IPPROTO_TCP = 6
|
|
||||||
IPPROTO_UDP = 0x11
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
_ = iota
|
|
||||||
IPV6_V6ONLY
|
|
||||||
SOMAXCONN
|
|
||||||
SO_ERROR
|
|
||||||
)
|
|
||||||
|
|
||||||
// Misc constants expected by package net but not supported.
|
|
||||||
const (
|
|
||||||
_ = iota
|
|
||||||
F_DUPFD_CLOEXEC
|
|
||||||
SYS_FCNTL = 500 // unsupported
|
|
||||||
)
|
|
||||||
|
|
||||||
type Sockaddr any
|
|
||||||
|
|
||||||
type SockaddrInet4 struct {
|
|
||||||
Port int
|
|
||||||
Addr [4]byte
|
|
||||||
}
|
|
||||||
|
|
||||||
type SockaddrInet6 struct {
|
|
||||||
Port int
|
|
||||||
ZoneId uint32
|
|
||||||
Addr [16]byte
|
|
||||||
}
|
|
||||||
|
|
||||||
type SockaddrUnix struct {
|
|
||||||
Name string
|
|
||||||
}
|
|
||||||
|
|
||||||
func Socket(proto, sotype, unused int) (fd int, err error) {
|
func Socket(proto, sotype, unused int) (fd int, err error) {
|
||||||
return 0, ENOSYS
|
return 0, ENOSYS
|
||||||
}
|
}
|
||||||
|
@ -2,66 +2,27 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// wasip1/wasm uses fake networking directly implemented in the net package.
|
|
||||||
// This file only exists to make the compiler happy.
|
|
||||||
|
|
||||||
//go:build wasip1
|
//go:build wasip1
|
||||||
|
|
||||||
package syscall
|
package syscall
|
||||||
|
|
||||||
const (
|
import "unsafe"
|
||||||
AF_UNSPEC = iota
|
|
||||||
AF_UNIX
|
|
||||||
AF_INET
|
|
||||||
AF_INET6
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SOCK_STREAM = 1 + iota
|
SHUT_RD = 0x1
|
||||||
SOCK_DGRAM
|
SHUT_WR = 0x2
|
||||||
SOCK_RAW
|
SHUT_RDWR = SHUT_RD | SHUT_WR
|
||||||
SOCK_SEQPACKET
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
type sdflags = uint32
|
||||||
IPPROTO_IP = 0
|
|
||||||
IPPROTO_IPV4 = 4
|
|
||||||
IPPROTO_IPV6 = 0x29
|
|
||||||
IPPROTO_TCP = 6
|
|
||||||
IPPROTO_UDP = 0x11
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
//go:wasmimport wasi_snapshot_preview1 sock_accept
|
||||||
_ = iota
|
//go:noescape
|
||||||
IPV6_V6ONLY
|
func sock_accept(fd int32, flags fdflags, newfd unsafe.Pointer) Errno
|
||||||
SOMAXCONN
|
|
||||||
SO_ERROR
|
|
||||||
)
|
|
||||||
|
|
||||||
// Misc constants expected by package net but not supported.
|
//go:wasmimport wasi_snapshot_preview1 sock_shutdown
|
||||||
const (
|
//go:noescape
|
||||||
_ = iota
|
func sock_shutdown(fd int32, flags sdflags) Errno
|
||||||
F_DUPFD_CLOEXEC
|
|
||||||
SYS_FCNTL = 500 // unsupported; same value as net_nacl.go
|
|
||||||
)
|
|
||||||
|
|
||||||
type Sockaddr interface {
|
|
||||||
}
|
|
||||||
|
|
||||||
type SockaddrInet4 struct {
|
|
||||||
Port int
|
|
||||||
Addr [4]byte
|
|
||||||
}
|
|
||||||
|
|
||||||
type SockaddrInet6 struct {
|
|
||||||
Port int
|
|
||||||
ZoneId uint32
|
|
||||||
Addr [16]byte
|
|
||||||
}
|
|
||||||
|
|
||||||
type SockaddrUnix struct {
|
|
||||||
Name string
|
|
||||||
}
|
|
||||||
|
|
||||||
func Socket(proto, sotype, unused int) (fd int, err error) {
|
func Socket(proto, sotype, unused int) (fd int, err error) {
|
||||||
return 0, ENOSYS
|
return 0, ENOSYS
|
||||||
@ -79,8 +40,10 @@ func Listen(fd int, backlog int) error {
|
|||||||
return ENOSYS
|
return ENOSYS
|
||||||
}
|
}
|
||||||
|
|
||||||
func Accept(fd int) (newfd int, sa Sockaddr, err error) {
|
func Accept(fd int) (int, Sockaddr, error) {
|
||||||
return 0, nil, ENOSYS
|
var newfd int32
|
||||||
|
errno := sock_accept(int32(fd), 0, unsafe.Pointer(&newfd))
|
||||||
|
return int(newfd), nil, errnoErr(errno)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Connect(fd int, sa Sockaddr) error {
|
func Connect(fd int, sa Sockaddr) error {
|
||||||
@ -120,5 +83,6 @@ func SetWriteDeadline(fd int, t int64) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Shutdown(fd int, how int) error {
|
func Shutdown(fd int, how int) error {
|
||||||
return ENOSYS
|
errno := sock_shutdown(int32(fd), sdflags(how))
|
||||||
|
return errnoErr(errno)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user