]>
Commit | Line | Data |
---|---|---|
d56a0c9b GP |
1 | /* |
2 | ||
3 | File: Reachability.m | |
4 | Abstract: Basic demonstration of how to use the SystemConfiguration Reachablity APIs. | |
5 | ||
6 | Version: 2.2 | |
7 | ||
8 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. | |
9 | ("Apple") in consideration of your agreement to the following terms, and your | |
10 | use, installation, modification or redistribution of this Apple software | |
11 | constitutes acceptance of these terms. If you do not agree with these terms, | |
12 | please do not use, install, modify or redistribute this Apple software. | |
13 | ||
14 | In consideration of your agreement to abide by the following terms, and subject | |
15 | to these terms, Apple grants you a personal, non-exclusive license, under | |
16 | Apple's copyrights in this original Apple software (the "Apple Software"), to | |
17 | use, reproduce, modify and redistribute the Apple Software, with or without | |
18 | modifications, in source and/or binary forms; provided that if you redistribute | |
19 | the Apple Software in its entirety and without modifications, you must retain | |
20 | this notice and the following text and disclaimers in all such redistributions | |
21 | of the Apple Software. | |
22 | Neither the name, trademarks, service marks or logos of Apple Inc. may be used | |
23 | to endorse or promote products derived from the Apple Software without specific | |
24 | prior written permission from Apple. Except as expressly stated in this notice, | |
25 | no other rights or licenses, express or implied, are granted by Apple herein, | |
26 | including but not limited to any patent rights that may be infringed by your | |
27 | derivative works or by other works in which the Apple Software may be | |
28 | incorporated. | |
29 | ||
30 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO | |
31 | WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED | |
32 | WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
33 | PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN | |
34 | COMBINATION WITH YOUR PRODUCTS. | |
35 | ||
36 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR | |
37 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | |
38 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
39 | ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR | |
40 | DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF | |
41 | CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF | |
42 | APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
43 | ||
44 | Copyright (C) 2010 Apple Inc. All Rights Reserved. | |
45 | ||
46 | */ | |
47 | ||
48 | #import <sys/socket.h> | |
49 | #import <netinet/in.h> | |
50 | #import <netinet6/in6.h> | |
51 | #import <arpa/inet.h> | |
52 | #import <ifaddrs.h> | |
53 | #import <netdb.h> | |
54 | ||
55 | #import <CoreFoundation/CoreFoundation.h> | |
56 | ||
57 | #import "Reachability.h" | |
58 | ||
59 | #define kShouldPrintReachabilityFlags 1 | |
60 | ||
61 | static void PrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment) | |
62 | { | |
63 | #if kShouldPrintReachabilityFlags | |
64 | ||
65 | NSLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n", | |
66 | (flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-', | |
67 | (flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-', | |
68 | ||
69 | (flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-', | |
70 | (flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-', | |
71 | (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-', | |
72 | (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-', | |
73 | (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-', | |
74 | (flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-', | |
75 | (flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-', | |
76 | comment | |
77 | ); | |
78 | #endif | |
79 | } | |
80 | ||
81 | ||
82 | @implementation Reachability | |
83 | static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info) | |
84 | { | |
85 | #pragma unused (target, flags) | |
86 | NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback"); | |
87 | NSCAssert([(NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback"); | |
88 | ||
89 | //We're on the main RunLoop, so an NSAutoreleasePool is not necessary, but is added defensively | |
90 | // in case someon uses the Reachablity object in a different thread. | |
91 | NSAutoreleasePool* myPool = [[NSAutoreleasePool alloc] init]; | |
92 | ||
93 | Reachability* noteObject = (Reachability*) info; | |
94 | // Post a notification to notify the client that the network reachability changed. | |
95 | [[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification object: noteObject]; | |
96 | ||
97 | [myPool release]; | |
98 | } | |
99 | ||
100 | - (BOOL) startNotifier | |
101 | { | |
102 | BOOL retVal = NO; | |
103 | SCNetworkReachabilityContext context = {0, self, NULL, NULL, NULL}; | |
104 | if(SCNetworkReachabilitySetCallback(reachabilityRef, ReachabilityCallback, &context)) | |
105 | { | |
106 | if(SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) | |
107 | { | |
108 | retVal = YES; | |
109 | } | |
110 | } | |
111 | return retVal; | |
112 | } | |
113 | ||
114 | - (void) stopNotifier | |
115 | { | |
116 | if(reachabilityRef!= NULL) | |
117 | { | |
118 | SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); | |
119 | } | |
120 | } | |
121 | ||
122 | - (void) dealloc | |
123 | { | |
124 | [self stopNotifier]; | |
125 | if(reachabilityRef!= NULL) | |
126 | { | |
127 | CFRelease(reachabilityRef); | |
128 | } | |
129 | [super dealloc]; | |
130 | } | |
131 | ||
132 | + (Reachability*) reachabilityWithHostName: (NSString*) hostName; | |
133 | { | |
134 | Reachability* retVal = NULL; | |
135 | SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]); | |
136 | if(reachability!= NULL) | |
137 | { | |
138 | retVal= [[[self alloc] init] autorelease]; | |
139 | if(retVal!= NULL) | |
140 | { | |
141 | retVal->reachabilityRef = reachability; | |
142 | retVal->localWiFiRef = NO; | |
143 | } | |
144 | } | |
145 | return retVal; | |
146 | } | |
147 | ||
148 | + (Reachability*) reachabilityWithAddress: (const struct sockaddr_in*) hostAddress; | |
149 | { | |
150 | SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress); | |
151 | Reachability* retVal = NULL; | |
152 | if(reachability!= NULL) | |
153 | { | |
154 | retVal= [[[self alloc] init] autorelease]; | |
155 | if(retVal!= NULL) | |
156 | { | |
157 | retVal->reachabilityRef = reachability; | |
158 | retVal->localWiFiRef = NO; | |
159 | } | |
160 | } | |
161 | return retVal; | |
162 | } | |
163 | ||
164 | + (Reachability*) reachabilityForInternetConnection; | |
165 | { | |
166 | struct sockaddr_in zeroAddress; | |
167 | bzero(&zeroAddress, sizeof(zeroAddress)); | |
168 | zeroAddress.sin_len = sizeof(zeroAddress); | |
169 | zeroAddress.sin_family = AF_INET; | |
170 | return [self reachabilityWithAddress: &zeroAddress]; | |
171 | } | |
172 | ||
173 | + (Reachability*) reachabilityForLocalWiFi; | |
174 | { | |
175 | struct sockaddr_in localWifiAddress; | |
176 | bzero(&localWifiAddress, sizeof(localWifiAddress)); | |
177 | localWifiAddress.sin_len = sizeof(localWifiAddress); | |
178 | localWifiAddress.sin_family = AF_INET; | |
179 | // IN_LINKLOCALNETNUM is defined in <netinet/in.h> as 169.254.0.0 | |
180 | localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM); | |
181 | Reachability* retVal = [self reachabilityWithAddress: &localWifiAddress]; | |
182 | if(retVal!= NULL) | |
183 | { | |
184 | retVal->localWiFiRef = YES; | |
185 | } | |
186 | return retVal; | |
187 | } | |
188 | ||
189 | #pragma mark Network Flag Handling | |
190 | ||
191 | - (NetworkStatus) localWiFiStatusForFlags: (SCNetworkReachabilityFlags) flags | |
192 | { | |
193 | PrintReachabilityFlags(flags, "localWiFiStatusForFlags"); | |
194 | ||
195 | BOOL retVal = NotReachable; | |
196 | if((flags & kSCNetworkReachabilityFlagsReachable) && (flags & kSCNetworkReachabilityFlagsIsDirect)) | |
197 | { | |
198 | retVal = ReachableViaWiFi; | |
199 | } | |
200 | return retVal; | |
201 | } | |
202 | ||
203 | - (NetworkStatus) networkStatusForFlags: (SCNetworkReachabilityFlags) flags | |
204 | { | |
205 | PrintReachabilityFlags(flags, "networkStatusForFlags"); | |
206 | if ((flags & kSCNetworkReachabilityFlagsReachable) == 0) | |
207 | { | |
208 | // if target host is not reachable | |
209 | return NotReachable; | |
210 | } | |
211 | ||
212 | BOOL retVal = NotReachable; | |
213 | ||
214 | if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0) | |
215 | { | |
216 | // if target host is reachable and no connection is required | |
217 | // then we'll assume (for now) that your on Wi-Fi | |
218 | retVal = ReachableViaWiFi; | |
219 | } | |
220 | ||
221 | ||
222 | if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) || | |
223 | (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0)) | |
224 | { | |
225 | // ... and the connection is on-demand (or on-traffic) if the | |
226 | // calling application is using the CFSocketStream or higher APIs | |
227 | ||
228 | if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0) | |
229 | { | |
230 | // ... and no [user] intervention is needed | |
231 | retVal = ReachableViaWiFi; | |
232 | } | |
233 | } | |
234 | ||
235 | if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN) | |
236 | { | |
237 | // ... but WWAN connections are OK if the calling application | |
238 | // is using the CFNetwork (CFSocketStream?) APIs. | |
239 | retVal = ReachableViaWWAN; | |
240 | } | |
241 | return retVal; | |
242 | } | |
243 | ||
244 | - (BOOL) connectionRequired; | |
245 | { | |
246 | NSAssert(reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef"); | |
247 | SCNetworkReachabilityFlags flags; | |
248 | if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) | |
249 | { | |
250 | return (flags & kSCNetworkReachabilityFlagsConnectionRequired); | |
251 | } | |
252 | return NO; | |
253 | } | |
254 | ||
255 | - (NetworkStatus) currentReachabilityStatus | |
256 | { | |
257 | NSAssert(reachabilityRef != NULL, @"currentNetworkStatus called with NULL reachabilityRef"); | |
258 | NetworkStatus retVal = NotReachable; | |
259 | SCNetworkReachabilityFlags flags; | |
260 | if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) | |
261 | { | |
262 | if(localWiFiRef) | |
263 | { | |
264 | retVal = [self localWiFiStatusForFlags: flags]; | |
265 | } | |
266 | else | |
267 | { | |
268 | retVal = [self networkStatusForFlags: flags]; | |
269 | } | |
270 | } | |
271 | return retVal; | |
272 | } | |
273 | @end |