Home | History | Annotate | Download | only in mDNSShared
      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