Skip to content

Commit da7a73a

Browse files
committed
WIP
Signed-off-by: Koichi Shiraishi <[email protected]>
1 parent e6b3bd9 commit da7a73a

13 files changed

+1648
-20
lines changed

vsock/_conn_linux.go

+217
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
// Copyright 2021 The Go Hypervisor Authors
2+
// SPDX-License-Identifier: BSD-3-Clause
3+
4+
//go:build linux
5+
6+
package vsock
7+
8+
import (
9+
"net"
10+
"os"
11+
"syscall"
12+
"time"
13+
14+
"golang.org/x/sys/unix"
15+
)
16+
17+
// A Conn is a VM sockets implementation of a net.Conn.
18+
type connLinux struct {
19+
fd connFD
20+
local *Addr
21+
remote *Addr
22+
}
23+
24+
// FD duplicates the underlying socket descriptor and returns it.
25+
//
26+
// FD implements Conn.FD.
27+
func (v *connLinux) FD() (*os.File, error) {
28+
return nil, nil
29+
// // this is equivalent to dup(2) but creates the new fd with CLOEXEC already set.
30+
// fd, err := fcntl(int(v.fd), unix.F_DUPFD_CLOEXEC, 0)
31+
// if err != nil {
32+
// return nil, os.NewSyscallError("fcntl", err)
33+
// }
34+
//
35+
// return os.NewFile(uintptr(fd), v.fd.Name()), nil
36+
}
37+
38+
// Close closes the connection.
39+
func (c *connLinux) Close() error {
40+
return c.opError(opClose, c.fd.Close())
41+
}
42+
43+
// CloseRead shuts down the reading side of the VM sockets connection. Most
44+
// callers should just use Close.
45+
//
46+
// CloseRead only works with Go 1.12+.
47+
func (c *connLinux) CloseRead() error {
48+
return c.opError(opClose, c.fd.Shutdown(unix.SHUT_RD))
49+
}
50+
51+
// CloseWrite shuts down the writing side of the VM sockets connection. Most
52+
// callers should just use Close.
53+
//
54+
// CloseWrite only works with Go 1.12+.
55+
func (c *connLinux) CloseWrite() error {
56+
return c.opError(opClose, c.fd.Shutdown(unix.SHUT_WR))
57+
}
58+
59+
// LocalAddr returns the local network address. The Addr returned is shared by
60+
// all invocations of LocalAddr, so do not modify it.
61+
func (c *connLinux) LocalAddr() net.Addr { return c.local }
62+
63+
// RemoteAddr returns the remote network address. The Addr returned is shared by
64+
// all invocations of RemoteAddr, so do not modify it.
65+
func (c *connLinux) RemoteAddr() net.Addr { return c.remote }
66+
67+
// Read implements the net.Conn Read method.
68+
func (c *connLinux) Read(b []byte) (int, error) {
69+
n, err := c.fd.Read(b)
70+
if err != nil {
71+
return n, c.opError(opRead, err)
72+
}
73+
74+
return n, nil
75+
}
76+
77+
// Write implements the net.Conn Write method.
78+
func (c *connLinux) Write(b []byte) (int, error) {
79+
n, err := c.fd.Write(b)
80+
if err != nil {
81+
return n, c.opError(opWrite, err)
82+
}
83+
84+
return n, nil
85+
}
86+
87+
// SetDeadline implements the net.Conn SetDeadline method.
88+
func (c *connLinux) SetDeadline(t time.Time) error {
89+
return c.opError(opSet, c.fd.SetDeadline(t, deadline))
90+
}
91+
92+
// SetReadDeadline implements the net.Conn SetReadDeadline method.
93+
func (c *connLinux) SetReadDeadline(t time.Time) error {
94+
return c.opError(opSet, c.fd.SetDeadline(t, readDeadline))
95+
}
96+
97+
// SetWriteDeadline implements the net.Conn SetWriteDeadline method.
98+
func (c *connLinux) SetWriteDeadline(t time.Time) error {
99+
return c.opError(opSet, c.fd.SetDeadline(t, writeDeadline))
100+
}
101+
102+
// SyscallConn returns a raw network connection. This implements the
103+
// syscall.Conn interface.
104+
func (c *connLinux) SyscallConn() (syscall.RawConn, error) {
105+
rc, err := c.fd.SyscallConn()
106+
if err != nil {
107+
return nil, c.opError(opSyscallConn, err)
108+
}
109+
110+
return &rawConn{
111+
rc: rc,
112+
local: c.local,
113+
remote: c.remote,
114+
}, nil
115+
}
116+
117+
// opError is a convenience for the function opError that also passes the local
118+
// and remote addresses of the Conn.
119+
func (c *connLinux) opError(op string, err error) error {
120+
return opError(op, err, c.local, c.remote)
121+
}
122+
123+
// A rawConn is a syscall.RawConn that wraps an internal syscall.RawConn in order
124+
// to produce net.OpError error values.
125+
type rawConn struct {
126+
rc syscall.RawConn
127+
local *Addr
128+
remote *Addr
129+
}
130+
131+
var _ syscall.RawConn = &rawConn{}
132+
133+
// Control implements the syscall.RawConn Control method.
134+
func (rc *rawConn) Control(fn func(fd uintptr)) error {
135+
return rc.opError(opRawControl, rc.rc.Control(fn))
136+
}
137+
138+
// Control implements the syscall.RawConn Read method.
139+
func (rc *rawConn) Read(fn func(fd uintptr) (done bool)) error {
140+
return rc.opError(opRawRead, rc.rc.Read(fn))
141+
}
142+
143+
// Control implements the syscall.RawConn Write method.
144+
func (rc *rawConn) Write(fn func(fd uintptr) (done bool)) error {
145+
return rc.opError(opRawWrite, rc.rc.Write(fn))
146+
}
147+
148+
// opError is a convenience for the function opError that also passes the local
149+
// and remote addresses of the rawConn.
150+
func (rc *rawConn) opError(op string, err error) error {
151+
return opError(op, err, rc.local, rc.remote)
152+
}
153+
154+
// newConn creates a Conn using a connFD, immediately setting the connFD to
155+
// non-blocking mode for use with the runtime network poller.
156+
func newConn(cfd connFD, local, remote *Addr) (Conn, error) {
157+
// Note: if any calls fail after this point, cfd.Close should be invoked
158+
// for cleanup because the socket is now non-blocking.
159+
if err := cfd.SetNonblocking(local.name()); err != nil {
160+
return nil, err
161+
}
162+
163+
return &connLinux{
164+
fd: cfd,
165+
local: local,
166+
remote: remote,
167+
}, nil
168+
}
169+
170+
// dial is the entry point for Dial on Linux.
171+
func dial(cid, port uint32) (Conn, error) {
172+
cfd, err := newConnFD()
173+
if err != nil {
174+
return nil, err
175+
}
176+
177+
return dialLinux(cfd, cid, port)
178+
}
179+
180+
// dialLinux is the entry point for tests on Linux.
181+
func dialLinux(cfd connFD, cid, port uint32) (c Conn, err error) {
182+
defer func() {
183+
if err != nil {
184+
// If any system calls fail during setup, the socket must be closed
185+
// to avoid file descriptor leaks.
186+
_ = cfd.EarlyClose()
187+
}
188+
}()
189+
190+
rsa := &unix.SockaddrVM{
191+
CID: cid,
192+
Port: port,
193+
}
194+
195+
if err := cfd.Connect(rsa); err != nil {
196+
return nil, err
197+
}
198+
199+
lsa, err := cfd.Getsockname()
200+
if err != nil {
201+
return nil, err
202+
}
203+
204+
lsavm := lsa.(*unix.SockaddrVM)
205+
206+
local := &Addr{
207+
CID: lsavm.CID,
208+
Port: lsavm.Port,
209+
}
210+
211+
remote := &Addr{
212+
CID: cid,
213+
Port: port,
214+
}
215+
216+
return newConn(cfd, local, remote)
217+
}

0 commit comments

Comments
 (0)