Get All of Mac's IP Addresses Using Objective-C - objective-c

I'm trying to get all of my Mac's IP addresses (IPv4 + IPv6) but am not seeing the results I expect. I'm using code from this Stack Overflow post to get an array of all IP addresses, but there's an IP address missing.
I'm using another Mac to share it's internet connection and create a NAT64 network per Apple's documentation for testing/supporting IPv6 networks.
For example here's what the System Preferences → Network pane says my IP address is:
... but I see that I actually have two IPv6 addresses upon further inspection:
... but only one of these is returned:
"169.254.38.213",
"2001:2:0:aab1:d0ef:646d:f22a:5d83",
"127.0.0.1"
... when using this:
#include <ifaddrs.h>
#include <arpa/inet.h>
#include <net/if.h>
#interface AppDelegate ()
#define IP_ADDR_IPv4 #"ipv4"
#define IP_ADDR_IPv6 #"ipv6"
#end
#implementation AppDelegate
- (void) applicationDidFinishLaunching: (NSNotification *) aNotification
{
NSMutableDictionary *addresses = [NSMutableDictionary dictionaryWithCapacity:8];
NSMutableArray *ipAddressesArray = [[NSMutableArray alloc] init];
// retrieve the current interfaces - returns 0 on success
struct ifaddrs *interfaces;
if (!getifaddrs(&interfaces))
{
// Loop through linked list of interfaces
struct ifaddrs *interface;
for (interface=interfaces; interface; interface=interface->ifa_next)
{
if (!(interface->ifa_flags & IFF_UP) /* || (interface->ifa_flags & IFF_LOOPBACK) */)
{
continue; // deeply nested code harder to read
}
const struct sockaddr_in *addr = (const struct sockaddr_in*)interface->ifa_addr;
char addrBuf[ MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) ];
if (addr && (addr->sin_family==AF_INET || addr->sin_family==AF_INET6))
{
NSString *name = [NSString stringWithUTF8String:interface->ifa_name];
NSString *type;
if (addr->sin_family == AF_INET)
{
if (inet_ntop(AF_INET, &addr->sin_addr, addrBuf, INET_ADDRSTRLEN))
{
type = IP_ADDR_IPv4;
}
}
else
{
const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6*)interface->ifa_addr;
if (inet_ntop(AF_INET6, &addr6->sin6_addr, addrBuf, INET6_ADDRSTRLEN))
{
type = IP_ADDR_IPv6;
}
}
if (type)
{
NSString *key = [NSString stringWithFormat:#"%#/%#", name, type];
addresses[key] = [NSString stringWithUTF8String:addrBuf];
}
}
}
for (id key in addresses)
{
if (![[addresses valueForKey:key] hasPrefix:#"fe80"])
{
[ipAddressesArray addObject:[addresses valueForKey:key]];
}
}
// Free memory
freeifaddrs(interfaces);
}
NSLog(#"%#", ipAddressesArray);
}
Any idea what is going on here? Does it matter? I'm trying to execute some other code conditionally based on IP address matching. It'd be one thing if the only IPv6 address returned was the one displayed to the user in System Preferences when first opening the Network pane, but instead the only IPv6 address returned is the "hidden" one that you have to dig into the Advanced... section to find. Thank you in advance.

The answer here is that I am an idiot. As suggested by Rob Napier in their comment on my question, I was essentially filtering out the missing IP addresses:
NSString *key = [NSString stringWithFormat:#"%#/%#", name, type];
addresses[key] = [NSString stringWithUTF8String:addrBuf];
Each interface can have more than one IP address, but I since I was using the interface type as the unique key in my addresses dictionary, only one IP address per interface was present in the dictionary. I fixed this by returning an array of dictionaries rather than a single dictionary:
if (![[NSString stringWithFormat:#"%s", addrBuf] hasPrefix:#"fe80"])
{
NSDictionary *addressDict = [NSDictionary dictionaryWithObjectsAndKeys :
[NSString stringWithFormat:#"%#/%#", name, type], #"Interface",
[NSString stringWithFormat:#"%s", addrBuf], #"Address",
nil];
[addresses addObject:addressDict];
}
return addresses;

Related

How to parse and take only this string value

I wanted to get only array string value app. As example(SLGoogleAuth ,HalfTunes,TheBackgrounder,Calculiator) . But don't know how to do?
It's a code.
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//
Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace");
SEL selector=NSSelectorFromString(#"defaultWorkspace");
NSObject* workspace = [LSApplicationWorkspace_class performSelector:selector];
SEL selectorALL = NSSelectorFromString(#"allApplications");
NSLog(#"apps: %#", [workspace performSelector:selectorALL]);
}
It's output:
Thanks in advance
You do not want to parse that. NSLog prints out a description of an object. You want to access that value directly.
[LSApplicationWorkspace allApplications];
returns NSArray of LSApplicationProxy. LSApplicationProxy class has a ivar _bundleURL that contains information that you need. You need runtime functions to access it. Working example below:
// #import <objc/runtime.h>
Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace");
SEL selector=NSSelectorFromString(#"defaultWorkspace");
NSObject* workspace = [LSApplicationWorkspace_class performSelector:selector];
SEL selectorALL = NSSelectorFromString(#"allApplications");
NSArray* appProxies = [workspace performSelector:selectorALL];
Ivar bundleUrlIvar = class_getInstanceVariable([appProxies.firstObject class], "_bundleURL");
NSMutableString* result = [NSMutableString string];
for (id appProxy in appProxies)
{
NSURL* url = object_getIvar(appProxy, bundleUrlIvar);
// at this point you have the information and you can do whatever you want with it
// I will make it a list as you asked
if (url)
{
[result appendFormat:#",%#", [url lastPathComponent]];
}
}
if (result.length > 0)
{
// remove comma from beginning of the list
[result deleteCharactersInRange:NSMakeRange(0, 1)];
}
NSLog(#"apps: %#", result);
Note that this will be rejected by AppStore as you are using private apis. So use at your own discretion.

How to store blocks in Objective C?

I started writing a simple JSON RPC TCP library in Objective C.
I have a method that invokes a RPC Method:
- (void)invokeMethod:(NSString *)method
withParameters:(id)parameters
requestId:(id)requestId
success:(void (^)(id responseObject))success
failure:(void (^)(NSError *error))failure
{
NSAssert(NSClassFromString(#"NSJSONSerialization"), #"NSJSONSerialization not found!");
NSDictionary *requestObject = #{#"jsonrpc": #"2.0",
#"method": method,
#"params": parameters,
#"id": requestId};
NSError *error = nil;
NSData *jsondData = [NSJSONSerialization dataWithJSONObject:requestObject options:0 error:&error];
if (error){
return failure(error);
}
[self->callbacks setObject:#{#"success": success ? [success copy] : [NSNull null],
#"failure": failure ? [failure copy] : [NSNull null]}
forKey:requestId];
NSString *str = [[NSString alloc] initWithData:jsondData encoding:NSUTF8StringEncoding];
NSLog(#"Sending: %#", str);
[self.socket writeData:jsondData withTimeout:-1 tag:1];
}
The class basically represents a TCP connection, when calling the above method, the JSON data is sent with an id over TCP to the server which either returns a success or a failure:
- (void) socket:(GCDAsyncSocket *)sender didReadData:(NSData *)data withTag:(long)tag
{
NSError *error = nil;
[self.socket readDataWithTimeout:-1 tag:2];
// … rpc response parsing code here, removed for simplicity …
// detect if error or success
NSDictionary *cbs = [self->callbacks objectForKey:JSONRPCObjectId];
void(^success)(id resultObject) = [cbs objectForKey:#"success"];
success ? success(JSONRPCObjectResult) : nil;
return;
}
Now, I am unsure how to keep track of the success and failure blocks, currently I am storing them in an NSMutableDict, using the requestId as key. Is it fine to do this or is there a better approach that I should use?
Blocks in objective-c are objects and you can treat the same way as other object, so storing them in NSDictionarys, NSArrays etc is perfectly fine. The only catch is that blocks when initially created exist in the same memory scope as local variable do and so they are no longer valid when the method that the block is defined in returns, just like all other local variables so you have to copy them first, just copy them and put the copy in the collection. There is a block copy function but you can just send them a copy message [myBlock copy];
Quick answer, seeing as you don't have anything workable yet...
This is more than you asked for; so, you'll probably have to pair it down to meet your specific need. Basically, it stores as many blocks as you specify at contiguous memory addresses. Paste this into a header file or somewhere global to the method from which you will call these:
typedef const typeof(id(^)(void)) retained_object;
static id (^retainable_object)(id(^)(void)) = ^ id (id(^object)(void)) {
return ^{
return object();
};
};
typeof (retained_object) *(^(^retain_object)(id (^__strong)(void)))(void) = ^ (id(^retainable_object)(void)) {
typeof(retained_object) * object_address;
object_address = &retainable_object;
typeof(retained_object) * persistent_object = (typeof(retained_object) *)CFBridgingRetain(retainable_object);
return ^ typeof(retained_object) * {
return persistent_object;
};
};
static void (^(^iterator)(const unsigned long))(id(^)(void)) = ^ (const unsigned long object_count) {
id const * retained_objects_ref[object_count];
return ^ (id const * retained_objects_t[]) {
return ^ (id(^object)(void)) {
object();
int index = 0UL;
int * index_t = &index;
for (; (*index_t) < object_count; ((*index_t) = (*index_t) + 1UL)) printf("retained_object: %p\n", (*((id * const)retained_objects_t + (object_count - index)) = retain_object(retainable_object(object()))));
};
}(retained_objects_ref);
};
From some method, add:
iterator(1000)(^ id { return (^{ printf("stored block\n"); }); });
This should store 1,000 blocks at as many unique memory addresses.

UILabel Address label is blank and Local Declaration hides instance variable

I am new to Xcode, and I am attempting to have my app access the Address Book, choose a person, and then create NSString values for the person (First Name, Last Name, Organization, Address, Email and Telephone Number) I can pull the first and last name, the organization, the first email entered (it would be nice to display all of the email address, and let the user choose), and the first phone number entered in (again, it would be nice to be able to choose), but the address for the person is always blank. I would really appreciate any help you can provide. In addition, I keep getting local declaration hides instance variable warnings - I have no idea how to resolve these.
#import "TACustomer.h"
#interface TACustomer ()
#end
#implementation TACustomer
#synthesize custfirstName;
#synthesize custlastName;
#synthesize custOrganization;
#synthesize custEmail;
#synthesize custAddress;
#synthesize custphoneNumber;
- (IBAction)showPicker:(id)sender
{
// Creating the Address Book Picker
ABPeoplePickerNavigationController *picker = [[ABPeoplePickerNavigationController alloc] init];
// Place the delegate of the picker to the control.
picker.peoplePickerDelegate = self;
// Showing the picker.
[self presentModalViewController:picker animated:YES];
}
- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker
{
//assigning control back to the main controller.
[self dismissModalViewControllerAnimated:YES];
}
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person
{
[self displayPerson:person];
[self dismissModalViewControllerAnimated:YES];
return NO;
}
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person
property:(ABPropertyID)property
identifier:(ABMultiValueIdentifier)identifier
{
// Only inspect the value if it's an address.
if (property == kABPersonAddressProperty)
{
//Set up an ABMultiValue to hold the address values; copy from a book record.
ABMutableMultiValueRef multicustValue = ABRecordCopyValue(person, property);
// Set up an NSArray and copy values into it.
NSArray *thecustArray = (__bridge id)ABMultiValueCopyArrayOfAllValues(multicustValue);
// Figure out which values we want and store the index.
const NSUInteger customerIndex = ABMultiValueGetIndexForIdentifier (multicustValue, identifier);
// Set up an NSDictionary to hold the contents of the array.
NSDictionary *custDict = [thecustArray objectAtIndex:customerIndex];
// Set up NSStrings to hold the keys and values. First, how many are there?
const NSUInteger theCount = [custDict count];
NSString * __unsafe_unretained keys[theCount];
NSString *__unsafe_unretained values[theCount];
// Get the keys and values from the CFDictionary.
[custDict getObjects:values andKeys:keys];
// Set the address label's text.
NSString *customeraddress;
customeraddress = [NSString stringWithFormat:#"%#, %#, %#, %#, %#",
[custDict objectForKey:(NSString *)kABPersonAddressStreetKey],
[custDict objectForKey:(NSString *)kABPersonAddressCityKey],
[custDict objectForKey:(NSString *)kABPersonAddressStateKey],
[custDict objectForKey:(NSString *)kABPersonAddressZIPKey],
[custDict objectForKey:(NSString *)kABPersonAddressCountryKey]];
self.custAddress.text = customeraddress;
}
return NO;
}
- (void)displayPerson:(ABRecordRef)person
{
// Get Customer First Name
NSString* custfirstname = (__bridge_transfer NSString*)ABRecordCopyValue(person,kABPersonFirstNameProperty);
self.custfirstName.text = custfirstname;
// Get Customer Last Name
NSString* custlastname = (__bridge_transfer NSString*)ABRecordCopyValue(person,kABPersonLastNameProperty);
self.custlastName.text = custlastname;
// Get Customer Organization
NSString* custorganization = (__bridge_transfer NSString*)ABRecordCopyValue(person,kABPersonOrganizationProperty);
self.custOrganization.text = custorganization;
//Get Customer Email Address
NSString* custemail = nil;
ABMultiValueRef custemailAddresses = ABRecordCopyValue (person,kABPersonEmailProperty);
if (ABMultiValueGetCount(custemailAddresses) > 0)
{
custemail = (__bridge_transfer NSString*)ABMultiValueCopyValueAtIndex(custemailAddresses, 0);
} else
{
custemail = #"[None]";
}
self.custEmail.text = custemail;
CFRelease(custemailAddresses);
// Get Customer Phone Number
NSString* custphone = nil;
ABMultiValueRef phoneNumbers = ABRecordCopyValue (person,kABPersonPhoneProperty);
if (ABMultiValueGetCount(phoneNumbers) > 0)
{
custphone = (__bridge_transfer NSString*)ABMultiValueCopyValueAtIndex(phoneNumbers, 0);
} else
{
custphone = #"[None]";
}
self.custphoneNumber.text = custphone;
CFRelease(phoneNumbers);
bundle:nil;
//[self.navigationController pushViewController:tempExamInfoView animated:YES];
}
#end
I have no answer for the problem that the address data is blank.
To get rid of the "local declaration hides instance variable" warning you need to use different variable names that do not clash with the names of the properties you are synthesizing.
For instance, in displayPerson: you have a local variable custfirstname. Because this uses the same name as a property, the local variable hides the instance variable of the same name that is being synthesized.
If you want to keep the local variable name, I believe it is also possible to tell #synthesize to use a different name for the instance variable that it generates. I am not familiar with the syntax, so if you want to go that way you have to look it up yourself.

Obtaining a server IP address from hostname

When performing an NSURLRequest to a hostname, is it possible to obtain the IP address of the server that the response came from?
The NSURL method:
- (NSString *)host;
simply returns the hostname, and I see no way of obtaining the IP address from any of the other NSURL methods.
Perhaps there is a way of performing a host lookup before inititing the NSURLRequest?
You can use the system call gethostbyname() to resolve a hostname then use the returning structure to get the ip address. Have a look at inet_ntop() for this last part.
EXAMPLE CODE
struct hostent *hostentry;
hostentry = gethostbyname("google.com");
char * ipbuf;
ipbuf = inet_ntoa(*((struct in_addr *)hostentry->h_addr_list[0]));
printf("%s",ipbuf);
I was asking a question regarding
"how to get IP from hostname in unix\linux?"
but found this question in a different context which is not for Unix I guess, let me correct if I am wrong
since this question already been asked so I am fearing to avoid asking the same question marked as duplicated by stack overflow team.
Quest: how to get IP from hostname in unix\linux?
Ans: the two commands over there
ping host_name
Ex:
ping -s google.co.in
PING google.co.in: 56 data bytes
64 bytes from dfw06s48-in-f3.1e100.net (216.58.194.99): icmp_seq=0. time=2.477 ms
64 bytes from dfw06s48-in-f3.1e100.net (216.58.194.99): icmp_seq=1. time=1.415 ms
64 bytes from dfw06s48-in-f3.1e100.net (216.58.194.99): icmp_seq=2. time=1.712 ms
nslookup host_name
Ex:
nslookup google.co.in
Server: 155.179.59.249
Address: 155.179.59.249#53
Non-authoritative answer:
Name: google.co.in
Address: 216.58.194.99
#import <arpa/inet.h>
- (BOOL)resolveHost:(NSString *)hostname {
Boolean result;
CFHostRef hostRef;
CFArrayRef addresses;
NSString *ipAddress = nil;
hostRef = CFHostCreateWithName(kCFAllocatorDefault, (__bridge
CFStringRef)hostname);
CFStreamError *error = NULL;
if (hostRef) {
result = CFHostStartInfoResolution(hostRef, kCFHostAddresses, error);
if (result) {
addresses = CFHostGetAddressing(hostRef, &result);
}
}
if (result) {
CFIndex index = 0;
CFDataRef ref = (CFDataRef) CFArrayGetValueAtIndex(addresses, index);
int port=0;
struct sockaddr *addressGeneric;
NSData *myData = (__bridge NSData *)ref;
addressGeneric = (struct sockaddr *)[myData bytes];
switch (addressGeneric->sa_family) {
case AF_INET: {
struct sockaddr_in *ip4;
char dest[INET_ADDRSTRLEN];
ip4 = (struct sockaddr_in *)[myData bytes];
port = ntohs(ip4->sin_port);
ipAddress = [NSString stringWithFormat:#"%s", inet_ntop(AF_INET, &ip4->sin_addr, dest, sizeof dest)];
}
break;
case AF_INET6: {
struct sockaddr_in6 *ip6;
char dest[INET6_ADDRSTRLEN];
ip6 = (struct sockaddr_in6 *)[myData bytes];
port = ntohs(ip6->sin6_port);
ipAddress = [NSString stringWithFormat:#"%s", inet_ntop(AF_INET6, &ip6->sin6_addr, dest, sizeof dest)];
}
break;
default:
ipAddress = nil;
break;
}
}
NSLog(#"%#", ipAddress);
if (ipAddress) {
return YES;
} else {
return NO;
}
}
[self resolveHost:#"google.com"]

Anyway to get string from variable name?

Say I have my class
#interface Person : NSObject { NSString *name; }
I need to get the name of NSString's within my class
Person *person = [[Person alloc] init];
NSLog(#"Name of variable %s\n", _NameofVariable_(person->name));
Thanks for the answers, here's the solution I came up from the replies
//returns nil if property is not found
-(NSString *)propertyName:(id)property {
unsigned int numIvars = 0;
NSString *key=nil;
Ivar * ivars = class_copyIvarList([self class], &numIvars);
for(int i = 0; i < numIvars; i++) {
Ivar thisIvar = ivars[i];
if ((object_getIvar(self, thisIvar) == property)) {
key = [NSString stringWithUTF8String:ivar_getName(thisIvar)];
break;
}
}
free(ivars);
return key;
}
As easy as
#define VariableName(arg) (#""#arg)
Then you do:
NSObject *obj;
NSString *str = VariableName(obj);
NSLog(#"STR %#", str);//obj
You can get the names of a class's instance variables with the Objective-C runtime API function class_copyIvarList. However, this is rather involved, rarely done and almost never the best way to accomplish something. If you have a more specific goal in mind than mere curiosity, it might be a good idea to ask about how to accomplish it in Objective-C.
Also, incidentally, person.name doesn't specify an instance variable in Objective-C — it's a property call. The instance variable would be person->name.
You might use preprocessor stringification and a bit of string twiddling:
NSUInteger lastIndexAfter(NSUInteger start, NSString *sub, NSString *str) {
NSRange found = [str rangeOfString:sub options:NSBackwardsSearch];
if(found.location != NSNotFound) {
NSUInteger newStart = NSMaxRange(found);
if(newStart > start)
return newStart;
}
return start;
}
NSString *lastMember(NSString *fullName) {
if(!fullName) return nil;
NSUInteger start = 0;
start = lastIndexAfter(start, #".", fullName);
start = lastIndexAfter(start, #"->", fullName);
return [fullName substringFromIndex: start];
}
#define NSStringify(v) (##v)
#define _NameofVariable_(v) lastMember(NSStringify(v))
If the person object is exposed as a property of the class, you can use objc_msgSend to get the value.
So, if you could access person using
[object person]
You could also do
objc_msgSend(object, "person")
For more details on message sending, including how to pass arguments to methods, see the Objective-C Runtime Programming Guide section on Messaging
The following works as a macro:
#define STRINGIZE(x) #x