OSSReachability.m 6.6 KB

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