From 9449f151d0ccf3ac755d5f2bd9b4057ae2b03157 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Thu, 30 Jan 2014 13:52:13 +0100 Subject: mDNS: Import The sources can be obtained via: http://opensource.apple.com/tarballs/mDNSResponder/mDNSResponder-544.tar.gz --- mDNSResponder/mDNSMacOSX/DNSServiceDiscovery.c | 674 +++++++++++++++++++++++++ 1 file changed, 674 insertions(+) create mode 100644 mDNSResponder/mDNSMacOSX/DNSServiceDiscovery.c (limited to 'mDNSResponder/mDNSMacOSX/DNSServiceDiscovery.c') diff --git a/mDNSResponder/mDNSMacOSX/DNSServiceDiscovery.c b/mDNSResponder/mDNSMacOSX/DNSServiceDiscovery.c new file mode 100644 index 00000000..717efca2 --- /dev/null +++ b/mDNSResponder/mDNSMacOSX/DNSServiceDiscovery.c @@ -0,0 +1,674 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Suppress "warning: 'DNSServiceDiscoveryMachPort' is deprecated" messages -- we already know this code is building the deprecated API +// Since we compile with all warnings treated as errors, we have to turn off the warnings here or the project won't compile +#include +#undef AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED +#define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED +#undef AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3 +#define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3 + +#include "../mDNSMacOSX/DNSServiceDiscovery.h" +#include "DNSServiceDiscoveryDefines.h" +#include "DNSServiceDiscoveryReplyServer.h" + +#include +#include +#include +#include +#include +#include + +#include + +extern boolean_t DNSServiceDiscoveryReply_server( + mach_msg_header_t *InHeadP, + mach_msg_header_t *OutHeadP); + +extern +kern_return_t DNSServiceBrowserCreate_rpc +( + mach_port_t server, + mach_port_t client, + DNSCString regtype, + DNSCString domain +); + +extern +kern_return_t DNSServiceDomainEnumerationCreate_rpc +( + mach_port_t server, + mach_port_t client, + int registrationDomains +); + +extern +kern_return_t DNSServiceRegistrationCreate_rpc +( + mach_port_t server, + mach_port_t client, + DNSCString name, + DNSCString regtype, + DNSCString domain, + IPPort port, + DNSCString txtRecord +); + +extern +kern_return_t DNSServiceResolverResolve_rpc +( + mach_port_t server, + mach_port_t client, + DNSCString name, + DNSCString regtype, + DNSCString domain +); + +extern +kern_return_t DNSServiceRegistrationAddRecord_rpc +( + mach_port_t server, + mach_port_t client, + int type, + record_data_t data, + mach_msg_type_number_t record_dataCnt, + uint32_t ttl, + natural_t *reference +); + +extern +int DNSServiceRegistrationUpdateRecord_rpc +( + mach_port_t server, + mach_port_t client, + natural_t reference, + record_data_t data, + mach_msg_type_number_t record_dataCnt, + uint32_t ttl +); + +extern +kern_return_t DNSServiceRegistrationRemoveRecord_rpc +( + mach_port_t server, + mach_port_t client, + natural_t reference +); + +struct a_requests { + struct a_requests *next; + mach_port_t client_port; + union { + DNSServiceBrowserReply browserCallback; + DNSServiceDomainEnumerationReply enumCallback; + DNSServiceRegistrationReply regCallback; + DNSServiceResolverReply resolveCallback; + } callout; + void *context; +}; + +static struct a_requests *a_requests = NULL; +static pthread_mutex_t a_requests_lock = PTHREAD_MUTEX_INITIALIZER; + +typedef struct _dns_service_discovery_t { + mach_port_t port; +} dns_service_discovery_t; + +static mach_port_t DNSServiceDiscoveryLookupServer(void) +{ + static mach_port_t sndPort = MACH_PORT_NULL; + kern_return_t result; + + if (sndPort != MACH_PORT_NULL) { + return sndPort; + } + + result = bootstrap_look_up(bootstrap_port, DNS_SERVICE_DISCOVERY_SERVER, &sndPort); + if (result != KERN_SUCCESS) { + printf("%s(): {%s:%d} bootstrap_look_up() failed: $%x\n", __FUNCTION__, __FILE__, __LINE__, (int) result); + sndPort = MACH_PORT_NULL; + } + + + return sndPort; +} + +static void _increaseQueueLengthOnPort(mach_port_t port) +{ + mach_port_limits_t qlimits; + kern_return_t result; + + qlimits.mpl_qlimit = 16; + result = mach_port_set_attributes(mach_task_self(), port, MACH_PORT_LIMITS_INFO, (mach_port_info_t)&qlimits, MACH_PORT_LIMITS_INFO_COUNT); + + if (result != KERN_SUCCESS) { + printf("%s(): {%s:%d} mach_port_set_attributes() failed: $%x %s\n", __FUNCTION__, __FILE__, __LINE__, (int) result, mach_error_string(result)); + } +} + +dns_service_discovery_ref DNSServiceBrowserCreate (const char *regtype, const char *domain, DNSServiceBrowserReply callBack,void *context) +{ + mach_port_t serverPort = DNSServiceDiscoveryLookupServer(); + mach_port_t clientPort; + kern_return_t result; + dns_service_discovery_ref return_t; + struct a_requests *request; + + if (!serverPort) { + return NULL; + } + + result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort); + if (result != KERN_SUCCESS) { + printf("Mach port receive creation failed, %s\n", mach_error_string(result)); + return NULL; + } + result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND); + if (result != KERN_SUCCESS) { + printf("Mach port send creation failed, %s\n", mach_error_string(result)); + mach_port_destroy(mach_task_self(), clientPort); + return NULL; + } + _increaseQueueLengthOnPort(clientPort); + + return_t = malloc(sizeof(dns_service_discovery_t)); + return_t->port = clientPort; + + request = malloc(sizeof(struct a_requests)); + request->client_port = clientPort; + request->context = context; + request->callout.browserCallback = callBack; + + result = DNSServiceBrowserCreate_rpc(serverPort, clientPort, (char *)regtype, (char *)domain); + + if (result != KERN_SUCCESS) { + printf("There was an error creating a browser, %s\n", mach_error_string(result)); + free(request); + return NULL; + } + + pthread_mutex_lock(&a_requests_lock); + request->next = a_requests; + a_requests = request; + pthread_mutex_unlock(&a_requests_lock); + + return return_t; +} + +/* Service Enumeration */ + +dns_service_discovery_ref DNSServiceDomainEnumerationCreate (int registrationDomains, DNSServiceDomainEnumerationReply callBack, void *context) +{ + mach_port_t serverPort = DNSServiceDiscoveryLookupServer(); + mach_port_t clientPort; + kern_return_t result; + dns_service_discovery_ref return_t; + struct a_requests *request; + + if (!serverPort) { + return NULL; + } + + result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort); + if (result != KERN_SUCCESS) { + printf("Mach port receive creation failed, %s\n", mach_error_string(result)); + return NULL; + } + result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND); + if (result != KERN_SUCCESS) { + printf("Mach port send creation failed, %s\n", mach_error_string(result)); + mach_port_destroy(mach_task_self(), clientPort); + return NULL; + } + _increaseQueueLengthOnPort(clientPort); + + return_t = malloc(sizeof(dns_service_discovery_t)); + return_t->port = clientPort; + + request = malloc(sizeof(struct a_requests)); + request->client_port = clientPort; + request->context = context; + request->callout.enumCallback = callBack; + + result = DNSServiceDomainEnumerationCreate_rpc(serverPort, clientPort, registrationDomains); + + if (result != KERN_SUCCESS) { + printf("There was an error creating an enumerator, %s\n", mach_error_string(result)); + free(request); + return NULL; + } + + pthread_mutex_lock(&a_requests_lock); + request->next = a_requests; + a_requests = request; + pthread_mutex_unlock(&a_requests_lock); + + return return_t; +} + + +/* Service Registration */ + +dns_service_discovery_ref DNSServiceRegistrationCreate + (const char *name, const char *regtype, const char *domain, uint16_t port, const char *txtRecord, DNSServiceRegistrationReply callBack, void *context) +{ + mach_port_t serverPort = DNSServiceDiscoveryLookupServer(); + mach_port_t clientPort; + kern_return_t result; + dns_service_discovery_ref return_t; + struct a_requests *request; + IPPort IpPort; + char *portptr = (char *)&port; + + if (!serverPort) { + return NULL; + } + + if (!txtRecord) { + txtRecord = ""; + } + + result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort); + if (result != KERN_SUCCESS) { + printf("Mach port receive creation failed, %s\n", mach_error_string(result)); + return NULL; + } + result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND); + if (result != KERN_SUCCESS) { + printf("Mach port send creation failed, %s\n", mach_error_string(result)); + mach_port_destroy(mach_task_self(), clientPort); + return NULL; + } + _increaseQueueLengthOnPort(clientPort); + + return_t = malloc(sizeof(dns_service_discovery_t)); + return_t->port = clientPort; + + request = malloc(sizeof(struct a_requests)); + request->client_port = clientPort; + request->context = context; + request->callout.regCallback = callBack; + + // older versions of this code passed the port via mach IPC as an int. + // we continue to pass it as 4 bytes to maintain binary compatibility, + // but now ensure that the network byte order is preserved by using a struct + IpPort.bytes[0] = 0; + IpPort.bytes[1] = 0; + IpPort.bytes[2] = portptr[0]; + IpPort.bytes[3] = portptr[1]; + + result = DNSServiceRegistrationCreate_rpc(serverPort, clientPort, (char *)name, (char *)regtype, (char *)domain, IpPort, (char *)txtRecord); + + if (result != KERN_SUCCESS) { + printf("There was an error creating a resolve, %s\n", mach_error_string(result)); + free(request); + return NULL; + } + + pthread_mutex_lock(&a_requests_lock); + request->next = a_requests; + a_requests = request; + pthread_mutex_unlock(&a_requests_lock); + + return return_t; +} + +/* Resolver requests */ + +dns_service_discovery_ref DNSServiceResolverResolve(const char *name, const char *regtype, const char *domain, DNSServiceResolverReply callBack, void *context) +{ + mach_port_t serverPort = DNSServiceDiscoveryLookupServer(); + mach_port_t clientPort; + kern_return_t result; + dns_service_discovery_ref return_t; + struct a_requests *request; + + if (!serverPort) { + return NULL; + } + + result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort); + if (result != KERN_SUCCESS) { + printf("Mach port receive creation failed, %s\n", mach_error_string(result)); + return NULL; + } + result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND); + if (result != KERN_SUCCESS) { + printf("Mach port send creation failed, %s\n", mach_error_string(result)); + mach_port_destroy(mach_task_self(), clientPort); + return NULL; + } + _increaseQueueLengthOnPort(clientPort); + + return_t = malloc(sizeof(dns_service_discovery_t)); + return_t->port = clientPort; + + request = malloc(sizeof(struct a_requests)); + request->client_port = clientPort; + request->context = context; + request->callout.resolveCallback = callBack; + + DNSServiceResolverResolve_rpc(serverPort, clientPort, (char *)name, (char *)regtype, (char *)domain); + + pthread_mutex_lock(&a_requests_lock); + request->next = a_requests; + a_requests = request; + pthread_mutex_unlock(&a_requests_lock); + + return return_t; +} + +DNSRecordReference DNSServiceRegistrationAddRecord(dns_service_discovery_ref ref, uint16_t rrtype, uint16_t rdlen, const char *rdata, uint32_t ttl) +{ + mach_port_t serverPort = DNSServiceDiscoveryLookupServer(); + mach_port_t clientPort; + natural_t reference = 0; + kern_return_t result = KERN_SUCCESS; + + if (!serverPort) { + return kDNSServiceDiscoveryUnknownErr; + } + + clientPort = DNSServiceDiscoveryMachPort(ref); + + if (!clientPort) { + return kDNSServiceDiscoveryUnknownErr; + } + + result = DNSServiceRegistrationAddRecord_rpc(serverPort, clientPort, rrtype, (record_data_t)rdata, rdlen, ttl, &reference); + + if (result != KERN_SUCCESS) { + printf("The result of the registration was not successful. Error %d, result %s\n", result, mach_error_string(result)); + } + + return reference; +} + +DNSServiceRegistrationReplyErrorType DNSServiceRegistrationUpdateRecord(dns_service_discovery_ref ref, DNSRecordReference reference, uint16_t rdlen, const char *rdata, uint32_t ttl) +{ + mach_port_t serverPort = DNSServiceDiscoveryLookupServer(); + mach_port_t clientPort; + kern_return_t result = KERN_SUCCESS; + + if (!serverPort) { + return kDNSServiceDiscoveryUnknownErr; + } + + clientPort = DNSServiceDiscoveryMachPort(ref); + + if (!clientPort) { + return kDNSServiceDiscoveryUnknownErr; + } + + result = DNSServiceRegistrationUpdateRecord_rpc(serverPort, clientPort, (natural_t)reference, (record_data_t)rdata, rdlen, ttl); + if (result != KERN_SUCCESS) { + printf("The result of the registration was not successful. Error %d, result %s\n", result, mach_error_string(result)); + return result; + } + + return kDNSServiceDiscoveryNoError; +} + + +DNSServiceRegistrationReplyErrorType DNSServiceRegistrationRemoveRecord(dns_service_discovery_ref ref, DNSRecordReference reference) +{ + mach_port_t serverPort = DNSServiceDiscoveryLookupServer(); + mach_port_t clientPort; + kern_return_t result = KERN_SUCCESS; + + if (!serverPort) { + return kDNSServiceDiscoveryUnknownErr; + } + + clientPort = DNSServiceDiscoveryMachPort(ref); + + if (!clientPort) { + return kDNSServiceDiscoveryUnknownErr; + } + + result = DNSServiceRegistrationRemoveRecord_rpc(serverPort, clientPort, (natural_t)reference); + + if (result != KERN_SUCCESS) { + printf("The result of the registration was not successful. Error %d, result %s\n", result, mach_error_string(result)); + return result; + } + + return kDNSServiceDiscoveryNoError; +} + +void DNSServiceDiscovery_handleReply(void *replyMsg) +{ + unsigned long result = 0xFFFFFFFF; + mach_msg_header_t * msgSendBufPtr; + mach_msg_header_t * receivedMessage; + unsigned msgSendBufLength; + + msgSendBufLength = internal_DNSServiceDiscoveryReply_subsystem.maxsize; + msgSendBufPtr = (mach_msg_header_t *) malloc(msgSendBufLength); + + + receivedMessage = ( mach_msg_header_t * ) replyMsg; + + // Call DNSServiceDiscoveryReply_server to change mig-generated message into a + // genuine mach message. It will then cause the callback to get called. + result = DNSServiceDiscoveryReply_server ( receivedMessage, msgSendBufPtr ); + ( void ) mach_msg_send ( msgSendBufPtr ); + free(msgSendBufPtr); +} + +mach_port_t DNSServiceDiscoveryMachPort(dns_service_discovery_ref dnsServiceDiscovery) +{ + return dnsServiceDiscovery->port; +} + +void DNSServiceDiscoveryDeallocate(dns_service_discovery_ref dnsServiceDiscovery) +{ + struct a_requests *request0, *request; + mach_port_t reply = dnsServiceDiscovery->port; + + if (dnsServiceDiscovery->port) { + pthread_mutex_lock(&a_requests_lock); + request0 = NULL; + request = a_requests; + while (request) { + if (request->client_port == reply) { + /* request info found, remove from list */ + if (request0) { + request0->next = request->next; + } else { + a_requests = request->next; + } + break; + } else { + /* not info for this request, skip to next */ + request0 = request; + request = request->next; + } + + } + pthread_mutex_unlock(&a_requests_lock); + + free(request); + + mach_port_destroy(mach_task_self(), dnsServiceDiscovery->port); + + free(dnsServiceDiscovery); + } + return; +} + +// reply functions, calls the users setup callbacks with function pointers + +kern_return_t internal_DNSServiceDomainEnumerationReply_rpc +( + mach_port_t reply, + int resultType, + DNSCString replyDomain, + int flags +) +{ + struct a_requests *request; + void *requestContext = NULL; + DNSServiceDomainEnumerationReply callback = NULL; + + pthread_mutex_lock(&a_requests_lock); + request = a_requests; + while (request) { + if (request->client_port == reply) { + break; + } + request = request->next; + } + + if (request != NULL) { + callback = (*request->callout.enumCallback); + requestContext = request->context; + } + pthread_mutex_unlock(&a_requests_lock); + + if (request != NULL) { + (callback)(resultType, replyDomain, flags, requestContext); + } + + return KERN_SUCCESS; + +} + +kern_return_t internal_DNSServiceBrowserReply_rpc +( + mach_port_t reply, + int resultType, + DNSCString replyName, + DNSCString replyType, + DNSCString replyDomain, + int flags +) +{ + struct a_requests *request; + void *requestContext = NULL; + DNSServiceBrowserReply callback = NULL; + + pthread_mutex_lock(&a_requests_lock); + request = a_requests; + while (request) { + if (request->client_port == reply) { + break; + } + request = request->next; + } + if (request != NULL) { + callback = (*request->callout.browserCallback); + requestContext = request->context; + } + + pthread_mutex_unlock(&a_requests_lock); + + if (request != NULL) { + (callback)(resultType, replyName, replyType, replyDomain, flags, requestContext); + } + + return KERN_SUCCESS; +} + + +kern_return_t internal_DNSServiceRegistrationReply_rpc +( + mach_port_t reply, + int resultType +) +{ + struct a_requests *request; + void *requestContext = NULL; + DNSServiceRegistrationReply callback = NULL; + + pthread_mutex_lock(&a_requests_lock); + request = a_requests; + while (request) { + if (request->client_port == reply) { + break; + } + request = request->next; + } + if (request != NULL) { + callback = (*request->callout.regCallback); + requestContext = request->context; + } + + pthread_mutex_unlock(&a_requests_lock); + if (request != NULL) { + (callback)(resultType, requestContext); + } + return KERN_SUCCESS; +} + + +kern_return_t internal_DNSServiceResolverReply_rpc +( + mach_port_t reply, + sockaddr_t interface, + sockaddr_t address, + DNSCString txtRecord, + int flags +) +{ + struct sockaddr *interface_storage = NULL; + struct sockaddr *address_storage = NULL; + struct a_requests *request; + void *requestContext = NULL; + DNSServiceResolverReply callback = NULL; + + if (interface) { + int len = ((struct sockaddr *)interface)->sa_len; + interface_storage = (struct sockaddr *)malloc(len); + memcpy(interface_storage, interface, len); + } + + if (address) { + int len = ((struct sockaddr *)address)->sa_len; + address_storage = (struct sockaddr *)malloc(len); + memcpy(address_storage, address, len); + } + + pthread_mutex_lock(&a_requests_lock); + request = a_requests; + while (request) { + if (request->client_port == reply) { + break; + } + request = request->next; + } + + if (request != NULL) { + callback = (*request->callout.resolveCallback); + requestContext = request->context; + } + pthread_mutex_unlock(&a_requests_lock); + + if (request != NULL) { + (callback)(interface_storage, address_storage, txtRecord, flags, requestContext); + } + + if (interface) { + free(interface_storage); + } + if (address) { + free(address_storage); + } + + return KERN_SUCCESS; +} -- cgit v1.2.3