1 /* -*- Mode: C; tab-width: 4 -*- 2 * 3 * Copyright (c) 2003 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 * This file defines a simple shim layer between a client calling the "/usr/include/dns_sd.h" APIs 18 * and an implementation of mDNSCore ("mDNSEmbeddedAPI.h" APIs) in the same address space. 19 * When the client calls a dns_sd.h function, the shim calls the corresponding mDNSEmbeddedAPI.h 20 * function, and when mDNSCore calls the shim's callback, we call through to the client's callback. 21 * The shim is responsible for two main things: 22 * - converting string parameters between C string format and native DNS format, 23 * - and for allocating and freeing memory. 24 */ 25 26 #include "dns_sd.h" // Defines the interface to the client layer above 27 #include "mDNSEmbeddedAPI.h" // The interface we're building on top of 28 #include <sys/socket.h> 29 #include <netinet/in.h> 30 31 extern mDNS mDNSStorage; // We need to pass the address of this storage to the lower-layer functions 32 33 #if MDNS_BUILDINGSHAREDLIBRARY || MDNS_BUILDINGSTUBLIBRARY 34 #pragma export on 35 #endif 36 37 //************************************************************************************************************* 38 // General Utility Functions 39 40 // All mDNS_DirectOP structures start with the pointer to the type-specific disposal function. 41 // Optional type-specific data follows these three fields 42 // When the client starts an operation, we return the address of the corresponding mDNS_DirectOP 43 // as the DNSServiceRef for the operation 44 // We stash the value in core context fields so we can get it back to recover our state in our callbacks, 45 // and pass it though to the client for it to recover its state 46 47 typedef struct mDNS_DirectOP_struct mDNS_DirectOP; 48 typedef void mDNS_DirectOP_Dispose(mDNS_DirectOP *op); 49 struct mDNS_DirectOP_struct 50 { 51 mDNS_DirectOP_Dispose *disposefn; 52 }; 53 54 typedef struct 55 { 56 mDNS_DirectOP_Dispose *disposefn; 57 DNSServiceRegisterReply callback; 58 void *context; 59 mDNSBool autoname; // Set if this name is tied to the Computer Name 60 mDNSBool autorename; // Set if we just got a name conflict and now need to automatically pick a new name 61 domainlabel name; 62 domainname host; 63 ServiceRecordSet s; 64 } mDNS_DirectOP_Register; 65 66 typedef struct 67 { 68 mDNS_DirectOP_Dispose *disposefn; 69 DNSServiceBrowseReply callback; 70 void *context; 71 DNSQuestion q; 72 } mDNS_DirectOP_Browse; 73 74 typedef struct 75 { 76 mDNS_DirectOP_Dispose *disposefn; 77 DNSServiceRef aQuery; 78 DNSServiceGetAddrInfoReply callback; 79 void *context; 80 } mDNS_DirectOP_GetAddrInfo; 81 82 typedef struct 83 { 84 mDNS_DirectOP_Dispose *disposefn; 85 DNSServiceResolveReply callback; 86 void *context; 87 const ResourceRecord *SRV; 88 const ResourceRecord *TXT; 89 DNSQuestion qSRV; 90 DNSQuestion qTXT; 91 } mDNS_DirectOP_Resolve; 92 93 typedef struct 94 { 95 mDNS_DirectOP_Dispose *disposefn; 96 DNSServiceQueryRecordReply callback; 97 void *context; 98 DNSQuestion q; 99 } mDNS_DirectOP_QueryRecord; 100 101 int DNSServiceRefSockFD(DNSServiceRef sdRef) 102 { 103 (void)sdRef; // Unused 104 return(0); 105 } 106 107 DNSServiceErrorType DNSServiceProcessResult(DNSServiceRef sdRef) 108 { 109 (void)sdRef; // Unused 110 return(kDNSServiceErr_NoError); 111 } 112 113 void DNSServiceRefDeallocate(DNSServiceRef sdRef) 114 { 115 mDNS_DirectOP *op = (mDNS_DirectOP *)sdRef; 116 //LogMsg("DNSServiceRefDeallocate"); 117 op->disposefn(op); 118 } 119 120 //************************************************************************************************************* 121 // Domain Enumeration 122 123 // Not yet implemented, so don't include in stub library 124 // We DO include it in the actual Extension, so that if a later client compiled to use this 125 // is run against this Extension, it will get a reasonable error code instead of just 126 // failing to launch (Strong Link) or calling an unresolved symbol and crashing (Weak Link) 127 #if !MDNS_BUILDINGSTUBLIBRARY 128 DNSServiceErrorType DNSServiceEnumerateDomains 129 ( 130 DNSServiceRef *sdRef, 131 DNSServiceFlags flags, 132 uint32_t interfaceIndex, 133 DNSServiceDomainEnumReply callback, 134 void *context /* may be NULL */ 135 ) 136 { 137 (void)sdRef; // Unused 138 (void)flags; // Unused 139 (void)interfaceIndex; // Unused 140 (void)callback; // Unused 141 (void)context; // Unused 142 return(kDNSServiceErr_Unsupported); 143 } 144 #endif 145 146 //************************************************************************************************************* 147 // Register Service 148 149 mDNSlocal void FreeDNSServiceRegistration(mDNS_DirectOP_Register *x) 150 { 151 while (x->s.Extras) 152 { 153 ExtraResourceRecord *extras = x->s.Extras; 154 x->s.Extras = x->s.Extras->next; 155 if (extras->r.resrec.rdata != &extras->r.rdatastorage) 156 mDNSPlatformMemFree(extras->r.resrec.rdata); 157 mDNSPlatformMemFree(extras); 158 } 159 160 if (x->s.RR_TXT.resrec.rdata != &x->s.RR_TXT.rdatastorage) 161 mDNSPlatformMemFree(x->s.RR_TXT.resrec.rdata); 162 163 if (x->s.SubTypes) mDNSPlatformMemFree(x->s.SubTypes); 164 165 mDNSPlatformMemFree(x); 166 } 167 168 static void DNSServiceRegisterDispose(mDNS_DirectOP *op) 169 { 170 mDNS_DirectOP_Register *x = (mDNS_DirectOP_Register*)op; 171 x->autorename = mDNSfalse; 172 // If mDNS_DeregisterService() returns mStatus_NoError, that means that the service was found in the list, 173 // is sending its goodbye packet, and we'll get an mStatus_MemFree message when we can free the memory. 174 // If mDNS_DeregisterService() returns an error, it means that the service had already been removed from 175 // the list, so we should go ahead and free the memory right now 176 if (mDNS_DeregisterService(&mDNSStorage, &x->s) != mStatus_NoError) 177 FreeDNSServiceRegistration(x); 178 } 179 180 mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus result) 181 { 182 mDNS_DirectOP_Register *x = (mDNS_DirectOP_Register*)sr->ServiceContext; 183 184 domainlabel name; 185 domainname type, dom; 186 char namestr[MAX_DOMAIN_LABEL+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL. 187 char typestr[MAX_ESCAPED_DOMAIN_NAME]; 188 char domstr [MAX_ESCAPED_DOMAIN_NAME]; 189 if (!DeconstructServiceName(sr->RR_SRV.resrec.name, &name, &type, &dom)) return; 190 if (!ConvertDomainLabelToCString_unescaped(&name, namestr)) return; 191 if (!ConvertDomainNameToCString(&type, typestr)) return; 192 if (!ConvertDomainNameToCString(&dom, domstr)) return; 193 194 if (result == mStatus_NoError) 195 { 196 if (x->callback) 197 x->callback((DNSServiceRef)x, 0, result, namestr, typestr, domstr, x->context); 198 } 199 else if (result == mStatus_NameConflict) 200 { 201 if (x->autoname) mDNS_RenameAndReregisterService(m, sr, mDNSNULL); 202 else if (x->autorename) { 203 IncrementLabelSuffix(&x->name, mDNStrue); 204 mDNS_RenameAndReregisterService(m, &x->s, &x->name); 205 } 206 else if (x->callback) 207 x->callback((DNSServiceRef)x, 0, result, namestr, typestr, domstr, x->context); 208 } 209 else if (result == mStatus_MemFree) 210 { 211 if (x->autorename) 212 { 213 x->autorename = mDNSfalse; 214 x->name = mDNSStorage.nicelabel; 215 mDNS_RenameAndReregisterService(m, &x->s, &x->name); 216 } 217 else 218 FreeDNSServiceRegistration(x); 219 } 220 } 221 222 DNSServiceErrorType DNSServiceRegister 223 ( 224 DNSServiceRef *sdRef, 225 DNSServiceFlags flags, 226 uint32_t interfaceIndex, 227 const char *name, /* may be NULL */ 228 const char *regtype, 229 const char *domain, /* may be NULL */ 230 const char *host, /* may be NULL */ 231 uint16_t notAnIntPort, 232 uint16_t txtLen, 233 const void *txtRecord, /* may be NULL */ 234 DNSServiceRegisterReply callback, /* may be NULL */ 235 void *context /* may be NULL */ 236 ) 237 { 238 mStatus err = mStatus_NoError; 239 const char *errormsg = "Unknown"; 240 domainlabel n; 241 domainname t, d, h, srv; 242 mDNSIPPort port; 243 unsigned int size = sizeof(RDataBody); 244 AuthRecord *SubTypes = mDNSNULL; 245 mDNSu32 NumSubTypes = 0; 246 mDNS_DirectOP_Register *x; 247 (void)flags; // Unused 248 (void)interfaceIndex; // Unused 249 250 // Check parameters 251 if (!name) name = ""; 252 if (!name[0]) n = mDNSStorage.nicelabel; 253 else if (!MakeDomainLabelFromLiteralString(&n, name)) { errormsg = "Bad Instance Name"; goto badparam; } 254 if (!regtype || !*regtype || !MakeDomainNameFromDNSNameString(&t, regtype)) { errormsg = "Bad Service Type"; goto badparam; } 255 if (!MakeDomainNameFromDNSNameString(&d, (domain && *domain) ? domain : "local.")) { errormsg = "Bad Domain"; goto badparam; } 256 if (!MakeDomainNameFromDNSNameString(&h, (host && *host ) ? host : "")) { errormsg = "Bad Target Host"; goto badparam; } 257 if (!ConstructServiceName(&srv, &n, &t, &d)) { errormsg = "Bad Name"; goto badparam; } 258 port.NotAnInteger = notAnIntPort; 259 260 // Allocate memory, and handle failure 261 if (size < txtLen) 262 size = txtLen; 263 x = (mDNS_DirectOP_Register *)mDNSPlatformMemAllocate(sizeof(*x) - sizeof(RDataBody) + size); 264 if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; } 265 266 // Set up object 267 x->disposefn = DNSServiceRegisterDispose; 268 x->callback = callback; 269 x->context = context; 270 x->autoname = (!name[0]); 271 x->autorename = !(flags & kDNSServiceFlagsNoAutoRename); 272 x->name = n; 273 x->host = h; 274 275 // Do the operation 276 err = mDNS_RegisterService(&mDNSStorage, &x->s, 277 &x->name, &t, &d, // Name, type, domain 278 &x->host, port, // Host and port 279 txtRecord, txtLen, // TXT data, length 280 SubTypes, NumSubTypes, // Subtypes 281 mDNSInterface_Any, // Interface ID 282 RegCallback, x, 0); // Callback, context, flags 283 if (err) { mDNSPlatformMemFree(x); errormsg = "mDNS_RegisterService"; goto fail; } 284 285 // Succeeded: Wrap up and return 286 *sdRef = (DNSServiceRef)x; 287 return(mStatus_NoError); 288 289 badparam: 290 err = mStatus_BadParamErr; 291 fail: 292 LogMsg("DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", regtype, domain, errormsg, err); 293 return(err); 294 } 295 296 //************************************************************************************************************* 297 // Add / Update / Remove records from existing Registration 298 299 // Not yet implemented, so don't include in stub library 300 // We DO include it in the actual Extension, so that if a later client compiled to use this 301 // is run against this Extension, it will get a reasonable error code instead of just 302 // failing to launch (Strong Link) or calling an unresolved symbol and crashing (Weak Link) 303 #if !MDNS_BUILDINGSTUBLIBRARY 304 DNSServiceErrorType DNSServiceAddRecord 305 ( 306 DNSServiceRef sdRef, 307 DNSRecordRef *RecordRef, 308 DNSServiceFlags flags, 309 uint16_t rrtype, 310 uint16_t rdlen, 311 const void *rdata, 312 uint32_t ttl 313 ) 314 { 315 (void)sdRef; // Unused 316 (void)RecordRef; // Unused 317 (void)flags; // Unused 318 (void)rrtype; // Unused 319 (void)rdlen; // Unused 320 (void)rdata; // Unused 321 (void)ttl; // Unused 322 return(kDNSServiceErr_Unsupported); 323 } 324 325 DNSServiceErrorType DNSServiceUpdateRecord 326 ( 327 DNSServiceRef sdRef, 328 DNSRecordRef RecordRef, /* may be NULL */ 329 DNSServiceFlags flags, 330 uint16_t rdlen, 331 const void *rdata, 332 uint32_t ttl 333 ) 334 { 335 (void)sdRef; // Unused 336 (void)RecordRef; // Unused 337 (void)flags; // Unused 338 (void)rdlen; // Unused 339 (void)rdata; // Unused 340 (void)ttl; // Unused 341 return(kDNSServiceErr_Unsupported); 342 } 343 344 DNSServiceErrorType DNSServiceRemoveRecord 345 ( 346 DNSServiceRef sdRef, 347 DNSRecordRef RecordRef, 348 DNSServiceFlags flags 349 ) 350 { 351 (void)sdRef; // Unused 352 (void)RecordRef; // Unused 353 (void)flags; // Unused 354 return(kDNSServiceErr_Unsupported); 355 } 356 #endif 357 358 //************************************************************************************************************* 359 // Browse for services 360 361 static void DNSServiceBrowseDispose(mDNS_DirectOP *op) 362 { 363 mDNS_DirectOP_Browse *x = (mDNS_DirectOP_Browse*)op; 364 //LogMsg("DNSServiceBrowseDispose"); 365 mDNS_StopBrowse(&mDNSStorage, &x->q); 366 mDNSPlatformMemFree(x); 367 } 368 369 mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) 370 { 371 DNSServiceFlags flags = AddRecord ? kDNSServiceFlagsAdd : (DNSServiceFlags)0; 372 domainlabel name; 373 domainname type, domain; 374 char cname[MAX_DOMAIN_LABEL+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL. 375 char ctype[MAX_ESCAPED_DOMAIN_NAME]; 376 char cdom [MAX_ESCAPED_DOMAIN_NAME]; 377 mDNS_DirectOP_Browse *x = (mDNS_DirectOP_Browse*)question->QuestionContext; 378 (void)m; // Unused 379 380 if (answer->rrtype != kDNSType_PTR) 381 { LogMsg("FoundInstance: Should not be called with rrtype %d (not a PTR record)", answer->rrtype); return; } 382 383 if (!DeconstructServiceName(&answer->rdata->u.name, &name, &type, &domain)) 384 { 385 LogMsg("FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer", 386 answer->name->c, answer->rdata->u.name.c); 387 return; 388 } 389 390 ConvertDomainLabelToCString_unescaped(&name, cname); 391 ConvertDomainNameToCString(&type, ctype); 392 ConvertDomainNameToCString(&domain, cdom); 393 if (x->callback) 394 x->callback((DNSServiceRef)x, flags, 0, 0, cname, ctype, cdom, x->context); 395 } 396 397 DNSServiceErrorType DNSServiceBrowse 398 ( 399 DNSServiceRef *sdRef, 400 DNSServiceFlags flags, 401 uint32_t interfaceIndex, 402 const char *regtype, 403 const char *domain, /* may be NULL */ 404 DNSServiceBrowseReply callback, 405 void *context /* may be NULL */ 406 ) 407 { 408 mStatus err = mStatus_NoError; 409 const char *errormsg = "Unknown"; 410 domainname t, d; 411 mDNS_DirectOP_Browse *x; 412 (void)flags; // Unused 413 (void)interfaceIndex; // Unused 414 415 // Check parameters 416 if (!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype)) { errormsg = "Illegal regtype"; goto badparam; } 417 if (!MakeDomainNameFromDNSNameString(&d, *domain ? domain : "local.")) { errormsg = "Illegal domain"; goto badparam; } 418 419 // Allocate memory, and handle failure 420 x = (mDNS_DirectOP_Browse *)mDNSPlatformMemAllocate(sizeof(*x)); 421 if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; } 422 423 // Set up object 424 x->disposefn = DNSServiceBrowseDispose; 425 x->callback = callback; 426 x->context = context; 427 x->q.QuestionContext = x; 428 429 // Do the operation 430 err = mDNS_StartBrowse(&mDNSStorage, &x->q, &t, &d, mDNSInterface_Any, (flags & kDNSServiceFlagsForceMulticast) != 0, FoundInstance, x); 431 if (err) { mDNSPlatformMemFree(x); errormsg = "mDNS_StartBrowse"; goto fail; } 432 433 // Succeeded: Wrap up and return 434 *sdRef = (DNSServiceRef)x; 435 return(mStatus_NoError); 436 437 badparam: 438 err = mStatus_BadParamErr; 439 fail: 440 LogMsg("DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", regtype, domain, errormsg, err); 441 return(err); 442 } 443 444 //************************************************************************************************************* 445 // Resolve Service Info 446 447 static void DNSServiceResolveDispose(mDNS_DirectOP *op) 448 { 449 mDNS_DirectOP_Resolve *x = (mDNS_DirectOP_Resolve*)op; 450 if (x->qSRV.ThisQInterval >= 0) mDNS_StopQuery(&mDNSStorage, &x->qSRV); 451 if (x->qTXT.ThisQInterval >= 0) mDNS_StopQuery(&mDNSStorage, &x->qTXT); 452 mDNSPlatformMemFree(x); 453 } 454 455 mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) 456 { 457 mDNS_DirectOP_Resolve *x = (mDNS_DirectOP_Resolve*)question->QuestionContext; 458 (void)m; // Unused 459 if (!AddRecord) 460 { 461 if (answer->rrtype == kDNSType_SRV && x->SRV == answer) x->SRV = mDNSNULL; 462 if (answer->rrtype == kDNSType_TXT && x->TXT == answer) x->TXT = mDNSNULL; 463 } 464 else 465 { 466 if (answer->rrtype == kDNSType_SRV) x->SRV = answer; 467 if (answer->rrtype == kDNSType_TXT) x->TXT = answer; 468 if (x->SRV && x->TXT && x->callback) 469 { 470 char fullname[MAX_ESCAPED_DOMAIN_NAME], targethost[MAX_ESCAPED_DOMAIN_NAME]; 471 ConvertDomainNameToCString(answer->name, fullname); 472 ConvertDomainNameToCString(&x->SRV->rdata->u.srv.target, targethost); 473 x->callback((DNSServiceRef)x, 0, 0, kDNSServiceErr_NoError, fullname, targethost, 474 x->SRV->rdata->u.srv.port.NotAnInteger, x->TXT->rdlength, (unsigned char*)x->TXT->rdata->u.txt.c, x->context); 475 } 476 } 477 } 478 479 DNSServiceErrorType DNSServiceResolve 480 ( 481 DNSServiceRef *sdRef, 482 DNSServiceFlags flags, 483 uint32_t interfaceIndex, 484 const char *name, 485 const char *regtype, 486 const char *domain, 487 DNSServiceResolveReply callback, 488 void *context /* may be NULL */ 489 ) 490 { 491 mStatus err = mStatus_NoError; 492 const char *errormsg = "Unknown"; 493 domainlabel n; 494 domainname t, d, srv; 495 mDNS_DirectOP_Resolve *x; 496 497 (void)flags; // Unused 498 (void)interfaceIndex; // Unused 499 500 // Check parameters 501 if (!name[0] || !MakeDomainLabelFromLiteralString(&n, name )) { errormsg = "Bad Instance Name"; goto badparam; } 502 if (!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype)) { errormsg = "Bad Service Type"; goto badparam; } 503 if (!domain[0] || !MakeDomainNameFromDNSNameString(&d, domain )) { errormsg = "Bad Domain"; goto badparam; } 504 if (!ConstructServiceName(&srv, &n, &t, &d)) { errormsg = "Bad Name"; goto badparam; } 505 506 // Allocate memory, and handle failure 507 x = (mDNS_DirectOP_Resolve *)mDNSPlatformMemAllocate(sizeof(*x)); 508 if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; } 509 510 // Set up object 511 x->disposefn = DNSServiceResolveDispose; 512 x->callback = callback; 513 x->context = context; 514 x->SRV = mDNSNULL; 515 x->TXT = mDNSNULL; 516 517 x->qSRV.ThisQInterval = -1; // So that DNSServiceResolveDispose() knows whether to cancel this question 518 x->qSRV.InterfaceID = mDNSInterface_Any; 519 x->qSRV.Target = zeroAddr; 520 AssignDomainName(&x->qSRV.qname, &srv); 521 x->qSRV.qtype = kDNSType_SRV; 522 x->qSRV.qclass = kDNSClass_IN; 523 x->qSRV.LongLived = mDNSfalse; 524 x->qSRV.ExpectUnique = mDNStrue; 525 x->qSRV.ForceMCast = mDNSfalse; 526 x->qSRV.ReturnIntermed = mDNSfalse; 527 x->qSRV.SuppressUnusable = mDNSfalse; 528 x->qSRV.SearchListIndex = 0; 529 x->qSRV.AppendSearchDomains = 0; 530 x->qSRV.RetryWithSearchDomains = mDNSfalse; 531 x->qSRV.TimeoutQuestion = 0; 532 x->qSRV.WakeOnResolve = 0; 533 x->qSRV.qnameOrig = mDNSNULL; 534 x->qSRV.QuestionCallback = FoundServiceInfo; 535 x->qSRV.QuestionContext = x; 536 537 x->qTXT.ThisQInterval = -1; // So that DNSServiceResolveDispose() knows whether to cancel this question 538 x->qTXT.InterfaceID = mDNSInterface_Any; 539 x->qTXT.Target = zeroAddr; 540 AssignDomainName(&x->qTXT.qname, &srv); 541 x->qTXT.qtype = kDNSType_TXT; 542 x->qTXT.qclass = kDNSClass_IN; 543 x->qTXT.LongLived = mDNSfalse; 544 x->qTXT.ExpectUnique = mDNStrue; 545 x->qTXT.ForceMCast = mDNSfalse; 546 x->qTXT.ReturnIntermed = mDNSfalse; 547 x->qTXT.SuppressUnusable = mDNSfalse; 548 x->qTXT.SearchListIndex = 0; 549 x->qTXT.AppendSearchDomains = 0; 550 x->qTXT.RetryWithSearchDomains = mDNSfalse; 551 x->qTXT.TimeoutQuestion = 0; 552 x->qTXT.WakeOnResolve = 0; 553 x->qTXT.qnameOrig = mDNSNULL; 554 x->qTXT.QuestionCallback = FoundServiceInfo; 555 x->qTXT.QuestionContext = x; 556 557 err = mDNS_StartQuery(&mDNSStorage, &x->qSRV); 558 if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery qSRV"; goto fail; } 559 err = mDNS_StartQuery(&mDNSStorage, &x->qTXT); 560 if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery qTXT"; goto fail; } 561 562 // Succeeded: Wrap up and return 563 *sdRef = (DNSServiceRef)x; 564 return(mStatus_NoError); 565 566 badparam: 567 err = mStatus_BadParamErr; 568 fail: 569 LogMsg("DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%ld)", name, regtype, domain, errormsg, err); 570 return(err); 571 } 572 573 //************************************************************************************************************* 574 // Connection-oriented calls 575 576 // Not yet implemented, so don't include in stub library 577 // We DO include it in the actual Extension, so that if a later client compiled to use this 578 // is run against this Extension, it will get a reasonable error code instead of just 579 // failing to launch (Strong Link) or calling an unresolved symbol and crashing (Weak Link) 580 #if !MDNS_BUILDINGSTUBLIBRARY 581 DNSServiceErrorType DNSServiceCreateConnection(DNSServiceRef *sdRef) 582 { 583 (void)sdRef; // Unused 584 return(kDNSServiceErr_Unsupported); 585 } 586 587 DNSServiceErrorType DNSServiceRegisterRecord 588 ( 589 DNSServiceRef sdRef, 590 DNSRecordRef *RecordRef, 591 DNSServiceFlags flags, 592 uint32_t interfaceIndex, 593 const char *fullname, 594 uint16_t rrtype, 595 uint16_t rrclass, 596 uint16_t rdlen, 597 const void *rdata, 598 uint32_t ttl, 599 DNSServiceRegisterRecordReply callback, 600 void *context /* may be NULL */ 601 ) 602 { 603 (void)sdRef; // Unused 604 (void)RecordRef; // Unused 605 (void)flags; // Unused 606 (void)interfaceIndex; // Unused 607 (void)fullname; // Unused 608 (void)rrtype; // Unused 609 (void)rrclass; // Unused 610 (void)rdlen; // Unused 611 (void)rdata; // Unused 612 (void)ttl; // Unused 613 (void)callback; // Unused 614 (void)context; // Unused 615 return(kDNSServiceErr_Unsupported); 616 } 617 #endif 618 619 //************************************************************************************************************* 620 // DNSServiceQueryRecord 621 622 static void DNSServiceQueryRecordDispose(mDNS_DirectOP *op) 623 { 624 mDNS_DirectOP_QueryRecord *x = (mDNS_DirectOP_QueryRecord*)op; 625 if (x->q.ThisQInterval >= 0) mDNS_StopQuery(&mDNSStorage, &x->q); 626 mDNSPlatformMemFree(x); 627 } 628 629 mDNSlocal void DNSServiceQueryRecordResponse(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) 630 { 631 mDNS_DirectOP_QueryRecord *x = (mDNS_DirectOP_QueryRecord*)question->QuestionContext; 632 char fullname[MAX_ESCAPED_DOMAIN_NAME]; 633 (void)m; // Unused 634 ConvertDomainNameToCString(answer->name, fullname); 635 x->callback((DNSServiceRef)x, AddRecord ? kDNSServiceFlagsAdd : (DNSServiceFlags)0, 0, kDNSServiceErr_NoError, 636 fullname, answer->rrtype, answer->rrclass, answer->rdlength, answer->rdata->u.data, answer->rroriginalttl, x->context); 637 } 638 639 DNSServiceErrorType DNSServiceQueryRecord 640 ( 641 DNSServiceRef *sdRef, 642 DNSServiceFlags flags, 643 uint32_t interfaceIndex, 644 const char *fullname, 645 uint16_t rrtype, 646 uint16_t rrclass, 647 DNSServiceQueryRecordReply callback, 648 void *context /* may be NULL */ 649 ) 650 { 651 mStatus err = mStatus_NoError; 652 const char *errormsg = "Unknown"; 653 mDNS_DirectOP_QueryRecord *x; 654 655 (void)flags; // Unused 656 (void)interfaceIndex; // Unused 657 658 // Allocate memory, and handle failure 659 x = (mDNS_DirectOP_QueryRecord *)mDNSPlatformMemAllocate(sizeof(*x)); 660 if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; } 661 662 // Set up object 663 x->disposefn = DNSServiceQueryRecordDispose; 664 x->callback = callback; 665 x->context = context; 666 667 x->q.ThisQInterval = -1; // So that DNSServiceResolveDispose() knows whether to cancel this question 668 x->q.InterfaceID = mDNSInterface_Any; 669 x->q.Target = zeroAddr; 670 MakeDomainNameFromDNSNameString(&x->q.qname, fullname); 671 x->q.qtype = rrtype; 672 x->q.qclass = rrclass; 673 x->q.LongLived = (flags & kDNSServiceFlagsLongLivedQuery) != 0; 674 x->q.ExpectUnique = mDNSfalse; 675 x->q.ForceMCast = (flags & kDNSServiceFlagsForceMulticast) != 0; 676 x->q.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0; 677 x->q.SuppressUnusable = (flags & kDNSServiceFlagsSuppressUnusable) != 0; 678 x->q.SearchListIndex = 0; 679 x->q.AppendSearchDomains = 0; 680 x->q.RetryWithSearchDomains = mDNSfalse; 681 x->q.WakeOnResolve = 0; 682 x->q.qnameOrig = mDNSNULL; 683 x->q.QuestionCallback = DNSServiceQueryRecordResponse; 684 x->q.QuestionContext = x; 685 686 err = mDNS_StartQuery(&mDNSStorage, &x->q); 687 if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery"; goto fail; } 688 689 // Succeeded: Wrap up and return 690 *sdRef = (DNSServiceRef)x; 691 return(mStatus_NoError); 692 693 fail: 694 LogMsg("DNSServiceQueryRecord(\"%s\", %d, %d) failed: %s (%ld)", fullname, rrtype, rrclass, errormsg, err); 695 return(err); 696 } 697 698 //************************************************************************************************************* 699 // DNSServiceGetAddrInfo 700 701 static void DNSServiceGetAddrInfoDispose(mDNS_DirectOP *op) 702 { 703 mDNS_DirectOP_GetAddrInfo *x = (mDNS_DirectOP_GetAddrInfo*)op; 704 if (x->aQuery) DNSServiceRefDeallocate(x->aQuery); 705 mDNSPlatformMemFree(x); 706 } 707 708 static void DNSSD_API DNSServiceGetAddrInfoResponse( 709 DNSServiceRef inRef, 710 DNSServiceFlags inFlags, 711 uint32_t inInterfaceIndex, 712 DNSServiceErrorType inErrorCode, 713 const char * inFullName, 714 uint16_t inRRType, 715 uint16_t inRRClass, 716 uint16_t inRDLen, 717 const void * inRData, 718 uint32_t inTTL, 719 void * inContext ) 720 { 721 mDNS_DirectOP_GetAddrInfo * x = (mDNS_DirectOP_GetAddrInfo*)inContext; 722 struct sockaddr_in sa4; 723 724 mDNSPlatformMemZero(&sa4, sizeof(sa4)); 725 if (inErrorCode == kDNSServiceErr_NoError && inRRType == kDNSServiceType_A) 726 { 727 sa4.sin_family = AF_INET; 728 mDNSPlatformMemCopy(&sa4.sin_addr.s_addr, inRData, 4); 729 } 730 731 x->callback((DNSServiceRef)x, inFlags, inInterfaceIndex, inErrorCode, inFullName, 732 (const struct sockaddr *) &sa4, inTTL, x->context); 733 } 734 735 DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo( 736 DNSServiceRef * outRef, 737 DNSServiceFlags inFlags, 738 uint32_t inInterfaceIndex, 739 DNSServiceProtocol inProtocol, 740 const char * inHostName, 741 DNSServiceGetAddrInfoReply inCallback, 742 void * inContext ) 743 { 744 const char * errormsg = "Unknown"; 745 DNSServiceErrorType err; 746 mDNS_DirectOP_GetAddrInfo * x; 747 748 // Allocate memory, and handle failure 749 x = (mDNS_DirectOP_GetAddrInfo *)mDNSPlatformMemAllocate(sizeof(*x)); 750 if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; } 751 752 // Set up object 753 x->disposefn = DNSServiceGetAddrInfoDispose; 754 x->callback = inCallback; 755 x->context = inContext; 756 x->aQuery = mDNSNULL; 757 758 // Start the query. 759 // (It would probably be more efficient to code this using mDNS_StartQuery directly, 760 // instead of wrapping DNSServiceQueryRecord, which then unnecessarily allocates 761 // more memory and then just calls through to mDNS_StartQuery. -- SC June 2010) 762 err = DNSServiceQueryRecord(&x->aQuery, inFlags, inInterfaceIndex, inHostName, kDNSServiceType_A, 763 kDNSServiceClass_IN, DNSServiceGetAddrInfoResponse, x); 764 if (err) { DNSServiceGetAddrInfoDispose((mDNS_DirectOP*)x); errormsg = "DNSServiceQueryRecord"; goto fail; } 765 766 *outRef = (DNSServiceRef)x; 767 return(mStatus_NoError); 768 769 fail: 770 LogMsg("DNSServiceGetAddrInfo(\"%s\", %d) failed: %s (%ld)", inHostName, inProtocol, errormsg, err); 771 return(err); 772 } 773 774 //************************************************************************************************************* 775 // DNSServiceReconfirmRecord 776 777 // Not yet implemented, so don't include in stub library 778 // We DO include it in the actual Extension, so that if a later client compiled to use this 779 // is run against this Extension, it will get a reasonable error code instead of just 780 // failing to launch (Strong Link) or calling an unresolved symbol and crashing (Weak Link) 781 #if !MDNS_BUILDINGSTUBLIBRARY 782 DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord 783 ( 784 DNSServiceFlags flags, 785 uint32_t interfaceIndex, 786 const char *fullname, 787 uint16_t rrtype, 788 uint16_t rrclass, 789 uint16_t rdlen, 790 const void *rdata 791 ) 792 { 793 (void)flags; // Unused 794 (void)interfaceIndex; // Unused 795 (void)fullname; // Unused 796 (void)rrtype; // Unused 797 (void)rrclass; // Unused 798 (void)rdlen; // Unused 799 (void)rdata; // Unused 800 return(kDNSServiceErr_Unsupported); 801 } 802 #endif 803