/*
- * Copyright (c) 2013-2015 Apple Inc. All rights reserved.
+ * Copyright (c) 2013-2018 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#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);
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;
}
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)
success = FALSE;
#ifdef TEST_IPMONITOR_CONTROL
my_log(LOG_NOTICE, "failure code %lld", error);
-#endif /* TEST_IPMONITOR_CONTROL */
+#endif /* TEST_IPMONITOR_CONTROL */
}
else {
success = TRUE;
if (event == XPC_ERROR_CONNECTION_INTERRUPTED) {
#ifdef TEST_IPMONITOR_CONTROL
my_log(LOG_NOTICE, "can retry");
-#endif /* TEST_IPMONITOR_CONTROL */
+#endif /* TEST_IPMONITOR_CONTROL */
retry = TRUE;
}
else {
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
**/
= xpc_connection_create_mach_service(kIPMonitorControlServerName,
queue, flags);
handler = ^(xpc_object_t event) {
- os_activity_t activity_id;
Boolean retry;
- activity_id = os_activity_start("processing IPMonitor [rank] reply",
- OS_ACTIVITY_FLAG_DEFAULT);
-
(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);
+ }
}
-
- os_activity_end(activity_id);
};
xpc_connection_set_event_handler(connection, handler);
control->connection = connection;
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);
}
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, "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, "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));
+}