From 3ac34e01df2a113148bbd44a7d002af694fac980 Mon Sep 17 00:00:00 2001 From: Kei Kamikawa Date: Thu, 27 Oct 2022 13:47:05 +0900 Subject: [PATCH 1/2] breaking change ConnectToPort --- socket.go | 19 ++++++++++++------- virtualization.m | 2 +- virtualization_test.go | 40 ++++++++++++++-------------------------- 3 files changed, 27 insertions(+), 34 deletions(-) diff --git a/socket.go b/socket.go index d6b182b..5779850 100644 --- a/socket.go +++ b/socket.go @@ -97,10 +97,10 @@ func (v *VirtioSocketDevice) Listen(port uint32) (*VirtioSocketListener, error) return nil, ErrUnsupportedOSVersion } - ch := make(chan accept, 1) // should I increase more caps? + ch := make(chan connResults, 1) // should I increase more caps? handler := cgo.NewHandle(func(conn *VirtioSocketConnection, err error) { - ch <- accept{conn, err} + ch <- connResults{conn, err} }) ptr := C.newVZVirtioSocketListener( unsafe.Pointer(&handler), @@ -139,20 +139,25 @@ func connectionHandler(connPtr, errPtr, cgoHandlerPtr unsafe.Pointer) { } } -// ConnectToPort Initiates a connection to the specified port of the guest operating system. +// Connect Initiates a connection to the specified port of the guest operating system. // // This method initiates the connection asynchronously, and executes the completion handler when the results are available. // If the guest operating system doesn’t listen for connections to the specifed port, this method does nothing. // // For a successful connection, this method sets the sourcePort property of the resulting VZVirtioSocketConnection object to a random port number. // see: https://developer.apple.com/documentation/virtualization/vzvirtiosocketdevice/3656677-connecttoport?language=objc -func (v *VirtioSocketDevice) ConnectToPort(port uint32, fn func(conn *VirtioSocketConnection, err error)) { - cgoHandler := cgo.NewHandle(fn) +func (v *VirtioSocketDevice) Connect(port uint32) (*VirtioSocketConnection, error) { + ch := make(chan connResults, 1) + cgoHandler := cgo.NewHandle(func(conn *VirtioSocketConnection, err error) { + ch <- connResults{conn, err} + }) C.VZVirtioSocketDevice_connectToPort(v.Ptr(), v.dispatchQueue, C.uint32_t(port), unsafe.Pointer(&cgoHandler)) + result := <-ch runtime.KeepAlive(v) + return result.conn, result.err } -type accept struct { +type connResults struct { conn *VirtioSocketConnection err error } @@ -165,7 +170,7 @@ type VirtioSocketListener struct { vsockDevice *VirtioSocketDevice handler cgo.Handle port uint32 - acceptch chan accept + acceptch chan connResults closeOnce sync.Once } diff --git a/virtualization.m b/virtualization.m index 3f2b4ca..732c2cc 100644 --- a/virtualization.m +++ b/virtualization.m @@ -812,7 +812,7 @@ void VZVirtioSocketDevice_removeSocketListenerForPort(void *socketDevice, void * void VZVirtioSocketDevice_connectToPort(void *socketDevice, void *vmQueue, uint32_t port, void *cgoHandlerPtr) { if (@available(macOS 11, *)) { - dispatch_sync((dispatch_queue_t)vmQueue, ^{ + dispatch_async((dispatch_queue_t)vmQueue, ^{ [(VZVirtioSocketDevice *)socketDevice connectToPort:port completionHandler:^(VZVirtioSocketConnection *connection, NSError *err) { connectionHandler(connection, err, cgoHandlerPtr); diff --git a/virtualization_test.go b/virtualization_test.go index 6ac19a0..a3a1ce9 100644 --- a/virtualization_test.go +++ b/virtualization_test.go @@ -168,9 +168,6 @@ func newVirtualizationMachine( HostKeyCallback: ssh.InsecureIgnoreHostKey(), } - clientCh := make(chan *ssh.Client, 1) - errCh := make(chan error, 1) - // Workaround for macOS 11 // // This is a workaround. This version of the API does not immediately return an error and @@ -181,24 +178,8 @@ func newVirtualizationMachine( RETRY: for i := 1; ; i++ { - socketDevice.ConnectToPort(2222, func(vsockConn *vz.VirtioSocketConnection, err error) { - if err != nil { - errCh <- fmt.Errorf("failed to connect vsock: %w", err) - return - } - - sshClient, err := newSshClient(vsockConn, ":22", sshConfig) - if err != nil { - vsockConn.Close() - errCh <- fmt.Errorf("failed to create a new ssh client: %w", err) - return - } - clientCh <- sshClient - close(clientCh) - }) - - select { - case err := <-errCh: + conn, err := socketDevice.Connect(2222) + if err != nil { var nserr *vz.NSError if !errors.As(err, &nserr) || i > 5 { t.Fatal(err) @@ -208,11 +189,18 @@ RETRY: time.Sleep(time.Second) continue RETRY } - case sshClient := <-clientCh: - return &Container{ - VirtualMachine: vm, - Client: sshClient, - } + t.Fatalf("failed to connect vsock: %v", err) + } + + sshClient, err := newSshClient(conn, ":22", sshConfig) + if err != nil { + conn.Close() + t.Fatalf("failed to create a new ssh client: %v", err) + } + + return &Container{ + VirtualMachine: vm, + Client: sshClient, } } } From 74f14d8c16eba582b142512a90809227ca9ac358 Mon Sep 17 00:00:00 2001 From: Kei Kamikawa Date: Thu, 27 Oct 2022 13:52:39 +0900 Subject: [PATCH 2/2] close channel --- socket.go | 1 + 1 file changed, 1 insertion(+) diff --git a/socket.go b/socket.go index 5779850..6e628e7 100644 --- a/socket.go +++ b/socket.go @@ -150,6 +150,7 @@ func (v *VirtioSocketDevice) Connect(port uint32) (*VirtioSocketConnection, erro ch := make(chan connResults, 1) cgoHandler := cgo.NewHandle(func(conn *VirtioSocketConnection, err error) { ch <- connResults{conn, err} + close(ch) }) C.VZVirtioSocketDevice_connectToPort(v.Ptr(), v.dispatchQueue, C.uint32_t(port), unsafe.Pointer(&cgoHandler)) result := <-ch