Source file src/net/fd_fake.go

     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         string
    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 string, 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 string, 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 = new(TCPAddr)
    61  		raddr = new(TCPAddr)
    62  	case "udp":
    63  		laddr = new(UDPAddr)
    64  		raddr = new(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() string {
    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() string { return "unknown" }
   171  func (unknownAddr) String() string  { return "unknown" }
   172  

View as plain text