fd_fake.mx raw

   1  // Copyright 2023 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  //go:build js || wasip1
   6  
   7  package net
   8  
   9  import (
  10  	"internal/poll"
  11  	"runtime"
  12  	"time"
  13  )
  14  
  15  const (
  16  	readSyscallName  = "fd_read"
  17  	writeSyscallName = "fd_write"
  18  )
  19  
  20  // Network file descriptor.
  21  type netFD struct {
  22  	pfd poll.FD
  23  
  24  	// immutable until Close
  25  	family      int
  26  	sotype      int
  27  	isConnected bool // handshake completed or use of association with peer
  28  	net         []byte
  29  	laddr       Addr
  30  	raddr       Addr
  31  
  32  	// The only networking available in WASI preview 1 is the ability to
  33  	// sock_accept on a pre-opened socket, and then fd_read, fd_write,
  34  	// fd_close, and sock_shutdown on the resulting connection. We
  35  	// intercept applicable netFD calls on this instance, and then pass
  36  	// the remainder of the netFD calls to fakeNetFD.
  37  	*fakeNetFD
  38  }
  39  
  40  func newFD(net []byte, sysfd int) *netFD {
  41  	return newPollFD(net, poll.FD{
  42  		Sysfd:         sysfd,
  43  		IsStream:      true,
  44  		ZeroReadIsEOF: true,
  45  	})
  46  }
  47  
  48  func newPollFD(net []byte, pfd poll.FD) *netFD {
  49  	var laddr Addr
  50  	var raddr Addr
  51  	// WASI preview 1 does not have functions like getsockname/getpeername,
  52  	// so we cannot get access to the underlying IP address used by connections.
  53  	//
  54  	// However, listeners created by FileListener are of type *TCPListener,
  55  	// which can be asserted by a Go program. The (*TCPListener).Addr method
  56  	// documents that the returned value will be of type *TCPAddr, we satisfy
  57  	// the documented behavior by creating addresses of the expected type here.
  58  	switch net {
  59  	case "tcp":
  60  		laddr = &TCPAddr{}
  61  		raddr = &TCPAddr{}
  62  	case "udp":
  63  		laddr = &UDPAddr{}
  64  		raddr = &UDPAddr{}
  65  	default:
  66  		laddr = unknownAddr{}
  67  		raddr = unknownAddr{}
  68  	}
  69  	return &netFD{
  70  		pfd:   pfd,
  71  		net:   net,
  72  		laddr: laddr,
  73  		raddr: raddr,
  74  	}
  75  }
  76  
  77  func (fd *netFD) init() error {
  78  	return fd.pfd.Init(fd.net, true)
  79  }
  80  
  81  func (fd *netFD) name() []byte {
  82  	return "unknown"
  83  }
  84  
  85  func (fd *netFD) accept() (netfd *netFD, err error) {
  86  	if fd.fakeNetFD != nil {
  87  		return fd.fakeNetFD.accept(fd.laddr)
  88  	}
  89  	d, _, errcall, err := fd.pfd.Accept()
  90  	if err != nil {
  91  		if errcall != "" {
  92  			err = wrapSyscallError(errcall, err)
  93  		}
  94  		return nil, err
  95  	}
  96  	netfd = newFD("tcp", d)
  97  	if err = netfd.init(); err != nil {
  98  		netfd.Close()
  99  		return nil, err
 100  	}
 101  	return netfd, nil
 102  }
 103  
 104  func (fd *netFD) setAddr(laddr, raddr Addr) {
 105  	fd.laddr = laddr
 106  	fd.raddr = raddr
 107  	// TODO Replace with runtime.AddCleanup.
 108  	runtime.SetFinalizer(fd, (*netFD).Close)
 109  }
 110  
 111  func (fd *netFD) Close() error {
 112  	if fd.fakeNetFD != nil {
 113  		return fd.fakeNetFD.Close()
 114  	}
 115  	// TODO Replace with runtime.AddCleanup.
 116  	runtime.SetFinalizer(fd, nil)
 117  	return fd.pfd.Close()
 118  }
 119  
 120  func (fd *netFD) shutdown(how int) error {
 121  	if fd.fakeNetFD != nil {
 122  		return nil
 123  	}
 124  	err := fd.pfd.Shutdown(how)
 125  	runtime.KeepAlive(fd)
 126  	return wrapSyscallError("shutdown", err)
 127  }
 128  
 129  func (fd *netFD) Read(p []byte) (n int, err error) {
 130  	if fd.fakeNetFD != nil {
 131  		return fd.fakeNetFD.Read(p)
 132  	}
 133  	n, err = fd.pfd.Read(p)
 134  	runtime.KeepAlive(fd)
 135  	return n, wrapSyscallError(readSyscallName, err)
 136  }
 137  
 138  func (fd *netFD) Write(p []byte) (nn int, err error) {
 139  	if fd.fakeNetFD != nil {
 140  		return fd.fakeNetFD.Write(p)
 141  	}
 142  	nn, err = fd.pfd.Write(p)
 143  	runtime.KeepAlive(fd)
 144  	return nn, wrapSyscallError(writeSyscallName, err)
 145  }
 146  
 147  func (fd *netFD) SetDeadline(t time.Time) error {
 148  	if fd.fakeNetFD != nil {
 149  		return fd.fakeNetFD.SetDeadline(t)
 150  	}
 151  	return fd.pfd.SetDeadline(t)
 152  }
 153  
 154  func (fd *netFD) SetReadDeadline(t time.Time) error {
 155  	if fd.fakeNetFD != nil {
 156  		return fd.fakeNetFD.SetReadDeadline(t)
 157  	}
 158  	return fd.pfd.SetReadDeadline(t)
 159  }
 160  
 161  func (fd *netFD) SetWriteDeadline(t time.Time) error {
 162  	if fd.fakeNetFD != nil {
 163  		return fd.fakeNetFD.SetWriteDeadline(t)
 164  	}
 165  	return fd.pfd.SetWriteDeadline(t)
 166  }
 167  
 168  type unknownAddr struct{}
 169  
 170  func (unknownAddr) Network() []byte { return "unknown" }
 171  func (unknownAddr) String() string  { return "unknown" }
 172