Every time I start build my Xcode Project, I get this in the console:
<CFData 0x100516c60 [0x7fff71adaea0]>{length = 6, capacity = 6, bytes = 0x0022412b03ad}
I have no idea, what it means and what it's causing it.
Can someone help me?
Thx!
Edit:
I think this method creates it:
//
// PrimaryMac.m
// Network Radar
//
// Created by Daniel Diener on 06.07.11.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#import "PrimaryMac.h"
#include <stdio.h>
#include <sys/param.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>
#include "if_types.h"
#include "route.h"
#include "if_ether.h"
#include <netinet/in.h>
#include <arpa/inet.h>
#include <err.h>
#include <errno.h>
#include <netdb.h>
#include <paths.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/network/IOEthernetInterface.h>
#include <IOKit/network/IONetworkInterface.h>
#include <IOKit/network/IOEthernetController.h>
#implementation PrimaryMac
#synthesize localMac, remoteMac;
static kern_return_t FindEthernetInterfaces(io_iterator_t *matchingServices);
static kern_return_t GetMACAddress(io_iterator_t intfIterator, UInt8 *MACAddress, UInt8 bufferSize);
- (id)init
{
self = [super init];
if (self) {
}
return self;
}
//LOCAL MAC:::::::::::::::::::
// Returns an iterator containing the primary (built-in) Ethernet interface. The caller is responsible for
// releasing the iterator after the caller is done with it.
static kern_return_t FindEthernetInterfaces(io_iterator_t *matchingServices)
{
kern_return_t kernResult;
CFMutableDictionaryRef matchingDict;
CFMutableDictionaryRef propertyMatchDict;
// Ethernet interfaces are instances of class kIOEthernetInterfaceClass.
// IOServiceMatching is a convenience function to create a dictionary with the key kIOProviderClassKey and
// the specified value.
matchingDict = IOServiceMatching(kIOEthernetInterfaceClass);
// Note that another option here would be:
// matchingDict = IOBSDMatching("en0");
// but en0: isn't necessarily the primary interface, especially on systems with multiple Ethernet ports.
if (NULL == matchingDict) {
printf("IOServiceMatching returned a NULL dictionary.\n");
}
else {
// Each IONetworkInterface object has a Boolean property with the key kIOPrimaryInterface. Only the
// primary (built-in) interface has this property set to TRUE.
// IOServiceGetMatchingServices uses the default matching criteria defined by IOService. This considers
// only the following properties plus any family-specific matching in this order of precedence
// (see IOService::passiveMatch):
//
// kIOProviderClassKey (IOServiceMatching)
// kIONameMatchKey (IOServiceNameMatching)
// kIOPropertyMatchKey
// kIOPathMatchKey
// kIOMatchedServiceCountKey
// family-specific matching
// kIOBSDNameKey (IOBSDNameMatching)
// kIOLocationMatchKey
// The IONetworkingFamily does not define any family-specific matching. This means that in
// order to have IOServiceGetMatchingServices consider the kIOPrimaryInterface property, we must
// add that property to a separate dictionary and then add that to our matching dictionary
// specifying kIOPropertyMatchKey.
propertyMatchDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (NULL == propertyMatchDict) {
printf("CFDictionaryCreateMutable returned a NULL dictionary.\n");
}
else {
// Set the value in the dictionary of the property with the given key, or add the key
// to the dictionary if it doesn't exist. This call retains the value object passed in.
CFDictionarySetValue(propertyMatchDict, CFSTR(kIOPrimaryInterface), kCFBooleanTrue);
// Now add the dictionary containing the matching value for kIOPrimaryInterface to our main
// matching dictionary. This call will retain propertyMatchDict, so we can release our reference
// on propertyMatchDict after adding it to matchingDict.
CFDictionarySetValue(matchingDict, CFSTR(kIOPropertyMatchKey), propertyMatchDict);
CFRelease(propertyMatchDict);
}
}
// IOServiceGetMatchingServices retains the returned iterator, so release the iterator when we're done with it.
// IOServiceGetMatchingServices also consumes a reference on the matching dictionary so we don't need to release
// the dictionary explicitly.
kernResult = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, matchingServices);
if (KERN_SUCCESS != kernResult) {
printf("IOServiceGetMatchingServices returned 0x%08x\n", kernResult);
}
return kernResult;
}
// Given an iterator across a set of Ethernet interfaces, return the MAC address of the last one.
// If no interfaces are found the MAC address is set to an empty string.
// In this sample the iterator should contain just the primary interface.
static kern_return_t GetMACAddress(io_iterator_t intfIterator, UInt8 *MACAddress, UInt8 bufferSize)
{
io_object_t intfService;
io_object_t controllerService;
kern_return_t kernResult = KERN_FAILURE;
// Make sure the caller provided enough buffer space. Protect against buffer overflow problems.
if (bufferSize < kIOEthernetAddressSize) {
return kernResult;
}
// Initialize the returned address
bzero(MACAddress, bufferSize);
// IOIteratorNext retains the returned object, so release it when we're done with it.
while ((intfService = IOIteratorNext(intfIterator)))
{
CFTypeRef MACAddressAsCFData;
// IONetworkControllers can't be found directly by the IOServiceGetMatchingServices call,
// since they are hardware nubs and do not participate in driver matching. In other words,
// registerService() is never called on them. So we've found the IONetworkInterface and will
// get its parent controller by asking for it specifically.
// IORegistryEntryGetParentEntry retains the returned object, so release it when we're done with it.
kernResult = IORegistryEntryGetParentEntry(intfService,
kIOServicePlane,
&controllerService);
if (KERN_SUCCESS != kernResult) {
printf("IORegistryEntryGetParentEntry returned 0x%08x\n", kernResult);
}
else {
// Retrieve the MAC address property from the I/O Registry in the form of a CFData
MACAddressAsCFData = IORegistryEntryCreateCFProperty(controllerService,
CFSTR(kIOMACAddress),
kCFAllocatorDefault,
0);
if (MACAddressAsCFData) {
CFShow(MACAddressAsCFData); // for display purposes only; output goes to stderr
// Get the raw bytes of the MAC address from the CFData
CFDataGetBytes(MACAddressAsCFData, CFRangeMake(0, kIOEthernetAddressSize), MACAddress);
CFRelease(MACAddressAsCFData);
}
// Done with the parent Ethernet controller object so we release it.
(void) IOObjectRelease(controllerService);
}
// Done with the Ethernet interface object so we release it.
(void) IOObjectRelease(intfService);
}
return kernResult;
}
- (void)createLocalMac{
kern_return_t kernResult = KERN_SUCCESS;
io_iterator_t intfIterator;
UInt8 MACAddress[kIOEthernetAddressSize];
kernResult = FindEthernetInterfaces(&intfIterator);
if (KERN_SUCCESS != kernResult) {
printf("FindEthernetInterfaces returned 0x%08x\n", kernResult);
}
else {
kernResult = GetMACAddress(intfIterator, MACAddress, sizeof(MACAddress));
if (KERN_SUCCESS != kernResult) {
printf("GetMACAddress returned 0x%08x\n", kernResult);
}
else {
localMac = [NSString stringWithFormat:#"%02x:%02x:%02x:%02x:%02x:%02x",
MACAddress[0], MACAddress[1], MACAddress[2], MACAddress[3], MACAddress[4], MACAddress[5]];
}
}
(void) IOObjectRelease(intfIterator); // Release the iterator.
}
//REMOTE MAC:::::::::::::::::::
- (void)createRemoteMac:(NSString *)ipAddr{
NSString *ret = nil;
in_addr_t addr = inet_addr([ipAddr UTF8String]);
size_t needed;
char *buf, *next;
struct rt_msghdr *rtm;
struct sockaddr_inarp *sin;
struct sockaddr_dl *sdl;
int mib[6];
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = AF_INET;
mib[4] = NET_RT_FLAGS;
mib[5] = RTF_LLINFO;
if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &needed, NULL, 0) < 0)
err(1, "route-sysctl-estimate");
if ((buf = (char*)malloc(needed)) == NULL)
err(1, "malloc");
if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &needed, NULL, 0) < 0)
err(1, "retrieval of routing table");
for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *)next;
sin = (struct sockaddr_inarp *)(rtm + 1);
sdl = (struct sockaddr_dl *)(sin + 1);
if (addr != sin->sin_addr.s_addr || sdl->sdl_alen < 6)
continue;
u_char *cp = (u_char*)LLADDR(sdl);
ret = [NSString stringWithFormat:#"%02X:%02X:%02X:%02X:%02X:%02X",
cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]];
break;
}
free(buf);
remoteMac = ret;
}
- (void)dealloc {
[remoteMac release];
[localMac release];
[super dealloc];
}
#end
I use it to get the active interface's MAC address.
Your print statement is happening on this line using CFShow. Just comment that out :)
if (MACAddressAsCFData) {
//Comment out the CFShow here
CFShow(MACAddressAsCFData); // for display purposes only; output goes to stderr
Related
I have the following code to read and write to serial ports on iOS 10.3.3 Jailbroken iPhone 6S (I used h3lix to jailbreak):
Serial.h:
//
// Serial.h
// iOUSB
//
// Created by Brandon on 2018-05-21.
// Copyright © 2018 XIO. All rights reserved.
//
#if !defined(__cplusplus) //-fmodules -fcxx-modules
#import Foundation;
#else
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wauto-import"
#import <Foundation/Foundation.h>
#pragma clang diagnostic pop
#endif
#define BAUD_RATE 9600
#interface Serial : NSObject
+ (instancetype)shared;
- (bool)setup:(NSString *)filePath;
- (bool)disconnect;
- (size_t)available;
- (size_t)read:(uint8_t *)bytes length:(int32_t)length;
- (size_t)write:(uint8_t *)bytes length:(int32_t)length;
- (void)flushInputStream;
- (void)flushOutputStream;
- (void)flush;
- (NSString *)lastError;
- (void)eraseLastError;
#end
Serial.mm:
//
// Serial.mm
// iOUSB
//
// Created by Brandon on 2018-05-21.
// Copyright © 2018 XIO. All rights reserved.
//
#import "Serial.h"
#include <fstream>
#include <iostream>
#include <sys/fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <unistd.h>
#define DEFAULT_BAUD_RATE 9600
#interface Serial()
#property (nonatomic, assign) int file_descriptor;
#property (nonatomic, strong) NSString *lastError;
#end
#implementation Serial
+ (instancetype)shared {
static Serial *instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[Serial alloc] init];
});
return instance;
}
- (instancetype)init {
if ((self = [super init])) {
self.file_descriptor = -1;
self.lastError = nil;
}
return self;
}
- (void)dealloc {
[self disconnect];
}
- (bool)setup:(NSString *)filePath {
if (self.file_descriptor != -1)
{
return true;
}
self.file_descriptor = open(filePath.UTF8String, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
if (self.file_descriptor == -1)
{
const char* error = strerror(errno);
self.lastError = [[NSString alloc] initWithUTF8String:error];
perror(error);
return false;
}
struct termios options;
struct termios oldoptions;
tcgetattr(self.file_descriptor, &oldoptions);
options = oldoptions;
#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
int baud_rates[] = {B0, B50, B75, B110, B134, B150, B200, B300, B1200, B1800, B2400, B4800, B9600, B19200, B38400, B7200, B14400, B28800, B57600, B76800, B115200, B230400
};
#else
int baud_rates[] = {B0, B50, B75, B110, B134, B150, B200, B300, B1200, B1800, B2400, B4800, B9600, B19200, B38400};
#endif
auto it = std::find(std::begin(baud_rates), std::end(baud_rates), BAUD_RATE);
if (it != std::end(baud_rates))
{
cfsetispeed(&options, *it);
cfsetospeed(&options, *it);
std::cout<<"BAUD_RATE Set Successfully!\n";
}
else
{
cfsetispeed(&options, DEFAULT_BAUD_RATE);
cfsetospeed(&options, DEFAULT_BAUD_RATE);
std::cerr<<"Invalid BAUD_RATE.. Setting to default: "<<DEFAULT_BAUD_RATE<<"\n";
}
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag |= CS8;
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
tcsetattr(self.file_descriptor, TCSANOW, &options);
return true;
}
- (bool)disconnect {
if (self.file_descriptor != -1)
{
close(self.file_descriptor);
self.file_descriptor = -1;
self.lastError = nil;
}
return self.file_descriptor == -1;
}
- (size_t)available {
if (self.file_descriptor == -1)
{
return -1;
}
int available = -1;
ioctl(self.file_descriptor, FIONREAD, &available);
return available;
}
- (size_t)read:(uint8_t *)bytes length:(int32_t)length {
if (self.file_descriptor == -1)
{
return -1;
}
ssize_t bytesRead = read(self.file_descriptor, bytes, length);
if (bytesRead < 0)
{
const char* error = strerror(errno);
self.lastError = [[NSString alloc] initWithUTF8String:error];
perror(error);
}
return bytesRead;
}
- (size_t)write:(uint8_t *)bytes length:(int32_t)length {
if (self.file_descriptor == -1)
{
return -1;
}
ssize_t bytesWritten = write(self.file_descriptor, bytes, length);
if (bytesWritten <= 0)
{
const char* error = strerror(errno);
self.lastError = [[NSString alloc] initWithUTF8String:error];
perror(error);
}
return bytesWritten;
}
- (void)flushInputStream {
if (self.file_descriptor == -1)
{
return;
}
tcflush(self.file_descriptor, TCIFLUSH);
}
- (void)flushOutputStream {
if (self.file_descriptor == -1)
{
return;
}
tcflush(self.file_descriptor, TCOFLUSH);
}
- (void)flush {
if (self.file_descriptor == -1)
{
return;
}
tcflush(self.file_descriptor, TCIOFLUSH);
}
- (NSString *)lastError {
return _lastError ?: #"";
}
- (void)eraseLastError {
_lastError = nil;
}
#end
I purchased the OTG adapter: "Lightning to USB 3 Camera Adapter" shown here: https://www.apple.com/ca/shop/product/MK0W2AM/A/lightning-to-usb-3-camera-adapter
I have plugged in the device and it shows up as unsupported device which is fine, since it's not MFI-Certified.
However, when I try to open /dev/tty.iap, I keep getting Error: Resource Busy.
I am able to open /dev/tty.wlan for example.. Only some ports give me trouble like the iap one.
What am I doing wrong that I cannot read tty.iap? I have tried to run the application as root by moving it to /Applications from /var/containers/Bundle/Applications.. I've tried to chown root:wheel the app and chmod 0777 the app. Still I get resource busy..
I've read online that you get this error when you are NOT root.
How can I run my app as root?
How can I fix this so I can read the lightning port?
I tried https://stackoverflow.com/a/15970080/1462718 but it doesn't seem to work. The app would launch and then immediately close no matter how many times I try.
By default the serial port is in use as an out-of-band management interface (allowing you to connect to the system via a serial connection if the network is down).
You will need to disable this before you can reuse the serial port for any other purpose.
The specifics of how to do this vary by OS version.
You can use GCD dispatch sources to read and write from sockets, monitor a listening socket for incoming connections, but I couldn't figure out how to also use a dispatch source to connect a socket?
In pseudo-code, it would look something like this:
dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, connectingSocket, ...);
dispatch_source_set_event_handler(source, ^{
// Socket did connect or not
});
fcntl(connectingSocket, F_SETFL, O_NONBLOCK);
connect(connectingSocket, addr, len);
dispatch_source_resume(source);
This would be nicer than having to use select().
I initially mis-parsed your question... sorry. I get it now... you want to get EINPROGRESS from connect and have a dispatch source notify you when the connect call needs attention instead of polling with select... This was fairly easy to hack up, and appears to work:
#import <sys/types.h>
#import <sys/socket.h>
#import <netinet/in.h>
#import <arpa/inet.h>
#implementation AppDelegate
{
dispatch_source_t foo;
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
int socketFD = socket(PF_INET, SOCK_STREAM, 0);
if (socketFD == -1)
{
socketFD = -1;
abort();
}
int flags = fcntl(socketFD, F_GETFL, 0);
int status = fcntl(socketFD, F_SETFL, flags | O_NONBLOCK);
if (status == -1)
{
close(socketFD);
socketFD = -1;
abort();
}
struct sockaddr_in sockaddr4 = {0};
sockaddr4.sin_len = sizeof(sockaddr4);
sockaddr4.sin_family = AF_INET;
sockaddr4.sin_port = htons(22);
inet_aton("127.0.0.1", &sockaddr4.sin_addr);
foo = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, socketFD, 0, dispatch_get_main_queue());
dispatch_source_set_event_handler(foo, ^{
if (connect(socketFD, (const struct sockaddr *)&sockaddr4, (socklen_t)sizeof(sockaddr4)))
{
int err = errno;
NSLog(#"errno: %s", strerror(err));
if (err == ECONNREFUSED)
{
abort();
}
else if (err == EISCONN)
{
// connected -- queue up other work
DoStuff();
// Cancel the source so it doesnt keep notifying...
dispatch_source_cancel(foo);
}
}
});
dispatch_source_set_cancel_handler(foo, ^{
NSLog(#"Cancel");
});
dispatch_resume(foo);
// Do initial connect
if (connect(socketFD, (const struct sockaddr *)&sockaddr4, (socklen_t)sizeof(sockaddr4)))
{
if(errno != EINPROGRESS)
{
close(socketFD);
socketFD = -1;
abort();
}
}
}
#end
Apportable error
arithmetic on a pointer to an incomplete type 'struct if_msghdr'
socketStruct = (struct sockaddr_dl *) (interfaceMsgStruct + 1);
Here is the code. The code is working fine on ios/xcode but gives above error to interfaceMsgStruct with apportable. I have get this code from google and it is widely used so i dont think the code might have error. If it does then please correct me.
#import "MFMacAddress.h"
#implementation MFMacAddress
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>
+ (NSString *)getMacAddress
{
int mgmtInfoBase[6];
char *msgBuffer = NULL;
size_t length;
unsigned char macAddress[6];
struct if_msghdr *interfaceMsgStruct;
struct sockaddr_dl *socketStruct;
NSString *errorFlag = NULL;
// Setup the management Information Base (mib)
mgmtInfoBase[0] = CTL_NET; // Request network subsystem
mgmtInfoBase[1] = AF_ROUTE; // Routing table info
mgmtInfoBase[2] = 0;
mgmtInfoBase[3] = AF_LINK; // Request link layer information
mgmtInfoBase[4] = NET_RT_IFLIST; // Request all configured interfaces
// With all configured interfaces requested, get handle index
if ((mgmtInfoBase[5] = if_nametoindex("en0")) == 0)
errorFlag = #"if_nametoindex failure";
else
{
// Get the size of the data available (store in len)
if (sysctl(mgmtInfoBase, 6, NULL, &length, NULL, 0) < 0)
errorFlag = #"sysctl mgmtInfoBase failure";
else
{
// Alloc memory based on above call
if ((msgBuffer = malloc(length)) == NULL)
errorFlag = #"buffer allocation failure";
else
{
// Get system information, store in buffer
if (sysctl(mgmtInfoBase, 6, msgBuffer, &length, NULL, 0) < 0)
errorFlag = #"sysctl msgBuffer failure";
}
}
}
// Befor going any further...
if (errorFlag != NULL)
{
NSLog(#"Error: %#", errorFlag);
return errorFlag;
}
// Map msgbuffer to interface message structure
interfaceMsgStruct = (struct if_msghdr *) msgBuffer;
// Map to link-level socket structure
socketStruct = (struct sockaddr_dl *) (interfaceMsgStruct + 1);
// Copy link layer address data in socket structure to an array
memcpy(&macAddress, socketStruct->sdl_data + socketStruct->sdl_nlen, 6);
// Read from char array into a string object, into traditional Mac address format
NSString *macAddressString = [NSString stringWithFormat:#"%02X:%02X:%02X:%02X:%02X:%02X",
macAddress[0], macAddress[1], macAddress[2],
macAddress[3], macAddress[4], macAddress[5]];
NSLog(#"Mac Address: %#", macAddressString);
// Release the buffer memory
free(msgBuffer);
return macAddressString;
}
#end
To get the mac address, you can do
[[UIDevice currentDevice] macAddress]
which returns an NSString *
The compile error you're seeing is the result of a different system headers between IOS and Android. We're working on a more transparent solution, but in the meantime the solution above is an easy workaround.
Often you get this error when the definition of struct if_msghdr is not 'visible'.
Check if you need to #include other header files, or if different conditional compilation options locked it out.
How to find the Mac OSX serial number.
Sometimes it is required to get serial number of a mac, and you validate on that.
I needed the same, few years back, when I developed a plugin for OsiriX. I was asked to release it in such a way, only few systems can use that plugin.
If we get any better solution than this, that will be quite helpful for all of us.
The following code is mainly copied from Technical Note TN1103,
with small modifications to return an NSString and to make it compile with ARC:
#include <IOKit/IOKitLib.h>
- (NSString *)getSerialNumber
{
NSString *serial = nil;
io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault,
IOServiceMatching("IOPlatformExpertDevice"));
if (platformExpert) {
CFTypeRef serialNumberAsCFString =
IORegistryEntryCreateCFProperty(platformExpert,
CFSTR(kIOPlatformSerialNumberKey),
kCFAllocatorDefault, 0);
if (serialNumberAsCFString) {
serial = CFBridgingRelease(serialNumberAsCFString);
}
IOObjectRelease(platformExpert);
}
return serial;
}
You have to add the IOKit.framework to your build settings.
This is the Swift version of the solution:
var serialNumber: String? {
let platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice") )
guard platformExpert > 0 else {
return nil
}
guard let serialNumber = (IORegistryEntryCreateCFProperty(platformExpert, kIOPlatformSerialNumberKey as CFString, kCFAllocatorDefault, 0).takeUnretainedValue() as? String) else {
return nil
}
IOObjectRelease(platformExpert)
return serialNumber
}
This is a C++ version based on the TN1103 that Martin mention above.
C++ example:
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
std::string example_class::getSerialNumber()
{
CFStringRef serial;
char buffer[64] = {0};
std::string seriaNumber("");
io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault,
IOServiceMatching("IOPlatformExpertDevice"));
if (platformExpert)
{
CFTypeRef serialNumberAsCFString = IORegistryEntryCreateCFProperty(platformExpert,
CFSTR(kIOPlatformSerialNumberKey),
kCFAllocatorDefault, 0);
if (serialNumberAsCFString) {
serial = (CFStringRef)serialNumberAsCFString;
}
if (CFStringGetCString(serial, buffer, 64, kCFStringEncodingUTF8)) {
seriaNumber = buffer;
}
IOObjectRelease(platformExpert);
}
return seriaNumber;
}
In my Cocoa application I want to show the user a list of available network interfaces, like Wireshark does:
What is the best way of getting such a list? Does Apple provide a framework for this, or must I use a C API from the standard library or another library?
Better than wrapping ifconfig you shall check the reference of SCNetworkConfiguration which is part of Core Foundation.
Check SCNetworkInterfaceXxx functions for details.
related answer:
Using Cocoa / Objective-C, get currently connected network's security type in Mac OS X
The following code will get all the interfaces from OS X through System Configuration, then use standard C functions to get the IP addresses (where available).
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include <net/if.h>
#define IFT_ETHER 0x6
#include <SystemConfiguration/SCDynamicStore.h>
+(void)getInterfaces
{
SCDynamicStoreRef storeRef = SCDynamicStoreCreate(NULL, (CFStringRef)#"FindCurrentInterfaceIpMac", NULL, NULL);
CFPropertyListRef global = SCDynamicStoreCopyValue (storeRef,CFSTR("State:/Network/Interface"));
id primaryInterface = [(__bridge NSDictionary *)global valueForKey:#"Interfaces"];
for (NSString* item in primaryInterface)
{
if(get_iface_address([item UTF8String]))
{
NSString *ip = [NSString stringWithUTF8String:get_iface_address([item UTF8String])];
NSLog(#"interface: %# - %#",item,ip);
} else
NSLog(#"interface: %#",item);
}
}
static char * get_iface_address (char *interface)
{
int sock;
uint32_t ip;
struct ifreq ifr;
char *val;
if (!interface)
return NULL;
/* determine UDN according to MAC address */
sock = socket (AF_INET, SOCK_STREAM, 0);
if (sock < 0)
{
perror ("socket");
return NULL;
}
strcpy (ifr.ifr_name, interface);
ifr.ifr_addr.sa_family = AF_INET;
if (ioctl (sock, SIOCGIFADDR, &ifr) < 0)
{
perror ("ioctl");
close (sock);
return NULL;
}
val = (char *) malloc (16 * sizeof (char));
ip = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr;
ip = ntohl (ip);
sprintf (val, "%d.%d.%d.%d",
(ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, ip & 0xFF);
close (sock);
return val;
}
#include <SystemConfiguration/SCDynamicStore.h>
SCDynamicStoreRef storeRef = SCDynamicStoreCreate(NULL, (CFStringRef)#"FindCurrentInterfaceIpMac", NULL, NULL);
CFPropertyListRef global = SCDynamicStoreCopyValue (storeRef,CFSTR("State:/Network/Interface"));
id primaryInterface = [(__bridge NSDictionary *)global valueForKey:#"Interfaces"];
for (NSString* item in primaryInterface)
{
NSLog(#"%#", item);
}
Your quickest and best bet is to write a wrapper for ifconfig command.