Closed chriso closed 1 year ago
Once syscall.Recvmsg
and syscall.SendmsgN
are implemented (e.g. https://github.com/stealthrocket/go/commit/b49d8b655fe7578252b7753151da9b3653cb7587), there's no need to call the host functions directly.
package main
import (
"log"
"net"
"os"
"syscall"
"time"
)
func main() {
if err := run(); err != nil {
log.Fatal(err)
}
}
func run() error {
l, err := net.FileListener(os.NewFile(3, ""))
if err != nil {
return err
}
defer l.Close()
c, err := l.Accept()
if err != nil {
return err
}
// Assume the connection has fd=4. There's currently no way to
// query the file descriptor given a c of type net.Conn or
// *net.TCPConn. c.File() is not implemented because dup(2) is
// not available.
fd := 4
var n int
var buf [1024]byte
for {
if n, _, _, _, err = syscall.Recvmsg(fd, buf[:], nil, 0); err != nil {
if err == syscall.EAGAIN {
time.Sleep(1 * time.Second)
continue
}
panic(err)
}
break
}
for {
_, err := syscall.SendmsgN(fd, buf[:n], nil, nil, 0)
if err != nil {
if err == syscall.EAGAIN {
time.Sleep(1 * time.Second)
continue
}
panic(err)
}
break
}
return c.Close()
}
And then if you're using the higher level net
package, those EAGAIN
errors are automatically handled by the net poller.
This PR provides implementations for the last two stubs:
sock_send
andsock_recv
.These are like the
sendmsg(2)
andrecvmsg(2)
syscalls. Theunix.SendmsgBuffers
andunix.RecvmsgBuffers
wrappers are available from x/sys/unix.tcp-server.go
```go package main import ( "fmt" "log" "net" "os" "time" "unsafe" ) func main() { if err := run(); err != nil { log.Fatal(err) } } func run() error { l, err := net.FileListener(os.NewFile(3, "")) if err != nil { return err } defer l.Close() c, err := l.Accept() if err != nil { return err } // Assume the connection has fd=4. There's currently no way to // query the file descriptor given a c of type net.Conn or // *net.TCPConn. c.File() is not implemented because dup(2) is // not available. var fd int32 = 4 var n size var buf [1024]byte iovecs := []iovec{ { buf: uintptr32(uintptr(unsafe.Pointer(&buf))), bufLen: size(len(buf)), }, } read_loop: for { var iflags riflags var oflags roflags errno := sock_recv(fd, unsafe.Pointer(unsafe.SliceData(iovecs)), 1, iflags, unsafe.Pointer(&n), unsafe.Pointer(&oflags)) switch errno { case 0: // ESUCCESS break read_loop case 6: // EAGAIN time.Sleep(1 * time.Second) continue default: panic(fmt.Sprintf("errno=%d", errno)) } } iovecs[0].bufLen = n write_loop: for { var iflags siflags errno := sock_send(fd, unsafe.Pointer(unsafe.SliceData(iovecs)), 1, iflags, unsafe.Pointer(&n)) switch errno { case 0: // ESUCCESS break write_loop case 6: // EAGAIN time.Sleep(1 * time.Second) continue default: panic(fmt.Sprintf("errno=%d", errno)) } } return c.Close() } //go:wasmimport wasi_snapshot_preview1 sock_send //go:noescape func sock_send(fd int32, iovs unsafe.Pointer, iovsLen size, siflags riflags, nread unsafe.Pointer) errno //go:wasmimport wasi_snapshot_preview1 sock_recv //go:noescape func sock_recv(fd int32, iovs unsafe.Pointer, iovsLen size, riflags riflags, nread unsafe.Pointer, roflags unsafe.Pointer) errno type errno = int32 type uintptr32 = uint32 type size = uint32 type siflags = uint32 type riflags = uint32 type roflags = uint32 type iovec struct { buf uintptr32 bufLen size } ```wasmtime:
wasirun:
wasirun --trace: