2 * Copyright (c) 2013-2018 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@
25 * IPMonitorControlServer.c
26 * - IPC channel to IPMonitor
27 * - used to create interface rank assertions
31 * Modification History
33 * December 16, 2013 Dieter Siegmund (dieter@apple.com)
37 #include <CoreFoundation/CoreFoundation.h>
39 #include <xpc/private.h>
40 #include <sys/queue.h>
41 #include <CoreFoundation/CFRunLoop.h>
42 #include <SystemConfiguration/SCNetworkConfigurationPrivate.h>
43 #include <SystemConfiguration/SCPrivate.h>
44 #include "IPMonitorControlServer.h"
45 #include "symbol_scope.h"
46 #include "IPMonitorControlPrivate.h"
47 #include "IPMonitorAWDReport.h"
49 #ifdef TEST_IPMONITOR_CONTROL
50 #define my_log(__level, __format, ...) SCPrint(TRUE, stdout, CFSTR(__format "\n"), ## __VA_ARGS__)
52 #else /* TEST_IPMONITOR_CONTROL */
53 #include "ip_plugin.h"
54 #endif /* TEST_IPMONITOR_CONTROL */
56 STATIC dispatch_queue_t S_IPMonitorControlServerQueue
;
58 typedef struct ControlSession ControlSession
, * ControlSessionRef
;
60 #define LIST_HEAD_ControlSession LIST_HEAD(ControlSessionHead, ControlSession)
61 #define LIST_ENTRY_ControlSession LIST_ENTRY(ControlSession)
62 LIST_HEAD_ControlSession S_ControlSessions
;
64 struct ControlSession
{
65 LIST_ENTRY_ControlSession link
;
66 xpc_connection_t connection
;
68 CFMutableDictionaryRef assertions
; /* ifname<string> = rank<number> */
69 CFMutableDictionaryRef advisories
; /* ifname<string> = advisory<number> */
75 STATIC CFMutableArrayRef S_if_changes
;
76 STATIC CFRange S_if_changes_range
;
79 RankLastNumberGet(void)
81 STATIC CFNumberRef rank_last
;
83 if (rank_last
== NULL
) {
84 SCNetworkServicePrimaryRank rank
;
86 rank
= kSCNetworkServicePrimaryRankLast
;
87 rank_last
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &rank
);
93 InterfaceChangedListAddInterface(CFStringRef ifname
)
95 if (S_if_changes
== NULL
) {
96 S_if_changes
= CFArrayCreateMutable(NULL
,
97 0, &kCFTypeArrayCallBacks
);
98 CFArrayAppendValue(S_if_changes
, ifname
);
99 S_if_changes_range
.length
= 1;
101 else if (!CFArrayContainsValue(S_if_changes
, S_if_changes_range
, ifname
)) {
102 CFArrayAppendValue(S_if_changes
, ifname
);
103 S_if_changes_range
.length
++;
108 InterfaceChangedListCopy(void)
110 CFArrayRef current_list
;
112 current_list
= S_if_changes
;
114 return (current_list
);
118 InterfaceRankAssertionAdd(const void * key
, const void * value
, void * context
)
120 CFMutableDictionaryRef
* assertions_p
;
121 CFNumberRef existing_rank
;
122 CFNumberRef rank
= (CFNumberRef
)value
;
124 assertions_p
= (CFMutableDictionaryRef
*)context
;
125 if (*assertions_p
== NULL
) {
127 = CFDictionaryCreateMutable(NULL
, 0,
128 &kCFTypeDictionaryKeyCallBacks
,
129 &kCFTypeDictionaryValueCallBacks
);
130 CFDictionarySetValue(*assertions_p
, key
, rank
);
133 existing_rank
= CFDictionaryGetValue(*assertions_p
, key
);
134 if (existing_rank
== NULL
135 || (CFNumberCompare(rank
, existing_rank
, NULL
)
136 == kCFCompareGreaterThan
)) {
137 CFDictionarySetValue(*assertions_p
, key
, rank
);
143 InterfaceAdvisoryAdd(const void * key
, const void * value
, void * context
)
145 #pragma unused(value)
146 CFMutableDictionaryRef
* assertions_p
;
147 CFNumberRef existing_rank
;
150 /* an interface advisory implies RankLast */
151 rank
= RankLastNumberGet();
152 assertions_p
= (CFMutableDictionaryRef
*)context
;
153 if (*assertions_p
== NULL
) {
155 = CFDictionaryCreateMutable(NULL
, 0,
156 &kCFTypeDictionaryKeyCallBacks
,
157 &kCFTypeDictionaryValueCallBacks
);
158 CFDictionarySetValue(*assertions_p
, key
, rank
);
161 existing_rank
= CFDictionaryGetValue(*assertions_p
, key
);
162 if (existing_rank
== NULL
163 || (CFNumberCompare(rank
, existing_rank
, NULL
)
164 == kCFCompareGreaterThan
)) {
165 CFDictionarySetValue(*assertions_p
, key
, rank
);
170 STATIC CFDictionaryRef
171 InterfaceRankAssertionsCopy(void)
173 CFMutableDictionaryRef assertions
= NULL
;
174 ControlSessionRef session
;
176 LIST_FOREACH(session
, &S_ControlSessions
, link
) {
177 if (session
->advisories
!= NULL
) {
178 CFDictionaryApplyFunction(session
->advisories
,
179 InterfaceAdvisoryAdd
,
182 if (session
->assertions
!= NULL
) {
183 CFDictionaryApplyFunction(session
->assertions
,
184 InterfaceRankAssertionAdd
,
192 InterfaceHasAdvisories(CFStringRef ifname
)
194 ControlSessionRef session
;
196 LIST_FOREACH(session
, &S_ControlSessions
, link
) {
197 if (session
->advisories
!= NULL
198 && CFDictionaryContainsKey(session
->advisories
, ifname
)) {
206 STATIC AWDIPMonitorInterfaceAdvisoryReport_Flags
207 advisory_to_flags(SCNetworkInterfaceAdvisory advisory
)
209 AWDIPMonitorInterfaceAdvisoryReport_Flags flags
;
212 case kSCNetworkInterfaceAdvisoryNone
:
216 case kSCNetworkInterfaceAdvisoryLinkLayerIssue
:
217 flags
= AWDIPMonitorInterfaceAdvisoryReport_Flags_LINK_LAYER_ISSUE
;
219 case kSCNetworkInterfaceAdvisoryUplinkIssue
:
220 flags
= AWDIPMonitorInterfaceAdvisoryReport_Flags_UPLINK_ISSUE
;
226 STATIC AWDIPMonitorInterfaceAdvisoryReport_Flags
227 InterfaceGetAdvisoryFlags(CFStringRef ifname
,
228 ControlSessionRef exclude_session
,
229 uint32_t * ret_count
)
232 AWDIPMonitorInterfaceAdvisoryReport_Flags flags
= 0;
233 ControlSessionRef session
;
236 LIST_FOREACH(session
, &S_ControlSessions
, link
) {
237 SCNetworkInterfaceAdvisory advisory
= 0;
238 CFNumberRef advisory_cf
;
240 if (session
->advisories
== NULL
) {
243 if (exclude_session
!= NULL
&& exclude_session
== session
) {
246 advisory_cf
= CFDictionaryGetValue(session
->advisories
, ifname
);
247 if (advisory_cf
== NULL
) {
248 /* session has no advisories for this interface */
251 (void)CFNumberGetValue(advisory_cf
, kCFNumberSInt32Type
, &advisory
);
252 flags
|= advisory_to_flags(advisory
);
260 AnyInterfaceHasAdvisories(void)
262 ControlSessionRef session
;
264 LIST_FOREACH(session
, &S_ControlSessions
, link
) {
265 if (session
->advisories
!= NULL
) {
272 STATIC CFRunLoopRef S_runloop
;
273 STATIC CFRunLoopSourceRef S_signal_source
;
276 SetNotificationInfo(CFRunLoopRef runloop
, CFRunLoopSourceRef rls
)
279 S_signal_source
= rls
;
284 NotifyIPMonitor(void)
286 if (S_signal_source
!= NULL
) {
287 CFRunLoopSourceSignal(S_signal_source
);
288 if (S_runloop
!= NULL
) {
289 CFRunLoopWakeUp(S_runloop
);
296 NotifyInterfaceAdvisory(CFStringRef ifname
)
300 key
= _IPMonitorControlCopyInterfaceAdvisoryNotificationKey(ifname
);
301 SCDynamicStoreNotifyValue(NULL
, key
);
307 SubmitInterfaceAdvisoryMetric(CFStringRef ifname
,
308 AWDIPMonitorInterfaceAdvisoryReport_Flags flags
,
311 InterfaceAdvisoryReportRef report
;
312 AWDIPMonitorInterfaceType type
;
314 /* XXX need to actually figure out what the interface type is */
315 if (CFStringHasPrefix(ifname
, CFSTR("pdp"))) {
316 type
= AWDIPMonitorInterfaceType_IPMONITOR_INTERFACE_TYPE_CELLULAR
;
319 type
= AWDIPMonitorInterfaceType_IPMONITOR_INTERFACE_TYPE_WIFI
;
321 report
= InterfaceAdvisoryReportCreate(type
);
322 if (report
== NULL
) {
325 InterfaceAdvisoryReportSetFlags(report
, flags
);
326 InterfaceAdvisoryReportSetAdvisoryCount(report
, count
);
327 InterfaceAdvisoryReportSubmit(report
);
328 my_log(LOG_NOTICE
, "%@: submitted AWD report %@", ifname
, report
);
336 AddChangedInterface(const void * key
, const void * value
, void * context
)
338 #pragma unused(value)
339 #pragma unused(context)
340 InterfaceChangedListAddInterface((CFStringRef
)key
);
345 AddChangedInterfaceNotify(const void * key
, const void * value
, void * context
)
347 #pragma unused(value)
348 #pragma unused(context)
349 InterfaceChangedListAddInterface((CFStringRef
)key
);
350 NotifyInterfaceAdvisory((CFStringRef
)key
);
355 GenerateMetricForInterfaceAtSessionClose(const void * key
, const void * value
,
358 uint32_t count_after
;
359 uint32_t count_before
;
360 AWDIPMonitorInterfaceAdvisoryReport_Flags flags_after
;
361 AWDIPMonitorInterfaceAdvisoryReport_Flags flags_before
;
362 CFStringRef ifname
= (CFStringRef
)key
;
363 ControlSessionRef session
= (ControlSessionRef
)context
;
365 #pragma unused(value)
367 * Get the flags and count including this session, then again
368 * excluding this session. If either flags or count are different,
369 * generate the metric.
371 flags_before
= InterfaceGetAdvisoryFlags(ifname
, NULL
, &count_before
);
372 flags_after
= InterfaceGetAdvisoryFlags(ifname
, session
, &count_after
);
373 if (flags_before
!= flags_after
|| count_before
!= count_after
) {
374 SubmitInterfaceAdvisoryMetric(ifname
, flags_after
, count_after
);
380 ControlSessionGenerateMetricsAtClose(ControlSessionRef session
)
382 if (session
->advisories
== NULL
) {
385 CFDictionaryApplyFunction(session
->advisories
,
386 GenerateMetricForInterfaceAtSessionClose
,
391 ControlSessionInvalidate(ControlSessionRef session
)
393 my_log(LOG_DEBUG
, "Invalidating %p", session
);
394 ControlSessionGenerateMetricsAtClose(session
);
395 LIST_REMOVE(session
, link
);
396 if (session
->assertions
!= NULL
|| session
->advisories
!= NULL
) {
397 if (session
->advisories
!= NULL
) {
399 "pid %d removing advisories %@",
400 xpc_connection_get_pid(session
->connection
),
401 session
->advisories
);
402 CFDictionaryApplyFunction(session
->advisories
,
403 AddChangedInterfaceNotify
,
405 my_CFRelease(&session
->advisories
);
407 if (session
->assertions
!= NULL
) {
409 "pid %d removing assertions %@",
410 xpc_connection_get_pid(session
->connection
),
411 session
->assertions
);
412 CFDictionaryApplyFunction(session
->assertions
, AddChangedInterface
,
414 my_CFRelease(&session
->assertions
);
422 ControlSessionRelease(void * p
)
424 my_log(LOG_DEBUG
, "Releasing %p", p
);
429 STATIC ControlSessionRef
430 ControlSessionLookup(xpc_connection_t connection
)
432 return ((ControlSessionRef
)xpc_connection_get_context(connection
));
435 STATIC ControlSessionRef
436 ControlSessionCreate(xpc_connection_t connection
)
438 ControlSessionRef session
;
440 session
= (ControlSessionRef
)malloc(sizeof(*session
));
441 memset(session
, 0, sizeof(*session
));
442 session
->connection
= connection
;
443 xpc_connection_set_finalizer_f(connection
, ControlSessionRelease
);
444 xpc_connection_set_context(connection
, session
);
445 LIST_INSERT_HEAD(&S_ControlSessions
, session
, link
);
446 my_log(LOG_DEBUG
, "Created %p (connection %p)", session
, connection
);
450 STATIC ControlSessionRef
451 ControlSessionForConnection(xpc_connection_t connection
)
453 ControlSessionRef session
;
455 session
= ControlSessionLookup(connection
);
456 if (session
!= NULL
) {
459 return (ControlSessionCreate(connection
));
463 ControlSessionSetInterfaceRank(ControlSessionRef session
,
465 SCNetworkServicePrimaryRank rank
)
467 CFStringRef ifname_cf
;
469 if (session
->assertions
== NULL
) {
470 if (rank
== kSCNetworkServicePrimaryRankDefault
) {
471 /* no assertions, no need to store rank */
475 = CFDictionaryCreateMutable(NULL
, 0,
476 &kCFTypeDictionaryKeyCallBacks
,
477 &kCFTypeDictionaryValueCallBacks
);
479 ifname_cf
= CFStringCreateWithCString(NULL
, ifname
,
480 kCFStringEncodingUTF8
);
482 if (rank
== kSCNetworkServicePrimaryRankDefault
) {
483 CFDictionaryRemoveValue(session
->assertions
, ifname_cf
);
484 if (CFDictionaryGetCount(session
->assertions
) == 0) {
485 CFRelease(session
->assertions
);
486 session
->assertions
= NULL
;
492 rank_cf
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &rank
);
493 CFDictionarySetValue(session
->assertions
, ifname_cf
, rank_cf
);
496 InterfaceChangedListAddInterface(ifname_cf
);
498 CFRelease(ifname_cf
);
502 STATIC SCNetworkServicePrimaryRank
503 ControlSessionGetInterfaceRank(ControlSessionRef session
,
506 SCNetworkServicePrimaryRank rank
= kSCNetworkServicePrimaryRankDefault
;
508 if (session
->assertions
!= NULL
) {
509 CFStringRef ifname_cf
;
512 ifname_cf
= CFStringCreateWithCString(NULL
, ifname
,
513 kCFStringEncodingUTF8
);
514 rank_cf
= CFDictionaryGetValue(session
->assertions
, ifname_cf
);
515 CFRelease(ifname_cf
);
516 if (rank_cf
!= NULL
) {
517 (void)CFNumberGetValue(rank_cf
, kCFNumberSInt32Type
, &rank
);
524 ControlSessionSetInterfaceAdvisory(ControlSessionRef session
,
526 SCNetworkInterfaceAdvisory advisory
)
528 uint32_t count_after
;
529 uint32_t count_before
;
530 AWDIPMonitorInterfaceAdvisoryReport_Flags flags_after
;
531 AWDIPMonitorInterfaceAdvisoryReport_Flags flags_before
;
532 CFStringRef ifname_cf
;
534 if (session
->advisories
== NULL
) {
535 if (advisory
== kSCNetworkInterfaceAdvisoryNone
) {
536 /* no advisories, no need to store advisory */
540 = CFDictionaryCreateMutable(NULL
, 0,
541 &kCFTypeDictionaryKeyCallBacks
,
542 &kCFTypeDictionaryValueCallBacks
);
544 ifname_cf
= CFStringCreateWithCString(NULL
, ifname
,
545 kCFStringEncodingUTF8
);
546 flags_before
= InterfaceGetAdvisoryFlags(ifname_cf
, NULL
, &count_before
);
547 if (advisory
== kSCNetworkInterfaceAdvisoryNone
) {
548 CFDictionaryRemoveValue(session
->advisories
, ifname_cf
);
549 if (CFDictionaryGetCount(session
->advisories
) == 0) {
550 CFRelease(session
->advisories
);
551 session
->advisories
= NULL
;
555 CFNumberRef advisory_cf
;
557 advisory_cf
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &advisory
);
558 CFDictionarySetValue(session
->advisories
, ifname_cf
, advisory_cf
);
559 CFRelease(advisory_cf
);
561 flags_after
= InterfaceGetAdvisoryFlags(ifname_cf
, NULL
, &count_after
);
562 if (flags_before
!= flags_after
|| count_before
!= count_after
) {
563 SubmitInterfaceAdvisoryMetric(ifname_cf
, flags_after
, count_after
);
565 InterfaceChangedListAddInterface(ifname_cf
);
566 NotifyInterfaceAdvisory(ifname_cf
);
568 CFRelease(ifname_cf
);
573 ** IPMonitorControlServer
577 get_process_name(xpc_object_t request
)
579 const char * process_name
;
582 = xpc_dictionary_get_string(request
,
583 kIPMonitorControlRequestKeyProcessName
);
584 if (process_name
== NULL
) {
585 process_name
= "<unknown>";
587 return (process_name
);
591 IPMonitorControlServerConnectionIsRoot(xpc_connection_t connection
)
595 uid
= xpc_connection_get_euid(connection
);
600 IPMonitorControlServerConnectionHasEntitlement(xpc_connection_t connection
,
601 const char * entitlement
)
603 Boolean entitled
= FALSE
;
606 val
= xpc_connection_copy_entitlement_value(connection
, entitlement
);
608 if (xpc_get_type(val
) == XPC_TYPE_BOOL
) {
609 entitled
= xpc_bool_get_value(val
);
617 get_rank_str(SCNetworkServicePrimaryRank rank
)
619 const char * str
= NULL
;
622 case kSCNetworkServicePrimaryRankDefault
:
625 case kSCNetworkServicePrimaryRankFirst
:
628 case kSCNetworkServicePrimaryRankLast
:
631 case kSCNetworkServicePrimaryRankNever
:
634 case kSCNetworkServicePrimaryRankScoped
:
644 HandleSetInterfaceRank(xpc_connection_t connection
,
645 xpc_object_t request
,
648 #pragma unused(reply)
650 SCNetworkServicePrimaryRank rank
;
651 const char * rank_str
;
652 ControlSessionRef session
;
654 if (!IPMonitorControlServerConnectionIsRoot(connection
)) {
655 my_log(LOG_INFO
, "connection %p pid %d permission denied",
656 connection
, xpc_connection_get_pid(connection
));
660 = xpc_dictionary_get_string(request
,
661 kIPMonitorControlRequestKeyInterfaceName
);
662 if (ifname
== NULL
) {
665 rank
= (SCNetworkServicePrimaryRank
)
666 xpc_dictionary_get_uint64(request
,
667 kIPMonitorControlRequestKeyPrimaryRank
);
668 rank_str
= get_rank_str(rank
);
669 if (rank_str
== NULL
) {
672 session
= ControlSessionForConnection(connection
);
673 ControlSessionSetInterfaceRank(session
, ifname
, rank
);
674 my_log(LOG_NOTICE
, "%s[%d] SetInterfaceRank(%s) = %s (%u)",
675 get_process_name(request
),
676 xpc_connection_get_pid(connection
), ifname
, rank_str
, rank
);
681 HandleGetInterfaceRank(xpc_connection_t connection
,
682 xpc_object_t request
,
686 SCNetworkServicePrimaryRank rank
;
687 ControlSessionRef session
;
690 /* no point in processing the request if we can't provide an answer */
693 session
= ControlSessionLookup(connection
);
694 if (session
== NULL
) {
695 /* no session, no rank assertion */
699 = xpc_dictionary_get_string(request
,
700 kIPMonitorControlRequestKeyInterfaceName
);
701 if (ifname
== NULL
) {
704 rank
= ControlSessionGetInterfaceRank(session
, ifname
);
705 xpc_dictionary_set_uint64(reply
, kIPMonitorControlResponseKeyPrimaryRank
,
711 get_advisory_str(SCNetworkInterfaceAdvisory advisory
)
713 const char * str
= NULL
;
716 case kSCNetworkInterfaceAdvisoryNone
:
719 case kSCNetworkInterfaceAdvisoryLinkLayerIssue
:
720 str
= "LinkLayerIssue";
722 case kSCNetworkInterfaceAdvisoryUplinkIssue
:
732 HandleSetInterfaceAdvisory(xpc_connection_t connection
,
733 xpc_object_t request
,
736 #pragma unused(reply)
737 SCNetworkInterfaceAdvisory advisory
;
738 const char * advisory_str
;
741 ControlSessionRef session
;
743 #define ENTITLEMENT "com.apple.SystemConfiguration.SCNetworkInterfaceSetAdvisory"
744 if (!IPMonitorControlServerConnectionIsRoot(connection
)
745 && !IPMonitorControlServerConnectionHasEntitlement(connection
,
747 my_log(LOG_INFO
, "connection %p pid %d permission denied",
748 connection
, xpc_connection_get_pid(connection
));
752 = xpc_dictionary_get_string(request
,
753 kIPMonitorControlRequestKeyInterfaceName
);
754 if (ifname
== NULL
) {
758 = xpc_dictionary_get_string(request
,
759 kIPMonitorControlRequestKeyReason
);
760 advisory
= (SCNetworkInterfaceAdvisory
)
761 xpc_dictionary_get_uint64(request
, kIPMonitorControlRequestKeyAdvisory
);
763 /* validate the advisory code */
764 advisory_str
= get_advisory_str(advisory
);
765 if (advisory_str
== NULL
) {
768 session
= ControlSessionForConnection(connection
);
769 ControlSessionSetInterfaceAdvisory(session
, ifname
, advisory
);
770 my_log(LOG_NOTICE
, "%s[%d] SetInterfaceAdvisory(%s) = %s (%u) reason='%s'",
771 get_process_name(request
),
772 xpc_connection_get_pid(connection
), ifname
, advisory_str
, advisory
,
773 reason
!= NULL
? reason
: "" );
778 HandleInterfaceAdvisoryIsSet(xpc_connection_t connection
,
779 xpc_object_t request
,
782 #pragma unused(connection)
784 CFStringRef ifname_cf
;
787 /* no point in processing the request if we can't provide an answer */
791 = xpc_dictionary_get_string(request
,
792 kIPMonitorControlRequestKeyInterfaceName
);
793 if (ifname
== NULL
) {
796 ifname_cf
= CFStringCreateWithCString(NULL
, ifname
,
797 kCFStringEncodingUTF8
);
798 xpc_dictionary_set_bool(reply
,
799 kIPMonitorControlResponseKeyAdvisoryIsSet
,
800 InterfaceHasAdvisories(ifname_cf
));
801 CFRelease(ifname_cf
);
806 HandleAnyInterfaceAdvisoryIsSet(xpc_connection_t connection
,
807 xpc_object_t request
,
810 #pragma unused(connection)
811 #pragma unused(request)
813 /* no point in processing the request if we can't provide an answer */
816 xpc_dictionary_set_bool(reply
,
817 kIPMonitorControlResponseKeyAdvisoryIsSet
,
818 AnyInterfaceHasAdvisories());
823 IPMonitorControlServerHandleDisconnect(xpc_connection_t connection
)
825 ControlSessionRef session
;
827 my_log(LOG_DEBUG
, "IPMonitorControlServer: client %p went away",
829 session
= ControlSessionLookup(connection
);
830 if (session
== NULL
) {
831 /* never asserted anything */
834 ControlSessionInvalidate(session
);
839 IPMonitorControlServerHandleRequest(xpc_connection_t connection
,
840 xpc_object_t request
)
844 type
= xpc_get_type(request
);
845 if (type
== XPC_TYPE_DICTIONARY
) {
847 uint64_t request_type
;
848 xpc_connection_t remote
;
852 = xpc_dictionary_get_uint64(request
,
853 kIPMonitorControlRequestKeyType
);
854 reply
= xpc_dictionary_create_reply(request
);
855 switch (request_type
) {
856 case kIPMonitorControlRequestTypeSetInterfaceRank
:
857 error
= HandleSetInterfaceRank(connection
, request
, reply
);
859 case kIPMonitorControlRequestTypeGetInterfaceRank
:
860 error
= HandleGetInterfaceRank(connection
, request
, reply
);
862 case kIPMonitorControlRequestTypeSetInterfaceAdvisory
:
863 error
= HandleSetInterfaceAdvisory(connection
, request
, reply
);
865 case kIPMonitorControlRequestTypeInterfaceAdvisoryIsSet
:
866 error
= HandleInterfaceAdvisoryIsSet(connection
, request
, reply
);
868 case kIPMonitorControlRequestTypeAnyInterfaceAdvisoryIsSet
:
869 error
= HandleAnyInterfaceAdvisoryIsSet(connection
, request
, reply
);
876 /* client didn't want a reply */
879 xpc_dictionary_set_int64(reply
, kIPMonitorControlResponseKeyError
,
881 remote
= xpc_dictionary_get_remote_connection(request
);
882 xpc_connection_send_message(remote
, reply
);
885 else if (type
== XPC_TYPE_ERROR
) {
886 if (request
== XPC_ERROR_CONNECTION_INVALID
) {
887 IPMonitorControlServerHandleDisconnect(connection
);
889 else if (request
== XPC_ERROR_CONNECTION_INTERRUPTED
) {
890 my_log(LOG_INFO
, "connection interrupted");
894 my_log(LOG_NOTICE
, "unexpected event");
900 IPMonitorControlServerHandleNewConnection(xpc_connection_t connection
)
902 xpc_handler_t handler
;
904 handler
= ^(xpc_object_t event
) {
905 IPMonitorControlServerHandleRequest(connection
, event
);
907 xpc_connection_set_event_handler(connection
, handler
);
908 xpc_connection_set_target_queue(connection
, S_IPMonitorControlServerQueue
);
909 xpc_connection_resume(connection
);
913 STATIC xpc_connection_t
914 IPMonitorControlServerCreate(dispatch_queue_t queue
, const char * name
)
916 uint64_t flags
= XPC_CONNECTION_MACH_SERVICE_LISTENER
;
917 xpc_connection_t connection
;
918 xpc_handler_t handler
;
920 connection
= xpc_connection_create_mach_service(name
, queue
, flags
);
921 if (connection
== NULL
) {
924 handler
= ^(xpc_object_t event
) {
927 type
= xpc_get_type(event
);
928 if (type
== XPC_TYPE_CONNECTION
) {
929 IPMonitorControlServerHandleNewConnection(event
);
931 else if (type
== XPC_TYPE_ERROR
) {
934 desc
= xpc_dictionary_get_string(event
, XPC_ERROR_KEY_DESCRIPTION
);
935 if (event
== XPC_ERROR_CONNECTION_INVALID
) {
936 my_log(LOG_NOTICE
, "%s", desc
);
937 xpc_release(connection
);
940 my_log(LOG_NOTICE
, "%s", desc
);
944 my_log(LOG_NOTICE
, "unknown event %p", type
);
947 S_IPMonitorControlServerQueue
= queue
;
948 xpc_connection_set_event_handler(connection
, handler
);
949 xpc_connection_resume(connection
);
953 PRIVATE_EXTERN Boolean
954 IPMonitorControlServerStart(CFRunLoopRef runloop
, CFRunLoopSourceRef rls
,
957 #pragma unused(verbose)
959 xpc_connection_t connection
;
961 SetNotificationInfo(runloop
, rls
);
962 q
= dispatch_queue_create("IPMonitorControlServer", NULL
);
963 connection
= IPMonitorControlServerCreate(q
, kIPMonitorControlServerName
);
964 if (connection
== NULL
) {
966 "IPMonitorControlServer: failed to create server");
973 PRIVATE_EXTERN CFArrayRef
974 IPMonitorControlServerCopyInterfaceRankInformation(CFDictionaryRef
* info
)
976 __block CFArrayRef changed
;
977 __block CFDictionaryRef dict
;
979 dispatch_sync(S_IPMonitorControlServerQueue
,
981 dict
= InterfaceRankAssertionsCopy();
982 changed
= InterfaceChangedListCopy();