Something went wrong. Try again.
Cider Isn't Darwin Emulation, Really
Something went wrong. Try again.
11 kB · 403 lines
C
at android
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404/* * Copyright (c) 2013-2014 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, fmt, ...) SCPrint(TRUE, stdout, CFSTR(fmt "\n"), ## __VA_ARGS__)
#else /* TEST_IPMONITOR_CONTROL */
#define my_log(__level, fmt, ...) SCLog(TRUE, __level, CFSTR(fmt), ## __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> */};
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) { xpc_release(control->queue); } 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); bzero(((void *)control) + sizeof(CFRuntimeBase), size); return (control);}
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, "IPMonitorControl: 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, "IPMonitorControl: 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, "IPMonitorControl: 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, "IPMonitorControl: %s", desc); } } else { my_log(LOG_NOTICE, "IPMonitorControl: unknown event type : %p", type); } if (retry_p != NULL) { *retry_p = retry; } return (success);}
STATIC voidIPMonitorControlSetInterfaceRank(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) { CFRelease(control->assertions); control->assertions = NULL; } } 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) == FALSE) { return; } if (CFNumberGetValue(value, kCFNumberSInt32Type, &rank) == FALSE) { return; } request = xpc_dictionary_create(NULL, NULL, 0); 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;}
/** ** 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 && control->assertions != NULL) { CFDictionaryApplyFunction(control->assertions, ApplyInterfaceRank, control->connection); } }; xpc_connection_set_event_handler(connection, handler); control->connection = connection; control->queue = queue; xpc_connection_resume(connection); return (control);}
PRIVATE_EXTERN BooleanIPMonitorControlSetInterfacePrimaryRank(IPMonitorControlRef control, CFStringRef ifname_cf, SCNetworkServicePrimaryRank rank){ char ifname[IF_NAMESIZE]; xpc_object_t request; Boolean success = FALSE;
if (CFStringGetCString(ifname_cf, ifname, sizeof(ifname), kCFStringEncodingUTF8) == FALSE) { return (FALSE); } request = xpc_dictionary_create(NULL, NULL, 0); xpc_dictionary_set_uint64(request, kIPMonitorControlRequestKeyType, kIPMonitorControlRequestTypeSetInterfaceRank); xpc_dictionary_set_string(request, kIPMonitorControlRequestKeyInterfaceName, ifname); xpc_dictionary_set_uint64(request, kIPMonitorControlRequestKeyPrimaryRank, rank); while (TRUE) { xpc_object_t reply; Boolean retry_on_error = FALSE;
reply = xpc_connection_send_message_with_reply_sync(control->connection, request); if (reply == NULL) { my_log(LOG_NOTICE, "IPMonitorControl: failed to send message"); break; } success = IPMonitorControlHandleResponse(reply, FALSE, &retry_on_error); xpc_release(reply); if (success) { break; } if (retry_on_error) { continue; } my_log(LOG_NOTICE, "IPMonitorControl: fatal error"); break; } xpc_release(request); if (success) { /* sync our state */ CFRetain(ifname_cf); CFRetain(control); dispatch_async(control->queue, ^{ IPMonitorControlSetInterfaceRank(control, ifname_cf, rank); CFRelease(ifname_cf); CFRelease(control); }); } return (success);}
SCNetworkServicePrimaryRankIPMonitorControlGetInterfacePrimaryRank(IPMonitorControlRef control, CFStringRef ifname_cf){ char ifname[IF_NAMESIZE]; SCNetworkServicePrimaryRank rank; xpc_object_t request;
rank = kSCNetworkServicePrimaryRankDefault; if (CFStringGetCString(ifname_cf, ifname, sizeof(ifname), kCFStringEncodingUTF8) == FALSE) { goto done; } request = xpc_dictionary_create(NULL, NULL, 0); xpc_dictionary_set_uint64(request, kIPMonitorControlRequestKeyType, kIPMonitorControlRequestTypeGetInterfaceRank); xpc_dictionary_set_string(request, kIPMonitorControlRequestKeyInterfaceName, ifname); while (TRUE) { xpc_object_t reply; 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, "IPMonitorControl: failed to send message"); break; } success = IPMonitorControlHandleResponse(reply, FALSE, &retry_on_error); if (success) { rank = (SCNetworkServicePrimaryRank) xpc_dictionary_get_uint64(reply, kIPMonitorControlResponseKeyPrimaryRank); } xpc_release(reply); if (success) { break; } if (retry_on_error) { continue; } break; } xpc_release(request);
done: return (rank);}