November 28 2009
iPhone Tip: No NSHost
by Brian Dunagan
On the iPhone, I miss NSHost . CocoaTouch does contain a private version of this Cocoa class, but again, it is private. Recently, I needed to resolve a DNS name to an IP address in an iPhone app. It’s a one-liner in Cocoa: [[NSHost hostWithName:@”www.google.com”] address] . Not so on the iPhone without NSHost . So, with a little help from Apple’s CFHostSample sample project and their docs on CFHost , I put together this short snippet.
2010-02-09 Update :
What about the local IP addresses and ethernet MAC addresses? Building off the code from Zach Waugh (developer of QuickPic) , I added two methods for getting the set of IP addresses and ethernet addresses. The wireless connection seems to be en0 , while the cellular connection is pdp_ip0 . Keep in mind that the IP addresses are what the device believes, not what the outside world sees (What Is My IP? ), thanks to NATs.
2010-08-17 Update :
What about names for addresses? Again referencing Apple’s CFHostSample , I added a quick wrapper for CFHostGetNames .
// MIT license
// Remember to add CFNetwork.framework to your project using Add=>Existing Frameworks.
#import "BDHost.h"
#import <CFNetwork/CFNetwork.h>
#import <netinet/in.h>
#import <netdb.h>
#import <ifaddrs.h>
#import <arpa/inet.h>
#import <net/ethernet.h>
#import <net/if_dl.h>
@implementation BDHost
+ ( NSString * ) addressForHostname :( NSString * ) hostname {
NSArray * addresses = [ BDHost addressesForHostname : hostname ];
if ([ addresses count ] > 0 )
return [ addresses objectAtIndex : 0 ];
else
return nil ;
}
+ ( NSArray * ) addressesForHostname :( NSString * ) hostname {
// Get the addresses for the given hostname.
CFHostRef hostRef = CFHostCreateWithName ( kCFAllocatorDefault , ( CFStringRef ) hostname );
BOOL isSuccess = CFHostStartInfoResolution ( hostRef , kCFHostAddresses , nil );
if ( ! isSuccess ) return nil ;
CFArrayRef addressesRef = CFHostGetAddressing ( hostRef , nil );
if ( addressesRef == nil ) return nil ;
// Convert these addresses into strings.
char ipAddress [ INET6_ADDRSTRLEN ];
NSMutableArray * addresses = [ NSMutableArray array ];
CFIndex numAddresses = CFArrayGetCount ( addressesRef );
for ( CFIndex currentIndex = 0 ; currentIndex < numAddresses ; currentIndex ++ ) {
struct sockaddr * address = ( struct sockaddr * ) CFDataGetBytePtr ( CFArrayGetValueAtIndex ( addressesRef , currentIndex ));
if ( address == nil ) return nil ;
getnameinfo ( address , address -> sa_len , ipAddress , INET6_ADDRSTRLEN , nil , 0 , NI_NUMERICHOST );
if ( ipAddress == nil ) return nil ;
[ addresses addObject :[ NSString stringWithCString : ipAddress encoding : NSASCIIStringEncoding ]];
}
return addresses ;
}
+ ( NSString * ) hostnameForAddress :( NSString * ) address {
NSArray * hostnames = [ BDHost hostnamesForAddress : address ];
if ([ hostnames count ] > 0 )
return [ hostnames objectAtIndex : 0 ];
else
return nil ;
}
+ ( NSArray * ) hostnamesForAddress :( NSString * ) address {
// Get the host reference for the given address.
struct addrinfo hints ;
struct addrinfo * result = NULL ;
memset ( & hints , 0 , sizeof ( hints ));
hints . ai_flags = AI_NUMERICHOST ;
hints . ai_family = PF_UNSPEC ;
hints . ai_socktype = SOCK_STREAM ;
hints . ai_protocol = 0 ;
int errorStatus = getaddrinfo ([ address cStringUsingEncoding : NSASCIIStringEncoding ], NULL , & hints , & result );
if ( errorStatus != 0 ) return nil ;
CFDataRef addressRef = CFDataCreate ( NULL , ( UInt8 * ) result -> ai_addr , result -> ai_addrlen );
if ( addressRef == nil ) return nil ;
freeaddrinfo ( result );
CFHostRef hostRef = CFHostCreateWithAddress ( kCFAllocatorDefault , addressRef );
if ( hostRef == nil ) return nil ;
CFRelease ( addressRef );
BOOL isSuccess = CFHostStartInfoResolution ( hostRef , kCFHostNames , NULL );
if ( ! isSuccess ) return nil ;
// Get the hostnames for the host reference.
CFArrayRef hostnamesRef = CFHostGetNames ( hostRef , NULL );
NSMutableArray * hostnames = [ NSMutableArray array ];
for ( int currentIndex = 0 ; currentIndex < [( NSArray * ) hostnamesRef count ]; currentIndex ++ ) {
[ hostnames addObject :[( NSArray * ) hostnamesRef objectAtIndex : currentIndex ]];
}
return hostnames ;
}
+ ( NSArray * ) ipAddresses {
NSMutableArray * addresses = [ NSMutableArray array ];
struct ifaddrs * interfaces = NULL ;
struct ifaddrs * currentAddress = NULL ;
int success = getifaddrs ( & interfaces );
if ( success == 0 ) {
currentAddress = interfaces ;
while ( currentAddress != NULL ) {
if ( currentAddress -> ifa_addr -> sa_family == AF_INET ) {
NSString * address = [ NSString stringWithUTF8String : inet_ntoa ((( struct sockaddr_in * ) currentAddress -> ifa_addr ) -> sin_addr )];
if ( ! [ address isEqual : @"127.0.0.1" ]) {
NSLog ( @"%@ ip: %@" , [ NSString stringWithUTF8String : currentAddress -> ifa_name ], address );
[ addresses addObject : address ];
}
}
currentAddress = currentAddress -> ifa_next ;
}
}
freeifaddrs ( interfaces );
return addresses ;
}
+ ( NSArray * ) ethernetAddresses {
NSMutableArray * addresses = [ NSMutableArray array ];
struct ifaddrs * interfaces = NULL ;
struct ifaddrs * currentAddress = NULL ;
int success = getifaddrs ( & interfaces );
if ( success == 0 ) {
currentAddress = interfaces ;
while ( currentAddress != NULL ) {
if ( currentAddress -> ifa_addr -> sa_family == AF_LINK ) {
NSString * address = [ NSString stringWithUTF8String : ether_ntoa (( const struct ether_addr * ) LLADDR (( struct sockaddr_dl * ) currentAddress -> ifa_addr ))];
// ether_ntoa doesn't format the ethernet address with padding.
char paddedAddress [ 80 ];
int a , b , c , d , e , f ;
sscanf ([ address UTF8String ], "%x:%x:%x:%x:%x:%x" , & a , & b , & c , & d , & e , & f );
sprintf ( paddedAddress , "%02X:%02X:%02X:%02X:%02X:%02X" , a , b , c , d , e , f );
address = [ NSString stringWithUTF8String : paddedAddress ];
if ( ! [ address isEqual : @"00:00:00:00:00:00" ] && ! [ address isEqual : @"00:00:00:00:00:FF" ]) {
NSLog ( @"%@ mac: %@" , [ NSString stringWithUTF8String : currentAddress -> ifa_name ], address );
[ addresses addObject : address ];
}
}
currentAddress = currentAddress -> ifa_next ;
}
}
freeifaddrs ( interfaces );
return addresses ;
}
@end