X-Git-Url: https://git.saurik.com/apple/configd.git/blobdiff_plain/78403150fdf95618c483be7dbe6bca9459b92a9f..ee4f8eb6ee4849d3f1e5588ade98ae78b03f5416:/IPMonitorControl/IPMonitorControl.c?ds=sidebyside diff --git a/IPMonitorControl/IPMonitorControl.c b/IPMonitorControl/IPMonitorControl.c index 83c6f10..39950ce 100644 --- a/IPMonitorControl/IPMonitorControl.c +++ b/IPMonitorControl/IPMonitorControl.c @@ -1,15 +1,15 @@ /* - * Copyright (c) 2013-2014 Apple Inc. All rights reserved. + * 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, @@ -17,7 +17,7 @@ * 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@ */ @@ -44,12 +44,14 @@ #include #ifdef TEST_IPMONITOR_CONTROL -#define my_log(__level, fmt, ...) SCPrint(TRUE, stdout, CFSTR(fmt "\n"), ## __VA_ARGS__) + +#define my_log(__level, __format, ...) SCPrint(TRUE, stdout, CFSTR(__format "\n"), ## __VA_ARGS__) #else /* TEST_IPMONITOR_CONTROL */ -#define my_log(__level, fmt, ...) SCLog(TRUE, __level, CFSTR(fmt), ## __VA_ARGS__) -#endif /* TEST_IPMONITOR_CONTROL */ +#define my_log(__level, __format, ...) SC_log(__level, __format, ## __VA_ARGS__) + +#endif /* TEST_IPMONITOR_CONTROL */ /** ** IPMonitorControl CF object glue @@ -60,7 +62,9 @@ struct IPMonitorControl { dispatch_queue_t queue; xpc_connection_t connection; + CFMutableDictionaryRef assertions; /* ifname = rank */ + CFMutableDictionaryRef advisories; /* ifname = adv */ }; STATIC CFStringRef __IPMonitorControlCopyDebugDesc(CFTypeRef cf); @@ -85,7 +89,7 @@ __IPMonitorControlCopyDebugDesc(CFTypeRef cf) { CFAllocatorRef allocator = CFGetAllocator(cf); IPMonitorControlRef control = (IPMonitorControlRef)cf; - + return (CFStringCreateWithFormat(allocator, NULL, CFSTR(""), control)); @@ -95,16 +99,18 @@ 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); + dispatch_release(control->queue); } + my_CFRelease(&control->advisories); + my_CFRelease(&control->assertions); return; } - + /** ** IPMonitorControl support functions **/ @@ -131,10 +137,25 @@ __IPMonitorControlAllocate(CFAllocatorRef allocator) control = (IPMonitorControlRef) _CFRuntimeCreateInstance(allocator, __kIPMonitorControlTypeID, size, NULL); - bzero(((void *)control) + sizeof(CFRuntimeBase), size); return (control); } +STATIC xpc_object_t +create_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 Boolean IPMonitorControlHandleResponse(xpc_object_t event, Boolean async, Boolean * retry_p) @@ -147,19 +168,18 @@ IPMonitorControlHandleResponse(xpc_object_t event, Boolean async, if (type == XPC_TYPE_DICTIONARY) { if (async) { /* we don't expect async responses messages */ - my_log(LOG_NOTICE, "IPMonitorControl: unexpected message"); + 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, - "IPMonitorControl: failure code %lld", error); -#endif /* TEST_IPMONITOR_CONTROL */ + my_log(LOG_NOTICE, "failure code %lld", error); +#endif /* TEST_IPMONITOR_CONTROL */ } else { success = TRUE; @@ -169,19 +189,19 @@ IPMonitorControlHandleResponse(xpc_object_t event, Boolean async, 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 */ + 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, "IPMonitorControl: %s", desc); + my_log(LOG_NOTICE, "%s", desc); } } else { - my_log(LOG_NOTICE, "IPMonitorControl: unknown event type : %p", type); + my_log(LOG_NOTICE, "unknown event type : %p", type); } if (retry_p != NULL) { *retry_p = retry; @@ -191,9 +211,9 @@ IPMonitorControlHandleResponse(xpc_object_t event, Boolean async, STATIC void -IPMonitorControlSetInterfaceRank(IPMonitorControlRef control, - CFStringRef ifname_cf, - SCNetworkServicePrimaryRank rank) +_IPMonitorControlSetInterfacePrimaryRank(IPMonitorControlRef control, + CFStringRef ifname_cf, + SCNetworkServicePrimaryRank rank) { if (control->assertions == NULL) { if (rank == kSCNetworkServicePrimaryRankDefault) { @@ -208,8 +228,7 @@ IPMonitorControlSetInterfaceRank(IPMonitorControlRef control, if (rank == kSCNetworkServicePrimaryRankDefault) { CFDictionaryRemoveValue(control->assertions, ifname_cf); if (CFDictionaryGetCount(control->assertions) == 0) { - CFRelease(control->assertions); - control->assertions = NULL; + my_CFRelease(&control->assertions); } } else { @@ -230,14 +249,14 @@ ApplyInterfaceRank(const void * key, const void * value, void * context) SCNetworkServicePrimaryRank rank; xpc_object_t request; - if (CFStringGetCString(key, ifname, sizeof(ifname), - kCFStringEncodingUTF8) == FALSE) { + if (!CFStringGetCString(key, ifname, sizeof(ifname), + kCFStringEncodingUTF8)) { return; } - if (CFNumberGetValue(value, kCFNumberSInt32Type, &rank) == FALSE) { + if (!CFNumberGetValue(value, kCFNumberSInt32Type, &rank)) { return; } - request = xpc_dictionary_create(NULL, NULL, 0); + request = create_request_dictionary(); xpc_dictionary_set_uint64(request, kIPMonitorControlRequestKeyType, kIPMonitorControlRequestTypeSetInterfaceRank); @@ -253,6 +272,68 @@ ApplyInterfaceRank(const void * key, const void * value, void * context) } +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 void +ApplyInterfaceAdvisory(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 **/ @@ -268,16 +349,23 @@ IPMonitorControlCreate(void) control = __IPMonitorControlAllocate(NULL); queue = dispatch_queue_create("IPMonitorControl", NULL); connection - = xpc_connection_create_mach_service(kIPMonitorControlServerName, + = xpc_connection_create_mach_service(kIPMonitorControlServerName, queue, flags); handler = ^(xpc_object_t event) { - Boolean retry; + Boolean retry; (void)IPMonitorControlHandleResponse(event, TRUE, &retry); - if (retry && control->assertions != NULL) { - CFDictionaryApplyFunction(control->assertions, - ApplyInterfaceRank, - control->connection); + 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); @@ -287,61 +375,77 @@ IPMonitorControlCreate(void) return (control); } -PRIVATE_EXTERN Boolean -IPMonitorControlSetInterfacePrimaryRank(IPMonitorControlRef control, - CFStringRef ifname_cf, - SCNetworkServicePrimaryRank rank) +STATIC xpc_object_t +IPMonitorControlSendRequest(IPMonitorControlRef control, + xpc_object_t request) { - char ifname[IF_NAMESIZE]; - xpc_object_t request; - Boolean success = FALSE; + xpc_object_t reply; - 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; + 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"); + my_log(LOG_NOTICE, "failed to send message"); break; } success = IPMonitorControlHandleResponse(reply, FALSE, &retry_on_error); - xpc_release(reply); if (success) { break; } + xpc_release(reply); + reply = NULL; if (retry_on_error) { continue; } - my_log(LOG_NOTICE, "IPMonitorControl: fatal error"); + my_log(LOG_NOTICE, "fatal error"); break; } + return (reply); +} + +PRIVATE_EXTERN Boolean +IPMonitorControlSetInterfacePrimaryRank(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 (success) { + if (reply != NULL) { + success = TRUE; + xpc_release(reply); + /* sync our state */ CFRetain(ifname_cf); CFRetain(control); dispatch_async(control->queue, ^{ - IPMonitorControlSetInterfaceRank(control, - ifname_cf, - rank); + _IPMonitorControlSetInterfacePrimaryRank(control, + ifname_cf, + rank); CFRelease(ifname_cf); CFRelease(control); }); @@ -349,55 +453,153 @@ IPMonitorControlSetInterfacePrimaryRank(IPMonitorControlRef control, return (success); } -SCNetworkServicePrimaryRank +PRIVATE_EXTERN SCNetworkServicePrimaryRank IPMonitorControlGetInterfacePrimaryRank(IPMonitorControlRef control, CFStringRef ifname_cf) { - char ifname[IF_NAMESIZE]; - SCNetworkServicePrimaryRank rank; - xpc_object_t request; + char ifname[IF_NAMESIZE]; + SCNetworkServicePrimaryRank rank; + xpc_object_t reply; + xpc_object_t request; rank = kSCNetworkServicePrimaryRankDefault; - if (CFStringGetCString(ifname_cf, ifname, sizeof(ifname), - kCFStringEncodingUTF8) == FALSE) { - goto done; + if (!CFStringGetCString(ifname_cf, ifname, sizeof(ifname), + kCFStringEncodingUTF8)) { + return rank; } - request = xpc_dictionary_create(NULL, NULL, 0); + + request = create_request_dictionary(); 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 = IPMonitorControlSendRequest(control, request); + if (reply != NULL) { + rank = (SCNetworkServicePrimaryRank) + xpc_dictionary_get_uint64(reply, + kIPMonitorControlResponseKeyPrimaryRank); + xpc_release(reply); + } + xpc_release(request); + return (rank); +} - 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); - } +PRIVATE_EXTERN Boolean +IPMonitorControlSetInterfaceAdvisory(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); - if (success) { - break; - } - if (retry_on_error) { - continue; - } - break; + 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 Boolean +IPMonitorControlInterfaceAdvisoryIsSet(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); +} - done: - return (rank); +PRIVATE_EXTERN Boolean +IPMonitorControlAnyInterfaceAdvisoryIsSet(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 CFStringRef +IPMonitorControlCopyInterfaceAdvisoryNotificationKey(CFStringRef ifname) +{ + return (_IPMonitorControlCopyInterfaceAdvisoryNotificationKey(ifname)); +}