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