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