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
}
|