github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/internal/sock/sock.go (about)

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