Libinfo-129.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 result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort);
279 if (result != KERN_SUCCESS) {
280 printf("Mach port receive creation failed, %s\n", mach_error_string(result));
281 return NULL;
282 }
283 result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND);
284 if (result != KERN_SUCCESS) {
285 printf("Mach port send creation failed, %s\n", mach_error_string(result));
286 mach_port_destroy(mach_task_self(), clientPort);
287 return NULL;
288 }
289 _increaseQueueLengthOnPort(clientPort);
290
291 return_t = malloc(sizeof(dns_service_discovery_t));
292 return_t->port = clientPort;
293
294 request = malloc(sizeof(struct a_requests));
295 request->client_port = clientPort;
296 request->context = context;
297 request->callout.regCallback = callBack;
298
299 result = DNSServiceRegistrationCreate_rpc(serverPort, clientPort, (char *)name, (char *)regtype, (char *)domain, port, (char *)txtRecord);
300
301 if (result != KERN_SUCCESS) {
302 printf("There was an error creating a resolve, %s\n", mach_error_string(result));
303 free(request);
304 return NULL;
305 }
306
307 pthread_mutex_lock(&a_requests_lock);
308 request->next = a_requests;
309 a_requests = request;
310 pthread_mutex_unlock(&a_requests_lock);
311
312 return return_t;
313 }
314
315 /* Resolver requests */
316
317 dns_service_discovery_ref DNSServiceResolverResolve(const char *name, const char *regtype, const char *domain, DNSServiceResolverReply callBack, void *context)
318 {
319 mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
320 mach_port_t clientPort;
321 kern_return_t result;
322 dns_service_discovery_ref return_t;
323 struct a_requests *request;
324
325 if (!serverPort) {
326 return NULL;
327 }
328
329 result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort);
330 if (result != KERN_SUCCESS) {
331 printf("Mach port receive creation failed, %s\n", mach_error_string(result));
332 return NULL;
333 }
334 result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND);
335 if (result != KERN_SUCCESS) {
336 printf("Mach port send creation failed, %s\n", mach_error_string(result));
337 mach_port_destroy(mach_task_self(), clientPort);
338 return NULL;
339 }
340 _increaseQueueLengthOnPort(clientPort);
341
342 return_t = malloc(sizeof(dns_service_discovery_t));
343 return_t->port = clientPort;
344
345 request = malloc(sizeof(struct a_requests));
346 request->client_port = clientPort;
347 request->context = context;
348 request->callout.resolveCallback = callBack;
349
350 DNSServiceResolverResolve_rpc(serverPort, clientPort, (char *)name, (char *)regtype, (char *)domain);
351
352 pthread_mutex_lock(&a_requests_lock);
353 request->next = a_requests;
354 a_requests = request;
355 pthread_mutex_unlock(&a_requests_lock);
356
357 return return_t;
358 }
359
360 DNSRecordReference DNSServiceRegistrationAddRecord(dns_service_discovery_ref ref, uint16_t rrtype, uint16_t rdlen, const char *rdata, uint32_t ttl)
361 {
362 mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
363 mach_port_t clientPort;
364 natural_t reference = 0;
365 kern_return_t result = KERN_SUCCESS;
366
367 if (!serverPort) {
368 return kDNSServiceDiscoveryUnknownErr;
369 }
370
371 clientPort = DNSServiceDiscoveryMachPort(ref);
372
373 if (!clientPort) {
374 return kDNSServiceDiscoveryUnknownErr;
375 }
376
377 result = DNSServiceRegistrationAddRecord_rpc(serverPort, clientPort, rrtype, (record_data_t)rdata, rdlen, ttl, &reference);
378
379 if (result != KERN_SUCCESS) {
380 printf("The result of the registration was not successful. Error %d, result %s\n", result, mach_error_string(result));
381 }
382
383 return reference;
384 }
385
386 DNSServiceRegistrationReplyErrorType DNSServiceRegistrationUpdateRecord(dns_service_discovery_ref ref, DNSRecordReference reference, uint16_t rdlen, const char *rdata, uint32_t ttl)
387 {
388 mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
389 mach_port_t clientPort;
390 kern_return_t result = KERN_SUCCESS;
391
392 if (!serverPort) {
393 return kDNSServiceDiscoveryUnknownErr;
394 }
395
396 clientPort = DNSServiceDiscoveryMachPort(ref);
397
398 if (!clientPort) {
399 return kDNSServiceDiscoveryUnknownErr;
400 }
401
402 result = DNSServiceRegistrationUpdateRecord_rpc(serverPort, clientPort, (natural_t)reference, (record_data_t)rdata, rdlen, ttl);
403 if (result != KERN_SUCCESS) {
404 printf("The result of the registration was not successful. Error %d, result %s\n", result, mach_error_string(result));
405 return result;
406 }
407
408 return kDNSServiceDiscoveryNoError;
409 }
410
411
412 DNSServiceRegistrationReplyErrorType DNSServiceRegistrationRemoveRecord(dns_service_discovery_ref ref, DNSRecordReference reference)
413 {
414 mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
415 mach_port_t clientPort;
416 kern_return_t result = KERN_SUCCESS;
417
418 if (!serverPort) {
419 return kDNSServiceDiscoveryUnknownErr;
420 }
421
422 clientPort = DNSServiceDiscoveryMachPort(ref);
423
424 if (!clientPort) {
425 return kDNSServiceDiscoveryUnknownErr;
426 }
427
428 result = DNSServiceRegistrationRemoveRecord_rpc(serverPort, clientPort, (natural_t)reference);
429
430 if (result != KERN_SUCCESS) {
431 printf("The result of the registration was not successful. Error %d, result %s\n", result, mach_error_string(result));
432 return result;
433 }
434
435 return kDNSServiceDiscoveryNoError;
436 }
437
438 void DNSServiceDiscovery_handleReply(void *replyMsg)
439 {
440 unsigned long result = 0xFFFFFFFF;
441 mach_msg_header_t * msgSendBufPtr;
442 mach_msg_header_t * receivedMessage;
443 unsigned msgSendBufLength;
444
445 msgSendBufLength = internal_DNSServiceDiscoveryReply_subsystem.maxsize;
446 msgSendBufPtr = (mach_msg_header_t *) malloc(msgSendBufLength);
447
448
449 receivedMessage = ( mach_msg_header_t * ) replyMsg;
450
451 // Call DNSServiceDiscoveryReply_server to change mig-generated message into a
452 // genuine mach message. It will then cause the callback to get called.
453 result = DNSServiceDiscoveryReply_server ( receivedMessage, msgSendBufPtr );
454 ( void ) mach_msg_send ( msgSendBufPtr );
455 free(msgSendBufPtr);
456 }
457
458 mach_port_t DNSServiceDiscoveryMachPort(dns_service_discovery_ref dnsServiceDiscovery)
459 {
460 return dnsServiceDiscovery->port;
461 }
462
463 void DNSServiceDiscoveryDeallocate(dns_service_discovery_ref dnsServiceDiscovery)
464 {
465 struct a_requests *request0, *request;
466 mach_port_t reply = dnsServiceDiscovery->port;
467
468 if (dnsServiceDiscovery->port) {
469 pthread_mutex_lock(&a_requests_lock);
470 request0 = NULL;
471 request = a_requests;
472 while (request) {
473 if (request->client_port == reply) {
474 /* request info found, remove from list */
475 if (request0) {
476 request0->next = request->next;
477 } else {
478 a_requests = request->next;
479 }
480 break;
481 } else {
482 /* not info for this request, skip to next */
483 request0 = request;
484 request = request->next;
485 }
486
487 }
488 pthread_mutex_unlock(&a_requests_lock);
489
490 free(request);
491
492 mach_port_destroy(mach_task_self(), dnsServiceDiscovery->port);
493
494 free(dnsServiceDiscovery);
495 }
496 return;
497 }
498
499 // reply functions, calls the users setup callbacks with function pointers
500
501 kern_return_t internal_DNSServiceDomainEnumerationReply_rpc
502 (
503 mach_port_t reply,
504 int resultType,
505 DNSCString replyDomain,
506 DNSServiceDiscoveryReplyFlags flags
507 )
508 {
509 struct a_requests *request;
510 void *requestContext = NULL;
511 DNSServiceDomainEnumerationReply callback = NULL;
512
513 pthread_mutex_lock(&a_requests_lock);
514 request = a_requests;
515 while (request) {
516 if (request->client_port == reply) {
517 break;
518 }
519 request = request->next;
520 }
521
522 if (request != NULL) {
523 callback = (*request->callout.enumCallback);
524 requestContext = request->context;
525 }
526 pthread_mutex_unlock(&a_requests_lock);
527
528 if (request != NULL) {
529 (callback)(resultType, replyDomain, flags, requestContext);
530 }
531
532 return KERN_SUCCESS;
533
534 }
535
536 kern_return_t internal_DNSServiceBrowserReply_rpc
537 (
538 mach_port_t reply,
539 int resultType,
540 DNSCString replyName,
541 DNSCString replyType,
542 DNSCString replyDomain,
543 DNSServiceDiscoveryReplyFlags flags
544 )
545 {
546 struct a_requests *request;
547 void *requestContext = NULL;
548 DNSServiceBrowserReply callback = NULL;
549
550 pthread_mutex_lock(&a_requests_lock);
551 request = a_requests;
552 while (request) {
553 if (request->client_port == reply) {
554 break;
555 }
556 request = request->next;
557 }
558 if (request != NULL) {
559 callback = (*request->callout.browserCallback);
560 requestContext = request->context;
561 }
562
563 pthread_mutex_unlock(&a_requests_lock);
564
565 if (request != NULL) {
566 (callback)(resultType, replyName, replyType, replyDomain, flags, requestContext);
567 }
568
569 return KERN_SUCCESS;
570 }
571
572
573 kern_return_t internal_DNSServiceRegistrationReply_rpc
574 (
575 mach_port_t reply,
576 int resultType
577 )
578 {
579 struct a_requests *request;
580 void *requestContext = NULL;
581 DNSServiceRegistrationReply callback = NULL;
582
583 pthread_mutex_lock(&a_requests_lock);
584 request = a_requests;
585 while (request) {
586 if (request->client_port == reply) {
587 break;
588 }
589 request = request->next;
590 }
591 if (request != NULL) {
592 callback = (*request->callout.regCallback);
593 requestContext = request->context;
594 }
595
596 pthread_mutex_unlock(&a_requests_lock);
597 if (request != NULL) {
598 (callback)(resultType, requestContext);
599 }
600 return KERN_SUCCESS;
601 }
602
603
604 kern_return_t internal_DNSServiceResolverReply_rpc
605 (
606 mach_port_t reply,
607 sockaddr_t interface,
608 sockaddr_t address,
609 DNSCString txtRecord,
610 DNSServiceDiscoveryReplyFlags flags
611 )
612 {
613 struct sockaddr *interface_storage = NULL;
614 struct sockaddr *address_storage = NULL;
615 struct a_requests *request;
616 void *requestContext = NULL;
617 DNSServiceResolverReply callback = NULL;
618
619 if (interface) {
620 int len = ((struct sockaddr *)interface)->sa_len;
621 interface_storage = (struct sockaddr *)malloc(len);
622 bcopy(interface, interface_storage,len);
623 }
624
625 if (address) {
626 int len = ((struct sockaddr *)address)->sa_len;
627 address_storage = (struct sockaddr *)malloc(len);
628 bcopy(address, address_storage, len);
629 }
630
631 pthread_mutex_lock(&a_requests_lock);
632 request = a_requests;
633 while (request) {
634 if (request->client_port == reply) {
635 break;
636 }
637 request = request->next;
638 }
639
640 if (request != NULL) {
641 callback = (*request->callout.resolveCallback);
642 requestContext = request->context;
643 }
644 pthread_mutex_unlock(&a_requests_lock);
645
646 if (request != NULL) {
647 (callback)(interface_storage, address_storage, txtRecord, flags, requestContext);
648 }
649
650 if (interface) {
651 free(interface_storage);
652 }
653 if (address) {
654 free(address_storage);
655 }
656
657 return KERN_SUCCESS;
658 }