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