FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
Reachability.m
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
61static 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' : '-', comment);
76#endif
77}
78
79@implementation Reachability
80static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags,
81 void *info)
82{
83#pragma unused(target, flags)
84 NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback");
85 NSCAssert([(NSObject *)info isKindOfClass:[Reachability class]],
86 @"info was wrong class in ReachabilityCallback");
87
88 // We're on the main RunLoop, so an NSAutoreleasePool is not necessary, but is added defensively
89 // in case someone uses the Reachablity object in a different thread.
90 NSAutoreleasePool *myPool = [[NSAutoreleasePool alloc] init];
91
92 Reachability *noteObject = (Reachability *)info;
93 // Post a notification to notify the client that the network reachability changed.
94 [[NSNotificationCenter defaultCenter] postNotificationName:kReachabilityChangedNotification
95 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(),
107 kCFRunLoopDefaultMode))
108 {
109 retVal = YES;
110 }
111 }
112 return retVal;
113}
114
115- (void)stopNotifier
116{
117 if (reachabilityRef != NULL)
118 {
119 SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef, CFRunLoopGetCurrent(),
120 kCFRunLoopDefaultMode);
121 }
122}
123
124- (void)dealloc
125{
126 [self stopNotifier];
127 if (reachabilityRef != NULL)
128 {
129 CFRelease(reachabilityRef);
130 }
131 [super dealloc];
132}
133
134+ (Reachability *)reachabilityWithHostName:(NSString *)hostName;
135{
136 Reachability *retVal = NULL;
137 SCNetworkReachabilityRef reachability =
138 SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
139 if (reachability != NULL)
140 {
141 retVal = [[[self alloc] init] autorelease];
142 if (retVal != NULL)
143 {
144 retVal->reachabilityRef = reachability;
145 retVal->localWiFiRef = NO;
146 }
147 }
148 return retVal;
149}
150
151+ (Reachability *)reachabilityWithAddress:(const struct sockaddr_in *)hostAddress;
152{
153 SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(
154 kCFAllocatorDefault, (const struct sockaddr *)hostAddress);
155 Reachability *retVal = NULL;
156 if (reachability != NULL)
157 {
158 retVal = [[[self alloc] init] autorelease];
159 if (retVal != NULL)
160 {
161 retVal->reachabilityRef = reachability;
162 retVal->localWiFiRef = NO;
163 }
164 }
165 return retVal;
166}
167
168+ (Reachability *)reachabilityForInternetConnection;
169{
170 struct sockaddr_in zeroAddress;
171 bzero(&zeroAddress, sizeof(zeroAddress));
172 zeroAddress.sin_len = sizeof(zeroAddress);
173 zeroAddress.sin_family = AF_INET;
174 return [self reachabilityWithAddress:&zeroAddress];
175}
176
177+ (Reachability *)reachabilityForLocalWiFi;
178{
179 struct sockaddr_in localWifiAddress;
180 bzero(&localWifiAddress, sizeof(localWifiAddress));
181 localWifiAddress.sin_len = sizeof(localWifiAddress);
182 localWifiAddress.sin_family = AF_INET;
183 // IN_LINKLOCALNETNUM is defined in <netinet/in.h> as 169.254.0.0
184 localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM);
185 Reachability *retVal = [self reachabilityWithAddress:&localWifiAddress];
186 if (retVal != NULL)
187 {
188 retVal->localWiFiRef = YES;
189 }
190 return retVal;
191}
192
193#pragma mark Network Flag Handling
194
195- (NetworkStatus)localWiFiStatusForFlags:(SCNetworkReachabilityFlags)flags
196{
197 PrintReachabilityFlags(flags, "localWiFiStatusForFlags");
198
199 BOOL retVal = NotReachable;
200 if ((flags & kSCNetworkReachabilityFlagsReachable) &&
201 (flags & kSCNetworkReachabilityFlagsIsDirect))
202 {
203 retVal = ReachableViaWiFi;
204 }
205 return retVal;
206}
207
208- (NetworkStatus)networkStatusForFlags:(SCNetworkReachabilityFlags)flags
209{
210 PrintReachabilityFlags(flags, "networkStatusForFlags");
211 if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)
212 {
213 // if target host is not reachable
214 return NotReachable;
215 }
216
217 BOOL retVal = NotReachable;
218
219 if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0)
220 {
221 // if target host is reachable and no connection is required
222 // then we'll assume (for now) that your on Wi-Fi
223 retVal = ReachableViaWiFi;
224 }
225
226 if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand) != 0) ||
227 (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))
228 {
229 // ... and the connection is on-demand (or on-traffic) if the
230 // calling application is using the CFSocketStream or higher APIs
231
232 if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0)
233 {
234 // ... and no [user] intervention is needed
235 retVal = ReachableViaWiFi;
236 }
237 }
238
239 if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
240 {
241 // ... but WWAN connections are OK if the calling application
242 // is using the CFNetwork (CFSocketStream?) APIs.
243 retVal = ReachableViaWWAN;
244 }
245 return retVal;
246}
247
248- (BOOL)connectionRequired;
249{
250 NSAssert(reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef");
251 SCNetworkReachabilityFlags flags;
252 if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
253 {
254 return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
255 }
256 return NO;
257}
258
259- (NetworkStatus)currentReachabilityStatus
260{
261 NSAssert(reachabilityRef != NULL, @"currentNetworkStatus called with NULL reachabilityRef");
262 NetworkStatus retVal = NotReachable;
263 SCNetworkReachabilityFlags flags;
264 if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
265 {
266 if (localWiFiRef)
267 {
268 retVal = [self localWiFiStatusForFlags:flags];
269 }
270 else
271 {
272 retVal = [self networkStatusForFlags:flags];
273 }
274 }
275 return retVal;
276}
277@end