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}