mirror of
https://github.com/golang/go
synced 2024-11-26 06:57:56 -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:
parent
d22b08bd64
commit
0b5a4afec9
@ -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
|
||||
|
@ -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()
|
||||
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
|
||||
}
|
||||
}()
|
||||
filetype, err := fd_fdstat_get_type(pfd.Sysfd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
if filetype != syscall.FILETYPE_SOCKET_STREAM {
|
||||
return nil, syscall.ENOTSOCK
|
||||
}
|
||||
|
||||
func newFileListener(fd *netFD) Listener {
|
||||
switch fd.net {
|
||||
case "tcp":
|
||||
return &TCPListener{fd: fd}
|
||||
default:
|
||||
panic("unsupported network for file listener: " + fd.net)
|
||||
}
|
||||
fd, err = newPollFD(pfd)
|
||||
if 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)
|
||||
}
|
||||
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
|
||||
|
92
src/net/file_wasip1_test.go
Normal file
92
src/net/file_wasip1_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.
|
||||
|
||||
//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)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user