diff --git a/CHANGES.md b/CHANGES.md index 0844ef3c8..cded439e3 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,6 @@ +### v0.4.0 (unreleased) +* allow longer paths when forwarding Unix domain sockets + ### v0.3.0 (2019-02-06) * support multiplexing forwarded connections along one Hyper-V socket connection diff --git a/go/Gopkg.lock b/go/Gopkg.lock index 5c611c4e4..2e2f076fb 100644 --- a/go/Gopkg.lock +++ b/go/Gopkg.lock @@ -214,15 +214,14 @@ version = "v1.0.1" [[projects]] - branch = "10586_fixes" - digest = "1:afcc93a5ffcbf5a73618d5f832fbf65a7d62f63763a1b31dccddf2390a7f11e4" + digest = "1:71f099e06b92187612832766c80a4bc4c8641b1a5cd262778c8b5716cb63fc4d" name = "github.com/linuxkit/virtsock" packages = [ "pkg/hvsock", "pkg/vsock", ] pruneopts = "NUT" - revision = "76c5cbe7912fc569ca7d3c02ddf9974ce670f7dd" + revision = "8e79449dea0735c1c056d814934dd035734cc97c" [[projects]] branch = "master" diff --git a/go/Gopkg.toml b/go/Gopkg.toml index 1471aa4c4..dcf142222 100644 --- a/go/Gopkg.toml +++ b/go/Gopkg.toml @@ -21,7 +21,7 @@ [[constraint]] name = "github.com/linuxkit/virtsock" - branch = "10586_fixes" + revision = "8e79449dea0735c1c056d814934dd035734cc97c" [[constraint]] name = "github.com/docker/go-p9p" diff --git a/go/cmd/vpnkit-forwarder/main.go b/go/cmd/vpnkit-forwarder/main.go index 54c7ced12..7e67cbd05 100644 --- a/go/cmd/vpnkit-forwarder/main.go +++ b/go/cmd/vpnkit-forwarder/main.go @@ -43,7 +43,7 @@ func main() { func hyperVListener(port int) net.Listener { serviceID := fmt.Sprintf("%08x-FACB-11E6-BD58-64006A7986D3", port) svcid, _ := hvsock.GUIDFromString(serviceID) - l, err := hvsock.Listen(hvsock.HypervAddr{VMID: hvsock.GUIDWildcard, ServiceID: svcid}) + l, err := hvsock.Listen(hvsock.Addr{VMID: hvsock.GUIDWildcard, ServiceID: svcid}) if err != nil { log.Fatalf("Failed to bind AF_HVSOCK guid: %s: %v", serviceID, err) } diff --git a/go/cmd/vpnkit-forwarder/proxy.go b/go/cmd/vpnkit-forwarder/proxy.go index 5f1083a6d..0c87a5853 100644 --- a/go/cmd/vpnkit-forwarder/proxy.go +++ b/go/cmd/vpnkit-forwarder/proxy.go @@ -6,8 +6,6 @@ import ( "log" "net" "os" - "os/signal" - "syscall" ) var interactiveMode bool @@ -74,12 +72,3 @@ func parseHostContainerAddrs() (host net.Addr, port int, container net.Addr, loc localIP = !*noLocalIP return host, port, container, localIP } - -func handleStopSignals() { - s := make(chan os.Signal, 10) - signal.Notify(s, os.Interrupt, syscall.SIGTERM, syscall.SIGSTOP) - - for range s { - os.Exit(0) - } -} diff --git a/go/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock.go b/go/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock.go index dde48a8b5..f54ddda5f 100644 --- a/go/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock.go +++ b/go/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock.go @@ -1,43 +1,45 @@ +// Package hvsock provides a Go interface to Hyper-V sockets both on +// Windows and on Linux. The Linux bindings require patches for the +// 4.9.x kernel. If you are using a Linux kernel 4.14.x or newer you +// should use the vsock package instead as the Hyper-V socket support +// in these kernels have been merged with the virtio sockets +// implementation. package hvsock import ( - "errors" + "encoding/binary" "fmt" - "io" - "log" "net" - "sync" - "syscall" - - "encoding/binary" + "reflect" ) -// This package provides a Go interface to Hyper-V sockets both on -// Windows and on Linux (assuming the appropriate Linux kernel patches -// have been applied). -// -// Unfortunately, it is not easy/possible to extend the existing Go -// socket implementations with new Address Families, so this module -// wraps directly around system calls (and handles Windows' -// asynchronous system calls). -// -// There is an additional wrinkle. Hyper-V sockets in currently -// shipping versions of Windows don't support graceful and/or -// unidirectional shutdown(). So we turn a stream based protocol into -// message based protocol which allows to send in-line "messages" to -// the other end. We then provide a stream based interface on top of -// that. Yuk. -// -// The message interface is pretty simple. We first send a 32bit -// message containing the size of the data in the following -// message. Messages are limited to 'maxmsgsize'. Special message -// (without data), `shutdownrd` and 'shutdownwr' are used to used to -// signal a shutdown to the other end. +var ( + // GUIDZero used by listeners to accept connections from all partitions + GUIDZero, _ = GUIDFromString("00000000-0000-0000-0000-000000000000") + // GUIDWildcard used by listeners to accept connections from all partitions + GUIDWildcard, _ = GUIDFromString("00000000-0000-0000-0000-000000000000") + // GUIDBroadcast undocumented + GUIDBroadcast, _ = GUIDFromString("FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF") + // GUIDChildren used by listeners to accept connections from children + GUIDChildren, _ = GUIDFromString("90db8b89-0d35-4f79-8ce9-49ea0ac8b7cd") + // GUIDLoopback use to connect in loopback mode + GUIDLoopback, _ = GUIDFromString("e0e16197-dd56-4a10-9195-5ee7a155a838") + // GUIDParent use to connect to the parent partition + GUIDParent, _ = GUIDFromString("a42e7cda-d03f-480c-9cc2-a4de20abb878") + + // GUIDs for LinuxVMs with the new Hyper-V socket implementation need to match this template + guidTemplate, _ = GUIDFromString("00000000-facb-11e6-bd58-64006a7986d3") +) -// On Windows 10 build 10586 larger maxMsgSize values work, but on -// newer builds it fails. It is unclear what the cause is... const ( - maxMsgSize = 4 * 1024 // Maximum message size + // The Hyper-V socket implementation used in the 4.9.x kernels + // seems to fail silently if messages are above 8k. The newer + // implementation in the 4.14.x (and newer) kernels seems to + // work fine with larger messages. This is constant is used as + // a temporary workaround to limit the amount of data sent and + // should be removed once support for 4.9.x kernels is + // deprecated. + maxMsgSize = 8 * 1024 ) // GUID is used by Hypper-V sockets for "addresses" and "ports" @@ -54,6 +56,18 @@ func (g *GUID) String() string { g[10], g[11], g[12], g[13], g[14], g[15]) } +// Port converts a Service GUID to a "port" usable by the vsock package. +// It can be used to convert hvsock code to vsock code. On 4.14.x +// kernels Service GUIDs for talking to Linux should have the form of +// xxxxxxxx-facb-11e6-bd58-64006a7986d3, where xxxxxxxx is the vsock port. +func (g *GUID) Port() (uint32, error) { + // Check that the GUID is as expected + if !reflect.DeepEqual(g[4:], guidTemplate[4:]) { + return 0, fmt.Errorf("%s does not conform with the template", g) + } + return binary.LittleEndian.Uint32(g[0:4]), nil +} + // GUIDFromString parses a string and returns a GUID func GUIDFromString(s string) (GUID, error) { var g GUID @@ -67,87 +81,24 @@ func GUIDFromString(s string) (GUID, error) { return g, err } -// HypervAddr combined "address" and "port" structure -type HypervAddr struct { +// Addr represents a Hyper-V socket address +type Addr struct { VMID GUID ServiceID GUID } // Network returns the type of network for Hyper-V sockets -func (a HypervAddr) Network() string { return "hvsock" } +func (a Addr) Network() string { + return "hvsock" +} -func (a HypervAddr) String() string { +func (a Addr) String() string { vmid := a.VMID.String() svc := a.ServiceID.String() return vmid + ":" + svc } -var ( - // Debug enables additional debug output - Debug = false - - // GUIDZero used by listeners to accept connections from all partitions - GUIDZero, _ = GUIDFromString("00000000-0000-0000-0000-000000000000") - // GUIDWildcard used by listeners to accept connections from all partitions - GUIDWildcard, _ = GUIDFromString("00000000-0000-0000-0000-000000000000") - // GUIDBroadcast undocumented - GUIDBroadcast, _ = GUIDFromString("FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF") - // GUIDChildren used by listeners to accept connections from children - GUIDChildren, _ = GUIDFromString("90db8b89-0d35-4f79-8ce9-49ea0ac8b7cd") - // GUIDLoopback use to connect in loopback mode - GUIDLoopback, _ = GUIDFromString("e0e16197-dd56-4a10-9195-5ee7a155a838") - // GUIDParent use to connect to the parent partition - GUIDParent, _ = GUIDFromString("a42e7cda-d03f-480c-9cc2-a4de20abb878") -) - -// Dial a Hyper-V socket address -func Dial(raddr HypervAddr) (Conn, error) { - fd, err := hvsocket(syscall.SOCK_STREAM, sysSHV_PROTO_RAW) - if err != nil { - return nil, err - } - - err = connect(fd, &raddr) - if err != nil { - return nil, err - } - - v, err := newHVsockConn(fd, HypervAddr{VMID: GUIDZero, ServiceID: GUIDZero}, raddr) - if err != nil { - return nil, err - } - v.wrlock = &sync.Mutex{} - return v, nil -} - -// Listen on a Hyper-V socket address -func Listen(addr HypervAddr) (net.Listener, error) { - - acceptFD, err := hvsocket(syscall.SOCK_STREAM, sysSHV_PROTO_RAW) - if err != nil { - return nil, err - } - - err = bind(acceptFD, addr) - if err != nil { - return nil, err - } - - err = syscall.Listen(acceptFD, syscall.SOMAXCONN) - if err != nil { - return nil, err - } - - return &hvsockListener{acceptFD, addr}, nil -} - -const ( - shutdownrd = 0xdeadbeef // Message for CloseRead() - shutdownwr = 0xbeefdead // Message for CloseWrite() - closemsg = 0xdeaddead // Message for Close() -) - // Conn is a hvsock connection which supports half-close. type Conn interface { net.Conn @@ -155,285 +106,10 @@ type Conn interface { CloseWrite() error } -func (v *hvsockListener) Accept() (net.Conn, error) { - var raddr HypervAddr - fd, err := accept(v.acceptFD, &raddr) - if err != nil { - return nil, err - } - - a, err := newHVsockConn(fd, v.laddr, raddr) - if err != nil { - return nil, err - } - a.wrlock = &sync.Mutex{} - return a, nil -} - -func (v *hvsockListener) Close() error { - // Note this won't cause the Accept to unblock. - return syscall.Close(v.acceptFD) -} - -func (v *hvsockListener) Addr() net.Addr { - return HypervAddr{VMID: v.laddr.VMID, ServiceID: v.laddr.ServiceID} -} - -/* - * A wrapper around FileConn which supports CloseRead and CloseWrite - */ - -var ( - // ErrSocketClosed is returned when an operation is attempted on a socket which has been closed - ErrSocketClosed = errors.New("HvSocket has already been closed") - // ErrSocketWriteClosed is returned on a write when the socket has been closed for write - ErrSocketWriteClosed = errors.New("HvSocket has been closed for write") - // ErrSocketReadClosed is returned on a write when the socket has been closed for read - ErrSocketReadClosed = errors.New("HvSocket has been closed for read") - // ErrSocketMsgSize is returned a message has the wrong size - ErrSocketMsgSize = errors.New("HvSocket message was of wrong size") - // ErrSocketMsgWrite is returned when a message write failed - ErrSocketMsgWrite = errors.New("HvSocket writing message") - // ErrSocketNotEnoughData is returned when not all data could be written - ErrSocketNotEnoughData = errors.New("HvSocket not enough data written") - // ErrSocketUnImplemented is returned a function is not implemented - ErrSocketUnImplemented = errors.New("Function not implemented") -) - -// HVsockConn maintains the state of a Hyper-V socket connection -type HVsockConn struct { - hvsockConn - - wrlock *sync.Mutex - - writeClosed bool - readClosed bool - - bytesToRead int -} - -// LocalAddr returns the local address of the Hyper-V socket connection -func (v *HVsockConn) LocalAddr() net.Addr { - return v.local -} - -// RemoteAddr returns the remote address of the Hyper-V socket connection -func (v *HVsockConn) RemoteAddr() net.Addr { - return v.remote -} - -// Close closes a Hyper-V connection -func (v *HVsockConn) Close() error { - prDebug("Close\n") - - v.readClosed = true - v.writeClosed = true - - prDebug("TX: Close\n") - v.wrlock.Lock() - err := v.sendMsg(closemsg) - v.wrlock.Unlock() - if err != nil { - // chances are that the other end beat us to the close - prDebug("Mmmm. %s\n", err) - return v.close() - } - - // wait for reply/ignore errors - // we may get a EOF because the other end closed, - b := make([]byte, 4) - _, _ = v.read(b) - prDebug("close\n") - return v.close() -} - -// CloseRead closes a Hyper-V connection for reading -func (v *HVsockConn) CloseRead() error { - if v.readClosed { - return ErrSocketReadClosed - } - - prDebug("TX: Shutdown Read\n") - v.wrlock.Lock() - err := v.sendMsg(shutdownrd) - v.wrlock.Unlock() - if err != nil { - return err - } - - v.readClosed = true - return nil -} - -// CloseWrite closes a Hyper-V connection for writing -func (v *HVsockConn) CloseWrite() error { - if v.writeClosed { - return ErrSocketWriteClosed - } - - prDebug("TX: Shutdown Write\n") - v.wrlock.Lock() - err := v.sendMsg(shutdownwr) - v.wrlock.Unlock() - if err != nil { - return err - } - - v.writeClosed = true - return nil -} - -func min(a, b int) int { - if a < b { - return a - } - return b -} - -// Read into buffer -// Also handles the inband control messages. -func (v *HVsockConn) Read(buf []byte) (int, error) { - if v.readClosed { - return 0, io.EOF - } - - if v.bytesToRead == 0 { - for { - // wait for next message - b := make([]byte, 4) - - n, err := v.read(b) - if err != nil { - return 0, err - } - - if n != 4 { - return n, ErrSocketMsgSize - } - - msg := int(binary.LittleEndian.Uint32(b)) - if msg == shutdownwr { - // The other end shutdown write. No point reading more - v.readClosed = true - prDebug("RX: ShutdownWrite\n") - return 0, io.EOF - } else if msg == shutdownrd { - // The other end shutdown read. No point writing more - v.writeClosed = true - prDebug("RX: ShutdownRead\n") - } else if msg == closemsg { - // Setting write close here forces a proper close - v.writeClosed = true - prDebug("RX: Close\n") - v.Close() - } else { - v.bytesToRead = msg - if v.bytesToRead == 0 { - // XXX Something is odd. If I don't have this here, this - // case is hit. However, with this code in place this - // case never get's hit. Suspect overly eager GC... - log.Printf("RX: Zero length %02x", b) - continue - } - break - } - } - } - - // If we get here, we know there is v.bytesToRead worth of - // data coming our way. Read it directly into to buffer passed - // in by the caller making sure we do not read mode than we - // should read by splicing the buffer. - toRead := min(len(buf), v.bytesToRead) - prDebug("READ: %d len=0x%x\n", int(v.fd), toRead) - n, err := v.read(buf[:toRead]) - if err != nil || n == 0 { - v.readClosed = true - return n, err - } - v.bytesToRead -= n - return n, nil -} - -// Write a buffer -func (v *HVsockConn) Write(buf []byte) (int, error) { - if v.writeClosed { - return 0, ErrSocketWriteClosed - } - - var err error - toWrite := len(buf) - written := 0 - - prDebug("WRITE: %d Total len=%x\n", int(v.fd), len(buf)) - - for toWrite > 0 { - if v.writeClosed { - return 0, ErrSocketWriteClosed - } - - // We write batches of MSG + data which need to be - // "atomic". We don't want to hold the lock for the - // entire Write() in case some other threads wants to - // send OOB data, e.g. for closing. - - v.wrlock.Lock() - - thisBatch := min(toWrite, maxMsgSize) - prDebug("WRITE: %d len=%x\n", int(v.fd), thisBatch) - // Write message header - err = v.sendMsg(uint32(thisBatch)) - if err != nil { - prDebug("Write MSG Error: %s\n", err) - goto ErrOut - } - - // Write data - n, err := v.write(buf[written : written+thisBatch]) - if err != nil { - prDebug("Write Error 3\n") - goto ErrOut - } - if n != thisBatch { - prDebug("Write Error 4\n") - err = ErrSocketNotEnoughData - goto ErrOut - } - toWrite -= n - written += n - v.wrlock.Unlock() - } - - return written, nil - -ErrOut: - v.wrlock.Unlock() - v.writeClosed = true - return 0, err -} - -// hvsockConn, SetDeadline(), SetReadDeadline(), and -// SetWriteDeadline() are OS specific. - -// Send a message to the other end -// The Lock must be held to call this functions -func (v *HVsockConn) sendMsg(msg uint32) error { - b := make([]byte, 4) - - binary.LittleEndian.PutUint32(b, msg) - n, err := v.write(b) - if err != nil { - prDebug("Write Error 1\n") - return err - } - if n != len(b) { - return ErrSocketMsgWrite - } - return nil -} - -func prDebug(format string, args ...interface{}) { - if Debug { - log.Printf(format, args...) +// Since there doesn't seem to be a standard min function +func min(x, y int) int { + if x < y { + return x } + return y } diff --git a/go/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock_fallback.go b/go/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock_fallback.go index 0c06204dd..050419bd3 100644 --- a/go/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock_fallback.go +++ b/go/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock_fallback.go @@ -3,73 +3,20 @@ package hvsock import ( - "errors" - "time" + "fmt" + "net" + "runtime" ) -const ( - sysAF_HYPERV = 42 - sysSHV_PROTO_RAW = 1 -) - -type hvsockListener struct { - acceptFD int - laddr HypervAddr -} - -// -// System call wrapper -// -func hvsocket(typ, proto int) (int, error) { - return 0, errors.New("hvsocket() not implemented") -} - -func connect(s int, a *HypervAddr) (err error) { - return errors.New("connect() not implemented") -} - -func bind(s int, a HypervAddr) error { - return errors.New("bind() not implemented") -} - -func accept(s int, a *HypervAddr) (int, error) { - return 0, errors.New("accept() not implemented") -} - -type hvsockConn struct { - fd int - local HypervAddr - remote HypervAddr -} - -func newHVsockConn(fd int, local HypervAddr, remote HypervAddr) (*HVsockConn, error) { - v := &hvsockConn{local: local, remote: remote} - return &HVsockConn{hvsockConn: *v}, errors.New("newHVsockConn() not implemented") -} - -func (v *HVsockConn) close() error { - return errors.New("close() not implemented") -} - -func (v *HVsockConn) read(buf []byte) (int, error) { - return 0, errors.New("read() not implemented") -} - -func (v *HVsockConn) write(buf []byte) (int, error) { - return 0, errors.New("write() not implemented") -} - -// SetReadDeadline dummy doc to silence lint -func (v *HVsockConn) SetReadDeadline(t time.Time) error { - return nil // FIXME +// Supported returns if hvsocks are supported on your platform +func Supported() bool { + return false } -// SetWriteDeadline dummy doc to silence lint -func (v *HVsockConn) SetWriteDeadline(t time.Time) error { - return nil // FIXME +func Dial(raddr Addr) (Conn, error) { + return nil, fmt.Errorf("Dial() not implemented on %s", runtime.GOOS) } -// SetDeadline dummy doc to silence lint -func (v *HVsockConn) SetDeadline(t time.Time) error { - return nil // FIXME +func Listen(addr Addr) (net.Listener, error) { + return nil, fmt.Errorf("Listen() not implemented on %s", runtime.GOOS) } diff --git a/go/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock_linux.go b/go/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock_linux.go index bc8295e85..8a9983eac 100644 --- a/go/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock_linux.go +++ b/go/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock_linux.go @@ -32,229 +32,227 @@ int connect_sockaddr_hv(int fd, const struct sockaddr_hv *sa_hv) { int accept_hv(int fd, struct sockaddr_hv *sa_hv, socklen_t *sa_hv_len) { return accept4(fd, (struct sockaddr *)sa_hv, sa_hv_len, 0); } - -struct sockaddr_vsock { - sa_family_t svm_family; - unsigned short svm_reserved1; - unsigned int svm_port; - unsigned int svm_cid; - unsigned char svm_zero[sizeof(struct sockaddr) - - sizeof(sa_family_t) - sizeof(unsigned short) - - sizeof(unsigned int) - sizeof(unsigned int)]; -}; -int bind_sockaddr_vsock(int fd, const struct sockaddr_vsock *sa_vsock) { - return bind(fd, (const struct sockaddr*)sa_vsock, sizeof(*sa_vsock)); -} -int connect_sockaddr_vsock(int fd, const struct sockaddr_vsock *sa_vsock) { - return connect(fd, (const struct sockaddr*)sa_vsock, sizeof(*sa_vsock)); -} -int accept_vsock(int fd, struct sockaddr_vsock *sa_vsock, socklen_t *sa_vsock_len) { - return accept4(fd, (struct sockaddr *)sa_vsock, sa_vsock_len, 0); -} */ import "C" import ( - "encoding/binary" - "errors" "fmt" + "net" "os" "syscall" "time" - "github.com/linuxkit/virtsock/pkg/vsock" -) - -var ( - legacyMode bool + "github.com/pkg/errors" + "golang.org/x/sys/unix" ) const ( - sysAF_HYPERV = 43 - sysAF_VSOCK = 40 - sysSHV_PROTO_RAW = 1 - - guidTmpl = "00000000-facb-11e6-bd58-64006a7986d3" + hvsockAF = 43 //SHV_PROTO_RAW + hvsockRaw = 1 // SHV_PROTO_RAW ) -type hvsockListener struct { - acceptFD int - laddr HypervAddr -} - -// Try to determine if we need to run in legacy mode. -// 4.11 defines AF_SMC as 43 but it doesn't support protocol 1 so the -// socket() call should fail. -func init() { - fd, err := syscall.Socket(sysAF_HYPERV, syscall.SOCK_STREAM, sysSHV_PROTO_RAW) +// Supported returns if hvsocks are supported on your platform +func Supported() bool { + // Try opening a hvsockAF socket. If it works we are on older, i.e. 4.9.x kernels. + // 4.11 defines AF_SMC as 43 but it doesn't support protocol 1 so the + // socket() call should fail. + fd, err := syscall.Socket(hvsockAF, syscall.SOCK_STREAM, hvsockRaw) if err != nil { - legacyMode = false - } else { - legacyMode = true - syscall.Close(fd) + return false } + syscall.Close(fd) + return true } -// -// System call wrapper -// -func hvsocket(typ, proto int) (int, error) { - if legacyMode { - return syscall.Socket(sysAF_HYPERV, typ, proto) +// Dial a Hyper-V socket address +func Dial(raddr Addr) (Conn, error) { + fd, err := syscall.Socket(hvsockAF, syscall.SOCK_STREAM, hvsockRaw) + if err != nil { + return nil, err } - return syscall.Socket(sysAF_VSOCK, typ, 0) -} -func connect(s int, a *HypervAddr) (err error) { - if legacyMode { - sa := C.struct_sockaddr_hv{} - sa.shv_family = sysAF_HYPERV - sa.reserved = 0 + sa := C.struct_sockaddr_hv{} + sa.shv_family = hvsockAF + sa.reserved = 0 - for i := 0; i < 16; i++ { - sa.shv_vm_id[i] = C.uchar(a.VMID[i]) - } - for i := 0; i < 16; i++ { - sa.shv_service_id[i] = C.uchar(a.ServiceID[i]) - } + for i := 0; i < 16; i++ { + sa.shv_vm_id[i] = C.uchar(raddr.VMID[i]) + } + for i := 0; i < 16; i++ { + sa.shv_service_id[i] = C.uchar(raddr.ServiceID[i]) + } - if ret, errno := C.connect_sockaddr_hv(C.int(s), &sa); ret != 0 { - return errors.New(fmt.Sprintf( - "connect(%s:%s) returned %d, errno %d: %s", - a.VMID, a.ServiceID, ret, errno, errno)) + // Retry connect in a loop if EINTR is encountered. + for { + if ret, errno := C.connect_sockaddr_hv(C.int(fd), &sa); ret != 0 { + if errno == syscall.EINTR { + continue + } + return nil, fmt.Errorf("connect(%s) failed with %d, errno=%d", raddr, ret, errno) } - return nil + break } - sa := C.struct_sockaddr_vsock{} - sa.svm_family = sysAF_VSOCK - sa.svm_port = C.uint(binary.LittleEndian.Uint32(a.ServiceID[0:4])) - // Ignore what's passed in. Use CIDAny as this is an accepted value - sa.svm_cid = C.uint(vsock.CIDAny) - - if ret, errno := C.connect_sockaddr_vsock(C.int(s), &sa); ret != 0 { - return errors.New(fmt.Sprintf( - "connect(%08x.%08x) returned %d, errno %d: %s", - sa.svm_cid, sa.svm_port, ret, errno, errno)) - } - return nil + return newHVsockConn(uintptr(fd), &Addr{VMID: GUIDZero, ServiceID: GUIDZero}, &raddr), nil } -func bind(s int, a HypervAddr) error { - if legacyMode { - sa := C.struct_sockaddr_hv{} - sa.shv_family = sysAF_HYPERV - sa.reserved = 0 +// Listen returns a net.Listener which can accept connections on the given port +func Listen(addr Addr) (net.Listener, error) { + fd, err := syscall.Socket(hvsockAF, syscall.SOCK_STREAM, hvsockRaw) + if err != nil { + return nil, err + } - for i := 0; i < 16; i++ { - sa.shv_vm_id[i] = C.uchar(GUIDZero[i]) - } - for i := 0; i < 16; i++ { - sa.shv_service_id[i] = C.uchar(a.ServiceID[i]) - } + sa := C.struct_sockaddr_hv{} + sa.shv_family = hvsockAF + sa.reserved = 0 - if ret, errno := C.bind_sockaddr_hv(C.int(s), &sa); ret != 0 { - return errors.New(fmt.Sprintf( - "bind(%s:%s) returned %d, errno %d: %s", - GUIDZero, a.ServiceID, ret, errno, errno)) - } - return nil + for i := 0; i < 16; i++ { + sa.shv_vm_id[i] = C.uchar(addr.VMID[i]) + } + for i := 0; i < 16; i++ { + sa.shv_service_id[i] = C.uchar(addr.ServiceID[i]) } - sa := C.struct_sockaddr_vsock{} - sa.svm_family = sysAF_VSOCK - sa.svm_port = C.uint(binary.LittleEndian.Uint32(a.ServiceID[0:4])) - // Ignore what's passed in. Use CIDAny as this is the only accepted value - sa.svm_cid = C.uint(vsock.CIDAny) + if ret, errno := C.bind_sockaddr_hv(C.int(fd), &sa); ret != 0 { + return nil, fmt.Errorf("listen(%s) failed with %d, errno=%d", addr, ret, errno) + } - if ret, errno := C.bind_sockaddr_vsock(C.int(s), &sa); ret != 0 { - return errors.New(fmt.Sprintf( - "connect(%08x.%08x) returned %d, errno %d: %s", - sa.svm_cid, sa.svm_port, ret, errno, errno)) + err = syscall.Listen(fd, syscall.SOMAXCONN) + if err != nil { + return nil, errors.Wrapf(err, "listen(%s) failed", addr) } - return nil + return &hvsockListener{fd, addr}, nil } -func accept(s int, a *HypervAddr) (int, error) { - if legacyMode { - var acceptSA C.struct_sockaddr_hv - var acceptSALen C.socklen_t - - acceptSALen = C.sizeof_struct_sockaddr_hv - fd, err := C.accept_hv(C.int(s), &acceptSA, &acceptSALen) - if err != nil { - return -1, err - } - - a.VMID = guidFromC(acceptSA.shv_vm_id) - a.ServiceID = guidFromC(acceptSA.shv_service_id) +// +// Hyper-v sockets Listener implementation +// - return int(fd), nil - } +type hvsockListener struct { + fd int + local Addr +} - var acceptSA C.struct_sockaddr_vsock +// Accept accepts an incoming call and returns the new connection. +func (v *hvsockListener) Accept() (net.Conn, error) { + var acceptSA C.struct_sockaddr_hv var acceptSALen C.socklen_t - acceptSALen = C.sizeof_struct_sockaddr_vsock - fd, err := C.accept_vsock(C.int(s), &acceptSA, &acceptSALen) + acceptSALen = C.sizeof_struct_sockaddr_hv + fd, err := C.accept_hv(C.int(v.fd), &acceptSA, &acceptSALen) if err != nil { - return -1, err + return nil, errors.Wrapf(err, "accept(%s) failed", v.local) } - a.VMID = GUIDParent - a.ServiceID, _ = GUIDFromString(guidTmpl) - tmp := make([]byte, 4) - binary.LittleEndian.PutUint32(tmp, uint32(acceptSA.svm_port)) - a.ServiceID[0] = tmp[0] - a.ServiceID[1] = tmp[1] - a.ServiceID[2] = tmp[2] - a.ServiceID[3] = tmp[3] - return int(fd), nil + remote := &Addr{VMID: guidFromC(acceptSA.shv_vm_id), ServiceID: guidFromC(acceptSA.shv_service_id)} + return newHVsockConn(uintptr(fd), &v.local, remote), nil +} + +// Close closes the listening connection +func (v *hvsockListener) Close() error { + // Note this won't cause the Accept to unblock. + return unix.Close(v.fd) } -// Internal representation. Complex mostly due to asynch send()/recv() syscalls. +// Addr returns the address the Listener is listening on +func (v *hvsockListener) Addr() net.Addr { + return v.local +} + +// +// Hyper-V socket connection implementation +// + +// hvsockConn represents a connection over a Hyper-V socket type hvsockConn struct { - fd int hvsock *os.File - local HypervAddr - remote HypervAddr + fd uintptr + local *Addr + remote *Addr +} + +func newHVsockConn(fd uintptr, local, remote *Addr) *hvsockConn { + hvsock := os.NewFile(fd, fmt.Sprintf("hvsock:%d", fd)) + return &hvsockConn{hvsock: hvsock, fd: fd, local: local, remote: remote} } -// Main constructor -func newHVsockConn(fd int, local HypervAddr, remote HypervAddr) (*HVsockConn, error) { - hvsock := os.NewFile(uintptr(fd), fmt.Sprintf("hvsock:%d", fd)) - v := &hvsockConn{fd: fd, hvsock: hvsock, local: local, remote: remote} +// LocalAddr returns the local address of a connection +func (v *hvsockConn) LocalAddr() net.Addr { + return v.local +} - return &HVsockConn{hvsockConn: *v}, nil +// RemoteAddr returns the remote address of a connection +func (v *hvsockConn) RemoteAddr() net.Addr { + return v.remote } -func (v *HVsockConn) close() error { +// Close closes the connection +func (v *hvsockConn) Close() error { return v.hvsock.Close() } -func (v *HVsockConn) read(buf []byte) (int, error) { +// CloseRead shuts down the reading side of a hvsock connection +func (v *hvsockConn) CloseRead() error { + return syscall.Shutdown(int(v.fd), syscall.SHUT_RD) +} + +// CloseWrite shuts down the writing side of a hvsock connection +func (v *hvsockConn) CloseWrite() error { + return syscall.Shutdown(int(v.fd), syscall.SHUT_WR) +} + +// Read reads data from the connection +func (v *hvsockConn) Read(buf []byte) (int, error) { return v.hvsock.Read(buf) } -func (v *HVsockConn) write(buf []byte) (int, error) { - return v.hvsock.Write(buf) +// Write writes data over the connection +// TODO(rn): replace with a straight call to v.hvsock.Write() once 4.9.x support is deprecated +func (v *hvsockConn) Write(buf []byte) (int, error) { + written := 0 + toWrite := len(buf) + for toWrite > 0 { + thisBatch := min(toWrite, maxMsgSize) + n, err := v.hvsock.Write(buf[written : written+thisBatch]) + if err != nil { + return written, err + } + if n != thisBatch { + return written, fmt.Errorf("short write %d != %d", n, thisBatch) + } + toWrite -= n + written += n + } + + return written, nil } -// SetReadDeadline is un-implemented -func (v *HVsockConn) SetReadDeadline(t time.Time) error { +// SetDeadline sets the read and write deadlines associated with the connection +func (v *hvsockConn) SetDeadline(t time.Time) error { return nil // FIXME } -// SetWriteDeadline is un-implemented -func (v *HVsockConn) SetWriteDeadline(t time.Time) error { +// SetReadDeadline sets the deadline for future Read calls. +func (v *hvsockConn) SetReadDeadline(t time.Time) error { return nil // FIXME } -// SetDeadline is un-implemented -func (v *HVsockConn) SetDeadline(t time.Time) error { +// SetWriteDeadline sets the deadline for future Write calls +func (v *hvsockConn) SetWriteDeadline(t time.Time) error { return nil // FIXME } +// File duplicates the underlying socket descriptor and returns it. +func (v *hvsockConn) File() (*os.File, error) { + // This is equivalent to dup(2) but creates the new fd with CLOEXEC already set. + r0, _, e1 := syscall.Syscall(syscall.SYS_FCNTL, uintptr(v.hvsock.Fd()), syscall.F_DUPFD_CLOEXEC, 0) + if e1 != 0 { + return nil, os.NewSyscallError("fcntl", e1) + } + return os.NewFile(r0, v.hvsock.Name()), nil +} + func guidFromC(cg [16]C.uchar) GUID { var g GUID for i := 0; i < 16; i++ { diff --git a/go/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock_windows.go b/go/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock_windows.go index 09a71b590..f21e9a315 100644 --- a/go/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock_windows.go +++ b/go/vendor/github.com/linuxkit/virtsock/pkg/hvsock/hvsock_windows.go @@ -1,15 +1,18 @@ package hvsock import ( - "errors" + "fmt" "io" "log" + "net" "runtime" "sync" "sync/atomic" "syscall" "time" "unsafe" + + "github.com/pkg/errors" ) // Make sure Winsock2 is initialised @@ -21,53 +24,124 @@ func init() { } const ( - sysAF_HYPERV = 34 - sysSHV_PROTO_RAW = 1 - - socket_error = uintptr(^uint32(0)) + hvsockAF = 34 // AF_HYPERV + hvsockRaw = 1 // SHV_PROTO_RAW ) var ( + // ErrTimeout is an error returned on timeout ErrTimeout = &timeoutError{} wsaData syscall.WSAData ) -// struck sockaddr equivalent -type rawSockaddrHyperv struct { - Family uint16 - Reserved uint16 - VMID GUID - ServiceID GUID +// Supported returns if hvsocks are supported on your platform +func Supported() bool { + return true +} + +// Dial a Hyper-V socket address +func Dial(raddr Addr) (Conn, error) { + fd, err := syscall.Socket(hvsockAF, syscall.SOCK_STREAM, hvsockRaw) + if err != nil { + return nil, err + } + + var sa rawSockaddrHyperv + ptr, n, err := raddr.sockaddr(&sa) + if err != nil { + return nil, err + } + + if err := sys_connect(fd, ptr, n); err != nil { + return nil, errors.Wrapf(err, "connect(%s) failed", raddr) + } + + return newHVsockConn(fd, Addr{VMID: GUIDZero, ServiceID: GUIDZero}, raddr) +} + +// Listen returns a net.Listener which can accept connections on the given port +func Listen(addr Addr) (net.Listener, error) { + fd, err := syscall.Socket(hvsockAF, syscall.SOCK_STREAM, hvsockRaw) + if err != nil { + return nil, err + } + + var sa rawSockaddrHyperv + ptr, n, err := addr.sockaddr(&sa) + if err != nil { + return nil, err + } + if err := sys_bind(fd, ptr, n); err != nil { + return nil, fmt.Errorf("bind(%s) failed with %v", addr, err) + } + + err = syscall.Listen(fd, syscall.SOMAXCONN) + if err != nil { + return nil, errors.Wrapf(err, "listen(%s) failed", addr) + } + + return &hvsockListener{fd, addr}, nil } +// +// Hyper-v sockets Listener implementation +// + type hvsockListener struct { - acceptFD syscall.Handle - laddr HypervAddr + fd syscall.Handle + local Addr +} + +// Accept accepts an incoming call and returns the new connection +func (v *hvsockListener) Accept() (net.Conn, error) { + var sa rawSockaddrHyperv + var n = int32(unsafe.Sizeof(sa)) + fd, err := sys_accept(v.fd, &sa, &n) + if err != nil { + return nil, err + } + + // Extract an Addr from sa + raddr := Addr{} + for i := 0; i < len(raddr.VMID); i++ { + raddr.VMID[i] = sa.VMID[i] + } + for i := 0; i < len(raddr.ServiceID); i++ { + raddr.ServiceID[i] = sa.ServiceID[i] + } + return newHVsockConn(fd, v.local, raddr) +} + +// Close closes the listening connection +func (v *hvsockListener) Close() error { + return syscall.Close(v.fd) +} + +// Addr returns the address the Listener is listening on +func (v *hvsockListener) Addr() net.Addr { + return v.local } -// Internal representation. Complex mostly due to asynch send()/recv() syscalls. +// +// Hyper-V socket connection implementation +// + +// hvsockConn represent a Hyper-V connection. Complex mostly due to asynch send()/recv() syscalls. type hvsockConn struct { fd syscall.Handle - local HypervAddr - remote HypervAddr + local Addr + remote Addr + + wg sync.WaitGroup + wgLock sync.RWMutex + closing atomicBool - wg sync.WaitGroup - closing bool readDeadline deadlineHandler writeDeadline deadlineHandler } -type deadlineHandler struct { - setLock sync.Mutex - channel timeoutChan - channelLock sync.RWMutex - timer *time.Timer - timedout atomicBool -} - -// Main constructor -func newHVsockConn(h syscall.Handle, local HypervAddr, remote HypervAddr) (*HVsockConn, error) { +func newHVsockConn(h syscall.Handle, local Addr, remote Addr) (*hvsockConn, error) { ioInitOnce.Do(initIo) v := &hvsockConn{fd: h, local: local, remote: remote} @@ -83,62 +157,37 @@ func newHVsockConn(h syscall.Handle, local HypervAddr, remote HypervAddr) (*HVso v.readDeadline.channel = make(timeoutChan) v.writeDeadline.channel = make(timeoutChan) - return &HVsockConn{hvsockConn: *v}, nil + return v, nil } -// Utility function to build a struct sockaddr for syscalls. -func (a HypervAddr) sockaddr(sa *rawSockaddrHyperv) (unsafe.Pointer, int32, error) { - sa.Family = sysAF_HYPERV - sa.Reserved = 0 - for i := 0; i < len(sa.VMID); i++ { - sa.VMID[i] = a.VMID[i] - } - for i := 0; i < len(sa.ServiceID); i++ { - sa.ServiceID[i] = a.ServiceID[i] - } - - return unsafe.Pointer(sa), int32(unsafe.Sizeof(*sa)), nil +// LocalAddr returns the local address of a connection +func (v *hvsockConn) LocalAddr() net.Addr { + return v.local } -func hvsocket(typ, proto int) (syscall.Handle, error) { - return syscall.Socket(sysAF_HYPERV, typ, proto) +// RemoteAddr returns the remote address of a connection +func (v *hvsockConn) RemoteAddr() net.Addr { + return v.remote } -func connect(s syscall.Handle, a *HypervAddr) (err error) { - var sa rawSockaddrHyperv - ptr, n, err := a.sockaddr(&sa) - if err != nil { - return err - } - - return sys_connect(s, ptr, n) -} - -func bind(s syscall.Handle, a HypervAddr) error { - var sa rawSockaddrHyperv - ptr, n, err := a.sockaddr(&sa) - if err != nil { - return err - } - - return sys_bind(s, ptr, n) +// Close closes the connection +func (v *hvsockConn) Close() error { + v.close() + return nil } -func accept(s syscall.Handle, a *HypervAddr) (syscall.Handle, error) { - return 0, errors.New("accept(): Unimplemented") +// CloseRead shuts down the reading side of a hvsock connection +func (v *hvsockConn) CloseRead() error { + return syscall.Shutdown(v.fd, syscall.SHUT_RD) } -// -// File IO/Socket interface -// -func (v *HVsockConn) close() error { - v.closeHandle() - - return nil +// CloseWrite shuts down the writing side of a hvsock connection +func (v *hvsockConn) CloseWrite() error { + return syscall.Shutdown(v.fd, syscall.SHUT_WR) } -// Underlying raw read() function. -func (v *HVsockConn) read(buf []byte) (int, error) { +// Read reads data from the connection +func (v *hvsockConn) Read(buf []byte) (int, error) { var b syscall.WSABuf var f uint32 @@ -149,6 +198,7 @@ func (v *HVsockConn) read(buf []byte) (int, error) { if err != nil { return 0, err } + defer v.wg.Done() if v.readDeadline.timedout.isSet() { return 0, ErrTimeout @@ -169,8 +219,28 @@ func (v *HVsockConn) read(buf []byte) (int, error) { } } -// Underlying raw write() function. -func (v *HVsockConn) write(buf []byte) (int, error) { +// Write writes data over the connection +// TODO(rn): Remove once 4.9.x support is deprecated +func (v *hvsockConn) Write(buf []byte) (int, error) { + written := 0 + toWrite := len(buf) + for toWrite > 0 { + thisBatch := min(toWrite, maxMsgSize) + n, err := v.write(buf[written : written+thisBatch]) + if err != nil { + return written, err + } + if n != thisBatch { + return written, fmt.Errorf("short write %d != %d", n, thisBatch) + } + toWrite -= n + written += n + } + + return written, nil +} + +func (v *hvsockConn) write(buf []byte) (int, error) { var b syscall.WSABuf var f uint32 @@ -186,6 +256,8 @@ func (v *HVsockConn) write(buf []byte) (int, error) { if err != nil { return 0, err } + defer v.wg.Done() + if v.writeDeadline.timedout.isSet() { return 0, ErrTimeout } @@ -198,23 +270,56 @@ func (v *HVsockConn) write(buf []byte) (int, error) { } // SetReadDeadline implementation for Hyper-V sockets -func (v *HVsockConn) SetReadDeadline(deadline time.Time) error { +func (v *hvsockConn) SetReadDeadline(deadline time.Time) error { return v.readDeadline.set(deadline) } // SetWriteDeadline implementation for Hyper-V sockets -func (v *HVsockConn) SetWriteDeadline(deadline time.Time) error { +func (v *hvsockConn) SetWriteDeadline(deadline time.Time) error { return v.writeDeadline.set(deadline) } // SetDeadline implementation for Hyper-V sockets -func (v *HVsockConn) SetDeadline(deadline time.Time) error { +func (v *hvsockConn) SetDeadline(deadline time.Time) error { if err := v.SetReadDeadline(deadline); err != nil { return err } return v.SetWriteDeadline(deadline) } +// Helper functions for conversion to sockaddr + +// struck sockaddr equivalent +type rawSockaddrHyperv struct { + Family uint16 + Reserved uint16 + VMID GUID + ServiceID GUID +} + +// Utility function to build a struct sockaddr for syscalls. +func (a Addr) sockaddr(sa *rawSockaddrHyperv) (unsafe.Pointer, int32, error) { + sa.Family = hvsockAF + sa.Reserved = 0 + for i := 0; i < len(sa.VMID); i++ { + sa.VMID[i] = a.VMID[i] + } + for i := 0; i < len(sa.ServiceID); i++ { + sa.ServiceID[i] = a.ServiceID[i] + } + + return unsafe.Pointer(sa), int32(unsafe.Sizeof(*sa)), nil +} + +// Help for read/write timeouts +type deadlineHandler struct { + setLock sync.Mutex + channel timeoutChan + channelLock sync.RWMutex + timer *time.Timer + timedout atomicBool +} + // The code below here is adjusted from: // https://github.com/Microsoft/go-winio/blob/master/file.go type atomicBool int32 @@ -222,11 +327,13 @@ type atomicBool int32 func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 } func (b *atomicBool) setFalse() { atomic.StoreInt32((*int32)(b), 0) } func (b *atomicBool) setTrue() { atomic.StoreInt32((*int32)(b), 1) } - -const ( - cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1 - cFILE_SKIP_SET_EVENT_ON_HANDLE = 2 -) +func (b *atomicBool) swap(new bool) bool { + var newInt int32 + if new { + newInt = 1 + } + return atomic.SwapInt32((*int32)(b), newInt) == 1 +} type timeoutError struct{} @@ -259,24 +366,30 @@ func initIo() { go ioCompletionProcessor(h) } -func (v *hvsockConn) closeHandle() { - if !v.closing { +func (v *hvsockConn) close() { + v.wgLock.Lock() + if !v.closing.swap(true) { + v.wgLock.Unlock() // cancel all IO and wait for it to complete - v.closing = true cancelIoEx(v.fd, nil) v.wg.Wait() // at this point, no new IO can start syscall.Close(v.fd) v.fd = 0 + } else { + v.wgLock.Unlock() } } // prepareIo prepares for a new IO operation func (v *hvsockConn) prepareIo() (*ioOperation, error) { - v.wg.Add(1) - if v.closing { - return nil, ErrSocketClosed + v.wgLock.RLock() + if v.closing.isSet() { + v.wgLock.RUnlock() + return nil, fmt.Errorf("HvSocket has already been closed") } + v.wg.Add(1) + v.wgLock.RUnlock() c := &ioOperation{} c.ch = make(chan ioResult) return c, nil @@ -302,11 +415,10 @@ func ioCompletionProcessor(h syscall.Handle) { // the operation has actually completed. func (v *hvsockConn) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, err error) (int, error) { if err != syscall.ERROR_IO_PENDING { - v.wg.Done() return int(bytes), err } - if v.closing { + if v.closing.isSet() { cancelIoEx(v.fd, &c.o) } @@ -322,8 +434,8 @@ func (v *hvsockConn) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, e case r = <-c.ch: err = r.err if err == syscall.ERROR_OPERATION_ABORTED { - if v.closing { - err = ErrSocketClosed + if v.closing.isSet() { + err = fmt.Errorf("HvSocket has already been closed") } } case <-timeout: @@ -339,7 +451,6 @@ func (v *hvsockConn) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, e // code to ioCompletionProcessor, c must remain alive // until the channel read is complete. runtime.KeepAlive(c) - v.wg.Done() return int(r.bytes), err } diff --git a/go/vendor/github.com/linuxkit/virtsock/pkg/hvsock/zsyscall_windows.go b/go/vendor/github.com/linuxkit/virtsock/pkg/hvsock/zsyscall_windows.go index d90ec985b..bd4ca8a4f 100644 --- a/go/vendor/github.com/linuxkit/virtsock/pkg/hvsock/zsyscall_windows.go +++ b/go/vendor/github.com/linuxkit/virtsock/pkg/hvsock/zsyscall_windows.go @@ -37,8 +37,10 @@ var ( modwinmm = syscall.NewLazyDLL("winmm.dll") modkernel32 = syscall.NewLazyDLL("kernel32.dll") - procConnect = modws2_32.NewProc("connect") - procbind = modws2_32.NewProc("bind") + procConnect = modws2_32.NewProc("connect") + procBind = modws2_32.NewProc("bind") + procAccept = modws2_32.NewProc("accept") + procCancelIoEx = modkernel32.NewProc("CancelIoEx") procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort") procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus") @@ -50,6 +52,10 @@ var ( // Errno values. const ( errnoERROR_IO_PENDING = 997 + socketError = uintptr(^uint32(0)) + + cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1 + cFILE_SKIP_SET_EVENT_ON_HANDLE = 2 ) var ( @@ -73,7 +79,7 @@ func errnoErr(e syscall.Errno) error { func sys_connect(s syscall.Handle, name unsafe.Pointer, namelen int32) (err error) { r1, _, e1 := syscall.Syscall(procConnect.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen)) - if r1 == socket_error { + if r1 == socketError { if e1 != 0 { err = errnoErr(e1) } else { @@ -85,8 +91,21 @@ func sys_connect(s syscall.Handle, name unsafe.Pointer, namelen int32) (err erro } func sys_bind(s syscall.Handle, name unsafe.Pointer, namelen int32) (err error) { - r1, _, e1 := syscall.Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen)) - if r1 == socket_error { + r1, _, e1 := syscall.Syscall(procBind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen)) + if r1 == socketError { + if e1 != 0 { + err = errnoErr(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func sys_accept(s syscall.Handle, rsa *rawSockaddrHyperv, addrlen *int32) (handle syscall.Handle, err error) { + r1, _, e1 := syscall.Syscall(procAccept.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + handle = syscall.Handle(r1) + if r1 == socketError { if e1 != 0 { err = errnoErr(e1) } else { diff --git a/go/vendor/github.com/linuxkit/virtsock/pkg/vsock/vsock.go b/go/vendor/github.com/linuxkit/virtsock/pkg/vsock/vsock.go index d2a0f34b2..819be1d36 100644 --- a/go/vendor/github.com/linuxkit/virtsock/pkg/vsock/vsock.go +++ b/go/vendor/github.com/linuxkit/virtsock/pkg/vsock/vsock.go @@ -26,19 +26,19 @@ const ( CIDHost = 2 ) -// VsockAddr represents the address of a vsock end point. -type VsockAddr struct { +// Addr represents the address of a vsock end point. +type Addr struct { CID uint32 Port uint32 } -// Network returns the network type for a VsockAddr -func (a VsockAddr) Network() string { +// Network returns the network type for a Addr +func (a Addr) Network() string { return "vsock" } -// String returns a string representation of a VsockAddr -func (a VsockAddr) String() string { +// String returns a string representation of a Addr +func (a Addr) String() string { return fmt.Sprintf("%08x.%08x", a.CID, a.Port) } diff --git a/go/vendor/github.com/linuxkit/virtsock/pkg/vsock/vsock_linux.go b/go/vendor/github.com/linuxkit/virtsock/pkg/vsock/vsock_linux.go index 221181a57..f8838eb5d 100644 --- a/go/vendor/github.com/linuxkit/virtsock/pkg/vsock/vsock_linux.go +++ b/go/vendor/github.com/linuxkit/virtsock/pkg/vsock/vsock_linux.go @@ -17,11 +17,11 @@ import ( func SocketMode(m string) { } -// Convert a generic unix.Sockaddr to a VsockAddr -func sockaddrToVsock(sa unix.Sockaddr) *VsockAddr { +// Convert a generic unix.Sockaddr to a Addr +func sockaddrToVsock(sa unix.Sockaddr) *Addr { switch sa := sa.(type) { case *unix.SockaddrVM: - return &VsockAddr{CID: sa.CID, Port: sa.Port} + return &Addr{CID: sa.CID, Port: sa.Port} } return nil } @@ -43,7 +43,7 @@ func Dial(cid, port uint32) (Conn, error) { } break } - return newVsockConn(uintptr(fd), nil, &VsockAddr{cid, port}), nil + return newVsockConn(uintptr(fd), nil, &Addr{cid, port}), nil } // Listen returns a net.Listener which can accept connections on the given port @@ -62,12 +62,12 @@ func Listen(cid, port uint32) (net.Listener, error) { if err != nil { return nil, errors.Wrapf(err, "listen() on %08x.%08x failed", cid, port) } - return &vsockListener{fd, VsockAddr{cid, port}}, nil + return &vsockListener{fd, Addr{cid, port}}, nil } type vsockListener struct { fd int - local VsockAddr + local Addr } // Accept accepts an incoming call and returns the new connection. @@ -94,72 +94,67 @@ func (v *vsockListener) Addr() net.Addr { type vsockConn struct { vsock *os.File fd uintptr - local *VsockAddr - remote *VsockAddr + local *Addr + remote *Addr } -// VsockConn represents a connection over a vsock -type VsockConn struct { - vsockConn -} - -func newVsockConn(fd uintptr, local, remote *VsockAddr) *VsockConn { +func newVsockConn(fd uintptr, local, remote *Addr) *vsockConn { vsock := os.NewFile(fd, fmt.Sprintf("vsock:%d", fd)) - return &VsockConn{vsockConn{vsock: vsock, fd: fd, local: local, remote: remote}} + return &vsockConn{vsock: vsock, fd: fd, local: local, remote: remote} } // LocalAddr returns the local address of a connection -func (v *VsockConn) LocalAddr() net.Addr { +func (v *vsockConn) LocalAddr() net.Addr { return v.local } // RemoteAddr returns the remote address of a connection -func (v *VsockConn) RemoteAddr() net.Addr { +func (v *vsockConn) RemoteAddr() net.Addr { return v.remote } // Close closes the connection -func (v *VsockConn) Close() error { +func (v *vsockConn) Close() error { return v.vsock.Close() } // CloseRead shuts down the reading side of a vsock connection -func (v *VsockConn) CloseRead() error { +func (v *vsockConn) CloseRead() error { return syscall.Shutdown(int(v.fd), syscall.SHUT_RD) } // CloseWrite shuts down the writing side of a vsock connection -func (v *VsockConn) CloseWrite() error { +func (v *vsockConn) CloseWrite() error { return syscall.Shutdown(int(v.fd), syscall.SHUT_WR) } // Read reads data from the connection -func (v *VsockConn) Read(buf []byte) (int, error) { +func (v *vsockConn) Read(buf []byte) (int, error) { return v.vsock.Read(buf) } // Write writes data over the connection -func (v *VsockConn) Write(buf []byte) (int, error) { +func (v *vsockConn) Write(buf []byte) (int, error) { return v.vsock.Write(buf) } // SetDeadline sets the read and write deadlines associated with the connection -func (v *VsockConn) SetDeadline(t time.Time) error { +func (v *vsockConn) SetDeadline(t time.Time) error { return nil // FIXME } // SetReadDeadline sets the deadline for future Read calls. -func (v *VsockConn) SetReadDeadline(t time.Time) error { +func (v *vsockConn) SetReadDeadline(t time.Time) error { return nil // FIXME } // SetWriteDeadline sets the deadline for future Write calls -func (v *VsockConn) SetWriteDeadline(t time.Time) error { +func (v *vsockConn) SetWriteDeadline(t time.Time) error { return nil // FIXME } // File duplicates the underlying socket descriptor and returns it. -func (v *VsockConn) File() (*os.File, error) { +func (v *vsockConn) File() (*os.File, error) { // This is equivalent to dup(2) but creates the new fd with CLOEXEC already set. r0, _, e1 := syscall.Syscall(syscall.SYS_FCNTL, uintptr(v.vsock.Fd()), syscall.F_DUPFD_CLOEXEC, 0) if e1 != 0 { diff --git a/src/bin/connect.ml b/src/bin/connect.ml index 320af7260..6d7cf729e 100644 --- a/src/bin/connect.ml +++ b/src/bin/connect.ml @@ -45,7 +45,7 @@ module Hvsock = struct (* Avoid using `detach` because we don't want to exhaust the thread pool since this will block the main TCP/IP stack. *) module F = - Hvsock_lwt.Flow_shutdown.Make(Host.Time) + Hvsock_lwt.Flow.Make(Host.Time) (Hvsock_lwt.In_main_thread.Make(Host.Main)) (Hvsock.Af_hyperv)