1
0
mirror of https://github.com/golang/go synced 2024-11-22 11:54:50 -07:00

net: test net.FileConn and net.FileListener with UDP sockets on wasip1

The WASI specification has file types for both stream and datagram
sockets. This change refactors the internal implementation of the
net.FileConn and net.FileListener functions to avoid returning a
misleading ENOTSOCK when calling net.FileConn with a file referencing
a datagram socket and instead properly construct net.UDPConn values
or return EOPNOTSUPP otherwise.

Change-Id: I594f700847254895cd6ce172979fd89c4b851940
Reviewed-on: https://go-review.googlesource.com/c/go/+/502316
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Ian Lance Taylor <iant@google.com>
Run-TryBot: Ian Lance Taylor <iant@google.com>
Reviewed-by: Johan Brandhorst-Satzkorn <johan.brandhorst@gmail.com>
Run-TryBot: Johan Brandhorst-Satzkorn <johan.brandhorst@gmail.com>
This commit is contained in:
Achille Roussel 2023-06-10 12:44:21 -07:00 committed by Gopher Robot
parent d22b08bd64
commit 0b5a4afec9
3 changed files with 161 additions and 33 deletions

View File

@ -38,22 +38,21 @@ type netFD struct {
*fakeNetFD
}
func newFD(sysfd int) (*netFD, error) {
return newPollFD(poll.FD{
func newFD(net string, sysfd int) *netFD {
return newPollFD(net, poll.FD{
Sysfd: sysfd,
IsStream: true,
ZeroReadIsEOF: true,
})
}
func newPollFD(pfd poll.FD) (*netFD, error) {
ret := &netFD{
func newPollFD(net string, pfd poll.FD) *netFD {
return &netFD{
pfd: pfd,
net: "tcp",
net: net,
laddr: unknownAddr{},
raddr: unknownAddr{},
}
return ret, nil
}
func (fd *netFD) init() error {
@ -75,10 +74,7 @@ func (fd *netFD) accept() (netfd *netFD, err error) {
}
return nil, err
}
if netfd, err = newFD(d); err != nil {
poll.CloseFunc(d)
return nil, err
}
netfd = newFD("tcp", d)
if err = netfd.init(); err != nil {
netfd.Close()
return nil, err

View File

@ -13,45 +13,85 @@ import (
)
func fileListener(f *os.File) (Listener, error) {
fd, err := newFileFD(f)
filetype, err := fd_fdstat_get_type(f.PollFD().Sysfd)
if err != nil {
return nil, err
}
return &TCPListener{fd: fd}, nil
net, err := fileListenNet(filetype)
if err != nil {
return nil, err
}
pfd := f.PollFD().Copy()
fd := newPollFD(net, pfd)
if err := fd.init(); err != nil {
pfd.Close()
return nil, err
}
return newFileListener(fd), nil
}
func fileConn(f *os.File) (Conn, error) {
fd, err := newFileFD(f)
filetype, err := fd_fdstat_get_type(f.PollFD().Sysfd)
if err != nil {
return nil, err
}
return &TCPConn{conn{fd: fd}}, nil
net, err := fileConnNet(filetype)
if err != nil {
return nil, err
}
pfd := f.PollFD().Copy()
fd := newPollFD(net, pfd)
if err := fd.init(); err != nil {
pfd.Close()
return nil, err
}
return newFileConn(fd), nil
}
func filePacketConn(f *os.File) (PacketConn, error) { return nil, syscall.ENOPROTOOPT }
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
func fileListenNet(filetype syscall.Filetype) (string, error) {
switch filetype {
case syscall.FILETYPE_SOCKET_STREAM:
return "tcp", nil
case syscall.FILETYPE_SOCKET_DGRAM:
return "", syscall.EOPNOTSUPP
default:
return "", syscall.ENOTSOCK
}
if filetype != syscall.FILETYPE_SOCKET_STREAM {
return nil, syscall.ENOTSOCK
}
func fileConnNet(filetype syscall.Filetype) (string, error) {
switch filetype {
case syscall.FILETYPE_SOCKET_STREAM:
return "tcp", nil
case syscall.FILETYPE_SOCKET_DGRAM:
return "udp", nil
default:
return "", syscall.ENOTSOCK
}
fd, err = newPollFD(pfd)
if err != nil {
return nil, err
}
func newFileListener(fd *netFD) Listener {
switch fd.net {
case "tcp":
return &TCPListener{fd: fd}
default:
panic("unsupported network for file listener: " + fd.net)
}
if err := fd.init(); err != nil {
return nil, err
}
func newFileConn(fd *netFD) Conn {
switch fd.net {
case "tcp":
return &TCPConn{conn{fd: fd}}
case "udp":
return &UDPConn{conn{fd: fd}}
default:
panic("unsupported network for file connection: " + fd.net)
}
return fd, nil
}
// This helper is implemented in the syscall package. It means we don't have

View 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.
//go:build wasip1
package net
import (
"syscall"
"testing"
)
// The tests in this file intend to validate the ability for net.FileConn and
// net.FileListener to handle both TCP and UDP sockets. Ideally we would test
// the public interface by constructing an *os.File from a file descriptor
// opened on a socket, but the WASI preview 1 specification is too limited to
// support this approach for UDP sockets. Instead, we test the internals that
// make it possible for WASI host runtimes and guest programs to integrate
// socket extensions with the net package using net.FileConn/net.FileListener.
//
// Note that the creation of net.Conn and net.Listener values for TCP sockets
// has an end-to-end test in src/runtime/internal/wasitest, here we are only
// verifying the code paths specific to UDP, and error handling for invalid use
// of the functions.
func TestWasip1FileConnNet(t *testing.T) {
tests := []struct {
filetype syscall.Filetype
network string
error error
}{
{syscall.FILETYPE_SOCKET_STREAM, "tcp", nil},
{syscall.FILETYPE_SOCKET_DGRAM, "udp", nil},
{syscall.FILETYPE_BLOCK_DEVICE, "", syscall.ENOTSOCK},
{syscall.FILETYPE_CHARACTER_DEVICE, "", syscall.ENOTSOCK},
{syscall.FILETYPE_DIRECTORY, "", syscall.ENOTSOCK},
{syscall.FILETYPE_REGULAR_FILE, "", syscall.ENOTSOCK},
{syscall.FILETYPE_SYMBOLIC_LINK, "", syscall.ENOTSOCK},
{syscall.FILETYPE_UNKNOWN, "", syscall.ENOTSOCK},
}
for _, test := range tests {
net, err := fileConnNet(test.filetype)
if net != test.network {
t.Errorf("fileConnNet: network mismatch: want=%q got=%q", test.network, net)
}
if err != test.error {
t.Errorf("fileConnNet: error mismatch: want=%v got=%v", test.error, err)
}
}
}
func TestWasip1FileListenNet(t *testing.T) {
tests := []struct {
filetype syscall.Filetype
network string
error error
}{
{syscall.FILETYPE_SOCKET_STREAM, "tcp", nil},
{syscall.FILETYPE_SOCKET_DGRAM, "", syscall.EOPNOTSUPP},
{syscall.FILETYPE_BLOCK_DEVICE, "", syscall.ENOTSOCK},
{syscall.FILETYPE_CHARACTER_DEVICE, "", syscall.ENOTSOCK},
{syscall.FILETYPE_DIRECTORY, "", syscall.ENOTSOCK},
{syscall.FILETYPE_REGULAR_FILE, "", syscall.ENOTSOCK},
{syscall.FILETYPE_SYMBOLIC_LINK, "", syscall.ENOTSOCK},
{syscall.FILETYPE_UNKNOWN, "", syscall.ENOTSOCK},
}
for _, test := range tests {
net, err := fileListenNet(test.filetype)
if net != test.network {
t.Errorf("fileListenNet: network mismatch: want=%q got=%q", test.network, net)
}
if err != test.error {
t.Errorf("fileListenNet: error mismatch: want=%v got=%v", test.error, err)
}
}
}
func TestWasip1NewFileListener(t *testing.T) {
if l, ok := newFileListener(newFD("tcp", -1)).(*TCPListener); !ok {
t.Errorf("newFileListener: tcp listener type mismatch: %T", l)
}
}
func TestWasip1NewFileConn(t *testing.T) {
if c, ok := newFileConn(newFD("tcp", -1)).(*TCPConn); !ok {
t.Errorf("newFileConn: tcp conn type mismatch: %T", c)
}
if c, ok := newFileConn(newFD("udp", -1)).(*UDPConn); !ok {
t.Errorf("newFileConn: udp conn type mismatch: %T", c)
}
}