/*
- * 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,
* 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@
*/
#include <SystemConfiguration/SCPrivate.h>
#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
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);
{
CFAllocatorRef allocator = CFGetAllocator(cf);
IPMonitorControlRef control = (IPMonitorControlRef)cf;
-
+
return (CFStringCreateWithFormat(allocator, NULL,
CFSTR("<IPMonitorControl %p>"),
control));
__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
**/
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)
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;
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;
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) {
if (rank == kSCNetworkServicePrimaryRankDefault) {
CFDictionaryRemoveValue(control->assertions, ifname_cf);
if (CFDictionaryGetCount(control->assertions) == 0) {
- CFRelease(control->assertions);
- control->assertions = NULL;
+ my_CFRelease(&control->assertions);
}
}
else {
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);
}
+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
**/
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);
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);
});
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));
+}