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 "../mDNSMacOSX/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 39extern boolean_t DNSServiceDiscoveryReply_server( 40 mach_msg_header_t *InHeadP, 41 mach_msg_header_t *OutHeadP); 42 43extern 44kern_return_t DNSServiceBrowserCreate_rpc 45( 46 mach_port_t server, 47 mach_port_t client, 48 DNSCString regtype, 49 DNSCString domain 50); 51 52extern 53kern_return_t DNSServiceDomainEnumerationCreate_rpc 54( 55 mach_port_t server, 56 mach_port_t client, 57 int registrationDomains 58); 59 60extern 61kern_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 72extern 73kern_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 82extern 83kern_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 94extern 95int 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 105extern 106kern_return_t DNSServiceRegistrationRemoveRecord_rpc 107( 108 mach_port_t server, 109 mach_port_t client, 110 natural_t reference 111); 112 113struct 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 125static struct a_requests *a_requests = NULL; 126static pthread_mutex_t a_requests_lock = PTHREAD_MUTEX_INITIALIZER; 127 128typedef struct _dns_service_discovery_t { 129 mach_port_t port; 130} dns_service_discovery_t; 131 132static 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 151static 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 164dns_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 215dns_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 267dns_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 333dns_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 376DNSRecordReference 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 402DNSServiceRegistrationReplyErrorType 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 428DNSServiceRegistrationReplyErrorType 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 454void 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 474mach_port_t DNSServiceDiscoveryMachPort(dns_service_discovery_ref dnsServiceDiscovery) 475{ 476 return dnsServiceDiscovery->port; 477} 478 479void 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 517kern_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 552kern_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 589kern_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 620kern_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} 675