]> git.saurik.com Git - apple/configd.git/blob - IPMonitorControl/IPMonitorControl.c
configd-699.1.5.tar.gz
[apple/configd.git] / IPMonitorControl / IPMonitorControl.c
1 /*
2 * Copyright (c) 2013-2014 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 /*
25 * IPMonitorControl.c
26 * - IPC channel to IPMonitor
27 * - used to create interface rank assertions
28 */
29
30 /*
31 * Modification History
32 *
33 * December 16, 2013 Dieter Siegmund (dieter@apple.com)
34 * - initial revision
35 */
36
37 #include "IPMonitorControl.h"
38 #include "IPMonitorControlPrivate.h"
39 #include "symbol_scope.h"
40 #include <CoreFoundation/CFRuntime.h>
41 #include <net/if.h>
42 #include <xpc/xpc.h>
43 #include <xpc/private.h>
44 #include <SystemConfiguration/SCPrivate.h>
45
46 #ifdef TEST_IPMONITOR_CONTROL
47 #define my_log(__level, fmt, ...) SCPrint(TRUE, stdout, CFSTR(fmt "\n"), ## __VA_ARGS__)
48
49 #else /* TEST_IPMONITOR_CONTROL */
50
51 #define my_log(__level, fmt, ...) SCLog(TRUE, __level, CFSTR(fmt), ## __VA_ARGS__)
52 #endif /* TEST_IPMONITOR_CONTROL */
53
54 /**
55 ** IPMonitorControl CF object glue
56 **/
57
58 struct IPMonitorControl {
59 CFRuntimeBase cf_base;
60
61 dispatch_queue_t queue;
62 xpc_connection_t connection;
63 CFMutableDictionaryRef assertions; /* ifname<string> = rank<number> */
64 };
65
66 STATIC CFStringRef __IPMonitorControlCopyDebugDesc(CFTypeRef cf);
67 STATIC void __IPMonitorControlDeallocate(CFTypeRef cf);
68
69 STATIC CFTypeID __kIPMonitorControlTypeID = _kCFRuntimeNotATypeID;
70
71 STATIC const CFRuntimeClass __IPMonitorControlClass = {
72 0, /* version */
73 "IPMonitorControl", /* className */
74 NULL, /* init */
75 NULL, /* copy */
76 __IPMonitorControlDeallocate, /* deallocate */
77 NULL, /* equal */
78 NULL, /* hash */
79 NULL, /* copyFormattingDesc */
80 __IPMonitorControlCopyDebugDesc /* copyDebugDesc */
81 };
82
83 STATIC CFStringRef
84 __IPMonitorControlCopyDebugDesc(CFTypeRef cf)
85 {
86 CFAllocatorRef allocator = CFGetAllocator(cf);
87 IPMonitorControlRef control = (IPMonitorControlRef)cf;
88
89 return (CFStringCreateWithFormat(allocator, NULL,
90 CFSTR("<IPMonitorControl %p>"),
91 control));
92 }
93
94 STATIC void
95 __IPMonitorControlDeallocate(CFTypeRef cf)
96 {
97 IPMonitorControlRef control = (IPMonitorControlRef)cf;
98
99 if (control->connection != NULL) {
100 xpc_release(control->connection);
101 }
102 if (control->queue != NULL) {
103 xpc_release(control->queue);
104 }
105 return;
106 }
107
108 /**
109 ** IPMonitorControl support functions
110 **/
111 STATIC void
112 __IPMonitorControlRegisterClass(void)
113 {
114 STATIC dispatch_once_t once;
115
116 dispatch_once(&once, ^{
117 __kIPMonitorControlTypeID
118 = _CFRuntimeRegisterClass(&__IPMonitorControlClass);
119 });
120 return;
121 }
122
123 STATIC IPMonitorControlRef
124 __IPMonitorControlAllocate(CFAllocatorRef allocator)
125 {
126 IPMonitorControlRef control;
127 int size;
128
129 __IPMonitorControlRegisterClass();
130 size = sizeof(*control) - sizeof(CFRuntimeBase);
131 control = (IPMonitorControlRef)
132 _CFRuntimeCreateInstance(allocator,
133 __kIPMonitorControlTypeID, size, NULL);
134 bzero(((void *)control) + sizeof(CFRuntimeBase), size);
135 return (control);
136 }
137
138 STATIC Boolean
139 IPMonitorControlHandleResponse(xpc_object_t event, Boolean async,
140 Boolean * retry_p)
141 {
142 Boolean retry = FALSE;
143 Boolean success = FALSE;
144 xpc_type_t type;
145
146 type = xpc_get_type(event);
147 if (type == XPC_TYPE_DICTIONARY) {
148 if (async) {
149 /* we don't expect async responses messages */
150 my_log(LOG_NOTICE, "IPMonitorControl: unexpected message");
151 }
152 else {
153 int64_t error;
154
155 error = xpc_dictionary_get_int64(event,
156 kIPMonitorControlResponseKeyError);
157 if (error != 0) {
158 success = FALSE;
159 #ifdef TEST_IPMONITOR_CONTROL
160 my_log(LOG_NOTICE,
161 "IPMonitorControl: failure code %lld", error);
162 #endif /* TEST_IPMONITOR_CONTROL */
163 }
164 else {
165 success = TRUE;
166 }
167 }
168 }
169 else if (type == XPC_TYPE_ERROR) {
170 if (event == XPC_ERROR_CONNECTION_INTERRUPTED) {
171 #ifdef TEST_IPMONITOR_CONTROL
172 my_log(LOG_NOTICE, "IPMonitorControl: can retry");
173 #endif /* TEST_IPMONITOR_CONTROL */
174 retry = TRUE;
175 }
176 else {
177 const char * desc;
178
179 desc = xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION);
180 my_log(LOG_NOTICE, "IPMonitorControl: %s", desc);
181 }
182 }
183 else {
184 my_log(LOG_NOTICE, "IPMonitorControl: unknown event type : %p", type);
185 }
186 if (retry_p != NULL) {
187 *retry_p = retry;
188 }
189 return (success);
190 }
191
192
193 STATIC void
194 IPMonitorControlSetInterfaceRank(IPMonitorControlRef control,
195 CFStringRef ifname_cf,
196 SCNetworkServicePrimaryRank rank)
197 {
198 if (control->assertions == NULL) {
199 if (rank == kSCNetworkServicePrimaryRankDefault) {
200 /* no assertions, no need to store rank */
201 return;
202 }
203 control->assertions
204 = CFDictionaryCreateMutable(NULL, 0,
205 &kCFTypeDictionaryKeyCallBacks,
206 &kCFTypeDictionaryValueCallBacks);
207 }
208 if (rank == kSCNetworkServicePrimaryRankDefault) {
209 CFDictionaryRemoveValue(control->assertions, ifname_cf);
210 if (CFDictionaryGetCount(control->assertions) == 0) {
211 CFRelease(control->assertions);
212 control->assertions = NULL;
213 }
214 }
215 else {
216 CFNumberRef rank_cf;
217
218 rank_cf = CFNumberCreate(NULL, kCFNumberSInt32Type, &rank);
219 CFDictionarySetValue(control->assertions, ifname_cf, rank_cf);
220 CFRelease(rank_cf);
221 }
222 return;
223 }
224
225 STATIC void
226 ApplyInterfaceRank(const void * key, const void * value, void * context)
227 {
228 xpc_connection_t connection = (xpc_connection_t)context;
229 char ifname[IF_NAMESIZE];
230 SCNetworkServicePrimaryRank rank;
231 xpc_object_t request;
232
233 if (CFStringGetCString(key, ifname, sizeof(ifname),
234 kCFStringEncodingUTF8) == FALSE) {
235 return;
236 }
237 if (CFNumberGetValue(value, kCFNumberSInt32Type, &rank) == FALSE) {
238 return;
239 }
240 request = xpc_dictionary_create(NULL, NULL, 0);
241 xpc_dictionary_set_uint64(request,
242 kIPMonitorControlRequestKeyType,
243 kIPMonitorControlRequestTypeSetInterfaceRank);
244 xpc_dictionary_set_string(request,
245 kIPMonitorControlRequestKeyInterfaceName,
246 ifname);
247 xpc_dictionary_set_uint64(request,
248 kIPMonitorControlRequestKeyPrimaryRank,
249 rank);
250 xpc_connection_send_message(connection, request);
251 xpc_release(request);
252 return;
253 }
254
255
256 /**
257 ** IPMonitorControl SPI
258 **/
259 PRIVATE_EXTERN IPMonitorControlRef
260 IPMonitorControlCreate(void)
261 {
262 xpc_connection_t connection;
263 IPMonitorControlRef control;
264 uint64_t flags = XPC_CONNECTION_MACH_SERVICE_PRIVILEGED;
265 xpc_handler_t handler;
266 dispatch_queue_t queue;
267
268 control = __IPMonitorControlAllocate(NULL);
269 queue = dispatch_queue_create("IPMonitorControl", NULL);
270 connection
271 = xpc_connection_create_mach_service(kIPMonitorControlServerName,
272 queue, flags);
273 handler = ^(xpc_object_t event) {
274 Boolean retry;
275
276 (void)IPMonitorControlHandleResponse(event, TRUE, &retry);
277 if (retry && control->assertions != NULL) {
278 CFDictionaryApplyFunction(control->assertions,
279 ApplyInterfaceRank,
280 control->connection);
281 }
282 };
283 xpc_connection_set_event_handler(connection, handler);
284 control->connection = connection;
285 control->queue = queue;
286 xpc_connection_resume(connection);
287 return (control);
288 }
289
290 PRIVATE_EXTERN Boolean
291 IPMonitorControlSetInterfacePrimaryRank(IPMonitorControlRef control,
292 CFStringRef ifname_cf,
293 SCNetworkServicePrimaryRank rank)
294 {
295 char ifname[IF_NAMESIZE];
296 xpc_object_t request;
297 Boolean success = FALSE;
298
299 if (CFStringGetCString(ifname_cf, ifname, sizeof(ifname),
300 kCFStringEncodingUTF8) == FALSE) {
301 return (FALSE);
302 }
303 request = xpc_dictionary_create(NULL, NULL, 0);
304 xpc_dictionary_set_uint64(request,
305 kIPMonitorControlRequestKeyType,
306 kIPMonitorControlRequestTypeSetInterfaceRank);
307 xpc_dictionary_set_string(request,
308 kIPMonitorControlRequestKeyInterfaceName,
309 ifname);
310 xpc_dictionary_set_uint64(request,
311 kIPMonitorControlRequestKeyPrimaryRank,
312 rank);
313 while (TRUE) {
314 xpc_object_t reply;
315 Boolean retry_on_error = FALSE;
316
317 reply = xpc_connection_send_message_with_reply_sync(control->connection,
318 request);
319 if (reply == NULL) {
320 my_log(LOG_NOTICE, "IPMonitorControl: failed to send message");
321 break;
322 }
323 success = IPMonitorControlHandleResponse(reply, FALSE,
324 &retry_on_error);
325 xpc_release(reply);
326 if (success) {
327 break;
328 }
329 if (retry_on_error) {
330 continue;
331 }
332 my_log(LOG_NOTICE, "IPMonitorControl: fatal error");
333 break;
334 }
335 xpc_release(request);
336 if (success) {
337 /* sync our state */
338 CFRetain(ifname_cf);
339 CFRetain(control);
340 dispatch_async(control->queue,
341 ^{
342 IPMonitorControlSetInterfaceRank(control,
343 ifname_cf,
344 rank);
345 CFRelease(ifname_cf);
346 CFRelease(control);
347 });
348 }
349 return (success);
350 }
351
352 SCNetworkServicePrimaryRank
353 IPMonitorControlGetInterfacePrimaryRank(IPMonitorControlRef control,
354 CFStringRef ifname_cf)
355 {
356 char ifname[IF_NAMESIZE];
357 SCNetworkServicePrimaryRank rank;
358 xpc_object_t request;
359
360 rank = kSCNetworkServicePrimaryRankDefault;
361 if (CFStringGetCString(ifname_cf, ifname, sizeof(ifname),
362 kCFStringEncodingUTF8) == FALSE) {
363 goto done;
364 }
365 request = xpc_dictionary_create(NULL, NULL, 0);
366 xpc_dictionary_set_uint64(request,
367 kIPMonitorControlRequestKeyType,
368 kIPMonitorControlRequestTypeGetInterfaceRank);
369 xpc_dictionary_set_string(request,
370 kIPMonitorControlRequestKeyInterfaceName,
371 ifname);
372 while (TRUE) {
373 xpc_object_t reply;
374 Boolean retry_on_error = FALSE;
375 Boolean success;
376
377 reply = xpc_connection_send_message_with_reply_sync(control->connection,
378 request);
379 if (reply == NULL) {
380 my_log(LOG_NOTICE, "IPMonitorControl: failed to send message");
381 break;
382 }
383 success = IPMonitorControlHandleResponse(reply, FALSE, &retry_on_error);
384 if (success) {
385 rank = (SCNetworkServicePrimaryRank)
386 xpc_dictionary_get_uint64(reply,
387 kIPMonitorControlResponseKeyPrimaryRank);
388 }
389 xpc_release(reply);
390 if (success) {
391 break;
392 }
393 if (retry_on_error) {
394 continue;
395 }
396 break;
397 }
398 xpc_release(request);
399
400 done:
401 return (rank);
402 }
403