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