sock.go

 1package sock
 2
 3import (
 4	"fmt"
 5	"net"
 6
 7	"github.com/tetratelabs/wazero/experimental/sys"
 8)
 9
10// TCPSock is a pseudo-file representing a TCP socket.
11type TCPSock interface {
12	sys.File
13
14	Accept() (TCPConn, sys.Errno)
15}
16
17// TCPConn is a pseudo-file representing a TCP connection.
18type 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.
30type ConfigKey struct{}
31
32// Config is an internal struct meant to implement
33// the interface in experimental/sock/Config.
34type 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.
40type 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.
51func (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.
58func (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.
66func (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
87func (t TCPAddress) String() string {
88	return fmt.Sprintf("%s:%d", t.Host, t.Port)
89}