From 42533ce2dfac6b6e015d1879d6d068b4685c0096 Mon Sep 17 00:00:00 2001 From: Vitaliy Gorbachov Date: Mon, 5 Jun 2023 21:29:31 +0700 Subject: [PATCH 1/4] Implement BridgeNetwork methods --- internal/objc/objc.go | 31 +++++++++++++++++++++++++++++++ network.go | 36 ++++++++++++++++++++++++++++++++++++ virtualization_11.h | 3 +++ virtualization_11.m | 27 +++++++++++++++++++++++++++ 4 files changed, 97 insertions(+) diff --git a/internal/objc/objc.go b/internal/objc/objc.go index cb232ea..cb69a2c 100644 --- a/internal/objc/objc.go +++ b/internal/objc/objc.go @@ -57,6 +57,16 @@ const char *getUUID() NSString *uuid = [[NSUUID UUID] UUIDString]; return [uuid UTF8String]; } + +const char *CStringFromNSString(void *ptr) +{ + return [(NSString *)ptr UTF8String]; +} + +int LengthFromNSString(void *ptr) +{ + return [(NSString *)ptr length]; +} */ import "C" import ( @@ -142,6 +152,27 @@ func (n *NSArray) ToPointerSlice() []unsafe.Pointer { return ret } +// NSString indicates NSString +type NSString struct { + *Pointer +} + +// NewNSString creates a new NSString from pointer. +func NewNSString(p unsafe.Pointer) *NSString { + return &NSString{NewPointer(p)} +} + +// CString converts *C.char from *NSString +func (s *NSString) CString() *C.char { + return C.CStringFromNSString(s.ptr()) +} + +// String converts Go string from *NSString +func (s *NSString) String() string { + length := C.LengthFromNSString(s.ptr()) + return C.GoStringN(s.CString(), C.int(length)) +} + // ConvertToNSMutableArray converts to NSMutableArray from NSObject slice in Go world. func ConvertToNSMutableArray(s []NSObject) *Pointer { ln := len(s) diff --git a/network.go b/network.go index 385b2f4..66e5f46 100644 --- a/network.go +++ b/network.go @@ -39,6 +39,42 @@ type BridgedNetwork interface { LocalizedDisplayName() string } +func NetworkInterfaces() []BridgedNetwork { + nsArray := objc.NewNSArray( + C.VZBridgedNetworkInterface_networkInterfaces(), + ) + ptrs := nsArray.ToPointerSlice() + networkInterfaces := make([]BridgedNetwork, len(ptrs)) + for i, ptr := range ptrs { + networkInterfaces[i] = &baseBridgedNetwork{ + pointer: objc.NewPointer(ptr), + } + } + return networkInterfaces +} + +type baseBridgedNetwork struct { + *pointer +} + +func (*baseBridgedNetwork) NetworkInterfaces() []BridgedNetwork { + return NetworkInterfaces() +} + +func (b *baseBridgedNetwork) Identifier() string { + nsStirng := objc.NewNSString( + C.VZBridgedNetworkInterface_identifier(objc.Ptr(b)), + ) + return nsStirng.String() +} + +func (b *baseBridgedNetwork) LocalizedDisplayName() string { + nsStirng := objc.NewNSString( + C.VZBridgedNetworkInterface_localizedDisplayName(objc.Ptr(b)), + ) + return nsStirng.String() +} + // Network device attachment using network address translation (NAT) with outside networks. // // Using the NAT attachment type, the host serves as router and performs network address translation diff --git a/virtualization_11.h b/virtualization_11.h index c92f827..768416c 100644 --- a/virtualization_11.h +++ b/virtualization_11.h @@ -64,6 +64,9 @@ void setStorageDevicesVZVirtualMachineConfiguration(void *config, void *newVZFileHandleSerialPortAttachment(int readFileDescriptor, int writeFileDescriptor); void *newVZFileSerialPortAttachment(const char *filePath, bool shouldAppend, void **error); void *newVZVirtioConsoleDeviceSerialPortConfiguration(void *attachment); +void *VZBridgedNetworkInterface_networkInterfaces(void); +void *VZBridgedNetworkInterface_identifier(void *networkInterface); +void *VZBridgedNetworkInterface_localizedDisplayName(void *networkInterface); void *newVZBridgedNetworkDeviceAttachment(void *networkInterface); void *newVZNATNetworkDeviceAttachment(void); void *newVZFileHandleNetworkDeviceAttachment(int fileDescriptor); diff --git a/virtualization_11.m b/virtualization_11.m index af7785e..8ddb713 100644 --- a/virtualization_11.m +++ b/virtualization_11.m @@ -393,6 +393,33 @@ void setStorageDevicesVZVirtualMachineConfiguration(void *config, RAISE_UNSUPPORTED_MACOS_EXCEPTION(); } +void *VZBridgedNetworkInterface_networkInterfaces() +{ + if (@available(macOS 11, *)) { + return [VZBridgedNetworkInterface networkInterfaces]; // NSArray + } + + RAISE_UNSUPPORTED_MACOS_EXCEPTION(); +} + +void *VZBridgedNetworkInterface_identifier(void *networkInterface) +{ + if (@available(macOS 11, *)) { + return [(VZBridgedNetworkInterface *)networkInterface identifier]; // NSString * + } + + RAISE_UNSUPPORTED_MACOS_EXCEPTION(); +} + +void *VZBridgedNetworkInterface_localizedDisplayName(void *networkInterface) +{ + if (@available(macOS 11, *)) { + return [(VZBridgedNetworkInterface *)networkInterface localizedDisplayName]; // NSString * + } + + RAISE_UNSUPPORTED_MACOS_EXCEPTION(); +} + /*! @abstract Create a new Network device attachment bridging a host physical interface with a virtual network device. @param networkInterface a network interface that bridges a physical interface. From 44cc2754d0b703693900176ec8049a141a64e10a Mon Sep 17 00:00:00 2001 From: Vitaliy Gorbachov Date: Tue, 13 Jun 2023 16:32:17 +0700 Subject: [PATCH 2/4] add inline doc --- virtualization_11.m | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/virtualization_11.m b/virtualization_11.m index 8ddb713..5f6dfc9 100644 --- a/virtualization_11.m +++ b/virtualization_11.m @@ -393,6 +393,17 @@ void setStorageDevicesVZVirtualMachineConfiguration(void *config, RAISE_UNSUPPORTED_MACOS_EXCEPTION(); } +/*! + @abstract Return the list of network interfaces available for bridging. + @discussion + A bridged interface is shared between the virtual machine and the host system. Both host and virtual machine send and receive packets on the same physical interface but have distinct network layers. + + VZBridgedNetworkInterface cannot be instantiated directly. It can be used with a VZBridgedNetworkDeviceAttachment to set up a network device VZNetworkDeviceConfiguration. + + @seealso VZBridgedNetworkDeviceAttachment + @seealso VZNATNetworkDeviceAttachment + @seealso VZNetworkDeviceConfiguration + */ void *VZBridgedNetworkInterface_networkInterfaces() { if (@available(macOS 11, *)) { @@ -402,6 +413,9 @@ void setStorageDevicesVZVirtualMachineConfiguration(void *config, RAISE_UNSUPPORTED_MACOS_EXCEPTION(); } +/*! + @abstract Return the unique identifier for this interface. The identifier is the BSD name associated with the interface (e.g. "en0"). + */ void *VZBridgedNetworkInterface_identifier(void *networkInterface) { if (@available(macOS 11, *)) { @@ -411,6 +425,9 @@ void setStorageDevicesVZVirtualMachineConfiguration(void *config, RAISE_UNSUPPORTED_MACOS_EXCEPTION(); } +/*! + @abstract Return a display name if available (e.g. "Ethernet"). + */ void *VZBridgedNetworkInterface_localizedDisplayName(void *networkInterface) { if (@available(macOS 11, *)) { From b9943047036e399cb72c6593849671daadb54ec8 Mon Sep 17 00:00:00 2001 From: Vitaliy Gorbachov Date: Wed, 20 Dec 2023 18:45:49 +0700 Subject: [PATCH 3/4] removed unnecessary usage of nsstring --- internal/objc/objc.go | 31 ------------------------------- network.go | 12 ++++-------- virtualization_11.h | 4 ++-- virtualization_11.m | 8 ++++---- 4 files changed, 10 insertions(+), 45 deletions(-) diff --git a/internal/objc/objc.go b/internal/objc/objc.go index cb69a2c..cb232ea 100644 --- a/internal/objc/objc.go +++ b/internal/objc/objc.go @@ -57,16 +57,6 @@ const char *getUUID() NSString *uuid = [[NSUUID UUID] UUIDString]; return [uuid UTF8String]; } - -const char *CStringFromNSString(void *ptr) -{ - return [(NSString *)ptr UTF8String]; -} - -int LengthFromNSString(void *ptr) -{ - return [(NSString *)ptr length]; -} */ import "C" import ( @@ -152,27 +142,6 @@ func (n *NSArray) ToPointerSlice() []unsafe.Pointer { return ret } -// NSString indicates NSString -type NSString struct { - *Pointer -} - -// NewNSString creates a new NSString from pointer. -func NewNSString(p unsafe.Pointer) *NSString { - return &NSString{NewPointer(p)} -} - -// CString converts *C.char from *NSString -func (s *NSString) CString() *C.char { - return C.CStringFromNSString(s.ptr()) -} - -// String converts Go string from *NSString -func (s *NSString) String() string { - length := C.LengthFromNSString(s.ptr()) - return C.GoStringN(s.CString(), C.int(length)) -} - // ConvertToNSMutableArray converts to NSMutableArray from NSObject slice in Go world. func ConvertToNSMutableArray(s []NSObject) *Pointer { ln := len(s) diff --git a/network.go b/network.go index 66e5f46..8f5e488 100644 --- a/network.go +++ b/network.go @@ -62,17 +62,13 @@ func (*baseBridgedNetwork) NetworkInterfaces() []BridgedNetwork { } func (b *baseBridgedNetwork) Identifier() string { - nsStirng := objc.NewNSString( - C.VZBridgedNetworkInterface_identifier(objc.Ptr(b)), - ) - return nsStirng.String() + cstring := (*char)(C.VZBridgedNetworkInterface_identifier(objc.Ptr(b))) + return cstring.String() } func (b *baseBridgedNetwork) LocalizedDisplayName() string { - nsStirng := objc.NewNSString( - C.VZBridgedNetworkInterface_localizedDisplayName(objc.Ptr(b)), - ) - return nsStirng.String() + cstring := (*char)(C.VZBridgedNetworkInterface_localizedDisplayName(objc.Ptr(b))) + return cstring.String() } // Network device attachment using network address translation (NAT) with outside networks. diff --git a/virtualization_11.h b/virtualization_11.h index a229c9c..f5b6aab 100644 --- a/virtualization_11.h +++ b/virtualization_11.h @@ -65,8 +65,8 @@ void *newVZFileHandleSerialPortAttachment(int readFileDescriptor, int writeFileD void *newVZFileSerialPortAttachment(const char *filePath, bool shouldAppend, void **error); void *newVZVirtioConsoleDeviceSerialPortConfiguration(void *attachment); void *VZBridgedNetworkInterface_networkInterfaces(void); -void *VZBridgedNetworkInterface_identifier(void *networkInterface); -void *VZBridgedNetworkInterface_localizedDisplayName(void *networkInterface); +const char *VZBridgedNetworkInterface_identifier(void *networkInterface); +const char *VZBridgedNetworkInterface_localizedDisplayName(void *networkInterface); void *newVZBridgedNetworkDeviceAttachment(void *networkInterface); void *newVZNATNetworkDeviceAttachment(void); void *newVZFileHandleNetworkDeviceAttachment(int fileDescriptor); diff --git a/virtualization_11.m b/virtualization_11.m index 7b85e66..700b303 100644 --- a/virtualization_11.m +++ b/virtualization_11.m @@ -415,10 +415,10 @@ void setStorageDevicesVZVirtualMachineConfiguration(void *config, /*! @abstract Return the unique identifier for this interface. The identifier is the BSD name associated with the interface (e.g. "en0"). */ -void *VZBridgedNetworkInterface_identifier(void *networkInterface) +const char *VZBridgedNetworkInterface_identifier(void *networkInterface) { if (@available(macOS 11, *)) { - return [(VZBridgedNetworkInterface *)networkInterface identifier]; // NSString * + return [[(VZBridgedNetworkInterface *)networkInterface identifier] UTF8String]; } RAISE_UNSUPPORTED_MACOS_EXCEPTION(); @@ -427,10 +427,10 @@ void setStorageDevicesVZVirtualMachineConfiguration(void *config, /*! @abstract Return a display name if available (e.g. "Ethernet"). */ -void *VZBridgedNetworkInterface_localizedDisplayName(void *networkInterface) +const char *VZBridgedNetworkInterface_localizedDisplayName(void *networkInterface) { if (@available(macOS 11, *)) { - return [(VZBridgedNetworkInterface *)networkInterface localizedDisplayName]; // NSString * + return [[(VZBridgedNetworkInterface *)networkInterface localizedDisplayName] UTF8String]; } RAISE_UNSUPPORTED_MACOS_EXCEPTION(); From c19980c193c0b07a3cd496fc65590cc65a3caf41 Mon Sep 17 00:00:00 2001 From: Vitaliy Gorbachov Date: Wed, 20 Dec 2023 18:49:58 +0700 Subject: [PATCH 4/4] added godoc --- network.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/network.go b/network.go index 8f5e488..0250e6c 100644 --- a/network.go +++ b/network.go @@ -23,7 +23,6 @@ import ( // virtual machine send and receive packets on the same physical interface but have distinct network layers. // // The BridgedNetwork can be used with a BridgedNetworkDeviceAttachment to set up a network device NetworkDeviceConfiguration. -// TODO(codehex): implement... // see: https://developer.apple.com/documentation/virtualization/vzbridgednetworkinterface?language=objc type BridgedNetwork interface { objc.NSObject @@ -39,6 +38,10 @@ type BridgedNetwork interface { LocalizedDisplayName() string } +// NewBridgedNetwork creates a new BridgedNetwork with identifier. +// +// This is only supported on macOS 11 and newer, error will +// be returned on older versions. func NetworkInterfaces() []BridgedNetwork { nsArray := objc.NewNSArray( C.VZBridgedNetworkInterface_networkInterfaces(), @@ -61,11 +64,17 @@ func (*baseBridgedNetwork) NetworkInterfaces() []BridgedNetwork { return NetworkInterfaces() } +// Identifier returns the unique identifier for this interface. +// +// The identifier is the BSD name associated with the interface (e.g. "en0"). func (b *baseBridgedNetwork) Identifier() string { cstring := (*char)(C.VZBridgedNetworkInterface_identifier(objc.Ptr(b))) return cstring.String() } +// LocalizedDisplayName returns a display name if available (e.g. "Ethernet"). +// +// If no display name is available, the identifier is returned. func (b *baseBridgedNetwork) LocalizedDisplayName() string { cstring := (*char)(C.VZBridgedNetworkInterface_localizedDisplayName(objc.Ptr(b))) return cstring.String()