2 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 #include "DNSServiceDiscovery.h"
24 #include "DNSServiceDiscoveryDefines.h"
28 #include <servers/bootstrap.h>
29 #include <mach/mach.h>
30 #include <mach/mach_error.h>
33 #include <netinet/in.h>
35 extern struct mig_subsystem internal_DNSServiceDiscoveryReply_subsystem
;
37 extern boolean_t
DNSServiceDiscoveryReply_server(
38 mach_msg_header_t
*InHeadP
,
39 mach_msg_header_t
*OutHeadP
);
42 kern_return_t DNSServiceBrowserCreate_rpc
51 kern_return_t DNSServiceDomainEnumerationCreate_rpc
55 int registrationDomains
59 kern_return_t DNSServiceRegistrationCreate_rpc
71 kern_return_t DNSServiceResolverResolve_rpc
81 kern_return_t DNSServiceRegistrationAddRecord_rpc
87 mach_msg_type_number_t record_dataCnt
,
93 int DNSServiceRegistrationUpdateRecord_rpc
99 mach_msg_type_number_t record_dataCnt
,
104 kern_return_t DNSServiceRegistrationRemoveRecord_rpc
112 struct a_requests
*next
;
113 mach_port_t client_port
;
115 DNSServiceBrowserReply browserCallback
;
116 DNSServiceDomainEnumerationReply enumCallback
;
117 DNSServiceRegistrationReply regCallback
;
118 DNSServiceResolverReply resolveCallback
;
123 static struct a_requests
*a_requests
= NULL
;
124 static pthread_mutex_t a_requests_lock
= PTHREAD_MUTEX_INITIALIZER
;
126 typedef struct _dns_service_discovery_t
{
128 } dns_service_discovery_t
;
130 mach_port_t
DNSServiceDiscoveryLookupServer(void)
132 static mach_port_t sndPort
= MACH_PORT_NULL
;
133 kern_return_t result
;
135 if (sndPort
!= MACH_PORT_NULL
) {
139 result
= bootstrap_look_up(bootstrap_port
, DNS_SERVICE_DISCOVERY_SERVER
, &sndPort
);
140 if (result
!= KERN_SUCCESS
) {
141 printf("%s(): {%s:%d} bootstrap_look_up() failed: $%x\n", __FUNCTION__
, __FILE__
, __LINE__
, (int) result
);
142 sndPort
= MACH_PORT_NULL
;
149 void _increaseQueueLengthOnPort(mach_port_t port
)
151 mach_port_limits_t qlimits
;
152 kern_return_t result
;
154 qlimits
.mpl_qlimit
= 16;
155 result
= mach_port_set_attributes(mach_task_self(), port
, MACH_PORT_LIMITS_INFO
, (mach_port_info_t
)&qlimits
, MACH_PORT_LIMITS_INFO_COUNT
);
157 if (result
!= KERN_SUCCESS
) {
158 printf("%s(): {%s:%d} mach_port_set_attributes() failed: $%x %s\n", __FUNCTION__
, __FILE__
, __LINE__
, (int) result
, mach_error_string(result
));
162 dns_service_discovery_ref
DNSServiceBrowserCreate (const char *regtype
, const char *domain
, DNSServiceBrowserReply callBack
,void *context
)
164 mach_port_t serverPort
= DNSServiceDiscoveryLookupServer();
165 mach_port_t clientPort
;
166 kern_return_t result
;
167 dns_service_discovery_ref return_t
;
168 struct a_requests
*request
;
174 result
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &clientPort
);
175 if (result
!= KERN_SUCCESS
) {
176 printf("Mach port receive creation failed, %s\n", mach_error_string(result
));
179 result
= mach_port_insert_right(mach_task_self(), clientPort
, clientPort
, MACH_MSG_TYPE_MAKE_SEND
);
180 if (result
!= KERN_SUCCESS
) {
181 printf("Mach port send creation failed, %s\n", mach_error_string(result
));
182 mach_port_destroy(mach_task_self(), clientPort
);
185 _increaseQueueLengthOnPort(clientPort
);
187 return_t
= malloc(sizeof(dns_service_discovery_t
));
188 return_t
->port
= clientPort
;
190 request
= malloc(sizeof(struct a_requests
));
191 request
->client_port
= clientPort
;
192 request
->context
= context
;
193 request
->callout
.browserCallback
= callBack
;
195 result
= DNSServiceBrowserCreate_rpc(serverPort
, clientPort
, (char *)regtype
, (char *)domain
);
197 if (result
!= KERN_SUCCESS
) {
198 printf("There was an error creating a browser, %s\n", mach_error_string(result
));
203 pthread_mutex_lock(&a_requests_lock
);
204 request
->next
= a_requests
;
205 a_requests
= request
;
206 pthread_mutex_unlock(&a_requests_lock
);
211 /* Service Enumeration */
213 dns_service_discovery_ref
DNSServiceDomainEnumerationCreate (int registrationDomains
, DNSServiceDomainEnumerationReply callBack
, void *context
)
215 mach_port_t serverPort
= DNSServiceDiscoveryLookupServer();
216 mach_port_t clientPort
;
217 kern_return_t result
;
218 dns_service_discovery_ref return_t
;
219 struct a_requests
*request
;
225 result
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &clientPort
);
226 if (result
!= KERN_SUCCESS
) {
227 printf("Mach port receive creation failed, %s\n", mach_error_string(result
));
230 result
= mach_port_insert_right(mach_task_self(), clientPort
, clientPort
, MACH_MSG_TYPE_MAKE_SEND
);
231 if (result
!= KERN_SUCCESS
) {
232 printf("Mach port send creation failed, %s\n", mach_error_string(result
));
233 mach_port_destroy(mach_task_self(), clientPort
);
236 _increaseQueueLengthOnPort(clientPort
);
238 return_t
= malloc(sizeof(dns_service_discovery_t
));
239 return_t
->port
= clientPort
;
241 request
= malloc(sizeof(struct a_requests
));
242 request
->client_port
= clientPort
;
243 request
->context
= context
;
244 request
->callout
.enumCallback
= callBack
;
246 result
= DNSServiceDomainEnumerationCreate_rpc(serverPort
, clientPort
, registrationDomains
);
248 if (result
!= KERN_SUCCESS
) {
249 printf("There was an error creating an enumerator, %s\n", mach_error_string(result
));
254 pthread_mutex_lock(&a_requests_lock
);
255 request
->next
= a_requests
;
256 a_requests
= request
;
257 pthread_mutex_unlock(&a_requests_lock
);
263 /* Service Registration */
265 dns_service_discovery_ref DNSServiceRegistrationCreate
266 (const char *name
, const char *regtype
, const char *domain
, uint16_t port
, const char *txtRecord
, DNSServiceRegistrationReply callBack
, void *context
)
268 mach_port_t serverPort
= DNSServiceDiscoveryLookupServer();
269 mach_port_t clientPort
;
270 kern_return_t result
;
271 dns_service_discovery_ref return_t
;
272 struct a_requests
*request
;
274 char *portptr
= (char *)&port
;
284 result
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &clientPort
);
285 if (result
!= KERN_SUCCESS
) {
286 printf("Mach port receive creation failed, %s\n", mach_error_string(result
));
289 result
= mach_port_insert_right(mach_task_self(), clientPort
, clientPort
, MACH_MSG_TYPE_MAKE_SEND
);
290 if (result
!= KERN_SUCCESS
) {
291 printf("Mach port send creation failed, %s\n", mach_error_string(result
));
292 mach_port_destroy(mach_task_self(), clientPort
);
295 _increaseQueueLengthOnPort(clientPort
);
297 return_t
= malloc(sizeof(dns_service_discovery_t
));
298 return_t
->port
= clientPort
;
300 request
= malloc(sizeof(struct a_requests
));
301 request
->client_port
= clientPort
;
302 request
->context
= context
;
303 request
->callout
.regCallback
= callBack
;
305 // older versions of this code passed the port via mach IPC as an int.
306 // we continue to pass it as 4 bytes to maintain binary compatibility,
307 // but now ensure that the network byte order is preserved by using a struct
310 IpPort
.bytes
[2] = portptr
[0];
311 IpPort
.bytes
[3] = portptr
[1];
313 result
= DNSServiceRegistrationCreate_rpc(serverPort
, clientPort
, (char *)name
, (char *)regtype
, (char *)domain
, IpPort
, (char *)txtRecord
);
315 if (result
!= KERN_SUCCESS
) {
316 printf("There was an error creating a resolve, %s\n", mach_error_string(result
));
321 pthread_mutex_lock(&a_requests_lock
);
322 request
->next
= a_requests
;
323 a_requests
= request
;
324 pthread_mutex_unlock(&a_requests_lock
);
329 /* Resolver requests */
331 dns_service_discovery_ref
DNSServiceResolverResolve(const char *name
, const char *regtype
, const char *domain
, DNSServiceResolverReply callBack
, void *context
)
333 mach_port_t serverPort
= DNSServiceDiscoveryLookupServer();
334 mach_port_t clientPort
;
335 kern_return_t result
;
336 dns_service_discovery_ref return_t
;
337 struct a_requests
*request
;
343 result
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &clientPort
);
344 if (result
!= KERN_SUCCESS
) {
345 printf("Mach port receive creation failed, %s\n", mach_error_string(result
));
348 result
= mach_port_insert_right(mach_task_self(), clientPort
, clientPort
, MACH_MSG_TYPE_MAKE_SEND
);
349 if (result
!= KERN_SUCCESS
) {
350 printf("Mach port send creation failed, %s\n", mach_error_string(result
));
351 mach_port_destroy(mach_task_self(), clientPort
);
354 _increaseQueueLengthOnPort(clientPort
);
356 return_t
= malloc(sizeof(dns_service_discovery_t
));
357 return_t
->port
= clientPort
;
359 request
= malloc(sizeof(struct a_requests
));
360 request
->client_port
= clientPort
;
361 request
->context
= context
;
362 request
->callout
.resolveCallback
= callBack
;
364 DNSServiceResolverResolve_rpc(serverPort
, clientPort
, (char *)name
, (char *)regtype
, (char *)domain
);
366 pthread_mutex_lock(&a_requests_lock
);
367 request
->next
= a_requests
;
368 a_requests
= request
;
369 pthread_mutex_unlock(&a_requests_lock
);
374 DNSRecordReference
DNSServiceRegistrationAddRecord(dns_service_discovery_ref ref
, uint16_t rrtype
, uint16_t rdlen
, const char *rdata
, uint32_t ttl
)
376 mach_port_t serverPort
= DNSServiceDiscoveryLookupServer();
377 mach_port_t clientPort
;
378 natural_t reference
= 0;
379 kern_return_t result
= KERN_SUCCESS
;
382 return kDNSServiceDiscoveryUnknownErr
;
385 clientPort
= DNSServiceDiscoveryMachPort(ref
);
388 return kDNSServiceDiscoveryUnknownErr
;
391 result
= DNSServiceRegistrationAddRecord_rpc(serverPort
, clientPort
, rrtype
, (record_data_t
)rdata
, rdlen
, ttl
, &reference
);
393 if (result
!= KERN_SUCCESS
) {
394 printf("The result of the registration was not successful. Error %d, result %s\n", result
, mach_error_string(result
));
400 DNSServiceRegistrationReplyErrorType
DNSServiceRegistrationUpdateRecord(dns_service_discovery_ref ref
, DNSRecordReference reference
, uint16_t rdlen
, const char *rdata
, uint32_t ttl
)
402 mach_port_t serverPort
= DNSServiceDiscoveryLookupServer();
403 mach_port_t clientPort
;
404 kern_return_t result
= KERN_SUCCESS
;
407 return kDNSServiceDiscoveryUnknownErr
;
410 clientPort
= DNSServiceDiscoveryMachPort(ref
);
413 return kDNSServiceDiscoveryUnknownErr
;
416 result
= DNSServiceRegistrationUpdateRecord_rpc(serverPort
, clientPort
, (natural_t
)reference
, (record_data_t
)rdata
, rdlen
, ttl
);
417 if (result
!= KERN_SUCCESS
) {
418 printf("The result of the registration was not successful. Error %d, result %s\n", result
, mach_error_string(result
));
422 return kDNSServiceDiscoveryNoError
;
426 DNSServiceRegistrationReplyErrorType
DNSServiceRegistrationRemoveRecord(dns_service_discovery_ref ref
, DNSRecordReference reference
)
428 mach_port_t serverPort
= DNSServiceDiscoveryLookupServer();
429 mach_port_t clientPort
;
430 kern_return_t result
= KERN_SUCCESS
;
433 return kDNSServiceDiscoveryUnknownErr
;
436 clientPort
= DNSServiceDiscoveryMachPort(ref
);
439 return kDNSServiceDiscoveryUnknownErr
;
442 result
= DNSServiceRegistrationRemoveRecord_rpc(serverPort
, clientPort
, (natural_t
)reference
);
444 if (result
!= KERN_SUCCESS
) {
445 printf("The result of the registration was not successful. Error %d, result %s\n", result
, mach_error_string(result
));
449 return kDNSServiceDiscoveryNoError
;
452 void DNSServiceDiscovery_handleReply(void *replyMsg
)
454 unsigned long result
= 0xFFFFFFFF;
455 mach_msg_header_t
* msgSendBufPtr
;
456 mach_msg_header_t
* receivedMessage
;
457 unsigned msgSendBufLength
;
459 msgSendBufLength
= internal_DNSServiceDiscoveryReply_subsystem
.maxsize
;
460 msgSendBufPtr
= (mach_msg_header_t
*) malloc(msgSendBufLength
);
463 receivedMessage
= ( mach_msg_header_t
* ) replyMsg
;
465 // Call DNSServiceDiscoveryReply_server to change mig-generated message into a
466 // genuine mach message. It will then cause the callback to get called.
467 result
= DNSServiceDiscoveryReply_server ( receivedMessage
, msgSendBufPtr
);
468 ( void ) mach_msg_send ( msgSendBufPtr
);
472 mach_port_t
DNSServiceDiscoveryMachPort(dns_service_discovery_ref dnsServiceDiscovery
)
474 return dnsServiceDiscovery
->port
;
477 void DNSServiceDiscoveryDeallocate(dns_service_discovery_ref dnsServiceDiscovery
)
479 struct a_requests
*request0
, *request
;
480 mach_port_t reply
= dnsServiceDiscovery
->port
;
482 if (dnsServiceDiscovery
->port
) {
483 pthread_mutex_lock(&a_requests_lock
);
485 request
= a_requests
;
487 if (request
->client_port
== reply
) {
488 /* request info found, remove from list */
490 request0
->next
= request
->next
;
492 a_requests
= request
->next
;
496 /* not info for this request, skip to next */
498 request
= request
->next
;
502 pthread_mutex_unlock(&a_requests_lock
);
506 mach_port_destroy(mach_task_self(), dnsServiceDiscovery
->port
);
508 free(dnsServiceDiscovery
);
513 // reply functions, calls the users setup callbacks with function pointers
515 kern_return_t internal_DNSServiceDomainEnumerationReply_rpc
519 DNSCString replyDomain
,
520 DNSServiceDiscoveryReplyFlags flags
523 struct a_requests
*request
;
524 void *requestContext
= NULL
;
525 DNSServiceDomainEnumerationReply callback
= NULL
;
527 pthread_mutex_lock(&a_requests_lock
);
528 request
= a_requests
;
530 if (request
->client_port
== reply
) {
533 request
= request
->next
;
536 if (request
!= NULL
) {
537 callback
= (*request
->callout
.enumCallback
);
538 requestContext
= request
->context
;
540 pthread_mutex_unlock(&a_requests_lock
);
542 if (request
!= NULL
) {
543 (callback
)(resultType
, replyDomain
, flags
, requestContext
);
550 kern_return_t internal_DNSServiceBrowserReply_rpc
554 DNSCString replyName
,
555 DNSCString replyType
,
556 DNSCString replyDomain
,
557 DNSServiceDiscoveryReplyFlags flags
560 struct a_requests
*request
;
561 void *requestContext
= NULL
;
562 DNSServiceBrowserReply callback
= NULL
;
564 pthread_mutex_lock(&a_requests_lock
);
565 request
= a_requests
;
567 if (request
->client_port
== reply
) {
570 request
= request
->next
;
572 if (request
!= NULL
) {
573 callback
= (*request
->callout
.browserCallback
);
574 requestContext
= request
->context
;
577 pthread_mutex_unlock(&a_requests_lock
);
579 if (request
!= NULL
) {
580 (callback
)(resultType
, replyName
, replyType
, replyDomain
, flags
, requestContext
);
587 kern_return_t internal_DNSServiceRegistrationReply_rpc
593 struct a_requests
*request
;
594 void *requestContext
= NULL
;
595 DNSServiceRegistrationReply callback
= NULL
;
597 pthread_mutex_lock(&a_requests_lock
);
598 request
= a_requests
;
600 if (request
->client_port
== reply
) {
603 request
= request
->next
;
605 if (request
!= NULL
) {
606 callback
= (*request
->callout
.regCallback
);
607 requestContext
= request
->context
;
610 pthread_mutex_unlock(&a_requests_lock
);
611 if (request
!= NULL
) {
612 (callback
)(resultType
, requestContext
);
618 kern_return_t internal_DNSServiceResolverReply_rpc
621 sockaddr_t interface
,
623 DNSCString txtRecord
,
624 DNSServiceDiscoveryReplyFlags flags
627 struct sockaddr
*interface_storage
= NULL
;
628 struct sockaddr
*address_storage
= NULL
;
629 struct a_requests
*request
;
630 void *requestContext
= NULL
;
631 DNSServiceResolverReply callback
= NULL
;
634 int len
= ((struct sockaddr
*)interface
)->sa_len
;
635 interface_storage
= (struct sockaddr
*)malloc(len
);
636 bcopy(interface
, interface_storage
,len
);
640 int len
= ((struct sockaddr
*)address
)->sa_len
;
641 address_storage
= (struct sockaddr
*)malloc(len
);
642 bcopy(address
, address_storage
, len
);
645 pthread_mutex_lock(&a_requests_lock
);
646 request
= a_requests
;
648 if (request
->client_port
== reply
) {
651 request
= request
->next
;
654 if (request
!= NULL
) {
655 callback
= (*request
->callout
.resolveCallback
);
656 requestContext
= request
->context
;
658 pthread_mutex_unlock(&a_requests_lock
);
660 if (request
!= NULL
) {
661 (callback
)(interface_storage
, address_storage
, txtRecord
, flags
, requestContext
);
665 free(interface_storage
);
668 free(address_storage
);