Something went wrong. Try again.
Cider Isn't Darwin Emulation, Really
Something went wrong. Try again.
16 kB · 605 lines
C
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606/* * 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@ */
/* * IPMonitorControl.c * - IPC channel to IPMonitor * - used to create interface rank assertions */
/* * Modification History * * December 16, 2013 Dieter Siegmund (dieter@apple.com) * - initial revision */
#include "IPMonitorControl.h"#include "IPMonitorControlPrivate.h"#include "symbol_scope.h"#include <CoreFoundation/CFRuntime.h>#include <net/if.h>#include <xpc/xpc.h>#include <xpc/private.h>#include <SystemConfiguration/SCPrivate.h>
#ifdef TEST_IPMONITOR_CONTROL
#define my_log(__level, __format, ...) SCPrint(TRUE, stdout, CFSTR(__format "\n"), ## __VA_ARGS__)
#else /* TEST_IPMONITOR_CONTROL */
#define my_log(__level, __format, ...) SC_log(__level, __format, ## __VA_ARGS__)
#endif /* TEST_IPMONITOR_CONTROL */
/** ** IPMonitorControl CF object glue **/
struct IPMonitorControl { CFRuntimeBase cf_base;
dispatch_queue_t queue; xpc_connection_t connection;
CFMutableDictionaryRef assertions; /* ifname<string> = rank<number> */ CFMutableDictionaryRef advisories; /* ifname<string> = adv<number> */};
STATIC CFStringRef __IPMonitorControlCopyDebugDesc(CFTypeRef cf);STATIC void __IPMonitorControlDeallocate(CFTypeRef cf);
STATIC CFTypeID __kIPMonitorControlTypeID = _kCFRuntimeNotATypeID;
STATIC const CFRuntimeClass __IPMonitorControlClass = { 0, /* version */ "IPMonitorControl", /* className */ NULL, /* init */ NULL, /* copy */ __IPMonitorControlDeallocate, /* deallocate */ NULL, /* equal */ NULL, /* hash */ NULL, /* copyFormattingDesc */ __IPMonitorControlCopyDebugDesc /* copyDebugDesc */};
STATIC CFStringRef__IPMonitorControlCopyDebugDesc(CFTypeRef cf){ CFAllocatorRef allocator = CFGetAllocator(cf); IPMonitorControlRef control = (IPMonitorControlRef)cf;
return (CFStringCreateWithFormat(allocator, NULL, CFSTR("<IPMonitorControl %p>"), control));}
STATIC void__IPMonitorControlDeallocate(CFTypeRef cf){ IPMonitorControlRef control = (IPMonitorControlRef)cf;
if (control->connection != NULL) { xpc_release(control->connection); } if (control->queue != NULL) { dispatch_release(control->queue); } my_CFRelease(&control->advisories); my_CFRelease(&control->assertions); return;}
/** ** IPMonitorControl support functions **/STATIC void__IPMonitorControlRegisterClass(void){ STATIC dispatch_once_t once;
dispatch_once(&once, ^{ __kIPMonitorControlTypeID = _CFRuntimeRegisterClass(&__IPMonitorControlClass); }); return;}
STATIC IPMonitorControlRef__IPMonitorControlAllocate(CFAllocatorRef allocator){ IPMonitorControlRef control; int size;
__IPMonitorControlRegisterClass(); size = sizeof(*control) - sizeof(CFRuntimeBase); control = (IPMonitorControlRef) _CFRuntimeCreateInstance(allocator, __kIPMonitorControlTypeID, size, NULL); return (control);}
STATIC xpc_object_tcreate_request_dictionary(void){ const char * progname; xpc_object_t request;
request = xpc_dictionary_create(NULL, NULL, 0); progname = getprogname(); if (progname != NULL) { xpc_dictionary_set_string(request, kIPMonitorControlRequestKeyProcessName, progname); } return (request);}
STATIC BooleanIPMonitorControlHandleResponse(xpc_object_t event, Boolean async, Boolean * retry_p){ Boolean retry = FALSE; Boolean success = FALSE; xpc_type_t type;
type = xpc_get_type(event); if (type == XPC_TYPE_DICTIONARY) { if (async) { /* we don't expect async responses messages */ my_log(LOG_NOTICE, "unexpected message"); } else { int64_t error;
error = xpc_dictionary_get_int64(event, kIPMonitorControlResponseKeyError); if (error != 0) { success = FALSE;#ifdef TEST_IPMONITOR_CONTROL my_log(LOG_NOTICE, "failure code %lld", error);#endif /* TEST_IPMONITOR_CONTROL */ } else { success = TRUE; } } } else if (type == XPC_TYPE_ERROR) { if (event == XPC_ERROR_CONNECTION_INTERRUPTED) {#ifdef TEST_IPMONITOR_CONTROL my_log(LOG_NOTICE, "can retry");#endif /* TEST_IPMONITOR_CONTROL */ retry = TRUE; } else { const char * desc;
desc = xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION); my_log(LOG_NOTICE, "%s", desc); } } else { my_log(LOG_NOTICE, "unknown event type : %p", type); } if (retry_p != NULL) { *retry_p = retry; } return (success);}
STATIC void_IPMonitorControlSetInterfacePrimaryRank(IPMonitorControlRef control, CFStringRef ifname_cf, SCNetworkServicePrimaryRank rank){ if (control->assertions == NULL) { if (rank == kSCNetworkServicePrimaryRankDefault) { /* no assertions, no need to store rank */ return; } control->assertions = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } if (rank == kSCNetworkServicePrimaryRankDefault) { CFDictionaryRemoveValue(control->assertions, ifname_cf); if (CFDictionaryGetCount(control->assertions) == 0) { my_CFRelease(&control->assertions); } } else { CFNumberRef rank_cf;
rank_cf = CFNumberCreate(NULL, kCFNumberSInt32Type, &rank); CFDictionarySetValue(control->assertions, ifname_cf, rank_cf); CFRelease(rank_cf); } return;}
STATIC voidApplyInterfaceRank(const void * key, const void * value, void * context){ xpc_connection_t connection = (xpc_connection_t)context; char ifname[IF_NAMESIZE]; SCNetworkServicePrimaryRank rank; xpc_object_t request;
if (!CFStringGetCString(key, ifname, sizeof(ifname), kCFStringEncodingUTF8)) { return; } if (!CFNumberGetValue(value, kCFNumberSInt32Type, &rank)) { return; } request = create_request_dictionary(); xpc_dictionary_set_uint64(request, kIPMonitorControlRequestKeyType, kIPMonitorControlRequestTypeSetInterfaceRank); xpc_dictionary_set_string(request, kIPMonitorControlRequestKeyInterfaceName, ifname); xpc_dictionary_set_uint64(request, kIPMonitorControlRequestKeyPrimaryRank, rank); xpc_connection_send_message(connection, request); xpc_release(request); return;}
STATIC void_IPMonitorControlSetInterfaceAdvisory(IPMonitorControlRef control, CFStringRef ifname_cf, SCNetworkInterfaceAdvisory advisory){ if (control->advisories == NULL) { if (advisory == kSCNetworkInterfaceAdvisoryNone) { /* no advisories, no need to store advisory */ return; } control->advisories = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } if (advisory == kSCNetworkInterfaceAdvisoryNone) { CFDictionaryRemoveValue(control->advisories, ifname_cf); if (CFDictionaryGetCount(control->advisories) == 0) { my_CFRelease(&control->advisories); } } else { CFNumberRef advisory_cf;
advisory_cf = CFNumberCreate(NULL, kCFNumberSInt32Type, &advisory); CFDictionarySetValue(control->advisories, ifname_cf, advisory_cf); CFRelease(advisory_cf); } return;}
STATIC voidApplyInterfaceAdvisory(const void * key, const void * value, void * context){ xpc_connection_t connection = (xpc_connection_t)context; char ifname[IF_NAMESIZE]; SCNetworkInterfaceAdvisory advisory; xpc_object_t request;
if (!CFStringGetCString(key, ifname, sizeof(ifname), kCFStringEncodingUTF8)) { return; } if (!CFNumberGetValue(value, kCFNumberSInt32Type, &advisory)) { return; } request = create_request_dictionary(); xpc_dictionary_set_uint64(request, kIPMonitorControlRequestKeyType, kIPMonitorControlRequestTypeSetInterfaceAdvisory); xpc_dictionary_set_string(request, kIPMonitorControlRequestKeyInterfaceName, ifname); xpc_dictionary_set_uint64(request, kIPMonitorControlRequestKeyAdvisory, advisory); xpc_connection_send_message(connection, request); xpc_release(request); return;}
/** ** IPMonitorControl SPI **/PRIVATE_EXTERN IPMonitorControlRefIPMonitorControlCreate(void){ xpc_connection_t connection; IPMonitorControlRef control; uint64_t flags = XPC_CONNECTION_MACH_SERVICE_PRIVILEGED; xpc_handler_t handler; dispatch_queue_t queue;
control = __IPMonitorControlAllocate(NULL); queue = dispatch_queue_create("IPMonitorControl", NULL); connection = xpc_connection_create_mach_service(kIPMonitorControlServerName, queue, flags); handler = ^(xpc_object_t event) { Boolean retry;
(void)IPMonitorControlHandleResponse(event, TRUE, &retry); if (retry) { if (control->assertions != NULL) { CFDictionaryApplyFunction(control->assertions, ApplyInterfaceRank, control->connection); } if (control->advisories != NULL) { CFDictionaryApplyFunction(control->advisories, ApplyInterfaceAdvisory, control->connection); } } }; xpc_connection_set_event_handler(connection, handler); control->connection = connection; control->queue = queue; xpc_connection_resume(connection); return (control);}
STATIC xpc_object_tIPMonitorControlSendRequest(IPMonitorControlRef control, xpc_object_t request){ xpc_object_t reply;
while (TRUE) { Boolean retry_on_error = FALSE; Boolean success;
reply = xpc_connection_send_message_with_reply_sync(control->connection, request); if (reply == NULL) { my_log(LOG_NOTICE, "failed to send message"); break; } success = IPMonitorControlHandleResponse(reply, FALSE, &retry_on_error); if (success) { break; } xpc_release(reply); reply = NULL; if (retry_on_error) { continue; } my_log(LOG_NOTICE, "fatal error"); break; } return (reply);}
PRIVATE_EXTERN BooleanIPMonitorControlSetInterfacePrimaryRank(IPMonitorControlRef control, CFStringRef ifname_cf, SCNetworkServicePrimaryRank rank){ char ifname[IF_NAMESIZE]; xpc_object_t reply; xpc_object_t request; Boolean success = FALSE;
if (!CFStringGetCString(ifname_cf, ifname, sizeof(ifname), kCFStringEncodingUTF8)) { return (FALSE); }
request = create_request_dictionary(); xpc_dictionary_set_uint64(request, kIPMonitorControlRequestKeyType, kIPMonitorControlRequestTypeSetInterfaceRank); xpc_dictionary_set_string(request, kIPMonitorControlRequestKeyInterfaceName, ifname); xpc_dictionary_set_uint64(request, kIPMonitorControlRequestKeyPrimaryRank, rank); reply = IPMonitorControlSendRequest(control, request); xpc_release(request); if (reply != NULL) { success = TRUE; xpc_release(reply);
/* sync our state */ CFRetain(ifname_cf); CFRetain(control); dispatch_async(control->queue, ^{ _IPMonitorControlSetInterfacePrimaryRank(control, ifname_cf, rank); CFRelease(ifname_cf); CFRelease(control); }); } return (success);}
PRIVATE_EXTERN SCNetworkServicePrimaryRankIPMonitorControlGetInterfacePrimaryRank(IPMonitorControlRef control, CFStringRef ifname_cf){ char ifname[IF_NAMESIZE]; SCNetworkServicePrimaryRank rank; xpc_object_t reply; xpc_object_t request;
rank = kSCNetworkServicePrimaryRankDefault; if (!CFStringGetCString(ifname_cf, ifname, sizeof(ifname), kCFStringEncodingUTF8)) { return rank; }
request = create_request_dictionary(); xpc_dictionary_set_uint64(request, kIPMonitorControlRequestKeyType, kIPMonitorControlRequestTypeGetInterfaceRank); xpc_dictionary_set_string(request, kIPMonitorControlRequestKeyInterfaceName, ifname); reply = IPMonitorControlSendRequest(control, request); if (reply != NULL) { rank = (SCNetworkServicePrimaryRank) xpc_dictionary_get_uint64(reply, kIPMonitorControlResponseKeyPrimaryRank); xpc_release(reply); } xpc_release(request); return (rank);}
PRIVATE_EXTERN BooleanIPMonitorControlSetInterfaceAdvisory(IPMonitorControlRef control, CFStringRef ifname_cf, SCNetworkInterfaceAdvisory advisory, CFStringRef reason){ char ifname[IF_NAMESIZE]; char * reason_str = NULL; xpc_object_t reply; xpc_object_t request; Boolean success = FALSE;
if (!CFStringGetCString(ifname_cf, ifname, sizeof(ifname), kCFStringEncodingUTF8)) { return (FALSE); } if (reason != NULL) { reason_str = _SC_cfstring_to_cstring(reason, NULL, 0, kCFStringEncodingUTF8); } request = create_request_dictionary(); xpc_dictionary_set_uint64(request, kIPMonitorControlRequestKeyType, kIPMonitorControlRequestTypeSetInterfaceAdvisory); xpc_dictionary_set_string(request, kIPMonitorControlRequestKeyInterfaceName, ifname); xpc_dictionary_set_uint64(request, kIPMonitorControlRequestKeyAdvisory, advisory); if (reason_str != NULL) { xpc_dictionary_set_string(request, kIPMonitorControlRequestKeyReason, reason_str); CFAllocatorDeallocate(NULL, reason_str); } reply = IPMonitorControlSendRequest(control, request); xpc_release(request); if (reply != NULL) { xpc_release(reply); success = TRUE;
/* sync our state */ CFRetain(ifname_cf); CFRetain(control); dispatch_async(control->queue, ^{ _IPMonitorControlSetInterfaceAdvisory(control, ifname_cf, advisory); CFRelease(ifname_cf); CFRelease(control); }); } return (success);}
PRIVATE_EXTERN BooleanIPMonitorControlInterfaceAdvisoryIsSet(IPMonitorControlRef control, CFStringRef ifname_cf){ char ifname[IF_NAMESIZE]; xpc_object_t reply; xpc_object_t request; Boolean is_set = FALSE;
if (!CFStringGetCString(ifname_cf, ifname, sizeof(ifname), kCFStringEncodingUTF8)) { return (FALSE); } request = create_request_dictionary(); xpc_dictionary_set_uint64(request, kIPMonitorControlRequestKeyType, kIPMonitorControlRequestTypeInterfaceAdvisoryIsSet); xpc_dictionary_set_string(request, kIPMonitorControlRequestKeyInterfaceName, ifname); reply = IPMonitorControlSendRequest(control, request); xpc_release(request); if (reply != NULL) { if (xpc_dictionary_get_bool(reply, kIPMonitorControlResponseKeyAdvisoryIsSet)) { is_set = TRUE; } xpc_release(reply); } return (is_set);}
PRIVATE_EXTERN BooleanIPMonitorControlAnyInterfaceAdvisoryIsSet(IPMonitorControlRef control){ xpc_object_t reply; xpc_object_t request; Boolean is_set = FALSE;
request = create_request_dictionary(); xpc_dictionary_set_uint64(request, kIPMonitorControlRequestKeyType, kIPMonitorControlRequestTypeAnyInterfaceAdvisoryIsSet); reply = IPMonitorControlSendRequest(control, request); xpc_release(request); if (reply != NULL) { if (xpc_dictionary_get_bool(reply, kIPMonitorControlResponseKeyAdvisoryIsSet)) { is_set = TRUE; } xpc_release(reply); } return (is_set);}
PRIVATE_EXTERN CFStringRefIPMonitorControlCopyInterfaceAdvisoryNotificationKey(CFStringRef ifname){ return (_IPMonitorControlCopyInterfaceAdvisoryNotificationKey(ifname));}