github.com/tetratelabs/wazero@v1.2.1/internal/sock/sock.go (about)

     1  package sock
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"syscall"
     7  
     8  	"github.com/tetratelabs/wazero/internal/fsapi"
     9  )
    10  
    11  // TCPSock is a pseudo-file representing a TCP socket.
    12  type TCPSock interface {
    13  	fsapi.File
    14  
    15  	Accept() (TCPConn, syscall.Errno)
    16  }
    17  
    18  // TCPConn is a pseudo-file representing a TCP connection.
    19  type TCPConn interface {
    20  	fsapi.File
    21  
    22  	// Recvfrom only supports the flag sysfs.MSG_PEEK
    23  	Recvfrom(p []byte, flags int) (n int, errno syscall.Errno)
    24  
    25  	Shutdown(how int) syscall.Errno
    26  }
    27  
    28  // ConfigKey is a context.Context Value key. Its associated value should be a Config.
    29  type ConfigKey struct{}
    30  
    31  // Config is an internal struct meant to implement
    32  // the interface in experimental/sock/Config.
    33  type Config struct {
    34  	// TCPAddresses is a slice of the configured host:port pairs.
    35  	TCPAddresses []TCPAddress
    36  }
    37  
    38  // TCPAddress is a host:port pair to pre-open.
    39  type TCPAddress struct {
    40  	// Host is the host name for this listener.
    41  	Host string
    42  	// Port is the port number for this listener.
    43  	Port int
    44  }
    45  
    46  // WithTCPListener implements the method of the same name in experimental/sock/Config.
    47  //
    48  // However, to avoid cyclic dependencies, this is returning the *Config in this scope.
    49  // The interface is implemented in experimental/sock/Config via delegation.
    50  func (c *Config) WithTCPListener(host string, port int) *Config {
    51  	ret := c.clone()
    52  	ret.TCPAddresses = append(ret.TCPAddresses, TCPAddress{host, port})
    53  	return &ret
    54  }
    55  
    56  // Makes a deep copy of this sockConfig.
    57  func (c *Config) clone() Config {
    58  	ret := *c
    59  	ret.TCPAddresses = make([]TCPAddress, 0, len(c.TCPAddresses))
    60  	ret.TCPAddresses = append(ret.TCPAddresses, c.TCPAddresses...)
    61  	return ret
    62  }
    63  
    64  // BuildTCPListeners build listeners from the current configuration.
    65  func (c *Config) BuildTCPListeners() (tcpListeners []*net.TCPListener, err error) {
    66  	for _, tcpAddr := range c.TCPAddresses {
    67  		var ln net.Listener
    68  		ln, err = net.Listen("tcp", tcpAddr.String())
    69  		if err != nil {
    70  			break
    71  		}
    72  		if tcpln, ok := ln.(*net.TCPListener); ok {
    73  			tcpListeners = append(tcpListeners, tcpln)
    74  		}
    75  	}
    76  	if err != nil {
    77  		// An error occurred, cleanup.
    78  		for _, l := range tcpListeners {
    79  			_ = l.Close() // Ignore errors, we are already cleaning.
    80  		}
    81  		tcpListeners = nil
    82  	}
    83  	return
    84  }
    85  
    86  func (t TCPAddress) String() string {
    87  	return fmt.Sprintf("%s:%d", t.Host, t.Port)
    88  }