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