Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

darwin: use Go type wrappers to avoid declaring Go methods on C types. #163

Merged
merged 4 commits into from
Aug 10, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 56 additions & 32 deletions enumerator/usb_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func nativeGetDetailedPortsList() ([]*PortDetails, error) {
for _, service := range services {
defer service.Release()

port, err := extractPortInfo(C.io_registry_entry_t(service))
port, err := extractPortInfo(io_registry_entry_t(service))
if err != nil {
return nil, &PortEnumerationError{causedBy: err}
}
Expand All @@ -37,7 +37,7 @@ func nativeGetDetailedPortsList() ([]*PortDetails, error) {
return ports, nil
}

func extractPortInfo(service C.io_registry_entry_t) (*PortDetails, error) {
func extractPortInfo(service io_registry_entry_t) (*PortDetails, error) {
port := &PortDetails{}
// If called too early the port may still not be ready or fully enumerated
// so we retry 5 times before returning error.
Expand Down Expand Up @@ -82,14 +82,14 @@ func extractPortInfo(service C.io_registry_entry_t) (*PortDetails, error) {
return port, nil
}

func getAllServices(serviceType string) ([]C.io_object_t, error) {
func getAllServices(serviceType string) ([]io_object_t, error) {
i, err := getMatchingServices(serviceMatching(serviceType))
if err != nil {
return nil, err
}
defer i.Release()

var services []C.io_object_t
var services []io_object_t
tries := 0
for tries < 5 {
// Extract all elements from iterator
Expand All @@ -105,7 +105,7 @@ func getAllServices(serviceType string) ([]C.io_object_t, error) {
for _, s := range services {
s.Release()
}
services = []C.io_object_t{}
services = []io_object_t{}
i.Reset()
tries++
}
Expand All @@ -121,58 +121,64 @@ func serviceMatching(serviceType string) C.CFMutableDictionaryRef {
}

// getMatchingServices look up registered IOService objects that match a matching dictionary.
func getMatchingServices(matcher C.CFMutableDictionaryRef) (C.io_iterator_t, error) {
func getMatchingServices(matcher C.CFMutableDictionaryRef) (io_iterator_t, error) {
var i C.io_iterator_t
err := C.IOServiceGetMatchingServices(C.kIOMasterPortDefault, C.CFDictionaryRef(matcher), &i)
if err != C.KERN_SUCCESS {
return 0, fmt.Errorf("IOServiceGetMatchingServices failed (code %d)", err)
}
return i, nil
return io_iterator_t(i), nil
}

// CFStringRef

func cfStringCreateWithString(s string) C.CFStringRef {
type cfStringRef C.CFStringRef

func cfStringCreateWithString(s string) cfStringRef {
c := C.CString(s)
defer C.free(unsafe.Pointer(c))
return C.CFStringCreateWithCString(
C.kCFAllocatorDefault, c, C.kCFStringEncodingMacRoman)
return cfStringRef(C.CFStringCreateWithCString(
C.kCFAllocatorDefault, c, C.kCFStringEncodingMacRoman))
}

func (ref C.CFStringRef) Release() {
func (ref cfStringRef) Release() {
C.CFRelease(C.CFTypeRef(ref))
}

// CFTypeRef

func (ref C.CFTypeRef) Release() {
C.CFRelease(ref)
type cfTypeRef C.CFTypeRef

func (ref cfTypeRef) Release() {
C.CFRelease(C.CFTypeRef(ref))
}

// io_registry_entry_t

func (me *C.io_registry_entry_t) GetParent(plane string) (C.io_registry_entry_t, error) {
type io_registry_entry_t C.io_registry_entry_t

func (me *io_registry_entry_t) GetParent(plane string) (io_registry_entry_t, error) {
cPlane := C.CString(plane)
defer C.free(unsafe.Pointer(cPlane))
var parent C.io_registry_entry_t
err := C.IORegistryEntryGetParentEntry(*me, cPlane, &parent)
err := C.IORegistryEntryGetParentEntry(C.io_registry_entry_t(*me), cPlane, &parent)
if err != 0 {
return 0, errors.New("No parent device available")
}
return parent, nil
return io_registry_entry_t(parent), nil
}

func (me *C.io_registry_entry_t) CreateCFProperty(key string) (C.CFTypeRef, error) {
func (me *io_registry_entry_t) CreateCFProperty(key string) (cfTypeRef, error) {
k := cfStringCreateWithString(key)
defer k.Release()
property := C.IORegistryEntryCreateCFProperty(*me, k, C.kCFAllocatorDefault, 0)
property := C.IORegistryEntryCreateCFProperty(C.io_registry_entry_t(*me), C.CFStringRef(k), C.kCFAllocatorDefault, 0)
if property == 0 {
return 0, errors.New("Property not found: " + key)
}
return property, nil
return cfTypeRef(property), nil
}

func (me *C.io_registry_entry_t) GetStringProperty(key string) (string, error) {
func (me *io_registry_entry_t) GetStringProperty(key string) (string, error) {
property, err := me.CreateCFProperty(key)
if err != nil {
return "", err
Expand All @@ -191,7 +197,7 @@ func (me *C.io_registry_entry_t) GetStringProperty(key string) (string, error) {
return C.GoString(&buff[0]), nil
}

func (me *C.io_registry_entry_t) GetIntProperty(key string, intType C.CFNumberType) (int, error) {
func (me *io_registry_entry_t) GetIntProperty(key string, intType C.CFNumberType) (int, error) {
property, err := me.CreateCFProperty(key)
if err != nil {
return 0, err
Expand All @@ -204,34 +210,52 @@ func (me *C.io_registry_entry_t) GetIntProperty(key string, intType C.CFNumberTy
return res, nil
}

func (me *io_registry_entry_t) Release() {
C.IOObjectRelease(C.io_object_t(*me))
}

func (me *io_registry_entry_t) GetClass() string {
class := make([]C.char, 1024)
C.IOObjectGetClass(C.io_object_t(*me), &class[0])
return C.GoString(&class[0])
}

// io_iterator_t

type io_iterator_t C.io_iterator_t

// IsValid checks if an iterator is still valid.
// Some iterators will be made invalid if changes are made to the
// structure they are iterating over. This function checks the iterator
// is still valid and should be called when Next returns zero.
// An invalid iterator can be Reset and the iteration restarted.
func (me *C.io_iterator_t) IsValid() bool {
return C.IOIteratorIsValid(*me) == C.true
func (me *io_iterator_t) IsValid() bool {
return C.IOIteratorIsValid(C.io_iterator_t(*me)) == C.true
}

func (me *C.io_iterator_t) Reset() {
C.IOIteratorReset(*me)
func (me *io_iterator_t) Reset() {
C.IOIteratorReset(C.io_iterator_t(*me))
}

func (me *C.io_iterator_t) Next() (C.io_object_t, bool) {
res := C.IOIteratorNext(*me)
return res, res != 0
func (me *io_iterator_t) Next() (io_object_t, bool) {
res := C.IOIteratorNext(C.io_iterator_t(*me))
return io_object_t(res), res != 0
}

func (me *io_iterator_t) Release() {
C.IOObjectRelease(C.io_object_t(*me))
}

// io_object_t

func (me *C.io_object_t) Release() {
C.IOObjectRelease(*me)
type io_object_t C.io_object_t

func (me *io_object_t) Release() {
C.IOObjectRelease(C.io_object_t(*me))
}

func (me *C.io_object_t) GetClass() string {
func (me *io_object_t) GetClass() string {
class := make([]C.char, 1024)
C.IOObjectGetClass(*me, &class[0])
C.IOObjectGetClass(C.io_object_t(*me), &class[0])
return C.GoString(&class[0])
}