Add an observer for both AF_INET (IPv4) and AF_INET6 (IPv6) DNS records for connection hosts. Fixes #12632.
authorZachary West <zacw@adium.im>
Sat Oct 24 11:32:51 2009 -0400 (2009-10-24)
changeset 2636f8d77bb2192d
parent 2635 08e3f43120bb
child 2637 b6baa3290a42
Add an observer for both AF_INET (IPv4) and AF_INET6 (IPv6) DNS records for connection hosts. Fixes #12632.

When we're determining reachability, we consult all entries for a host, instead of the one that changed. We only add one observer for each record type.
Frameworks/AIUtilities Framework/Source/AIHostReachabilityMonitor.m
     1.1 --- a/Frameworks/AIUtilities Framework/Source/AIHostReachabilityMonitor.m	Tue Oct 20 23:07:17 2009 -0400
     1.2 +++ b/Frameworks/AIUtilities Framework/Source/AIHostReachabilityMonitor.m	Sat Oct 24 11:32:51 2009 -0400
     1.3 @@ -198,7 +198,7 @@
     1.4   * @param reachability The SCNetworkReachabilityRef for the host which changed
     1.5   * @param isReachable YES if the host is now reachable; NO if it is not reachable
     1.6   */
     1.7 -- (void)reachability:(SCNetworkReachabilityRef)reachability changedToReachable:(BOOL)isReachable
     1.8 +- (void)reachabilityChanged:(SCNetworkReachabilityRef)reachability
     1.9  {
    1.10  	[hostAndObserverListLock lock];
    1.11  
    1.12 @@ -207,7 +207,26 @@
    1.13  		NSString *host = [hosts objectAtIndex:i];
    1.14  		id <AIHostReachabilityObserver> observer = [observers objectAtIndex:i];
    1.15  		
    1.16 -		if (isReachable) {
    1.17 +		BOOL anyHostsReachable = NO;
    1.18 +		
    1.19 +		// If we have multiple host <-> IP links (AAAA record and an A record), we need to check agreement.
    1.20 +		for (NSUInteger index = 0; index < hosts.count; index++) {
    1.21 +			if (![host isEqualToString:[hosts objectAtIndex:index]])
    1.22 +				continue;
    1.23 +			
    1.24 +			SCNetworkReachabilityRef otherReachability = (SCNetworkReachabilityRef)[reachabilities objectAtIndex:index];
    1.25 +			SCNetworkConnectionFlags flags;
    1.26 +
    1.27 +			if (SCNetworkReachabilityGetFlags(otherReachability, &flags)
    1.28 +				&& (flags & kSCNetworkFlagsReachable)
    1.29 +				&& !(flags & kSCNetworkFlagsConnectionRequired)) {
    1.30 +				anyHostsReachable = YES;
    1.31 +				break;
    1.32 +			}
    1.33 +		}
    1.34 +		
    1.35 +		// Return reachability based on any reachability response.
    1.36 +		if (anyHostsReachable) {
    1.37  			[observer hostReachabilityMonitor:self hostIsReachable:host];
    1.38  		} else {
    1.39  			[observer hostReachabilityMonitor:self hostIsNotReachable:host];
    1.40 @@ -224,9 +243,6 @@
    1.41   */
    1.42  static void hostReachabilityChangedCallback(SCNetworkReachabilityRef target, SCNetworkConnectionFlags flags, void *info)
    1.43  {
    1.44 -	BOOL reachable =  (flags & kSCNetworkFlagsReachable)			&&
    1.45 -					 !(flags & kSCNetworkFlagsConnectionRequired);
    1.46 -
    1.47  #if CONNECTIVITY_DEBUG
    1.48  	NSLog(@"*** hostReachabilityChangedCallback got flags: %c%c%c%c%c%c%c \n",  
    1.49   	      (flags & kSCNetworkFlagsTransientConnection)  ? 't' : '-',  
    1.50 @@ -237,9 +253,9 @@
    1.51   	      (flags & kSCNetworkFlagsIsLocalAddress)       ? 'l' : '-',  
    1.52   	      (flags & kSCNetworkFlagsIsDirect)             ? 'd' : '-');
    1.53  #endif
    1.54 -
    1.55 +	
    1.56  	AIHostReachabilityMonitor *self = info;
    1.57 -	[self reachability:target changedToReachable:reachable];
    1.58 +	[self reachabilityChanged:target];
    1.59  }
    1.60  
    1.61  /*
    1.62 @@ -255,8 +271,34 @@
    1.63  	NSString					*host = [infoDict objectForKey:@"host"];
    1.64  
    1.65  	if (typeInfo == kCFHostAddresses) {
    1.66 +		//CFHostGetAddressing returns a CFArrayRef of CFDataRefs which wrap struct sockaddr
    1.67  		CFArrayRef addresses = CFHostGetAddressing(theHost, NULL);
    1.68 -		if (addresses && CFArrayGetCount(addresses)) {
    1.69 +		
    1.70 +		if (!CFArrayGetCount(addresses)) {
    1.71 +			/* We were not able to resolve the host name to an IP address.  This is most likely because we have no
    1.72 +			 * Internet connection or because the user is attempting to connect to MSN.
    1.73 +			 *
    1.74 +			 * Add to unconfiguredHostsAndObservers so we can try configuring again later.
    1.75 +			 */
    1.76 +			[self addUnconfiguredHost:host
    1.77 +							 observer:observer];
    1.78 +		}
    1.79 +		
    1.80 +		// Only add 1 observer for IPv6 and one for IPv4.
    1.81 +		BOOL addedIPv4 = NO, addedIPv6 = NO;
    1.82 +		
    1.83 +		for (NSData *saData in (NSArray *)addresses) {
    1.84 +			struct sockaddr							*remoteAddr = (struct sockaddr *)saData.bytes;
    1.85 +			
    1.86 +			if ((remoteAddr->sa_family == AF_INET && addedIPv4) || (remoteAddr->sa_family == AF_INET6 && addedIPv6)) {
    1.87 +				continue;
    1.88 +			}
    1.89 +			
    1.90 +			if (remoteAddr->sa_family == AF_INET)
    1.91 +				addedIPv4 = YES;
    1.92 +			if (remoteAddr->sa_family == AF_INET6)
    1.93 +				addedIPv6 = YES;
    1.94 +						
    1.95  			SCNetworkReachabilityRef		reachabilityRef;
    1.96  			SCNetworkReachabilityContext	reachabilityContext = {
    1.97  				.version         = 0,
    1.98 @@ -267,7 +309,6 @@
    1.99  			};
   1.100  			SCNetworkConnectionFlags				flags;
   1.101  			struct sockaddr_in						localAddr;
   1.102 -			struct sockaddr							*remoteAddr;
   1.103  			
   1.104  			/* Create a reachability reference pair with localhost and the remote host */
   1.105  			
   1.106 @@ -277,10 +318,6 @@
   1.107  			localAddr.sin_family = AF_INET;
   1.108  			inet_aton("127.0.0.1", &localAddr.sin_addr);
   1.109  			
   1.110 -			//CFHostGetAddressing returns a CFArrayRef of CFDataRefs which wrap struct sockaddr
   1.111 -			CFDataRef saData = (CFDataRef)CFArrayGetValueAtIndex(addresses, 0);
   1.112 -			remoteAddr = (struct sockaddr *)CFDataGetBytePtr(saData);
   1.113 -			
   1.114  			//Create the pair
   1.115  			reachabilityRef = SCNetworkReachabilityCreateWithAddressPair(NULL, 
   1.116  																		 (struct sockaddr *)&localAddr, 
   1.117 @@ -303,9 +340,9 @@
   1.118  
   1.119  			if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
   1.120  				//We already have valid flags for the reachabilityRef
   1.121 -#if CONNECTIVITY_DEBUG
   1.122 +		#if CONNECTIVITY_DEBUG
   1.123  				NSLog(@"Immediate reachability info for %@", reachabilityRef);
   1.124 -#endif
   1.125 +		#endif
   1.126  				hostReachabilityChangedCallback(reachabilityRef,
   1.127  												flags,
   1.128  												self);
   1.129 @@ -335,14 +372,6 @@
   1.130  										  NULL);
   1.131  			}
   1.132  
   1.133 -		} else {
   1.134 -			/* We were not able to resolve the host name to an IP address.  This is most likely because we have no
   1.135 -			* Internet connection or because the user is attempting to connect to MSN.
   1.136 -			*
   1.137 -			* Add to unconfiguredHostsAndObservers so we can try configuring again later.
   1.138 -			*/
   1.139 -			[self addUnconfiguredHost:host
   1.140 -							 observer:observer];
   1.141  		}
   1.142  		
   1.143  	} else if (typeInfo == kCFHostReachability) {