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 extern 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 44 typedef struct mDNS_DirectOP_struct mDNS_DirectOP; 45 typedef void mDNS_DirectOP_Dispose(mDNS_DirectOP *op); 46 struct mDNS_DirectOP_struct 47 { 48 mDNS_DirectOP_Dispose *disposefn; 49 }; 50 51 typedef 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 63 typedef struct 64 { 65 mDNS_DirectOP_Dispose *disposefn; 66 DNSServiceBrowseReply callback; 67 void *context; 68 DNSQuestion q; 69 } mDNS_DirectOP_Browse; 70 71 typedef 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 82 typedef struct 83 { 84 mDNS_DirectOP_Dispose *disposefn; 85 DNSServiceQueryRecordReply callback; 86 void *context; 87 DNSQuestion q; 88 } mDNS_DirectOP_QueryRecord; 89 90 int DNSServiceRefSockFD(DNSServiceRef sdRef) 91 { 92 (void)sdRef; // Unused 93 return(0); 94 } 95 96 DNSServiceErrorType DNSServiceProcessResult(DNSServiceRef sdRef) 97 { 98 (void)sdRef; // Unused 99 return(kDNSServiceErr_NoError); 100 } 101 102 void 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 117 DNSServiceErrorType 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 138 mDNSlocal 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 157 static 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 169 mDNSlocal 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 207 DNSServiceErrorType 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 274 badparam: 275 err = mStatus_BadParamErr; 276 fail: 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 289 DNSServiceErrorType 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 310 DNSServiceErrorType 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 329 DNSServiceErrorType 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 346 static 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 354 mDNSlocal 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 382 DNSServiceErrorType 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, mDNSInterface_Any, (flags & kDNSServiceFlagsForceMulticast) != 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 422 badparam: 423 err = mStatus_BadParamErr; 424 fail: 425 LogMsg("DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", regtype, domain, errormsg, err); 426 return(err); 427 } 428 429 //************************************************************************************************************* 430 // Resolve Service Info 431 432 static 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 440 mDNSlocal 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 464 DNSServiceErrorType 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.Target = zeroAddr; 505 AssignDomainName(&x->qSRV.qname, &srv); 506 x->qSRV.qtype = kDNSType_SRV; 507 x->qSRV.qclass = kDNSClass_IN; 508 x->qSRV.LongLived = mDNSfalse; 509 x->qSRV.ExpectUnique = mDNStrue; 510 x->qSRV.ForceMCast = mDNSfalse; 511 x->qSRV.ReturnIntermed = mDNSfalse; 512 x->qSRV.SuppressUnusable = mDNSfalse; 513 x->qSRV.SearchListIndex = 0; 514 x->qSRV.AppendSearchDomains = 0; 515 x->qSRV.RetryWithSearchDomains = mDNSfalse; 516 x->qSRV.TimeoutQuestion = 0; 517 x->qSRV.WakeOnResolve = 0; 518 x->qSRV.qnameOrig = mDNSNULL; 519 x->qSRV.QuestionCallback = FoundServiceInfo; 520 x->qSRV.QuestionContext = x; 521 522 x->qTXT.ThisQInterval = -1; // So that DNSServiceResolveDispose() knows whether to cancel this question 523 x->qTXT.InterfaceID = mDNSInterface_Any; 524 x->qTXT.Target = zeroAddr; 525 AssignDomainName(&x->qTXT.qname, &srv); 526 x->qTXT.qtype = kDNSType_TXT; 527 x->qTXT.qclass = kDNSClass_IN; 528 x->qTXT.LongLived = mDNSfalse; 529 x->qTXT.ExpectUnique = mDNStrue; 530 x->qTXT.ForceMCast = mDNSfalse; 531 x->qTXT.ReturnIntermed = mDNSfalse; 532 x->qTXT.SuppressUnusable = mDNSfalse; 533 x->qTXT.SearchListIndex = 0; 534 x->qTXT.AppendSearchDomains = 0; 535 x->qTXT.RetryWithSearchDomains = mDNSfalse; 536 x->qTXT.TimeoutQuestion = 0; 537 x->qTXT.WakeOnResolve = 0; 538 x->qTXT.qnameOrig = mDNSNULL; 539 x->qTXT.QuestionCallback = FoundServiceInfo; 540 x->qTXT.QuestionContext = x; 541 542 err = mDNS_StartQuery(&mDNSStorage, &x->qSRV); 543 if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery qSRV"; goto fail; } 544 err = mDNS_StartQuery(&mDNSStorage, &x->qTXT); 545 if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery qTXT"; goto fail; } 546 547 // Succeeded: Wrap up and return 548 *sdRef = (DNSServiceRef)x; 549 return(mStatus_NoError); 550 551 badparam: 552 err = mStatus_BadParamErr; 553 fail: 554 LogMsg("DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%ld)", name, regtype, domain, errormsg, err); 555 return(err); 556 } 557 558 //************************************************************************************************************* 559 // Connection-oriented calls 560 561 // Not yet implemented, so don't include in stub library 562 // We DO include it in the actual Extension, so that if a later client compiled to use this 563 // is run against this Extension, it will get a reasonable error code instead of just 564 // failing to launch (Strong Link) or calling an unresolved symbol and crashing (Weak Link) 565 #if !MDNS_BUILDINGSTUBLIBRARY 566 DNSServiceErrorType DNSServiceCreateConnection(DNSServiceRef *sdRef) 567 { 568 (void)sdRef; // Unused 569 return(kDNSServiceErr_Unsupported); 570 } 571 572 DNSServiceErrorType DNSServiceRegisterRecord 573 ( 574 DNSServiceRef sdRef, 575 DNSRecordRef *RecordRef, 576 DNSServiceFlags flags, 577 uint32_t interfaceIndex, 578 const char *fullname, 579 uint16_t rrtype, 580 uint16_t rrclass, 581 uint16_t rdlen, 582 const void *rdata, 583 uint32_t ttl, 584 DNSServiceRegisterRecordReply callback, 585 void *context /* may be NULL */ 586 ) 587 { 588 (void)sdRef; // Unused 589 (void)RecordRef; // Unused 590 (void)flags; // Unused 591 (void)interfaceIndex; // Unused 592 (void)fullname; // Unused 593 (void)rrtype; // Unused 594 (void)rrclass; // Unused 595 (void)rdlen; // Unused 596 (void)rdata; // Unused 597 (void)ttl; // Unused 598 (void)callback; // Unused 599 (void)context; // Unused 600 return(kDNSServiceErr_Unsupported); 601 } 602 #endif 603 604 //************************************************************************************************************* 605 // DNSServiceQueryRecord 606 607 static void DNSServiceQueryRecordDispose(mDNS_DirectOP *op) 608 { 609 mDNS_DirectOP_QueryRecord *x = (mDNS_DirectOP_QueryRecord*)op; 610 if (x->q.ThisQInterval >= 0) mDNS_StopQuery(&mDNSStorage, &x->q); 611 mDNSPlatformMemFree(x); 612 } 613 614 mDNSlocal void DNSServiceQueryRecordResponse(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) 615 { 616 mDNS_DirectOP_QueryRecord *x = (mDNS_DirectOP_QueryRecord*)question->QuestionContext; 617 char fullname[MAX_ESCAPED_DOMAIN_NAME]; 618 (void)m; // Unused 619 ConvertDomainNameToCString(answer->name, fullname); 620 x->callback((DNSServiceRef)x, AddRecord ? kDNSServiceFlagsAdd : (DNSServiceFlags)0, 0, kDNSServiceErr_NoError, 621 fullname, answer->rrtype, answer->rrclass, answer->rdlength, answer->rdata->u.data, answer->rroriginalttl, x->context); 622 } 623 624 DNSServiceErrorType DNSServiceQueryRecord 625 ( 626 DNSServiceRef *sdRef, 627 DNSServiceFlags flags, 628 uint32_t interfaceIndex, 629 const char *fullname, 630 uint16_t rrtype, 631 uint16_t rrclass, 632 DNSServiceQueryRecordReply callback, 633 void *context /* may be NULL */ 634 ) 635 { 636 mStatus err = mStatus_NoError; 637 const char *errormsg = "Unknown"; 638 mDNS_DirectOP_QueryRecord *x; 639 640 (void)flags; // Unused 641 (void)interfaceIndex; // Unused 642 643 // Allocate memory, and handle failure 644 x = (mDNS_DirectOP_QueryRecord *)mDNSPlatformMemAllocate(sizeof(*x)); 645 if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; } 646 647 // Set up object 648 x->disposefn = DNSServiceQueryRecordDispose; 649 x->callback = callback; 650 x->context = context; 651 652 x->q.ThisQInterval = -1; // So that DNSServiceResolveDispose() knows whether to cancel this question 653 x->q.InterfaceID = mDNSInterface_Any; 654 x->q.Target = zeroAddr; 655 MakeDomainNameFromDNSNameString(&x->q.qname, fullname); 656 x->q.qtype = rrtype; 657 x->q.qclass = rrclass; 658 x->q.LongLived = (flags & kDNSServiceFlagsLongLivedQuery) != 0; 659 x->q.ExpectUnique = mDNSfalse; 660 x->q.ForceMCast = (flags & kDNSServiceFlagsForceMulticast) != 0; 661 x->q.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0; 662 x->q.SuppressUnsable = (flags & kDNSServiceFlagsSuppressUnusable) != 0; 663 x->q.SearchListIndex = 0; 664 x->q.AppendSearchDomains = 0; 665 x->q.RetryWithSearchDomains = mDNSfalse; 666 x->q.WakeOnResolve = 0; 667 x->q.qnameOrig = mDNSNULL; 668 x->q.QuestionCallback = DNSServiceQueryRecordResponse; 669 x->q.QuestionContext = x; 670 671 err = mDNS_StartQuery(&mDNSStorage, &x->q); 672 if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery"; goto fail; } 673 674 // Succeeded: Wrap up and return 675 *sdRef = (DNSServiceRef)x; 676 return(mStatus_NoError); 677 678 fail: 679 LogMsg("DNSServiceQueryRecord(\"%s\", %d, %d) failed: %s (%ld)", fullname, rrtype, rrclass, errormsg, err); 680 return(err); 681 } 682 683 //************************************************************************************************************* 684 // DNSServiceGetAddrInfo 685 686 static void DNSServiceGetAddrInfoDispose(mDNS_DirectOP *op) 687 { 688 mDNS_DirectOP_GetAddrInfo *x = (mDNS_DirectOP_GetAddrInfo*)op; 689 if (x->aQuery) DNSServiceRefDeallocate(x->aQuery); 690 mDNSPlatformMemFree(x); 691 } 692 693 static void DNSSD_API DNSServiceGetAddrInfoResponse( 694 DNSServiceRef inRef, 695 DNSServiceFlags inFlags, 696 uint32_t inInterfaceIndex, 697 DNSServiceErrorType inErrorCode, 698 const char * inFullName, 699 uint16_t inRRType, 700 uint16_t inRRClass, 701 uint16_t inRDLen, 702 const void * inRData, 703 uint32_t inTTL, 704 void * inContext ) 705 { 706 mDNS_DirectOP_GetAddrInfo * x = (mDNS_DirectOP_GetAddrInfo*)inContext; 707 struct sockaddr_in sa4; 708 709 mDNSPlatformMemZero(&sa4, sizeof(sa4)); 710 if (inErrorCode == kDNSServiceErr_NoError && inRRType == kDNSServiceType_A) 711 { 712 sa4.sin_family = AF_INET; 713 mDNSPlatformMemCopy(&sa4.sin_addr.s_addr, inRData, 4); 714 } 715 716 x->callback((DNSServiceRef)x, inFlags, inInterfaceIndex, inErrorCode, inFullName, 717 (const struct sockaddr *) &sa4, inTTL, x->context); 718 } 719 720 DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo( 721 DNSServiceRef * outRef, 722 DNSServiceFlags inFlags, 723 uint32_t inInterfaceIndex, 724 DNSServiceProtocol inProtocol, 725 const char * inHostName, 726 DNSServiceGetAddrInfoReply inCallback, 727 void * inContext ) 728 { 729 const char * errormsg = "Unknown"; 730 DNSServiceErrorType err; 731 mDNS_DirectOP_GetAddrInfo * x; 732 733 // Allocate memory, and handle failure 734 x = (mDNS_DirectOP_GetAddrInfo *)mDNSPlatformMemAllocate(sizeof(*x)); 735 if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; } 736 737 // Set up object 738 x->disposefn = DNSServiceGetAddrInfoDispose; 739 x->callback = inCallback; 740 x->context = inContext; 741 x->aQuery = mDNSNULL; 742 743 // Start the query. 744 // (It would probably be more efficient to code this using mDNS_StartQuery directly, 745 // instead of wrapping DNSServiceQueryRecord, which then unnecessarily allocates 746 // more memory and then just calls through to mDNS_StartQuery. -- SC June 2010) 747 err = DNSServiceQueryRecord(&x->aQuery, inFlags, inInterfaceIndex, inHostName, kDNSServiceType_A, 748 kDNSServiceClass_IN, DNSServiceGetAddrInfoResponse, x); 749 if (err) { DNSServiceGetAddrInfoDispose((mDNS_DirectOP*)x); errormsg = "DNSServiceQueryRecord"; goto fail; } 750 751 *outRef = (DNSServiceRef)x; 752 return(mStatus_NoError); 753 754 fail: 755 LogMsg("DNSServiceGetAddrInfo(\"%s\", %d) failed: %s (%ld)", inHostName, inProtocol, errormsg, err); 756 return(err); 757 } 758 759 //************************************************************************************************************* 760 // DNSServiceReconfirmRecord 761 762 // Not yet implemented, so don't include in stub library 763 // We DO include it in the actual Extension, so that if a later client compiled to use this 764 // is run against this Extension, it will get a reasonable error code instead of just 765 // failing to launch (Strong Link) or calling an unresolved symbol and crashing (Weak Link) 766 #if !MDNS_BUILDINGSTUBLIBRARY 767 DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord 768 ( 769 DNSServiceFlags flags, 770 uint32_t interfaceIndex, 771 const char *fullname, 772 uint16_t rrtype, 773 uint16_t rrclass, 774 uint16_t rdlen, 775 const void *rdata 776 ) 777 { 778 (void)flags; // Unused 779 (void)interfaceIndex; // Unused 780 (void)fullname; // Unused 781 (void)rrtype; // Unused 782 (void)rrclass; // Unused 783 (void)rdlen; // Unused 784 (void)rdata; // Unused 785 return(kDNSServiceErr_Unsupported); 786 } 787 #endif 788