diff options
Diffstat (limited to 'mDNSResponder/mDNSMacOSX/Private/dns_services.c')
-rw-r--r-- | mDNSResponder/mDNSMacOSX/Private/dns_services.c | 245 |
1 files changed, 141 insertions, 104 deletions
diff --git a/mDNSResponder/mDNSMacOSX/Private/dns_services.c b/mDNSResponder/mDNSMacOSX/Private/dns_services.c index 1df3b21d..794e2526 100644 --- a/mDNSResponder/mDNSMacOSX/Private/dns_services.c +++ b/mDNSResponder/mDNSMacOSX/Private/dns_services.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 4 -*- * - * Copyright (c) 2012 Apple Inc. All rights reserved. + * Copyright (c) 2012-2015 Apple Inc. All rights reserved. * * PRIVATE DNSX CLIENT LIBRARY --FOR Apple Platforms ONLY OSX/iOS-- * Resides in /usr/lib/libdns_services.dylib @@ -10,10 +10,10 @@ #include "dns_xpc.h" #include <xpc/xpc.h> #include <Block.h> -#include <stdio.h> -#include <stdlib.h> #include <syslog.h> +#define LOG_NOW LOG_INFO + //************************************************************************************************************* // Globals @@ -22,7 +22,7 @@ struct _DNSXConnRef_t { connection_t conn_ref; // xpc_connection between client and daemon - dispatch_queue_t lib_q; // internal queue created in library itself + dispatch_queue_t lib_q; // internal queue created in library itself void *AppCallBack; // Callback function ptr for Client dispatch_queue_t client_q; // Queue specified by client for scheduling its Callback }; @@ -37,11 +37,11 @@ static bool LogDebugEnabled() static void LogDebug(const char *prefix, xpc_object_t o) { - if (!LogDebugEnabled()) + if (!LogDebugEnabled()) return; char *desc = xpc_copy_description(o); - syslog(LOG_INFO, "%s: %s", prefix, desc); + syslog(LOG_NOW, "%s: %s", prefix, desc); free(desc); } @@ -49,164 +49,201 @@ static void LogDebug(const char *prefix, xpc_object_t o) void DNSXRefDeAlloc(DNSXConnRef connRef) { - if (!connRef) + if (connRef == NULL) { - syslog(LOG_WARNING, "dns_services: DNSXRefDeAlloc called with NULL DNSXConnRef"); + syslog(LOG_WARNING, "dns_services DD: DNSXRefDeAlloc called with NULL DNSXConnRef"); return; } - + // Schedule this work on the internal library queue dispatch_sync(connRef->lib_q, ^{ - + xpc_connection_set_event_handler((connRef)->conn_ref, ^(__unused xpc_object_t event){}); // ignore any more events xpc_release(connRef->conn_ref); + connRef->conn_ref = NULL; + dispatch_release(connRef->lib_q); + connRef->lib_q = NULL; connRef->AppCallBack = NULL; - dispatch_release(connRef->client_q); - + syslog(LOG_NOW, "dns_services DD: DNSXRefDeAlloc successfully DeAllocated conn_ref & lib_q"); + + dispatch_async((connRef)->client_q, ^{ + dispatch_release(connRef->client_q); + connRef->client_q = NULL; + free(connRef); + syslog(LOG_NOW, "dns_services DD: DNSXRefDeAlloc successfully DeAllocated client_q & freed connRef"); + }); }); - - dispatch_release(connRef->lib_q); - free(connRef); - - syslog(LOG_INFO, "dns_services: DNSXRefDeAlloc successfully DeAllocated connRef"); - + + // DO NOT reference connRef after this comment, as it may have been freed + syslog(LOG_NOW, "dns_services DD: DNSXRefDeAlloc successfully DeAllocated connRef"); + } -// Sends the Msg(Dictionary) to the Server -static DNSXErrorType SendMsgToServer(DNSXConnRef *connRef, xpc_object_t msg, bool old_conn) +// Sends the Msg(Dictionary) to the Server Daemon +static DNSXErrorType SendMsgToServer(DNSXConnRef connRef, xpc_object_t msg) { DNSXErrorType errx = kDNSX_NoError; - - LogDebug("dns_services: SendMsgToServer", msg); - xpc_connection_set_event_handler((*connRef)->conn_ref, ^(xpc_object_t recv_msg) + LogDebug("dns_services DD: SendMsgToServer Sending msg to Daemon", msg); + + xpc_connection_send_message_with_reply((connRef)->conn_ref, msg, (connRef)->lib_q, ^(xpc_object_t recv_msg) { xpc_type_t type = xpc_get_type(recv_msg); - + if (type == XPC_TYPE_DICTIONARY) { - LogDebug("dns_services: SendMsgToServer SUCCESS CALLBACK FROM SERVER", recv_msg); - syslog(LOG_INFO, "dns_services: Successfully Sent Msg to the Daemon"); + LogDebug("dns_services DD: SendMsgToServer Received reply msg from Daemon", recv_msg); uint64_t daemon_status = xpc_dictionary_get_uint64(recv_msg, kDNSDaemonReply); - - // Schedule the AppCallBacks on the Client Specified Queue - switch (daemon_status) - { - case kDNSDaemonEngaged: - dispatch_async((*connRef)->client_q, ^{ - ((DNSXEnableProxyReply)(*connRef)->AppCallBack)((*connRef), kDNSX_Engaged); - }); - break; - case kDNSMsgReceived: - dispatch_async((*connRef)->client_q, ^{ - ((DNSXEnableProxyReply)(*connRef)->AppCallBack)((*connRef), kDNSX_NoError); - }); - break; - default: - dispatch_async((*connRef)->client_q, ^{ - ((DNSXEnableProxyReply)(*connRef)->AppCallBack)((*connRef), kDNSX_UnknownErr); - }); - break; - } - + + if (connRef == NULL || connRef->client_q == NULL || connRef->AppCallBack == NULL) + { + // If connRef is bad, do not schedule any callbacks to the client + syslog(LOG_WARNING, "dns_services DD: SendMsgToServer: connRef is BAD Daemon status code [%llu]", daemon_status); + } + else + { + switch (daemon_status) + { + case kDNSMsg_NoError: + dispatch_async((connRef)->client_q, ^{ + if (connRef->AppCallBack != NULL) + ((DNSXEnableProxyReply)connRef->AppCallBack)(connRef, kDNSX_NoError); + }); + break; + + case kDNSMsg_BadArg: + dispatch_async((connRef)->client_q, ^{ + if (connRef->AppCallBack != NULL) + ((DNSXEnableProxyReply)connRef->AppCallBack)(connRef, kDNSX_BadParam); + }); + break; + + default: + dispatch_async((connRef)->client_q, ^{ + if (connRef->AppCallBack != NULL) + ((DNSXEnableProxyReply)connRef->AppCallBack)(connRef, kDNSX_UnknownErr); + }); + break; + } + } } else { - LogDebug("dns_services: SendMsgToServer UNEXPECTED CALLBACK FROM SERVER", recv_msg); - syslog(LOG_WARNING, "dns_services: Connection failed since NO privileges to access service OR Daemon NOT Running"); - dispatch_async((*connRef)->client_q, ^{ - ((DNSXEnableProxyReply)(*connRef)->AppCallBack)((*connRef), kDNSX_DaemonNotRunning); - }); + syslog(LOG_WARNING, "dns_services DD: SendMsgToServer Received unexpected reply from daemon [%s]", + xpc_dictionary_get_string(recv_msg, XPC_ERROR_KEY_DESCRIPTION)); + LogDebug("dns_services DD: SendMsgToServer Unexpected Reply contents", recv_msg); } }); - // To prevent Over-Resume of a connection - if (!old_conn) - xpc_connection_resume((*connRef)->conn_ref); - xpc_connection_send_message((*connRef)->conn_ref, msg); - if (!errx) - syslog(LOG_INFO, "dns_services: SendMSgToServer sent Msg Dict successfully to Daemon"); return errx; } -// Creates a new DNSX Connection Reference(DNSXConnRef). -// If DNSXConnRef exists, you may want to use that depending on the use case -static DNSXErrorType InitConnection(DNSXConnRef *connRef, const char *servname, dispatch_queue_t clientq, void *AppCallBack) +// Creates a new DNSX Connection Reference(DNSXConnRef) +static DNSXErrorType InitConnection(DNSXConnRef *connRefOut, const char *servname, dispatch_queue_t clientq, void *AppCallBack) { - if (!connRef) + if (connRefOut == NULL) + return kDNSX_BadParam; + + // Use a DNSXConnRef on the stack to be captured in the blocks below, rather than capturing the DNSXConnRef* owned by the client + DNSXConnRef connRef = malloc(sizeof(struct _DNSXConnRef_t)); + if (connRef == NULL) { - syslog(LOG_WARNING, "dns_services: InitConnection() called with NULL DNSXConnRef"); - return kDNSX_BadParam; + syslog(LOG_WARNING, "dns_services DD: InitConnection() No memory to allocate!"); + return kDNSX_NoMem; } - - *connRef = malloc(sizeof(struct _DNSXConnRef_t)); - if (!(*connRef)) + + // Initialize the DNSXConnRef + dispatch_retain(clientq); + connRef->client_q = clientq; + connRef->AppCallBack = AppCallBack; + connRef->lib_q = dispatch_queue_create("com.apple.mDNSResponder.libdns_services.q", DISPATCH_QUEUE_SERIAL); + connRef->conn_ref = xpc_connection_create_mach_service(servname, connRef->lib_q, XPC_CONNECTION_MACH_SERVICE_PRIVILEGED); + + if (connRef->conn_ref == NULL || connRef->lib_q == NULL) { - syslog(LOG_WARNING, "dns_services: InitConnection() No memory to allocate"); + syslog(LOG_WARNING, "dns_services DD: InitConnection() conn_ref/lib_q is NULL"); + if (connRef != NULL) + free(connRef); return kDNSX_NoMem; } - - // Initialize the DNSXConnRef - dispatch_retain(clientq); - (*connRef)->client_q = clientq; - (*connRef)->AppCallBack = AppCallBack; - (*connRef)->lib_q = dispatch_queue_create("com.apple.mDNSResponder.libdns_services.q", NULL); - (*connRef)->conn_ref = xpc_connection_create_mach_service(servname, (*connRef)->lib_q, XPC_CONNECTION_MACH_SERVICE_PRIVILEGED); - - syslog(LOG_INFO, "dns_services: InitConnection() successfully create a new DNSXConnRef"); + + xpc_connection_set_event_handler(connRef->conn_ref, ^(xpc_object_t event) + { + if (connRef == NULL || connRef->client_q == NULL || connRef->AppCallBack == NULL) + { + // If connRef is bad, do not schedule any callbacks to the client + syslog(LOG_WARNING, "dns_services DD: InitConnection: connRef is BAD Unexpected Connection Error [%s]", + xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION)); + } + else + { + syslog(LOG_WARNING, "dns_services DD: InitConnection: Unexpected Connection Error [%s] Ping the client", + xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION)); + dispatch_async(connRef->client_q, ^{ + if (connRef->AppCallBack != NULL) + ((DNSXEnableProxyReply)connRef->AppCallBack)(connRef, kDNSX_DaemonNotRunning); + }); + } + + }); + xpc_connection_resume(connRef->conn_ref); + + *connRefOut = connRef; + return kDNSX_NoError; } -DNSXErrorType DNSXEnableProxy(DNSXConnRef *connRef, DNSProxyParameters proxyparam, IfIndex inIfindexArr[MaxInputIf], - IfIndex outIfindex, dispatch_queue_t clientq, DNSXEnableProxyReply callBack) +DNSXErrorType DNSXEnableProxy(DNSXConnRef *connRef, DNSProxyParameters proxyparam, IfIndex inIfindexArr[MaxInputIf], + IfIndex outIfindex, dispatch_queue_t clientq, DNSXEnableProxyReply callBack) { - + DNSXErrorType errx = kDNSX_NoError; - bool old_conn = false; - + // Sanity Checks - if (!connRef || !callBack || !clientq) + if (connRef == NULL || callBack == NULL || clientq == NULL) { - syslog(LOG_WARNING, "dns_services: DNSXEnableProxy called with NULL DNSXConnRef OR Callback OR ClientQ parameter"); + syslog(LOG_WARNING, "dns_services DD: DNSXEnableProxy called with NULL DNSXConnRef OR Callback OR ClientQ parameter"); return kDNSX_BadParam; - } - - // If no connRef, get it from InitConnection() - if (!*connRef) + } + + // Get connRef from InitConnection() + if (*connRef == NULL) { errx = InitConnection(connRef, kDNSProxyService, clientq, callBack); if (errx) // On error InitConnection() leaves *connRef set to NULL { - syslog(LOG_WARNING, "dns_services: Since InitConnection() returned %d error returning w/o sending msg", errx); + syslog(LOG_WARNING, "dns_services DD: Since InitConnection() returned %d error returning w/o sending msg", errx); return errx; } } - else // Client already has a valid connRef + else // Client already has a connRef and this is not valid use for this SPI { - old_conn = true; + syslog(LOG_WARNING, "dns_services DD: Client already has a valid connRef! This is incorrect usage from the client"); + return kDNSX_BadParam; } - + // Create Dictionary To Send - xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0); - if (!dict) + xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0); + if (dict == NULL) { - syslog(LOG_WARNING, "dns_services: DNSXEnableProxy could not create the Msg Dict To Send!"); + syslog(LOG_WARNING, "dns_services DD: DNSXEnableProxy could not create the Msg Dict To Send!"); DNSXRefDeAlloc(*connRef); - return kDNSX_DictError; + return kDNSX_NoMem; } - + xpc_dictionary_set_uint64(dict, kDNSProxyParameters, proxyparam); - + xpc_dictionary_set_uint64(dict, kDNSInIfindex0, inIfindexArr[0]); xpc_dictionary_set_uint64(dict, kDNSInIfindex1, inIfindexArr[1]); - xpc_dictionary_set_uint64(dict, kDNSInIfindex2, inIfindexArr[2]); + xpc_dictionary_set_uint64(dict, kDNSInIfindex2, inIfindexArr[2]); xpc_dictionary_set_uint64(dict, kDNSInIfindex3, inIfindexArr[3]); xpc_dictionary_set_uint64(dict, kDNSInIfindex4, inIfindexArr[4]); - + xpc_dictionary_set_uint64(dict, kDNSOutIfindex, outIfindex); - - errx = SendMsgToServer(connRef, dict, old_conn); + + errx = SendMsgToServer(*connRef, dict); xpc_release(dict); - - return errx; + dict = NULL; + + return errx; } |