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  	runtime.SetFinalizer(fd, (*netFD).Close)
   108  }
   109  
   110  func (fd *netFD) Close() error {
   111  	if fd.fakeNetFD != nil {
   112  		return fd.fakeNetFD.Close()
   113  	}
   114  	runtime.SetFinalizer(fd, nil)
   115  	return fd.pfd.Close()
   116  }
   117  
   118  func (fd *netFD) shutdown(how int) error {
   119  	if fd.fakeNetFD != nil {
   120  		return nil
   121  	}
   122  	err := fd.pfd.Shutdown(how)
   123  	runtime.KeepAlive(fd)
   124  	return wrapSyscallError("shutdown", err)
   125  }
   126  
   127  func (fd *netFD) Read(p []byte) (n int, err error) {
   128  	if fd.fakeNetFD != nil {
   129  		return fd.fakeNetFD.Read(p)
   130  	}
   131  	n, err = fd.pfd.Read(p)
   132  	runtime.KeepAlive(fd)
   133  	return n, wrapSyscallError(readSyscallName, err)
   134  }
   135  
   136  func (fd *netFD) Write(p []byte) (nn int, err error) {
   137  	if fd.fakeNetFD != nil {
   138  		return fd.fakeNetFD.Write(p)
   139  	}
   140  	nn, err = fd.pfd.Write(p)
   141  	runtime.KeepAlive(fd)
   142  	return nn, wrapSyscallError(writeSyscallName, err)
   143  }
   144  
   145  func (fd *netFD) SetDeadline(t time.Time) error {
   146  	if fd.fakeNetFD != nil {
   147  		return fd.fakeNetFD.SetDeadline(t)
   148  	}
   149  	return fd.pfd.SetDeadline(t)
   150  }
   151  
   152  func (fd *netFD) SetReadDeadline(t time.Time) error {
   153  	if fd.fakeNetFD != nil {
   154  		return fd.fakeNetFD.SetReadDeadline(t)
   155  	}
   156  	return fd.pfd.SetReadDeadline(t)
   157  }
   158  
   159  func (fd *netFD) SetWriteDeadline(t time.Time) error {
   160  	if fd.fakeNetFD != nil {
   161  		return fd.fakeNetFD.SetWriteDeadline(t)
   162  	}
   163  	return fd.pfd.SetWriteDeadline(t)
   164  }
   165  
   166  type unknownAddr struct{}
   167  
   168  func (unknownAddr) Network() string { return "unknown" }
   169  func (unknownAddr) String() string  { return "unknown" }
   170  

View as plain text