/* -*- 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; }