Reachability.m 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. /*
  2. Copyright (C) 2016 Apple Inc. All Rights Reserved.
  3. See LICENSE.txt for this sample’s licensing information
  4. Abstract:
  5. Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
  6. */
  7. #import <arpa/inet.h>
  8. #import <ifaddrs.h>
  9. #import <netdb.h>
  10. #import <sys/socket.h>
  11. #import <netinet/in.h>
  12. #import <CoreFoundation/CoreFoundation.h>
  13. #import "Reachability.h"
  14. #pragma mark IPv6 Support
  15. //Reachability fully support IPv6. For full details, see ReadMe.md.
  16. NSString *kReachabilityChangedNotification = @"kNetworkReachabilityChangedNotification";
  17. #pragma mark - Supporting functions
  18. #define kShouldPrintReachabilityFlags 1
  19. static void PrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment)
  20. {
  21. #if kShouldPrintReachabilityFlags
  22. HLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n",
  23. (flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-',
  24. (flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-',
  25. (flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-',
  26. (flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-',
  27. (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-',
  28. (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
  29. (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-',
  30. (flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-',
  31. (flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-',
  32. comment
  33. );
  34. #endif
  35. }
  36. static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)
  37. {
  38. #pragma unused (target, flags)
  39. NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback");
  40. NSCAssert([(__bridge NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback");
  41. Reachability* noteObject = (__bridge Reachability *)info;
  42. // Post a notification to notify the client that the network reachability changed.
  43. [[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification object: noteObject];
  44. }
  45. #pragma mark - Reachability implementation
  46. @implementation Reachability
  47. {
  48. SCNetworkReachabilityRef _reachabilityRef;
  49. }
  50. + (instancetype)reachabilityWithHostName:(NSString *)hostName
  51. {
  52. Reachability* returnValue = NULL;
  53. SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
  54. if (reachability != NULL)
  55. {
  56. returnValue= [[self alloc] init];
  57. if (returnValue != NULL)
  58. {
  59. returnValue->_reachabilityRef = reachability;
  60. }
  61. else {
  62. CFRelease(reachability);
  63. }
  64. }
  65. return returnValue;
  66. }
  67. + (instancetype)reachabilityWithAddress:(const struct sockaddr *)hostAddress
  68. {
  69. SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, hostAddress);
  70. Reachability* returnValue = NULL;
  71. if (reachability != NULL)
  72. {
  73. returnValue = [[self alloc] init];
  74. if (returnValue != NULL)
  75. {
  76. returnValue->_reachabilityRef = reachability;
  77. }
  78. else {
  79. CFRelease(reachability);
  80. }
  81. }
  82. return returnValue;
  83. }
  84. + (instancetype)reachabilityForInternetConnection
  85. {
  86. struct sockaddr_in zeroAddress;
  87. bzero(&zeroAddress, sizeof(zeroAddress));
  88. zeroAddress.sin_len = sizeof(zeroAddress);
  89. zeroAddress.sin_family = AF_INET;
  90. return [self reachabilityWithAddress: (const struct sockaddr *) &zeroAddress];
  91. }
  92. #pragma mark reachabilityForLocalWiFi
  93. //reachabilityForLocalWiFi has been removed from the sample. See ReadMe.md for more information.
  94. //+ (instancetype)reachabilityForLocalWiFi
  95. #pragma mark - Start and stop notifier
  96. - (BOOL)startNotifier
  97. {
  98. BOOL returnValue = NO;
  99. SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};
  100. if (SCNetworkReachabilitySetCallback(_reachabilityRef, ReachabilityCallback, &context))
  101. {
  102. if (SCNetworkReachabilityScheduleWithRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode))
  103. {
  104. returnValue = YES;
  105. }
  106. }
  107. return returnValue;
  108. }
  109. - (void)stopNotifier
  110. {
  111. if (_reachabilityRef != NULL)
  112. {
  113. SCNetworkReachabilityUnscheduleFromRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
  114. }
  115. }
  116. - (void)dealloc
  117. {
  118. [self stopNotifier];
  119. if (_reachabilityRef != NULL)
  120. {
  121. CFRelease(_reachabilityRef);
  122. }
  123. }
  124. #pragma mark - Network Flag Handling
  125. - (NetworkStatus)networkStatusForFlags:(SCNetworkReachabilityFlags)flags
  126. {
  127. PrintReachabilityFlags(flags, "networkStatusForFlags");
  128. if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)
  129. {
  130. // The target host is not reachable.
  131. return NotReachable;
  132. }
  133. NetworkStatus returnValue = NotReachable;
  134. if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0)
  135. {
  136. /*
  137. If the target host is reachable and no connection is required then we'll assume (for now) that you're on Wi-Fi...
  138. */
  139. returnValue = ReachableViaWiFi;
  140. }
  141. if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||
  142. (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))
  143. {
  144. /*
  145. ... and the connection is on-demand (or on-traffic) if the calling application is using the CFSocketStream or higher APIs...
  146. */
  147. if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0)
  148. {
  149. /*
  150. ... and no [user] intervention is needed...
  151. */
  152. returnValue = ReachableViaWiFi;
  153. }
  154. }
  155. if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
  156. {
  157. /*
  158. ... but WWAN connections are OK if the calling application is using the CFNetwork APIs.
  159. */
  160. returnValue = ReachableViaWWAN;
  161. }
  162. return returnValue;
  163. }
  164. - (BOOL)connectionRequired
  165. {
  166. NSAssert(_reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef");
  167. SCNetworkReachabilityFlags flags;
  168. if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))
  169. {
  170. return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
  171. }
  172. return NO;
  173. }
  174. - (NetworkStatus)currentReachabilityStatus
  175. {
  176. NSAssert(_reachabilityRef != NULL, @"currentNetworkStatus called with NULL SCNetworkReachabilityRef");
  177. NetworkStatus returnValue = NotReachable;
  178. SCNetworkReachabilityFlags flags;
  179. if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))
  180. {
  181. returnValue = [self networkStatusForFlags:flags];
  182. }
  183. return returnValue;
  184. }
  185. @end