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
31extern 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
47typedef struct mDNS_DirectOP_struct mDNS_DirectOP;
48typedef void mDNS_DirectOP_Dispose(mDNS_DirectOP *op);
49struct mDNS_DirectOP_struct
50	{
51	mDNS_DirectOP_Dispose  *disposefn;
52	};
53
54typedef 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
66typedef struct
67	{
68	mDNS_DirectOP_Dispose  *disposefn;
69	DNSServiceBrowseReply   callback;
70	void                   *context;
71	DNSQuestion             q;
72	} mDNS_DirectOP_Browse;
73
74typedef struct
75	{
76	mDNS_DirectOP_Dispose        *disposefn;
77	DNSServiceRef                aQuery;
78	DNSServiceGetAddrInfoReply   callback;
79  	void                         *context;
80	} mDNS_DirectOP_GetAddrInfo;
81
82typedef 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
93typedef struct
94	{
95	mDNS_DirectOP_Dispose      *disposefn;
96	DNSServiceQueryRecordReply  callback;
97	void                       *context;
98	DNSQuestion                 q;
99	} mDNS_DirectOP_QueryRecord;
100
101int DNSServiceRefSockFD(DNSServiceRef sdRef)
102	{
103	(void)sdRef;	// Unused
104	return(0);
105	}
106
107DNSServiceErrorType DNSServiceProcessResult(DNSServiceRef sdRef)
108	{
109	(void)sdRef;	// Unused
110	return(kDNSServiceErr_NoError);
111	}
112
113void 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
128DNSServiceErrorType 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
149mDNSlocal 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
168static 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
180mDNSlocal 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
222DNSServiceErrorType 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
289badparam:
290	err = mStatus_BadParamErr;
291fail:
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
304DNSServiceErrorType 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
325DNSServiceErrorType 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
344DNSServiceErrorType 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
361static 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
369mDNSlocal 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
397DNSServiceErrorType 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
437badparam:
438	err = mStatus_BadParamErr;
439fail:
440	LogMsg("DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", regtype, domain, errormsg, err);
441	return(err);
442	}
443
444//*************************************************************************************************************
445// Resolve Service Info
446
447static 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
455mDNSlocal 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
479DNSServiceErrorType 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
566badparam:
567	err = mStatus_BadParamErr;
568fail:
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
581DNSServiceErrorType DNSServiceCreateConnection(DNSServiceRef *sdRef)
582	{
583	(void)sdRef;	// Unused
584	return(kDNSServiceErr_Unsupported);
585	}
586
587DNSServiceErrorType 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
622static 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
629mDNSlocal 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
639DNSServiceErrorType 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
693fail:
694	LogMsg("DNSServiceQueryRecord(\"%s\", %d, %d) failed: %s (%ld)", fullname, rrtype, rrclass, errormsg, err);
695	return(err);
696	}
697
698//*************************************************************************************************************
699// DNSServiceGetAddrInfo
700
701static 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
708static 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
735DNSServiceErrorType 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
769fail:
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
782DNSServiceErrorType 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