1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 // Suppress "warning: 'DNSServiceDiscoveryMachPort' is deprecated" messages -- we already know this code is building the deprecated API
19 // Since we compile with all warnings treated as errors, we have to turn off the warnings here or the project won't compile
20 #include <AvailabilityMacros.h>
21 #undef AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED
22 #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED
23 #undef AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3
24 #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3
26 #include "DNSServiceDiscovery.h"
27 #include "DNSServiceDiscoveryDefines.h"
28 #include "DNSServiceDiscoveryReplyServer.h"
32 #include <servers/bootstrap.h>
33 #include <mach/mach.h>
34 #include <mach/mach_error.h>
37 #include <netinet/in.h>
39 extern boolean_t
DNSServiceDiscoveryReply_server(
40 mach_msg_header_t
*InHeadP
,
41 mach_msg_header_t
*OutHeadP
);
44 kern_return_t DNSServiceBrowserCreate_rpc
53 kern_return_t DNSServiceDomainEnumerationCreate_rpc
57 int registrationDomains
61 kern_return_t DNSServiceRegistrationCreate_rpc
73 kern_return_t DNSServiceResolverResolve_rpc
83 kern_return_t DNSServiceRegistrationAddRecord_rpc
89 mach_msg_type_number_t record_dataCnt
,
95 int DNSServiceRegistrationUpdateRecord_rpc
101 mach_msg_type_number_t record_dataCnt
,
106 kern_return_t DNSServiceRegistrationRemoveRecord_rpc
114 struct a_requests
*next
;
115 mach_port_t client_port
;
117 DNSServiceBrowserReply browserCallback
;
118 DNSServiceDomainEnumerationReply enumCallback
;
119 DNSServiceRegistrationReply regCallback
;
120 DNSServiceResolverReply resolveCallback
;
125 static struct a_requests
*a_requests
= NULL
;
126 static pthread_mutex_t a_requests_lock
= PTHREAD_MUTEX_INITIALIZER
;
128 typedef struct _dns_service_discovery_t
{
130 } dns_service_discovery_t
;
132 static mach_port_t
DNSServiceDiscoveryLookupServer(void)
134 static mach_port_t sndPort
= MACH_PORT_NULL
;
135 kern_return_t result
;
137 if (sndPort
!= MACH_PORT_NULL
) {
141 result
= bootstrap_look_up(bootstrap_port
, DNS_SERVICE_DISCOVERY_SERVER
, &sndPort
);
142 if (result
!= KERN_SUCCESS
) {
143 printf("%s(): {%s:%d} bootstrap_look_up() failed: $%x\n", __FUNCTION__
, __FILE__
, __LINE__
, (int) result
);
144 sndPort
= MACH_PORT_NULL
;
151 static void _increaseQueueLengthOnPort(mach_port_t port
)
153 mach_port_limits_t qlimits
;
154 kern_return_t result
;
156 qlimits
.mpl_qlimit
= 16;
157 result
= mach_port_set_attributes(mach_task_self(), port
, MACH_PORT_LIMITS_INFO
, (mach_port_info_t
)&qlimits
, MACH_PORT_LIMITS_INFO_COUNT
);
159 if (result
!= KERN_SUCCESS
) {
160 printf("%s(): {%s:%d} mach_port_set_attributes() failed: $%x %s\n", __FUNCTION__
, __FILE__
, __LINE__
, (int) result
, mach_error_string(result
));
164 dns_service_discovery_ref
DNSServiceBrowserCreate (const char *regtype
, const char *domain
, DNSServiceBrowserReply callBack
,void *context
)
166 mach_port_t serverPort
= DNSServiceDiscoveryLookupServer();
167 mach_port_t clientPort
;
168 kern_return_t result
;
169 dns_service_discovery_ref return_t
;
170 struct a_requests
*request
;
176 result
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &clientPort
);
177 if (result
!= KERN_SUCCESS
) {
178 printf("Mach port receive creation failed, %s\n", mach_error_string(result
));
181 result
= mach_port_insert_right(mach_task_self(), clientPort
, clientPort
, MACH_MSG_TYPE_MAKE_SEND
);
182 if (result
!= KERN_SUCCESS
) {
183 printf("Mach port send creation failed, %s\n", mach_error_string(result
));
184 mach_port_destroy(mach_task_self(), clientPort
);
187 _increaseQueueLengthOnPort(clientPort
);
189 return_t
= malloc(sizeof(dns_service_discovery_t
));
190 return_t
->port
= clientPort
;
192 request
= malloc(sizeof(struct a_requests
));
193 request
->client_port
= clientPort
;
194 request
->context
= context
;
195 request
->callout
.browserCallback
= callBack
;
197 result
= DNSServiceBrowserCreate_rpc(serverPort
, clientPort
, (char *)regtype
, (char *)domain
);
199 if (result
!= KERN_SUCCESS
) {
200 printf("There was an error creating a browser, %s\n", mach_error_string(result
));
205 pthread_mutex_lock(&a_requests_lock
);
206 request
->next
= a_requests
;
207 a_requests
= request
;
208 pthread_mutex_unlock(&a_requests_lock
);
213 /* Service Enumeration */
215 dns_service_discovery_ref
DNSServiceDomainEnumerationCreate (int registrationDomains
, DNSServiceDomainEnumerationReply callBack
, void *context
)
217 mach_port_t serverPort
= DNSServiceDiscoveryLookupServer();
218 mach_port_t clientPort
;
219 kern_return_t result
;
220 dns_service_discovery_ref return_t
;
221 struct a_requests
*request
;
227 result
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &clientPort
);
228 if (result
!= KERN_SUCCESS
) {
229 printf("Mach port receive creation failed, %s\n", mach_error_string(result
));
232 result
= mach_port_insert_right(mach_task_self(), clientPort
, clientPort
, MACH_MSG_TYPE_MAKE_SEND
);
233 if (result
!= KERN_SUCCESS
) {
234 printf("Mach port send creation failed, %s\n", mach_error_string(result
));
235 mach_port_destroy(mach_task_self(), clientPort
);
238 _increaseQueueLengthOnPort(clientPort
);
240 return_t
= malloc(sizeof(dns_service_discovery_t
));
241 return_t
->port
= clientPort
;
243 request
= malloc(sizeof(struct a_requests
));
244 request
->client_port
= clientPort
;
245 request
->context
= context
;
246 request
->callout
.enumCallback
= callBack
;
248 result
= DNSServiceDomainEnumerationCreate_rpc(serverPort
, clientPort
, registrationDomains
);
250 if (result
!= KERN_SUCCESS
) {
251 printf("There was an error creating an enumerator, %s\n", mach_error_string(result
));
256 pthread_mutex_lock(&a_requests_lock
);
257 request
->next
= a_requests
;
258 a_requests
= request
;
259 pthread_mutex_unlock(&a_requests_lock
);
265 /* Service Registration */
267 dns_service_discovery_ref DNSServiceRegistrationCreate
268 (const char *name
, const char *regtype
, const char *domain
, uint16_t port
, const char *txtRecord
, DNSServiceRegistrationReply callBack
, void *context
)
270 mach_port_t serverPort
= DNSServiceDiscoveryLookupServer();
271 mach_port_t clientPort
;
272 kern_return_t result
;
273 dns_service_discovery_ref return_t
;
274 struct a_requests
*request
;
276 char *portptr
= (char *)&port
;
286 result
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &clientPort
);
287 if (result
!= KERN_SUCCESS
) {
288 printf("Mach port receive creation failed, %s\n", mach_error_string(result
));
291 result
= mach_port_insert_right(mach_task_self(), clientPort
, clientPort
, MACH_MSG_TYPE_MAKE_SEND
);
292 if (result
!= KERN_SUCCESS
) {
293 printf("Mach port send creation failed, %s\n", mach_error_string(result
));
294 mach_port_destroy(mach_task_self(), clientPort
);
297 _increaseQueueLengthOnPort(clientPort
);
299 return_t
= malloc(sizeof(dns_service_discovery_t
));
300 return_t
->port
= clientPort
;
302 request
= malloc(sizeof(struct a_requests
));
303 request
->client_port
= clientPort
;
304 request
->context
= context
;
305 request
->callout
.regCallback
= callBack
;
307 // older versions of this code passed the port via mach IPC as an int.
308 // we continue to pass it as 4 bytes to maintain binary compatibility,
309 // but now ensure that the network byte order is preserved by using a struct
312 IpPort
.bytes
[2] = portptr
[0];
313 IpPort
.bytes
[3] = portptr
[1];
315 result
= DNSServiceRegistrationCreate_rpc(serverPort
, clientPort
, (char *)name
, (char *)regtype
, (char *)domain
, IpPort
, (char *)txtRecord
);
317 if (result
!= KERN_SUCCESS
) {
318 printf("There was an error creating a resolve, %s\n", mach_error_string(result
));
323 pthread_mutex_lock(&a_requests_lock
);
324 request
->next
= a_requests
;
325 a_requests
= request
;
326 pthread_mutex_unlock(&a_requests_lock
);
331 /* Resolver requests */
333 dns_service_discovery_ref
DNSServiceResolverResolve(const char *name
, const char *regtype
, const char *domain
, DNSServiceResolverReply callBack
, void *context
)
335 mach_port_t serverPort
= DNSServiceDiscoveryLookupServer();
336 mach_port_t clientPort
;
337 kern_return_t result
;
338 dns_service_discovery_ref return_t
;
339 struct a_requests
*request
;
345 result
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &clientPort
);
346 if (result
!= KERN_SUCCESS
) {
347 printf("Mach port receive creation failed, %s\n", mach_error_string(result
));
350 result
= mach_port_insert_right(mach_task_self(), clientPort
, clientPort
, MACH_MSG_TYPE_MAKE_SEND
);
351 if (result
!= KERN_SUCCESS
) {
352 printf("Mach port send creation failed, %s\n", mach_error_string(result
));
353 mach_port_destroy(mach_task_self(), clientPort
);
356 _increaseQueueLengthOnPort(clientPort
);
358 return_t
= malloc(sizeof(dns_service_discovery_t
));
359 return_t
->port
= clientPort
;
361 request
= malloc(sizeof(struct a_requests
));
362 request
->client_port
= clientPort
;
363 request
->context
= context
;
364 request
->callout
.resolveCallback
= callBack
;
366 DNSServiceResolverResolve_rpc(serverPort
, clientPort
, (char *)name
, (char *)regtype
, (char *)domain
);
368 pthread_mutex_lock(&a_requests_lock
);
369 request
->next
= a_requests
;
370 a_requests
= request
;
371 pthread_mutex_unlock(&a_requests_lock
);
376 DNSRecordReference
DNSServiceRegistrationAddRecord(dns_service_discovery_ref ref
, uint16_t rrtype
, uint16_t rdlen
, const char *rdata
, uint32_t ttl
)
378 mach_port_t serverPort
= DNSServiceDiscoveryLookupServer();
379 mach_port_t clientPort
;
380 natural_t reference
= 0;
381 kern_return_t result
= KERN_SUCCESS
;
384 return kDNSServiceDiscoveryUnknownErr
;
387 clientPort
= DNSServiceDiscoveryMachPort(ref
);
390 return kDNSServiceDiscoveryUnknownErr
;
393 result
= DNSServiceRegistrationAddRecord_rpc(serverPort
, clientPort
, rrtype
, (record_data_t
)rdata
, rdlen
, ttl
, &reference
);
395 if (result
!= KERN_SUCCESS
) {
396 printf("The result of the registration was not successful. Error %d, result %s\n", result
, mach_error_string(result
));
402 DNSServiceRegistrationReplyErrorType
DNSServiceRegistrationUpdateRecord(dns_service_discovery_ref ref
, DNSRecordReference reference
, uint16_t rdlen
, const char *rdata
, uint32_t ttl
)
404 mach_port_t serverPort
= DNSServiceDiscoveryLookupServer();
405 mach_port_t clientPort
;
406 kern_return_t result
= KERN_SUCCESS
;
409 return kDNSServiceDiscoveryUnknownErr
;
412 clientPort
= DNSServiceDiscoveryMachPort(ref
);
415 return kDNSServiceDiscoveryUnknownErr
;
418 result
= DNSServiceRegistrationUpdateRecord_rpc(serverPort
, clientPort
, (natural_t
)reference
, (record_data_t
)rdata
, rdlen
, ttl
);
419 if (result
!= KERN_SUCCESS
) {
420 printf("The result of the registration was not successful. Error %d, result %s\n", result
, mach_error_string(result
));
424 return kDNSServiceDiscoveryNoError
;
428 DNSServiceRegistrationReplyErrorType
DNSServiceRegistrationRemoveRecord(dns_service_discovery_ref ref
, DNSRecordReference reference
)
430 mach_port_t serverPort
= DNSServiceDiscoveryLookupServer();
431 mach_port_t clientPort
;
432 kern_return_t result
= KERN_SUCCESS
;
435 return kDNSServiceDiscoveryUnknownErr
;
438 clientPort
= DNSServiceDiscoveryMachPort(ref
);
441 return kDNSServiceDiscoveryUnknownErr
;
444 result
= DNSServiceRegistrationRemoveRecord_rpc(serverPort
, clientPort
, (natural_t
)reference
);
446 if (result
!= KERN_SUCCESS
) {
447 printf("The result of the registration was not successful. Error %d, result %s\n", result
, mach_error_string(result
));
451 return kDNSServiceDiscoveryNoError
;
454 void DNSServiceDiscovery_handleReply(void *replyMsg
)
456 unsigned long result
= 0xFFFFFFFF;
457 mach_msg_header_t
* msgSendBufPtr
;
458 mach_msg_header_t
* receivedMessage
;
459 unsigned msgSendBufLength
;
461 msgSendBufLength
= internal_DNSServiceDiscoveryReply_subsystem
.maxsize
;
462 msgSendBufPtr
= (mach_msg_header_t
*) malloc(msgSendBufLength
);
465 receivedMessage
= ( mach_msg_header_t
* ) replyMsg
;
467 // Call DNSServiceDiscoveryReply_server to change mig-generated message into a
468 // genuine mach message. It will then cause the callback to get called.
469 result
= DNSServiceDiscoveryReply_server ( receivedMessage
, msgSendBufPtr
);
470 ( void ) mach_msg_send ( msgSendBufPtr
);
474 mach_port_t
DNSServiceDiscoveryMachPort(dns_service_discovery_ref dnsServiceDiscovery
)
476 return dnsServiceDiscovery
->port
;
479 void DNSServiceDiscoveryDeallocate(dns_service_discovery_ref dnsServiceDiscovery
)
481 struct a_requests
*request0
, *request
;
482 mach_port_t reply
= dnsServiceDiscovery
->port
;
484 if (dnsServiceDiscovery
->port
) {
485 pthread_mutex_lock(&a_requests_lock
);
487 request
= a_requests
;
489 if (request
->client_port
== reply
) {
490 /* request info found, remove from list */
492 request0
->next
= request
->next
;
494 a_requests
= request
->next
;
498 /* not info for this request, skip to next */
500 request
= request
->next
;
504 pthread_mutex_unlock(&a_requests_lock
);
508 mach_port_destroy(mach_task_self(), dnsServiceDiscovery
->port
);
510 free(dnsServiceDiscovery
);
515 // reply functions, calls the users setup callbacks with function pointers
517 kern_return_t internal_DNSServiceDomainEnumerationReply_rpc
521 DNSCString replyDomain
,
525 struct a_requests
*request
;
526 void *requestContext
= NULL
;
527 DNSServiceDomainEnumerationReply callback
= NULL
;
529 pthread_mutex_lock(&a_requests_lock
);
530 request
= a_requests
;
532 if (request
->client_port
== reply
) {
535 request
= request
->next
;
538 if (request
!= NULL
) {
539 callback
= (*request
->callout
.enumCallback
);
540 requestContext
= request
->context
;
542 pthread_mutex_unlock(&a_requests_lock
);
544 if (request
!= NULL
) {
545 (callback
)(resultType
, replyDomain
, flags
, requestContext
);
552 kern_return_t internal_DNSServiceBrowserReply_rpc
556 DNSCString replyName
,
557 DNSCString replyType
,
558 DNSCString replyDomain
,
562 struct a_requests
*request
;
563 void *requestContext
= NULL
;
564 DNSServiceBrowserReply callback
= NULL
;
566 pthread_mutex_lock(&a_requests_lock
);
567 request
= a_requests
;
569 if (request
->client_port
== reply
) {
572 request
= request
->next
;
574 if (request
!= NULL
) {
575 callback
= (*request
->callout
.browserCallback
);
576 requestContext
= request
->context
;
579 pthread_mutex_unlock(&a_requests_lock
);
581 if (request
!= NULL
) {
582 (callback
)(resultType
, replyName
, replyType
, replyDomain
, flags
, requestContext
);
589 kern_return_t internal_DNSServiceRegistrationReply_rpc
595 struct a_requests
*request
;
596 void *requestContext
= NULL
;
597 DNSServiceRegistrationReply callback
= NULL
;
599 pthread_mutex_lock(&a_requests_lock
);
600 request
= a_requests
;
602 if (request
->client_port
== reply
) {
605 request
= request
->next
;
607 if (request
!= NULL
) {
608 callback
= (*request
->callout
.regCallback
);
609 requestContext
= request
->context
;
612 pthread_mutex_unlock(&a_requests_lock
);
613 if (request
!= NULL
) {
614 (callback
)(resultType
, requestContext
);
620 kern_return_t internal_DNSServiceResolverReply_rpc
623 sockaddr_t interface
,
625 DNSCString txtRecord
,
629 struct sockaddr
*interface_storage
= NULL
;
630 struct sockaddr
*address_storage
= NULL
;
631 struct a_requests
*request
;
632 void *requestContext
= NULL
;
633 DNSServiceResolverReply callback
= NULL
;
636 int len
= ((struct sockaddr
*)interface
)->sa_len
;
637 interface_storage
= (struct sockaddr
*)malloc(len
);
638 memcpy(interface_storage
, interface
, len
);
642 int len
= ((struct sockaddr
*)address
)->sa_len
;
643 address_storage
= (struct sockaddr
*)malloc(len
);
644 memcpy(address_storage
, address
, len
);
647 pthread_mutex_lock(&a_requests_lock
);
648 request
= a_requests
;
650 if (request
->client_port
== reply
) {
653 request
= request
->next
;
656 if (request
!= NULL
) {
657 callback
= (*request
->callout
.resolveCallback
);
658 requestContext
= request
->context
;
660 pthread_mutex_unlock(&a_requests_lock
);
662 if (request
!= NULL
) {
663 (callback
)(interface_storage
, address_storage
, txtRecord
, flags
, requestContext
);
667 free(interface_storage
);
670 free(address_storage
);