-
Notifications
You must be signed in to change notification settings - Fork 66
/
listener_linux.go
133 lines (108 loc) · 2.8 KB
/
listener_linux.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//go:build linux
// +build linux
package vsock
import (
"context"
"net"
"os"
"time"
"github.com/mdlayher/socket"
"golang.org/x/sys/unix"
)
var _ net.Listener = &listener{}
// A listener is the net.Listener implementation for connection-oriented
// VM sockets.
type listener struct {
c *socket.Conn
addr *Addr
}
// Addr and Close implement the net.Listener interface for listener.
func (l *listener) Addr() net.Addr { return l.addr }
func (l *listener) Close() error { return l.c.Close() }
func (l *listener) SetDeadline(t time.Time) error { return l.c.SetDeadline(t) }
// Accept accepts a single connection from the listener, and sets up
// a net.Conn backed by conn.
func (l *listener) Accept() (net.Conn, error) {
c, rsa, err := l.c.Accept(context.Background(), 0)
if err != nil {
return nil, err
}
savm := rsa.(*unix.SockaddrVM)
remote := &Addr{
ContextID: savm.CID,
Port: savm.Port,
}
return &Conn{
c: c,
local: l.addr,
remote: remote,
}, nil
}
// name is the socket name passed to package socket.
const name = "vsock"
// listen is the entry point for Listen on Linux.
func listen(cid, port uint32, _ *Config) (*Listener, error) {
// TODO(mdlayher): Config default nil check and initialize. Pass options to
// socket.Config where necessary.
c, err := socket.Socket(unix.AF_VSOCK, unix.SOCK_STREAM, 0, name, nil)
if err != nil {
return nil, err
}
// Be sure to close the Conn if any of the system calls fail before we
// return the Conn to the caller.
if port == 0 {
port = unix.VMADDR_PORT_ANY
}
if err := c.Bind(&unix.SockaddrVM{CID: cid, Port: port}); err != nil {
_ = c.Close()
return nil, err
}
if err := c.Listen(unix.SOMAXCONN); err != nil {
_ = c.Close()
return nil, err
}
l, err := newListener(c)
if err != nil {
_ = c.Close()
return nil, err
}
return l, nil
}
// fileListener is the entry point for FileListener on Linux.
func fileListener(f *os.File) (*Listener, error) {
c, err := socket.FileConn(f, name)
if err != nil {
return nil, err
}
l, err := newListener(c)
if err != nil {
_ = c.Close()
return nil, err
}
return l, nil
}
// newListener creates a Listener from a raw socket.Conn.
func newListener(c *socket.Conn) (*Listener, error) {
lsa, err := c.Getsockname()
if err != nil {
return nil, err
}
// Now that the library can also accept arbitrary os.Files, we have to
// verify the address family so we don't accidentally create a
// *vsock.Listener backed by TCP or some other socket type.
lsavm, ok := lsa.(*unix.SockaddrVM)
if !ok {
// All errors should wrapped with os.SyscallError.
return nil, os.NewSyscallError("listen", unix.EINVAL)
}
addr := &Addr{
ContextID: lsavm.CID,
Port: lsavm.Port,
}
return &Listener{
l: &listener{
c: c,
addr: addr,
},
}, nil
}