Reachability.m 6.7 KB

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