• 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 #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 
DNSServiceRefSockFD(DNSServiceRef sdRef)101 int DNSServiceRefSockFD(DNSServiceRef sdRef)
102 	{
103 	(void)sdRef;	// Unused
104 	return(0);
105 	}
106 
DNSServiceProcessResult(DNSServiceRef sdRef)107 DNSServiceErrorType DNSServiceProcessResult(DNSServiceRef sdRef)
108 	{
109 	(void)sdRef;	// Unused
110 	return(kDNSServiceErr_NoError);
111 	}
112 
DNSServiceRefDeallocate(DNSServiceRef sdRef)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
DNSServiceEnumerateDomains(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,DNSServiceDomainEnumReply callback,void * context)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 
FreeDNSServiceRegistration(mDNS_DirectOP_Register * x)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 
DNSServiceRegisterDispose(mDNS_DirectOP * op)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 
RegCallback(mDNS * const m,ServiceRecordSet * const sr,mStatus result)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 
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)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
DNSServiceAddRecord(DNSServiceRef sdRef,DNSRecordRef * RecordRef,DNSServiceFlags flags,uint16_t rrtype,uint16_t rdlen,const void * rdata,uint32_t ttl)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 
DNSServiceUpdateRecord(DNSServiceRef sdRef,DNSRecordRef RecordRef,DNSServiceFlags flags,uint16_t rdlen,const void * rdata,uint32_t ttl)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 
DNSServiceRemoveRecord(DNSServiceRef sdRef,DNSRecordRef RecordRef,DNSServiceFlags flags)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 
DNSServiceBrowseDispose(mDNS_DirectOP * op)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 
FoundInstance(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,QC_result AddRecord)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 
DNSServiceBrowse(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * regtype,const char * domain,DNSServiceBrowseReply callback,void * context)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 
DNSServiceResolveDispose(mDNS_DirectOP * op)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 
FoundServiceInfo(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,QC_result AddRecord)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 
DNSServiceResolve(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * name,const char * regtype,const char * domain,DNSServiceResolveReply callback,void * context)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
DNSServiceCreateConnection(DNSServiceRef * sdRef)581 DNSServiceErrorType DNSServiceCreateConnection(DNSServiceRef *sdRef)
582 	{
583 	(void)sdRef;	// Unused
584 	return(kDNSServiceErr_Unsupported);
585 	}
586 
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)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 
DNSServiceQueryRecordDispose(mDNS_DirectOP * op)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 
DNSServiceQueryRecordResponse(mDNS * const m,DNSQuestion * question,const ResourceRecord * const answer,QC_result AddRecord)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 
DNSServiceQueryRecord(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * fullname,uint16_t rrtype,uint16_t rrclass,DNSServiceQueryRecordReply callback,void * context)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 
DNSServiceGetAddrInfoDispose(mDNS_DirectOP * op)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 
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)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 
DNSServiceGetAddrInfo(DNSServiceRef * outRef,DNSServiceFlags inFlags,uint32_t inInterfaceIndex,DNSServiceProtocol inProtocol,const char * inHostName,DNSServiceGetAddrInfoReply inCallback,void * inContext)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
DNSServiceReconfirmRecord(DNSServiceFlags flags,uint32_t interfaceIndex,const char * fullname,uint16_t rrtype,uint16_t rrclass,uint16_t rdlen,const void * rdata)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