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