Something went wrong. Try again.
Cider Isn't Darwin Emulation, Really
Something went wrong. Try again.
27 kB · 986 lines
C
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987/* * Copyright (c) 2013-2018 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */
/* * IPMonitorControlServer.c * - IPC channel to IPMonitor * - used to create interface rank assertions */
/* * Modification History * * December 16, 2013 Dieter Siegmund (dieter@apple.com) * - initial revision */
#include <CoreFoundation/CoreFoundation.h>#include <xpc/xpc.h>#include <xpc/private.h>#include <sys/queue.h>#include <CoreFoundation/CFRunLoop.h>#include <SystemConfiguration/SCNetworkConfigurationPrivate.h>#include <SystemConfiguration/SCPrivate.h>#include "IPMonitorControlServer.h"#include "symbol_scope.h"#include "IPMonitorControlPrivate.h"#include "IPMonitorAWDReport.h"
#ifdef TEST_IPMONITOR_CONTROL#define my_log(__level, __format, ...) SCPrint(TRUE, stdout, CFSTR(__format "\n"), ## __VA_ARGS__)
#else /* TEST_IPMONITOR_CONTROL */#include "ip_plugin.h"#endif /* TEST_IPMONITOR_CONTROL */
STATIC dispatch_queue_t S_IPMonitorControlServerQueue;
typedef struct ControlSession ControlSession, * ControlSessionRef;
#define LIST_HEAD_ControlSession LIST_HEAD(ControlSessionHead, ControlSession)#define LIST_ENTRY_ControlSession LIST_ENTRY(ControlSession)LIST_HEAD_ControlSession S_ControlSessions;
struct ControlSession { LIST_ENTRY_ControlSession link; xpc_connection_t connection;
CFMutableDictionaryRef assertions; /* ifname<string> = rank<number> */ CFMutableDictionaryRef advisories; /* ifname<string> = advisory<number> */};
/** ** Support Functions **/STATIC CFMutableArrayRef S_if_changes;STATIC CFRange S_if_changes_range;
STATIC CFNumberRefRankLastNumberGet(void){ STATIC CFNumberRef rank_last;
if (rank_last == NULL) { SCNetworkServicePrimaryRank rank;
rank = kSCNetworkServicePrimaryRankLast; rank_last = CFNumberCreate(NULL, kCFNumberSInt32Type, &rank); } return (rank_last);}
STATIC voidInterfaceChangedListAddInterface(CFStringRef ifname){ if (S_if_changes == NULL) { S_if_changes = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); CFArrayAppendValue(S_if_changes, ifname); S_if_changes_range.length = 1; } else if (!CFArrayContainsValue(S_if_changes, S_if_changes_range, ifname)) { CFArrayAppendValue(S_if_changes, ifname); S_if_changes_range.length++; }}
STATIC CFArrayRefInterfaceChangedListCopy(void){ CFArrayRef current_list;
current_list = S_if_changes; S_if_changes = NULL; return (current_list);}
STATIC voidInterfaceRankAssertionAdd(const void * key, const void * value, void * context){ CFMutableDictionaryRef * assertions_p; CFNumberRef existing_rank; CFNumberRef rank = (CFNumberRef)value;
assertions_p = (CFMutableDictionaryRef *)context; if (*assertions_p == NULL) { *assertions_p = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(*assertions_p, key, rank); return; } existing_rank = CFDictionaryGetValue(*assertions_p, key); if (existing_rank == NULL || (CFNumberCompare(rank, existing_rank, NULL) == kCFCompareGreaterThan)) { CFDictionarySetValue(*assertions_p, key, rank); } return;}
STATIC voidInterfaceAdvisoryAdd(const void * key, const void * value, void * context){#pragma unused(value) CFMutableDictionaryRef * assertions_p; CFNumberRef existing_rank; CFNumberRef rank;
/* an interface advisory implies RankLast */ rank = RankLastNumberGet(); assertions_p = (CFMutableDictionaryRef *)context; if (*assertions_p == NULL) { *assertions_p = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(*assertions_p, key, rank); return; } existing_rank = CFDictionaryGetValue(*assertions_p, key); if (existing_rank == NULL || (CFNumberCompare(rank, existing_rank, NULL) == kCFCompareGreaterThan)) { CFDictionarySetValue(*assertions_p, key, rank); } return;}
STATIC CFDictionaryRefInterfaceRankAssertionsCopy(void){ CFMutableDictionaryRef assertions = NULL; ControlSessionRef session;
LIST_FOREACH(session, &S_ControlSessions, link) { if (session->advisories != NULL) { CFDictionaryApplyFunction(session->advisories, InterfaceAdvisoryAdd, &assertions); } if (session->assertions != NULL) { CFDictionaryApplyFunction(session->assertions, InterfaceRankAssertionAdd, &assertions); } } return (assertions);}
STATIC BooleanInterfaceHasAdvisories(CFStringRef ifname){ ControlSessionRef session;
LIST_FOREACH(session, &S_ControlSessions, link) { if (session->advisories != NULL && CFDictionaryContainsKey(session->advisories, ifname)) { return (TRUE); } } return (FALSE);}
STATIC AWDIPMonitorInterfaceAdvisoryReport_Flagsadvisory_to_flags(SCNetworkInterfaceAdvisory advisory){ AWDIPMonitorInterfaceAdvisoryReport_Flags flags;
switch (advisory) { case kSCNetworkInterfaceAdvisoryNone: default: flags = 0; break; case kSCNetworkInterfaceAdvisoryLinkLayerIssue: flags = AWDIPMonitorInterfaceAdvisoryReport_Flags_LINK_LAYER_ISSUE; break; case kSCNetworkInterfaceAdvisoryUplinkIssue: flags = AWDIPMonitorInterfaceAdvisoryReport_Flags_UPLINK_ISSUE; break; } return (flags);}
STATIC AWDIPMonitorInterfaceAdvisoryReport_FlagsInterfaceGetAdvisoryFlags(CFStringRef ifname, ControlSessionRef exclude_session, uint32_t * ret_count){ uint32_t count; AWDIPMonitorInterfaceAdvisoryReport_Flags flags = 0; ControlSessionRef session;
count = 0; LIST_FOREACH(session, &S_ControlSessions, link) { SCNetworkInterfaceAdvisory advisory = 0; CFNumberRef advisory_cf;
if (session->advisories == NULL) { continue; } if (exclude_session != NULL && exclude_session == session) { continue; } advisory_cf = CFDictionaryGetValue(session->advisories, ifname); if (advisory_cf == NULL) { /* session has no advisories for this interface */ continue; } (void)CFNumberGetValue(advisory_cf, kCFNumberSInt32Type, &advisory); flags |= advisory_to_flags(advisory); count++; } *ret_count = count; return (flags);}
STATIC BooleanAnyInterfaceHasAdvisories(void){ ControlSessionRef session;
LIST_FOREACH(session, &S_ControlSessions, link) { if (session->advisories != NULL) { return (TRUE); } } return (FALSE);}
STATIC CFRunLoopRef S_runloop;STATIC CFRunLoopSourceRef S_signal_source;
STATIC voidSetNotificationInfo(CFRunLoopRef runloop, CFRunLoopSourceRef rls){ S_runloop = runloop; S_signal_source = rls; return;}
STATIC voidNotifyIPMonitor(void){ if (S_signal_source != NULL) { CFRunLoopSourceSignal(S_signal_source); if (S_runloop != NULL) { CFRunLoopWakeUp(S_runloop); } } return;}
STATIC voidNotifyInterfaceAdvisory(CFStringRef ifname){ CFStringRef key;
key = _IPMonitorControlCopyInterfaceAdvisoryNotificationKey(ifname); SCDynamicStoreNotifyValue(NULL, key); CFRelease(key); return;}
STATIC voidSubmitInterfaceAdvisoryMetric(CFStringRef ifname, AWDIPMonitorInterfaceAdvisoryReport_Flags flags, uint32_t count){ InterfaceAdvisoryReportRef report; AWDIPMonitorInterfaceType type;
/* XXX need to actually figure out what the interface type is */ if (CFStringHasPrefix(ifname, CFSTR("pdp"))) { type = AWDIPMonitorInterfaceType_IPMONITOR_INTERFACE_TYPE_CELLULAR; } else { type = AWDIPMonitorInterfaceType_IPMONITOR_INTERFACE_TYPE_WIFI; } report = InterfaceAdvisoryReportCreate(type); if (report == NULL) { return; } InterfaceAdvisoryReportSetFlags(report, flags); InterfaceAdvisoryReportSetAdvisoryCount(report, count); InterfaceAdvisoryReportSubmit(report); my_log(LOG_NOTICE, "%@: submitted AWD report %@", ifname, report); CFRelease(report);}
/** ** ControlSession **/STATIC voidAddChangedInterface(const void * key, const void * value, void * context){#pragma unused(value)#pragma unused(context) InterfaceChangedListAddInterface((CFStringRef)key); return;}
STATIC voidAddChangedInterfaceNotify(const void * key, const void * value, void * context){#pragma unused(value)#pragma unused(context) InterfaceChangedListAddInterface((CFStringRef)key); NotifyInterfaceAdvisory((CFStringRef)key); return;}
STATIC voidGenerateMetricForInterfaceAtSessionClose(const void * key, const void * value, void * context){ uint32_t count_after; uint32_t count_before; AWDIPMonitorInterfaceAdvisoryReport_Flags flags_after; AWDIPMonitorInterfaceAdvisoryReport_Flags flags_before; CFStringRef ifname = (CFStringRef)key; ControlSessionRef session = (ControlSessionRef)context;
#pragma unused(value) /* * Get the flags and count including this session, then again * excluding this session. If either flags or count are different, * generate the metric. */ flags_before = InterfaceGetAdvisoryFlags(ifname, NULL, &count_before); flags_after = InterfaceGetAdvisoryFlags(ifname, session, &count_after); if (flags_before != flags_after || count_before != count_after) { SubmitInterfaceAdvisoryMetric(ifname, flags_after, count_after); } return;}
STATIC voidControlSessionGenerateMetricsAtClose(ControlSessionRef session){ if (session->advisories == NULL) { return; } CFDictionaryApplyFunction(session->advisories, GenerateMetricForInterfaceAtSessionClose, session);}
STATIC voidControlSessionInvalidate(ControlSessionRef session){ my_log(LOG_DEBUG, "Invalidating %p", session); ControlSessionGenerateMetricsAtClose(session); LIST_REMOVE(session, link); if (session->assertions != NULL || session->advisories != NULL) { if (session->advisories != NULL) { my_log(LOG_NOTICE, "pid %d removing advisories %@", xpc_connection_get_pid(session->connection), session->advisories); CFDictionaryApplyFunction(session->advisories, AddChangedInterfaceNotify, NULL); my_CFRelease(&session->advisories); } if (session->assertions != NULL) { my_log(LOG_NOTICE, "pid %d removing assertions %@", xpc_connection_get_pid(session->connection), session->assertions); CFDictionaryApplyFunction(session->assertions, AddChangedInterface, NULL); my_CFRelease(&session->assertions); } NotifyIPMonitor(); } return;}
STATIC voidControlSessionRelease(void * p){ my_log(LOG_DEBUG, "Releasing %p", p); free(p); return;}
STATIC ControlSessionRefControlSessionLookup(xpc_connection_t connection){ return ((ControlSessionRef)xpc_connection_get_context(connection));}
STATIC ControlSessionRefControlSessionCreate(xpc_connection_t connection){ ControlSessionRef session;
session = (ControlSessionRef)malloc(sizeof(*session)); memset(session, 0, sizeof(*session)); session->connection = connection; xpc_connection_set_finalizer_f(connection, ControlSessionRelease); xpc_connection_set_context(connection, session); LIST_INSERT_HEAD(&S_ControlSessions, session, link); my_log(LOG_DEBUG, "Created %p (connection %p)", session, connection); return (session);}
STATIC ControlSessionRefControlSessionForConnection(xpc_connection_t connection){ ControlSessionRef session;
session = ControlSessionLookup(connection); if (session != NULL) { return (session); } return (ControlSessionCreate(connection));}
STATIC voidControlSessionSetInterfaceRank(ControlSessionRef session, const char * ifname, SCNetworkServicePrimaryRank rank){ CFStringRef ifname_cf;
if (session->assertions == NULL) { if (rank == kSCNetworkServicePrimaryRankDefault) { /* no assertions, no need to store rank */ return; } session->assertions = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } ifname_cf = CFStringCreateWithCString(NULL, ifname, kCFStringEncodingUTF8);
if (rank == kSCNetworkServicePrimaryRankDefault) { CFDictionaryRemoveValue(session->assertions, ifname_cf); if (CFDictionaryGetCount(session->assertions) == 0) { CFRelease(session->assertions); session->assertions = NULL; } } else { CFNumberRef rank_cf;
rank_cf = CFNumberCreate(NULL, kCFNumberSInt32Type, &rank); CFDictionarySetValue(session->assertions, ifname_cf, rank_cf); CFRelease(rank_cf); } InterfaceChangedListAddInterface(ifname_cf); NotifyIPMonitor(); CFRelease(ifname_cf); return;}
STATIC SCNetworkServicePrimaryRankControlSessionGetInterfaceRank(ControlSessionRef session, const char * ifname){ SCNetworkServicePrimaryRank rank = kSCNetworkServicePrimaryRankDefault;
if (session->assertions != NULL) { CFStringRef ifname_cf; CFNumberRef rank_cf;
ifname_cf = CFStringCreateWithCString(NULL, ifname, kCFStringEncodingUTF8); rank_cf = CFDictionaryGetValue(session->assertions, ifname_cf); CFRelease(ifname_cf); if (rank_cf != NULL) { (void)CFNumberGetValue(rank_cf, kCFNumberSInt32Type, &rank); } } return (rank);}
STATIC voidControlSessionSetInterfaceAdvisory(ControlSessionRef session, const char * ifname, SCNetworkInterfaceAdvisory advisory){ uint32_t count_after; uint32_t count_before; AWDIPMonitorInterfaceAdvisoryReport_Flags flags_after; AWDIPMonitorInterfaceAdvisoryReport_Flags flags_before; CFStringRef ifname_cf;
if (session->advisories == NULL) { if (advisory == kSCNetworkInterfaceAdvisoryNone) { /* no advisories, no need to store advisory */ return; } session->advisories = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } ifname_cf = CFStringCreateWithCString(NULL, ifname, kCFStringEncodingUTF8); flags_before = InterfaceGetAdvisoryFlags(ifname_cf, NULL, &count_before); if (advisory == kSCNetworkInterfaceAdvisoryNone) { CFDictionaryRemoveValue(session->advisories, ifname_cf); if (CFDictionaryGetCount(session->advisories) == 0) { CFRelease(session->advisories); session->advisories = NULL; } } else { CFNumberRef advisory_cf;
advisory_cf = CFNumberCreate(NULL, kCFNumberSInt32Type, &advisory); CFDictionarySetValue(session->advisories, ifname_cf, advisory_cf); CFRelease(advisory_cf); } flags_after = InterfaceGetAdvisoryFlags(ifname_cf, NULL, &count_after); if (flags_before != flags_after || count_before != count_after) { SubmitInterfaceAdvisoryMetric(ifname_cf, flags_after, count_after); } InterfaceChangedListAddInterface(ifname_cf); NotifyInterfaceAdvisory(ifname_cf); NotifyIPMonitor(); CFRelease(ifname_cf); return;}
/** ** IPMonitorControlServer **/
STATIC const char *get_process_name(xpc_object_t request){ const char * process_name;
process_name = xpc_dictionary_get_string(request, kIPMonitorControlRequestKeyProcessName); if (process_name == NULL) { process_name = "<unknown>"; } return (process_name);}
STATIC BooleanIPMonitorControlServerConnectionIsRoot(xpc_connection_t connection){ uid_t uid;
uid = xpc_connection_get_euid(connection); return (uid == 0);}
STATIC BooleanIPMonitorControlServerConnectionHasEntitlement(xpc_connection_t connection, const char * entitlement){ Boolean entitled = FALSE; xpc_object_t val;
val = xpc_connection_copy_entitlement_value(connection, entitlement); if (val != NULL) { if (xpc_get_type(val) == XPC_TYPE_BOOL) { entitled = xpc_bool_get_value(val); } xpc_release(val); } return (entitled);}
STATIC const char *get_rank_str(SCNetworkServicePrimaryRank rank){ const char * str = NULL;
switch (rank) { case kSCNetworkServicePrimaryRankDefault: str = "Default"; break; case kSCNetworkServicePrimaryRankFirst: str = "First"; break; case kSCNetworkServicePrimaryRankLast: str = "Last"; break; case kSCNetworkServicePrimaryRankNever: str = "Never"; break; case kSCNetworkServicePrimaryRankScoped: str = "Scoped"; break; default: break; } return (str);}
STATIC intHandleSetInterfaceRank(xpc_connection_t connection, xpc_object_t request, xpc_object_t reply){#pragma unused(reply) const char * ifname; SCNetworkServicePrimaryRank rank; const char * rank_str; ControlSessionRef session;
if (!IPMonitorControlServerConnectionIsRoot(connection)) { my_log(LOG_INFO, "connection %p pid %d permission denied", connection, xpc_connection_get_pid(connection)); return (EPERM); } ifname = xpc_dictionary_get_string(request, kIPMonitorControlRequestKeyInterfaceName); if (ifname == NULL) { return (EINVAL); } rank = (SCNetworkServicePrimaryRank) xpc_dictionary_get_uint64(request, kIPMonitorControlRequestKeyPrimaryRank); rank_str = get_rank_str(rank); if (rank_str == NULL) { return (EINVAL); } session = ControlSessionForConnection(connection); ControlSessionSetInterfaceRank(session, ifname, rank); my_log(LOG_NOTICE, "%s[%d] SetInterfaceRank(%s) = %s (%u)", get_process_name(request), xpc_connection_get_pid(connection), ifname, rank_str, rank); return (0);}
STATIC intHandleGetInterfaceRank(xpc_connection_t connection, xpc_object_t request, xpc_object_t reply){ const char * ifname; SCNetworkServicePrimaryRank rank; ControlSessionRef session;
if (reply == NULL) { /* no point in processing the request if we can't provide an answer */ return (EINVAL); } session = ControlSessionLookup(connection); if (session == NULL) { /* no session, no rank assertion */ return (ENOENT); } ifname = xpc_dictionary_get_string(request, kIPMonitorControlRequestKeyInterfaceName); if (ifname == NULL) { return (EINVAL); } rank = ControlSessionGetInterfaceRank(session, ifname); xpc_dictionary_set_uint64(reply, kIPMonitorControlResponseKeyPrimaryRank, rank); return (0);}
STATIC const char *get_advisory_str(SCNetworkInterfaceAdvisory advisory){ const char * str = NULL;
switch (advisory) { case kSCNetworkInterfaceAdvisoryNone: str = "None"; break; case kSCNetworkInterfaceAdvisoryLinkLayerIssue: str = "LinkLayerIssue"; break; case kSCNetworkInterfaceAdvisoryUplinkIssue: str = "UplinkIssue"; break; default: break; } return (str);}
STATIC intHandleSetInterfaceAdvisory(xpc_connection_t connection, xpc_object_t request, xpc_object_t reply){#pragma unused(reply) SCNetworkInterfaceAdvisory advisory; const char * advisory_str; const char * ifname; const char * reason; ControlSessionRef session;
#define ENTITLEMENT "com.apple.SystemConfiguration.SCNetworkInterfaceSetAdvisory" if (!IPMonitorControlServerConnectionIsRoot(connection) && !IPMonitorControlServerConnectionHasEntitlement(connection, ENTITLEMENT)) { my_log(LOG_INFO, "connection %p pid %d permission denied", connection, xpc_connection_get_pid(connection)); return (EPERM); } ifname = xpc_dictionary_get_string(request, kIPMonitorControlRequestKeyInterfaceName); if (ifname == NULL) { return (EINVAL); } reason = xpc_dictionary_get_string(request, kIPMonitorControlRequestKeyReason); advisory = (SCNetworkInterfaceAdvisory) xpc_dictionary_get_uint64(request, kIPMonitorControlRequestKeyAdvisory);
/* validate the advisory code */ advisory_str = get_advisory_str(advisory); if (advisory_str == NULL) { return (EINVAL); } session = ControlSessionForConnection(connection); ControlSessionSetInterfaceAdvisory(session, ifname, advisory); my_log(LOG_NOTICE, "%s[%d] SetInterfaceAdvisory(%s) = %s (%u) reason='%s'", get_process_name(request), xpc_connection_get_pid(connection), ifname, advisory_str, advisory, reason != NULL ? reason : "" ); return (0);}
STATIC intHandleInterfaceAdvisoryIsSet(xpc_connection_t connection, xpc_object_t request, xpc_object_t reply){#pragma unused(connection) const char * ifname; CFStringRef ifname_cf;
if (reply == NULL) { /* no point in processing the request if we can't provide an answer */ return (EINVAL); } ifname = xpc_dictionary_get_string(request, kIPMonitorControlRequestKeyInterfaceName); if (ifname == NULL) { return (EINVAL); } ifname_cf = CFStringCreateWithCString(NULL, ifname, kCFStringEncodingUTF8); xpc_dictionary_set_bool(reply, kIPMonitorControlResponseKeyAdvisoryIsSet, InterfaceHasAdvisories(ifname_cf)); CFRelease(ifname_cf); return (0);}
STATIC intHandleAnyInterfaceAdvisoryIsSet(xpc_connection_t connection, xpc_object_t request, xpc_object_t reply){#pragma unused(connection)#pragma unused(request) if (reply == NULL) { /* no point in processing the request if we can't provide an answer */ return (EINVAL); } xpc_dictionary_set_bool(reply, kIPMonitorControlResponseKeyAdvisoryIsSet, AnyInterfaceHasAdvisories()); return (0);}
STATIC voidIPMonitorControlServerHandleDisconnect(xpc_connection_t connection){ ControlSessionRef session;
my_log(LOG_DEBUG, "IPMonitorControlServer: client %p went away", connection); session = ControlSessionLookup(connection); if (session == NULL) { /* never asserted anything */ return; } ControlSessionInvalidate(session); return;}
STATIC voidIPMonitorControlServerHandleRequest(xpc_connection_t connection, xpc_object_t request){ xpc_type_t type;
type = xpc_get_type(request); if (type == XPC_TYPE_DICTIONARY) { int error = 0; uint64_t request_type; xpc_connection_t remote; xpc_object_t reply;
request_type = xpc_dictionary_get_uint64(request, kIPMonitorControlRequestKeyType); reply = xpc_dictionary_create_reply(request); switch (request_type) { case kIPMonitorControlRequestTypeSetInterfaceRank: error = HandleSetInterfaceRank(connection, request, reply); break; case kIPMonitorControlRequestTypeGetInterfaceRank: error = HandleGetInterfaceRank(connection, request, reply); break; case kIPMonitorControlRequestTypeSetInterfaceAdvisory: error = HandleSetInterfaceAdvisory(connection, request, reply); break; case kIPMonitorControlRequestTypeInterfaceAdvisoryIsSet: error = HandleInterfaceAdvisoryIsSet(connection, request, reply); break; case kIPMonitorControlRequestTypeAnyInterfaceAdvisoryIsSet: error = HandleAnyInterfaceAdvisoryIsSet(connection, request, reply); break; default: error = EINVAL; break; } if (reply == NULL) { /* client didn't want a reply */ return; } xpc_dictionary_set_int64(reply, kIPMonitorControlResponseKeyError, error); remote = xpc_dictionary_get_remote_connection(request); xpc_connection_send_message(remote, reply); xpc_release(reply); } else if (type == XPC_TYPE_ERROR) { if (request == XPC_ERROR_CONNECTION_INVALID) { IPMonitorControlServerHandleDisconnect(connection); } else if (request == XPC_ERROR_CONNECTION_INTERRUPTED) { my_log(LOG_INFO, "connection interrupted"); } } else { my_log(LOG_NOTICE, "unexpected event"); } return;}
STATIC voidIPMonitorControlServerHandleNewConnection(xpc_connection_t connection){ xpc_handler_t handler;
handler = ^(xpc_object_t event) { IPMonitorControlServerHandleRequest(connection, event); }; xpc_connection_set_event_handler(connection, handler); xpc_connection_set_target_queue(connection, S_IPMonitorControlServerQueue); xpc_connection_resume(connection); return;}
STATIC xpc_connection_tIPMonitorControlServerCreate(dispatch_queue_t queue, const char * name){ uint64_t flags = XPC_CONNECTION_MACH_SERVICE_LISTENER; xpc_connection_t connection; xpc_handler_t handler;
connection = xpc_connection_create_mach_service(name, queue, flags); if (connection == NULL) { return (NULL); } handler = ^(xpc_object_t event) { xpc_type_t type;
type = xpc_get_type(event); if (type == XPC_TYPE_CONNECTION) { IPMonitorControlServerHandleNewConnection(event); } else if (type == XPC_TYPE_ERROR) { const char * desc;
desc = xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION); if (event == XPC_ERROR_CONNECTION_INVALID) { my_log(LOG_NOTICE, "%s", desc); xpc_release(connection); } else { my_log(LOG_NOTICE, "%s", desc); } } else { my_log(LOG_NOTICE, "unknown event %p", type); } }; S_IPMonitorControlServerQueue = queue; xpc_connection_set_event_handler(connection, handler); xpc_connection_resume(connection); return (connection);}
PRIVATE_EXTERN BooleanIPMonitorControlServerStart(CFRunLoopRef runloop, CFRunLoopSourceRef rls, Boolean * verbose){#pragma unused(verbose) dispatch_queue_t q; xpc_connection_t connection;
SetNotificationInfo(runloop, rls); q = dispatch_queue_create("IPMonitorControlServer", NULL); connection = IPMonitorControlServerCreate(q, kIPMonitorControlServerName); if (connection == NULL) { my_log(LOG_ERR, "IPMonitorControlServer: failed to create server"); dispatch_release(q); return (FALSE); } return (TRUE);}
PRIVATE_EXTERN CFArrayRefIPMonitorControlServerCopyInterfaceRankInformation(CFDictionaryRef * info){ __block CFArrayRef changed; __block CFDictionaryRef dict;
dispatch_sync(S_IPMonitorControlServerQueue, ^{ dict = InterfaceRankAssertionsCopy(); changed = InterfaceChangedListCopy(); }); *info = dict; return (changed);}