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