2 * Copyright (c) 2012 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
27 #include <CoreFoundation/CoreFoundation.h>
28 #include <CFNetwork/CFNetwork.h>
29 #include <SystemConfiguration/SystemConfiguration.h>
31 static SCNetworkReachabilityRef g_reachability
= NULL
;
32 static CFURLRef g_url
= NULL
;
33 static CFReadStreamRef g_rstream
= NULL
;
36 string2CString(CFStringRef str
)
40 CFRange r
= CFRangeMake(0, CFStringGetLength(str
));
42 if (CFStringGetBytes(str
, r
, kCFStringEncodingASCII
, 0, false, NULL
, 0, &clen
) > 0) {
43 buffer
= (UInt8
*)CFAllocatorAllocate(kCFAllocatorDefault
, (clen
+ 1) * sizeof(UInt8
), 0);
46 if (CFStringGetBytes(str
, r
, kCFStringEncodingASCII
, 0, false, buffer
, clen
, NULL
)) {
48 return (char *)buffer
;
50 CFAllocatorDeallocate(kCFAllocatorDefault
, buffer
);
58 printReachabilityFlags(const char *source
, SCNetworkReachabilityFlags flags
)
60 printf("[%s] Reachability flags (%x):\n", source
, flags
);
61 if (flags
& kSCNetworkReachabilityFlagsTransientConnection
) {
62 printf("[%s] transient\n", source
);
64 if (flags
& kSCNetworkReachabilityFlagsReachable
) {
65 printf("[%s] reachable\n", source
);
67 if (flags
& kSCNetworkReachabilityFlagsConnectionRequired
) {
68 printf("[%s] connection required\n", source
);
70 if (flags
& kSCNetworkReachabilityFlagsConnectionOnTraffic
) {
71 printf("[%s] connection on traffic\n", source
);
73 if (flags
& kSCNetworkReachabilityFlagsInterventionRequired
) {
74 printf("[%s] intervention required\n", source
);
76 if (flags
& kSCNetworkReachabilityFlagsConnectionOnDemand
) {
77 printf("[%s] connection on demand\n", source
);
79 if (flags
& kSCNetworkReachabilityFlagsIsLocalAddress
) {
80 printf("[%s] local address\n", source
);
82 if (flags
& kSCNetworkReachabilityFlagsIsDirect
) {
83 printf("[%s] direct\n", source
);
85 #if TARGET_OS_EMBEDDED
86 if (flags
& kSCNetworkReachabilityFlagsIsWWAN
) {
87 printf("[%s] wwan\n", source
);
93 handleReachabilityUpdate(
94 SCNetworkReachabilityRef target
,
95 SCNetworkReachabilityFlags flags
,
98 printReachabilityFlags("RunLoop", flags
);
101 static SCNetworkReachabilityRef
102 createReachabilityWithCFHost(CFHostRef theHost
)
104 SCNetworkReachabilityRef reachRef
= NULL
;
105 Boolean resolved
= FALSE
;
106 CFArrayRef addrs
= CFHostGetAddressing(theHost
, &resolved
);
108 if (resolved
&& addrs
!= NULL
&& CFArrayGetCount(addrs
) > 0) {
109 CFDataRef addr
= (CFDataRef
)CFArrayGetValueAtIndex(addrs
, 0);
111 reachRef
= SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault
, (struct sockaddr
*)CFDataGetBytePtr(addr
));
113 CFArrayRef names
= CFHostGetNames(theHost
, NULL
);
115 if (names
!= NULL
&& CFArrayGetCount(names
) > 0) {
116 CFStringRef host
= (CFStringRef
)CFArrayGetValueAtIndex(names
, 0);
117 char *chost
= string2CString(host
);
119 reachRef
= SCNetworkReachabilityCreateWithName(kCFAllocatorDefault
, chost
);
121 CFAllocatorDeallocate(kCFAllocatorDefault
, chost
);
125 if (reachRef
!= NULL
) {
126 SCNetworkReachabilityContext reach_ctx
= { 0, NULL
, NULL
, NULL
, NULL
};
127 SCNetworkReachabilitySetCallback(reachRef
, handleReachabilityUpdate
,
131 fprintf(stderr
, "Failed to create a reachability object\n");
138 handleDownload(CFReadStreamRef rstream
, CFStreamEventType eventType
, void *info
)
140 Boolean done
= FALSE
;
142 if (eventType
== kCFStreamEventHasBytesAvailable
) {
145 while (CFReadStreamHasBytesAvailable(rstream
)) {
146 CFIndex count
= CFReadStreamRead(rstream
, buffer
, sizeof(buffer
));
151 } else if (eventType
== kCFStreamEventEndEncountered
) {
152 printf("Download completed\n");
154 } else if (eventType
== kCFStreamEventErrorOccurred
) {
155 printf("Download error\n");
158 printf("Got stream event: %lu\n", eventType
);
165 CFReadStreamUnscheduleFromRunLoop(rstream
, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
);
166 CFReadStreamClose(rstream
);
175 CFHTTPMessageRef request
= CFHTTPMessageCreateRequest(kCFAllocatorDefault
, CFSTR("GET"), g_url
, kCFHTTPVersion1_1
);
176 CFReadStreamRef rstream
= CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault
, request
);
177 CFStreamClientContext ctx
= { 0, NULL
, NULL
, NULL
, NULL
};
179 printf("Starting download\n");
181 CFReadStreamSetClient(rstream
,
182 kCFStreamEventEndEncountered
| kCFStreamEventErrorOccurred
| kCFStreamEventHasBytesAvailable
,
186 CFReadStreamScheduleWithRunLoop(rstream
, CFRunLoopGetMain(), kCFRunLoopDefaultMode
);
188 CFReadStreamOpen(rstream
);
196 downloadTimerFired(CFRunLoopTimerRef timer
, void *info
)
198 if (g_rstream
!= NULL
) {
199 handleDownload(g_rstream
, kCFStreamEventErrorOccurred
, NULL
);
203 SCNetworkReachabilityUnscheduleFromRunLoop(g_reachability
, CFRunLoopGetMain(), kCFRunLoopDefaultMode
);
207 SCNetworkReachabilityScheduleWithRunLoop(g_reachability
, CFRunLoopGetMain(), kCFRunLoopDefaultMode
);
211 startDownloadLoop(void)
213 CFRunLoopTimerRef timer
;
214 CFRunLoopTimerContext ctx
= { 0, NULL
, NULL
, NULL
, NULL
};
215 CFAbsoluteTime now
= CFAbsoluteTimeGetCurrent();
217 timer
= CFRunLoopTimerCreate(kCFAllocatorDefault
,
225 CFRunLoopAddTimer(CFRunLoopGetMain(), timer
, kCFRunLoopCommonModes
);
229 reachabilityLoop(void *arg
)
232 SCNetworkReachabilityFlags flags
;
233 SCNetworkReachabilityGetFlags(g_reachability
, &flags
);
235 printReachabilityFlags("thread", flags
);
244 startReachabilityThread(void)
246 pthread_attr_t tattr
;
249 pthread_attr_init(&tattr
);
250 pthread_create(&th
, &tattr
, reachabilityLoop
, NULL
);
251 pthread_attr_destroy(&tattr
);
255 addressResolutionCallback(CFHostRef theHost
, CFHostInfoType typeInfo
, const CFStreamError
*error
, void *info
)
257 g_reachability
= createReachabilityWithCFHost(theHost
);
259 if (g_reachability
!= NULL
) {
261 startReachabilityThread();
268 startAddressResolution(Boolean resolve
)
270 CFStringRef hostStr
= CFURLCopyHostName(g_url
);
271 CFHostRef cfhost
= CFHostCreateWithName(kCFAllocatorDefault
, hostStr
);
272 CFHostClientContext ctx
= { 0, NULL
, NULL
, NULL
, NULL
};
276 CFHostSetClient(cfhost
, addressResolutionCallback
, &ctx
);
277 CFHostScheduleWithRunLoop(cfhost
, CFRunLoopGetMain(), kCFRunLoopDefaultMode
);
278 CFHostStartInfoResolution(cfhost
, kCFHostAddresses
, &err
);
280 addressResolutionCallback(cfhost
, kCFHostNames
, NULL
, NULL
);
287 main(int argc
, char *argv
[])
290 Boolean resolve
= TRUE
;
293 fprintf(stderr
, "usage: %s <url> [-byname]", argv
[0]);
297 urlStr
= CFStringCreateWithCString(kCFAllocatorDefault
, argv
[1], kCFStringEncodingASCII
);
298 g_url
= CFURLCreateWithString(kCFAllocatorDefault
, urlStr
, NULL
);
302 if (argc
> 2 && !strcmp(argv
[2], "-byname")) {
306 startAddressResolution(resolve
);
312 SCNetworkReachabilityUnscheduleFromRunLoop(g_reachability
, CFRunLoopGetMain(), kCFRunLoopDefaultMode
);
313 CFRelease(g_reachability
);