Libinfo-173.tar.gz
[apple/libinfo.git] / mdns.subproj / DNSServiceDiscovery.c
1 /*
2 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25
26 #include "DNSServiceDiscovery.h"
27 #include "DNSServiceDiscoveryDefines.h"
28
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <servers/bootstrap.h>
32 #include <mach/mach.h>
33 #include <mach/mach_error.h>
34 #include <pthread.h>
35
36 #include <netinet/in.h>
37
38 extern struct rpc_subsystem internal_DNSServiceDiscoveryReply_subsystem;
39
40 extern boolean_t DNSServiceDiscoveryReply_server(
41 mach_msg_header_t *InHeadP,
42 mach_msg_header_t *OutHeadP);
43
44 extern
45 kern_return_t DNSServiceBrowserCreate_rpc
46 (
47 mach_port_t server,
48 mach_port_t client,
49 DNSCString regtype,
50 DNSCString domain
51 );
52
53 extern
54 kern_return_t DNSServiceDomainEnumerationCreate_rpc
55 (
56 mach_port_t server,
57 mach_port_t client,
58 int registrationDomains
59 );
60
61 extern
62 kern_return_t DNSServiceRegistrationCreate_rpc
63 (
64 mach_port_t server,
65 mach_port_t client,
66 DNSCString name,
67 DNSCString regtype,
68 DNSCString domain,
69 int port,
70 DNSCString txtRecord
71 );
72
73 extern
74 kern_return_t DNSServiceResolverResolve_rpc
75 (
76 mach_port_t server,
77 mach_port_t client,
78 DNSCString name,
79 DNSCString regtype,
80 DNSCString domain
81 );
82
83 extern
84 kern_return_t DNSServiceRegistrationAddRecord_rpc
85 (
86 mach_port_t server,
87 mach_port_t client,
88 int type,
89 record_data_t data,
90 mach_msg_type_number_t record_dataCnt,
91 uint32_t ttl,
92 natural_t *reference
93 );
94
95 extern
96 int DNSServiceRegistrationUpdateRecord_rpc
97 (
98 mach_port_t server,
99 mach_port_t client,
100 natural_t reference,
101 record_data_t data,
102 mach_msg_type_number_t record_dataCnt,
103 uint32_t ttl
104 );
105
106 extern
107 kern_return_t DNSServiceRegistrationRemoveRecord_rpc
108 (
109 mach_port_t server,
110 mach_port_t client,
111 natural_t reference
112 );
113
114 struct a_requests {
115 struct a_requests *next;
116 mach_port_t client_port;
117 union {
118 DNSServiceBrowserReply browserCallback;
119 DNSServiceDomainEnumerationReply enumCallback;
120 DNSServiceRegistrationReply regCallback;
121 DNSServiceResolverReply resolveCallback;
122 } callout;
123 void *context;
124 };
125
126 static struct a_requests *a_requests = NULL;
127 static pthread_mutex_t a_requests_lock = PTHREAD_MUTEX_INITIALIZER;
128
129 typedef struct _dns_service_discovery_t {
130 mach_port_t port;
131 } dns_service_discovery_t;
132
133 mach_port_t DNSServiceDiscoveryLookupServer(void)
134 {
135 static mach_port_t sndPort = MACH_PORT_NULL;
136 kern_return_t result;
137
138 if (sndPort != MACH_PORT_NULL) {
139 return sndPort;
140 }
141
142 result = bootstrap_look_up(bootstrap_port, DNS_SERVICE_DISCOVERY_SERVER, &sndPort);
143 if (result != KERN_SUCCESS) {
144 printf("%s(): {%s:%d} bootstrap_look_up() failed: $%x\n", __FUNCTION__, __FILE__, __LINE__, (int) result);
145 sndPort = MACH_PORT_NULL;
146 }
147
148
149 return sndPort;
150 }
151
152 void _increaseQueueLengthOnPort(mach_port_t port)
153 {
154 mach_port_limits_t qlimits;
155 kern_return_t result;
156
157 qlimits.mpl_qlimit = 16;
158 result = mach_port_set_attributes(mach_task_self(), port, MACH_PORT_LIMITS_INFO, (mach_port_info_t)&qlimits, MACH_PORT_LIMITS_INFO_COUNT);
159
160 if (result != KERN_SUCCESS) {
161 printf("%s(): {%s:%d} mach_port_set_attributes() failed: $%x %s\n", __FUNCTION__, __FILE__, __LINE__, (int) result, mach_error_string(result));
162 }
163 }
164
165 dns_service_discovery_ref DNSServiceBrowserCreate (const char *regtype, const char *domain, DNSServiceBrowserReply callBack,void *context)
166 {
167 mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
168 mach_port_t clientPort;
169 kern_return_t result;
170 dns_service_discovery_ref return_t;
171 struct a_requests *request;
172
173 if (!serverPort) {
174 return NULL;
175 }
176
177 result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort);
178 if (result != KERN_SUCCESS) {
179 printf("Mach port receive creation failed, %s\n", mach_error_string(result));
180 return NULL;
181 }
182 result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND);
183 if (result != KERN_SUCCESS) {
184 printf("Mach port send creation failed, %s\n", mach_error_string(result));
185 mach_port_destroy(mach_task_self(), clientPort);
186 return NULL;
187 }
188 _increaseQueueLengthOnPort(clientPort);
189
190 return_t = malloc(sizeof(dns_service_discovery_t));
191 return_t->port = clientPort;
192
193 request = malloc(sizeof(struct a_requests));
194 request->client_port = clientPort;
195 request->context = context;
196 request->callout.browserCallback = callBack;
197
198 result = DNSServiceBrowserCreate_rpc(serverPort, clientPort, (char *)regtype, (char *)domain);
199
200 if (result != KERN_SUCCESS) {
201 printf("There was an error creating a browser, %s\n", mach_error_string(result));
202 free(request);
203 return NULL;
204 }
205
206 pthread_mutex_lock(&a_requests_lock);
207 request->next = a_requests;
208 a_requests = request;
209 pthread_mutex_unlock(&a_requests_lock);
210
211 return return_t;
212 }
213
214 /* Service Enumeration */
215
216 dns_service_discovery_ref DNSServiceDomainEnumerationCreate (int registrationDomains, DNSServiceDomainEnumerationReply callBack, void *context)
217 {
218 mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
219 mach_port_t clientPort;
220 kern_return_t result;
221 dns_service_discovery_ref return_t;
222 struct a_requests *request;
223
224 if (!serverPort) {
225 return NULL;
226 }
227
228 result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort);
229 if (result != KERN_SUCCESS) {
230 printf("Mach port receive creation failed, %s\n", mach_error_string(result));
231 return NULL;
232 }
233 result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND);
234 if (result != KERN_SUCCESS) {
235 printf("Mach port send creation failed, %s\n", mach_error_string(result));
236 mach_port_destroy(mach_task_self(), clientPort);
237 return NULL;
238 }
239 _increaseQueueLengthOnPort(clientPort);
240
241 return_t = malloc(sizeof(dns_service_discovery_t));
242 return_t->port = clientPort;
243
244 request = malloc(sizeof(struct a_requests));
245 request->client_port = clientPort;
246 request->context = context;
247 request->callout.enumCallback = callBack;
248
249 result = DNSServiceDomainEnumerationCreate_rpc(serverPort, clientPort, registrationDomains);
250
251 if (result != KERN_SUCCESS) {
252 printf("There was an error creating an enumerator, %s\n", mach_error_string(result));
253 free(request);
254 return NULL;
255 }
256
257 pthread_mutex_lock(&a_requests_lock);
258 request->next = a_requests;
259 a_requests = request;
260 pthread_mutex_unlock(&a_requests_lock);
261
262 return return_t;
263 }
264
265
266 /* Service Registration */
267
268 dns_service_discovery_ref DNSServiceRegistrationCreate
269 (const char *name, const char *regtype, const char *domain, uint16_t port, const char *txtRecord, DNSServiceRegistrationReply callBack, void *context)
270 {
271 mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
272 mach_port_t clientPort;
273 kern_return_t result;
274 dns_service_discovery_ref return_t;
275 struct a_requests *request;
276
277 if (!serverPort) {
278 return NULL;
279 }
280
281 if (!txtRecord) {
282 txtRecord = "";
283 }
284
285 result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort);
286 if (result != KERN_SUCCESS) {
287 printf("Mach port receive creation failed, %s\n", mach_error_string(result));
288 return NULL;
289 }
290 result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND);
291 if (result != KERN_SUCCESS) {
292 printf("Mach port send creation failed, %s\n", mach_error_string(result));
293 mach_port_destroy(mach_task_self(), clientPort);
294 return NULL;
295 }
296 _increaseQueueLengthOnPort(clientPort);
297
298 return_t = malloc(sizeof(dns_service_discovery_t));
299 return_t->port = clientPort;
300
301 request = malloc(sizeof(struct a_requests));
302 request->client_port = clientPort;
303 request->context = context;
304 request->callout.regCallback = callBack;
305
306 result = DNSServiceRegistrationCreate_rpc(serverPort, clientPort, (char *)name, (char *)regtype, (char *)domain, port, (char *)txtRecord);
307
308 if (result != KERN_SUCCESS) {
309 printf("There was an error creating a resolve, %s\n", mach_error_string(result));
310 free(request);
311 return NULL;
312 }
313
314 pthread_mutex_lock(&a_requests_lock);
315 request->next = a_requests;
316 a_requests = request;
317 pthread_mutex_unlock(&a_requests_lock);
318
319 return return_t;
320 }
321
322 /* Resolver requests */
323
324 dns_service_discovery_ref DNSServiceResolverResolve(const char *name, const char *regtype, const char *domain, DNSServiceResolverReply callBack, void *context)
325 {
326 mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
327 mach_port_t clientPort;
328 kern_return_t result;
329 dns_service_discovery_ref return_t;
330 struct a_requests *request;
331
332 if (!serverPort) {
333 return NULL;
334 }
335
336 result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort);
337 if (result != KERN_SUCCESS) {
338 printf("Mach port receive creation failed, %s\n", mach_error_string(result));
339 return NULL;
340 }
341 result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND);
342 if (result != KERN_SUCCESS) {
343 printf("Mach port send creation failed, %s\n", mach_error_string(result));
344 mach_port_destroy(mach_task_self(), clientPort);
345 return NULL;
346 }
347 _increaseQueueLengthOnPort(clientPort);
348
349 return_t = malloc(sizeof(dns_service_discovery_t));
350 return_t->port = clientPort;
351
352 request = malloc(sizeof(struct a_requests));
353 request->client_port = clientPort;
354 request->context = context;
355 request->callout.resolveCallback = callBack;
356
357 DNSServiceResolverResolve_rpc(serverPort, clientPort, (char *)name, (char *)regtype, (char *)domain);
358
359 pthread_mutex_lock(&a_requests_lock);
360 request->next = a_requests;
361 a_requests = request;
362 pthread_mutex_unlock(&a_requests_lock);
363
364 return return_t;
365 }
366
367 DNSRecordReference DNSServiceRegistrationAddRecord(dns_service_discovery_ref ref, uint16_t rrtype, uint16_t rdlen, const char *rdata, uint32_t ttl)
368 {
369 mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
370 mach_port_t clientPort;
371 natural_t reference = 0;
372 kern_return_t result = KERN_SUCCESS;
373
374 if (!serverPort) {
375 return kDNSServiceDiscoveryUnknownErr;
376 }
377
378 clientPort = DNSServiceDiscoveryMachPort(ref);
379
380 if (!clientPort) {
381 return kDNSServiceDiscoveryUnknownErr;
382 }
383
384 result = DNSServiceRegistrationAddRecord_rpc(serverPort, clientPort, rrtype, (record_data_t)rdata, rdlen, ttl, &reference);
385
386 if (result != KERN_SUCCESS) {
387 printf("The result of the registration was not successful. Error %d, result %s\n", result, mach_error_string(result));
388 }
389
390 return reference;
391 }
392
393 DNSServiceRegistrationReplyErrorType DNSServiceRegistrationUpdateRecord(dns_service_discovery_ref ref, DNSRecordReference reference, uint16_t rdlen, const char *rdata, uint32_t ttl)
394 {
395 mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
396 mach_port_t clientPort;
397 kern_return_t result = KERN_SUCCESS;
398
399 if (!serverPort) {
400 return kDNSServiceDiscoveryUnknownErr;
401 }
402
403 clientPort = DNSServiceDiscoveryMachPort(ref);
404
405 if (!clientPort) {
406 return kDNSServiceDiscoveryUnknownErr;
407 }
408
409 result = DNSServiceRegistrationUpdateRecord_rpc(serverPort, clientPort, (natural_t)reference, (record_data_t)rdata, rdlen, ttl);
410 if (result != KERN_SUCCESS) {
411 printf("The result of the registration was not successful. Error %d, result %s\n", result, mach_error_string(result));
412 return result;
413 }
414
415 return kDNSServiceDiscoveryNoError;
416 }
417
418
419 DNSServiceRegistrationReplyErrorType DNSServiceRegistrationRemoveRecord(dns_service_discovery_ref ref, DNSRecordReference reference)
420 {
421 mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
422 mach_port_t clientPort;
423 kern_return_t result = KERN_SUCCESS;
424
425 if (!serverPort) {
426 return kDNSServiceDiscoveryUnknownErr;
427 }
428
429 clientPort = DNSServiceDiscoveryMachPort(ref);
430
431 if (!clientPort) {
432 return kDNSServiceDiscoveryUnknownErr;
433 }
434
435 result = DNSServiceRegistrationRemoveRecord_rpc(serverPort, clientPort, (natural_t)reference);
436
437 if (result != KERN_SUCCESS) {
438 printf("The result of the registration was not successful. Error %d, result %s\n", result, mach_error_string(result));
439 return result;
440 }
441
442 return kDNSServiceDiscoveryNoError;
443 }
444
445 void DNSServiceDiscovery_handleReply(void *replyMsg)
446 {
447 unsigned long result = 0xFFFFFFFF;
448 mach_msg_header_t * msgSendBufPtr;
449 mach_msg_header_t * receivedMessage;
450 unsigned msgSendBufLength;
451
452 msgSendBufLength = internal_DNSServiceDiscoveryReply_subsystem.maxsize;
453 msgSendBufPtr = (mach_msg_header_t *) malloc(msgSendBufLength);
454
455
456 receivedMessage = ( mach_msg_header_t * ) replyMsg;
457
458 // Call DNSServiceDiscoveryReply_server to change mig-generated message into a
459 // genuine mach message. It will then cause the callback to get called.
460 result = DNSServiceDiscoveryReply_server ( receivedMessage, msgSendBufPtr );
461 ( void ) mach_msg_send ( msgSendBufPtr );
462 free(msgSendBufPtr);
463 }
464
465 mach_port_t DNSServiceDiscoveryMachPort(dns_service_discovery_ref dnsServiceDiscovery)
466 {
467 return dnsServiceDiscovery->port;
468 }
469
470 void DNSServiceDiscoveryDeallocate(dns_service_discovery_ref dnsServiceDiscovery)
471 {
472 struct a_requests *request0, *request;
473 mach_port_t reply = dnsServiceDiscovery->port;
474
475 if (dnsServiceDiscovery->port) {
476 pthread_mutex_lock(&a_requests_lock);
477 request0 = NULL;
478 request = a_requests;
479 while (request) {
480 if (request->client_port == reply) {
481 /* request info found, remove from list */
482 if (request0) {
483 request0->next = request->next;
484 } else {
485 a_requests = request->next;
486 }
487 break;
488 } else {
489 /* not info for this request, skip to next */
490 request0 = request;
491 request = request->next;
492 }
493
494 }
495 pthread_mutex_unlock(&a_requests_lock);
496
497 free(request);
498
499 mach_port_destroy(mach_task_self(), dnsServiceDiscovery->port);
500
501 free(dnsServiceDiscovery);
502 }
503 return;
504 }
505
506 // reply functions, calls the users setup callbacks with function pointers
507
508 kern_return_t internal_DNSServiceDomainEnumerationReply_rpc
509 (
510 mach_port_t reply,
511 int resultType,
512 DNSCString replyDomain,
513 DNSServiceDiscoveryReplyFlags flags
514 )
515 {
516 struct a_requests *request;
517 void *requestContext = NULL;
518 DNSServiceDomainEnumerationReply callback = NULL;
519
520 pthread_mutex_lock(&a_requests_lock);
521 request = a_requests;
522 while (request) {
523 if (request->client_port == reply) {
524 break;
525 }
526 request = request->next;
527 }
528
529 if (request != NULL) {
530 callback = (*request->callout.enumCallback);
531 requestContext = request->context;
532 }
533 pthread_mutex_unlock(&a_requests_lock);
534
535 if (request != NULL) {
536 (callback)(resultType, replyDomain, flags, requestContext);
537 }
538
539 return KERN_SUCCESS;
540
541 }
542
543 kern_return_t internal_DNSServiceBrowserReply_rpc
544 (
545 mach_port_t reply,
546 int resultType,
547 DNSCString replyName,
548 DNSCString replyType,
549 DNSCString replyDomain,
550 DNSServiceDiscoveryReplyFlags flags
551 )
552 {
553 struct a_requests *request;
554 void *requestContext = NULL;
555 DNSServiceBrowserReply callback = NULL;
556
557 pthread_mutex_lock(&a_requests_lock);
558 request = a_requests;
559 while (request) {
560 if (request->client_port == reply) {
561 break;
562 }
563 request = request->next;
564 }
565 if (request != NULL) {
566 callback = (*request->callout.browserCallback);
567 requestContext = request->context;
568 }
569
570 pthread_mutex_unlock(&a_requests_lock);
571
572 if (request != NULL) {
573 (callback)(resultType, replyName, replyType, replyDomain, flags, requestContext);
574 }
575
576 return KERN_SUCCESS;
577 }
578
579
580 kern_return_t internal_DNSServiceRegistrationReply_rpc
581 (
582 mach_port_t reply,
583 int resultType
584 )
585 {
586 struct a_requests *request;
587 void *requestContext = NULL;
588 DNSServiceRegistrationReply callback = NULL;
589
590 pthread_mutex_lock(&a_requests_lock);
591 request = a_requests;
592 while (request) {
593 if (request->client_port == reply) {
594 break;
595 }
596 request = request->next;
597 }
598 if (request != NULL) {
599 callback = (*request->callout.regCallback);
600 requestContext = request->context;
601 }
602
603 pthread_mutex_unlock(&a_requests_lock);
604 if (request != NULL) {
605 (callback)(resultType, requestContext);
606 }
607 return KERN_SUCCESS;
608 }
609
610
611 kern_return_t internal_DNSServiceResolverReply_rpc
612 (
613 mach_port_t reply,
614 sockaddr_t interface,
615 sockaddr_t address,
616 DNSCString txtRecord,
617 DNSServiceDiscoveryReplyFlags flags
618 )
619 {
620 struct sockaddr *interface_storage = NULL;
621 struct sockaddr *address_storage = NULL;
622 struct a_requests *request;
623 void *requestContext = NULL;
624 DNSServiceResolverReply callback = NULL;
625
626 if (interface) {
627 int len = ((struct sockaddr *)interface)->sa_len;
628 interface_storage = (struct sockaddr *)malloc(len);
629 bcopy(interface, interface_storage,len);
630 }
631
632 if (address) {
633 int len = ((struct sockaddr *)address)->sa_len;
634 address_storage = (struct sockaddr *)malloc(len);
635 bcopy(address, address_storage, len);
636 }
637
638 pthread_mutex_lock(&a_requests_lock);
639 request = a_requests;
640 while (request) {
641 if (request->client_port == reply) {
642 break;
643 }
644 request = request->next;
645 }
646
647 if (request != NULL) {
648 callback = (*request->callout.resolveCallback);
649 requestContext = request->context;
650 }
651 pthread_mutex_unlock(&a_requests_lock);
652
653 if (request != NULL) {
654 (callback)(interface_storage, address_storage, txtRecord, flags, requestContext);
655 }
656
657 if (interface) {
658 free(interface_storage);
659 }
660 if (address) {
661 free(address_storage);
662 }
663
664 return KERN_SUCCESS;
665 }