• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
DNSServiceRefSockFD(DNSServiceRef sdRef)90 int DNSServiceRefSockFD(DNSServiceRef sdRef)
91 	{
92 	(void)sdRef;	// Unused
93 	return(0);
94 	}
95 
DNSServiceProcessResult(DNSServiceRef sdRef)96 DNSServiceErrorType DNSServiceProcessResult(DNSServiceRef sdRef)
97 	{
98 	(void)sdRef;	// Unused
99 	return(kDNSServiceErr_NoError);
100 	}
101 
DNSServiceRefDeallocate(DNSServiceRef sdRef)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
DNSServiceEnumerateDomains(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,DNSServiceDomainEnumReply callback,void * context)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 
FreeDNSServiceRegistration(mDNS_DirectOP_Register * x)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 
DNSServiceRegisterDispose(mDNS_DirectOP * op)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 
RegCallback(mDNS * const m,ServiceRecordSet * const sr,mStatus result)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 
DNSServiceRegister(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * name,const char * regtype,const char * domain,const char * host,uint16_t notAnIntPort,uint16_t txtLen,const void * txtRecord,DNSServiceRegisterReply callback,void * context)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
DNSServiceAddRecord(DNSServiceRef sdRef,DNSRecordRef * RecordRef,DNSServiceFlags flags,uint16_t rrtype,uint16_t rdlen,const void * rdata,uint32_t ttl)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 
DNSServiceUpdateRecord(DNSServiceRef sdRef,DNSRecordRef RecordRef,DNSServiceFlags flags,uint16_t rdlen,const void * rdata,uint32_t ttl)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 
DNSServiceRemoveRecord(DNSServiceRef sdRef,DNSRecordRef RecordRef,DNSServiceFlags flags)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 
DNSServiceBrowseDispose(mDNS_DirectOP * op)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 
FoundInstance(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,QC_result AddRecord)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 
DNSServiceBrowse(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * regtype,const char * domain,DNSServiceBrowseReply callback,void * context)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 
DNSServiceResolveDispose(mDNS_DirectOP * op)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 
FoundServiceInfo(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,QC_result AddRecord)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 
DNSServiceResolve(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * name,const char * regtype,const char * domain,DNSServiceResolveReply callback,void * context)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
DNSServiceCreateConnection(DNSServiceRef * sdRef)566 DNSServiceErrorType DNSServiceCreateConnection(DNSServiceRef *sdRef)
567 	{
568 	(void)sdRef;	// Unused
569 	return(kDNSServiceErr_Unsupported);
570 	}
571 
DNSServiceRegisterRecord(DNSServiceRef sdRef,DNSRecordRef * RecordRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * fullname,uint16_t rrtype,uint16_t rrclass,uint16_t rdlen,const void * rdata,uint32_t ttl,DNSServiceRegisterRecordReply callback,void * context)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 
DNSServiceQueryRecordDispose(mDNS_DirectOP * op)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 
DNSServiceQueryRecordResponse(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,QC_result AddRecord)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 
DNSServiceQueryRecord(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * fullname,uint16_t rrtype,uint16_t rrclass,DNSServiceQueryRecordReply callback,void * context)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 
DNSServiceGetAddrInfoDispose(mDNS_DirectOP * op)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 
DNSServiceGetAddrInfoResponse(DNSServiceRef inRef,DNSServiceFlags inFlags,uint32_t inInterfaceIndex,DNSServiceErrorType inErrorCode,const char * inFullName,uint16_t inRRType,uint16_t inRRClass,uint16_t inRDLen,const void * inRData,uint32_t inTTL,void * inContext)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 
DNSServiceGetAddrInfo(DNSServiceRef * outRef,DNSServiceFlags inFlags,uint32_t inInterfaceIndex,DNSServiceProtocol inProtocol,const char * inHostName,DNSServiceGetAddrInfoReply inCallback,void * inContext)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
DNSServiceReconfirmRecord(DNSServiceFlags flags,uint32_t interfaceIndex,const char * fullname,uint16_t rrtype,uint16_t rrclass,uint16_t rdlen,const void * rdata)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