]> git.saurik.com Git - apple/configd.git/blob - tests/ReachabilityTester.c
configd-963.50.8.tar.gz
[apple/configd.git] / tests / ReachabilityTester.c
1 /*
2 * Copyright (c) 2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <stdio.h>
25 #include <pthread.h>
26
27 #include <CoreFoundation/CoreFoundation.h>
28 #include <CFNetwork/CFNetwork.h>
29 #include <SystemConfiguration/SystemConfiguration.h>
30
31 static SCNetworkReachabilityRef g_reachability = NULL;
32 static CFURLRef g_url = NULL;
33 static CFReadStreamRef g_rstream = NULL;
34
35 static char *
36 string2CString(CFStringRef str)
37 {
38 UInt8 *buffer;
39 CFIndex clen;
40 CFRange r = CFRangeMake(0, CFStringGetLength(str));
41
42 if (CFStringGetBytes(str, r, kCFStringEncodingASCII, 0, false, NULL, 0, &clen) > 0) {
43 buffer = (UInt8 *)CFAllocatorAllocate(kCFAllocatorDefault, (clen + 1) * sizeof(UInt8), 0);
44
45 if (buffer != NULL) {
46 if (CFStringGetBytes(str, r, kCFStringEncodingASCII, 0, false, buffer, clen, NULL)) {
47 buffer[clen] = '\0';
48 return (char *)buffer;
49 }
50 CFAllocatorDeallocate(kCFAllocatorDefault, buffer);
51 }
52 }
53
54 return NULL;
55 }
56
57 static void
58 printReachabilityFlags(const char *source, SCNetworkReachabilityFlags flags)
59 {
60 printf("[%s] Reachability flags (%x):\n", source, flags);
61 if (flags & kSCNetworkReachabilityFlagsTransientConnection) {
62 printf("[%s] transient\n", source);
63 }
64 if (flags & kSCNetworkReachabilityFlagsReachable) {
65 printf("[%s] reachable\n", source);
66 }
67 if (flags & kSCNetworkReachabilityFlagsConnectionRequired) {
68 printf("[%s] connection required\n", source);
69 }
70 if (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) {
71 printf("[%s] connection on traffic\n", source);
72 }
73 if (flags & kSCNetworkReachabilityFlagsInterventionRequired) {
74 printf("[%s] intervention required\n", source);
75 }
76 if (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) {
77 printf("[%s] connection on demand\n", source);
78 }
79 if (flags & kSCNetworkReachabilityFlagsIsLocalAddress) {
80 printf("[%s] local address\n", source);
81 }
82 if (flags & kSCNetworkReachabilityFlagsIsDirect) {
83 printf("[%s] direct\n", source);
84 }
85 #if TARGET_OS_EMBEDDED
86 if (flags & kSCNetworkReachabilityFlagsIsWWAN) {
87 printf("[%s] wwan\n", source);
88 }
89 #endif
90 }
91
92 static void
93 handleReachabilityUpdate(
94 SCNetworkReachabilityRef target,
95 SCNetworkReachabilityFlags flags,
96 void *info)
97 {
98 printReachabilityFlags("RunLoop", flags);
99 }
100
101 static SCNetworkReachabilityRef
102 createReachabilityWithCFHost(CFHostRef theHost)
103 {
104 SCNetworkReachabilityRef reachRef = NULL;
105 Boolean resolved = FALSE;
106 CFArrayRef addrs = CFHostGetAddressing(theHost, &resolved);
107
108 if (resolved && addrs != NULL && CFArrayGetCount(addrs) > 0) {
109 CFDataRef addr = (CFDataRef)CFArrayGetValueAtIndex(addrs, 0);
110
111 reachRef = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (struct sockaddr *)CFDataGetBytePtr(addr));
112 } else {
113 CFArrayRef names = CFHostGetNames(theHost, NULL);
114
115 if (names != NULL && CFArrayGetCount(names) > 0) {
116 CFStringRef host = (CFStringRef)CFArrayGetValueAtIndex(names, 0);
117 char *chost = string2CString(host);
118
119 reachRef = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, chost);
120
121 CFAllocatorDeallocate(kCFAllocatorDefault, chost);
122 }
123 }
124
125 if (reachRef != NULL) {
126 SCNetworkReachabilityContext reach_ctx = { 0, NULL, NULL, NULL, NULL };
127 SCNetworkReachabilitySetCallback(reachRef, handleReachabilityUpdate,
128 &reach_ctx);
129 CFShow(reachRef);
130 } else {
131 fprintf(stderr, "Failed to create a reachability object\n");
132 }
133
134 return reachRef;
135 }
136
137 static void
138 handleDownload(CFReadStreamRef rstream, CFStreamEventType eventType, void *info)
139 {
140 Boolean done = FALSE;
141
142 if (eventType == kCFStreamEventHasBytesAvailable) {
143 UInt8 buffer[1024];
144
145 while (CFReadStreamHasBytesAvailable(rstream)) {
146 CFIndex count = CFReadStreamRead(rstream, buffer, sizeof(buffer));
147 if (count == 0) {
148 done = TRUE;
149 }
150 }
151 } else if (eventType == kCFStreamEventEndEncountered) {
152 printf("Download completed\n");
153 done = TRUE;
154 } else if (eventType == kCFStreamEventErrorOccurred) {
155 printf("Download error\n");
156 done = TRUE;
157 } else {
158 printf("Got stream event: %lu\n", eventType);
159 }
160
161 if (!done) {
162 return;
163 }
164
165 CFReadStreamUnscheduleFromRunLoop(rstream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
166 CFReadStreamClose(rstream);
167 CFRelease(rstream);
168
169 g_rstream = NULL;
170 }
171
172 static void
173 startDownload(void)
174 {
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 };
178
179 printf("Starting download\n");
180
181 CFReadStreamSetClient(rstream,
182 kCFStreamEventEndEncountered | kCFStreamEventErrorOccurred | kCFStreamEventHasBytesAvailable,
183 handleDownload,
184 &ctx);
185
186 CFReadStreamScheduleWithRunLoop(rstream, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
187
188 CFReadStreamOpen(rstream);
189
190 g_rstream = rstream;
191
192 CFRelease(request);
193 }
194
195 static void
196 downloadTimerFired(CFRunLoopTimerRef timer, void *info)
197 {
198 if (g_rstream != NULL) {
199 handleDownload(g_rstream, kCFStreamEventErrorOccurred, NULL);
200 }
201
202
203 SCNetworkReachabilityUnscheduleFromRunLoop(g_reachability, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
204
205 startDownload();
206
207 SCNetworkReachabilityScheduleWithRunLoop(g_reachability, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
208 }
209
210 static void
211 startDownloadLoop(void)
212 {
213 CFRunLoopTimerRef timer;
214 CFRunLoopTimerContext ctx = { 0, NULL, NULL, NULL, NULL };
215 CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
216
217 timer = CFRunLoopTimerCreate(kCFAllocatorDefault,
218 now + 0.1,
219 7.0,
220 0,
221 0,
222 downloadTimerFired,
223 &ctx);
224
225 CFRunLoopAddTimer(CFRunLoopGetMain(), timer, kCFRunLoopCommonModes);
226 }
227
228 static void *
229 reachabilityLoop(void *arg)
230 {
231 while (1) {
232 SCNetworkReachabilityFlags flags;
233 SCNetworkReachabilityGetFlags(g_reachability, &flags);
234
235 printReachabilityFlags("thread", flags);
236
237 sleep(1);
238 }
239
240 return NULL;
241 }
242
243 static void
244 startReachabilityThread(void)
245 {
246 pthread_attr_t tattr;
247 pthread_t th;
248
249 pthread_attr_init(&tattr);
250 pthread_create(&th, &tattr, reachabilityLoop, NULL);
251 pthread_attr_destroy(&tattr);
252 }
253
254 static void
255 addressResolutionCallback(CFHostRef theHost, CFHostInfoType typeInfo, const CFStreamError *error, void *info)
256 {
257 g_reachability = createReachabilityWithCFHost(theHost);
258
259 if (g_reachability != NULL) {
260 startDownloadLoop();
261 startReachabilityThread();
262 }
263
264 CFRelease(theHost);
265 }
266
267 static void
268 startAddressResolution(Boolean resolve)
269 {
270 CFStringRef hostStr = CFURLCopyHostName(g_url);
271 CFHostRef cfhost = CFHostCreateWithName(kCFAllocatorDefault, hostStr);
272 CFHostClientContext ctx = { 0, NULL, NULL, NULL, NULL };
273 CFStreamError err;
274
275 if (resolve) {
276 CFHostSetClient(cfhost, addressResolutionCallback, &ctx);
277 CFHostScheduleWithRunLoop(cfhost, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
278 CFHostStartInfoResolution(cfhost, kCFHostAddresses, &err);
279 } else {
280 addressResolutionCallback(cfhost, kCFHostNames, NULL, NULL);
281 }
282
283 CFRelease(hostStr);
284 }
285
286 int
287 main(int argc, char *argv[])
288 {
289 CFStringRef urlStr;
290 Boolean resolve = TRUE;
291
292 if (argc < 2) {
293 fprintf(stderr, "usage: %s <url> [-byname]", argv[0]);
294 return 1;
295 }
296
297 urlStr = CFStringCreateWithCString(kCFAllocatorDefault, argv[1], kCFStringEncodingASCII);
298 g_url = CFURLCreateWithString(kCFAllocatorDefault, urlStr, NULL);
299
300 CFRelease(urlStr);
301
302 if (argc > 2 && !strcmp(argv[2], "-byname")) {
303 resolve = FALSE;
304 }
305
306 startAddressResolution(resolve);
307
308 CFRunLoopRun();
309
310 CFRelease(g_url);
311
312 SCNetworkReachabilityUnscheduleFromRunLoop(g_reachability, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
313 CFRelease(g_reachability);
314
315 return 0;
316 }