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
28extern 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
44typedef struct mDNS_DirectOP_struct mDNS_DirectOP;
45typedef void mDNS_DirectOP_Dispose(mDNS_DirectOP *op);
46struct mDNS_DirectOP_struct
47	{
48	mDNS_DirectOP_Dispose  *disposefn;
49	};
50
51typedef 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
63typedef struct
64	{
65	mDNS_DirectOP_Dispose  *disposefn;
66	DNSServiceBrowseReply   callback;
67	void                   *context;
68	DNSQuestion             q;
69	} mDNS_DirectOP_Browse;
70
71typedef 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
82typedef struct
83	{
84	mDNS_DirectOP_Dispose      *disposefn;
85	DNSServiceQueryRecordReply  callback;
86	void                       *context;
87	DNSQuestion                 q;
88	} mDNS_DirectOP_QueryRecord;
89
90int DNSServiceRefSockFD(DNSServiceRef sdRef)
91	{
92	(void)sdRef;	// Unused
93	return(0);
94	}
95
96DNSServiceErrorType DNSServiceProcessResult(DNSServiceRef sdRef)
97	{
98	(void)sdRef;	// Unused
99	return(kDNSServiceErr_NoError);
100	}
101
102void 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
117DNSServiceErrorType 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
138mDNSlocal 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
157static 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
169mDNSlocal 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
207DNSServiceErrorType 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
274badparam:
275	err = mStatus_BadParamErr;
276fail:
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
289DNSServiceErrorType 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
310DNSServiceErrorType 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
329DNSServiceErrorType 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
346static 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
354mDNSlocal 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
382DNSServiceErrorType 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
422badparam:
423	err = mStatus_BadParamErr;
424fail:
425	LogMsg("DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", regtype, domain, errormsg, err);
426	return(err);
427	}
428
429//*************************************************************************************************************
430// Resolve Service Info
431
432static 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
440mDNSlocal 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
464DNSServiceErrorType 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
551badparam:
552	err = mStatus_BadParamErr;
553fail:
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
566DNSServiceErrorType DNSServiceCreateConnection(DNSServiceRef *sdRef)
567	{
568	(void)sdRef;	// Unused
569	return(kDNSServiceErr_Unsupported);
570	}
571
572DNSServiceErrorType 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
607static 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
614mDNSlocal 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
624DNSServiceErrorType 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
678fail:
679	LogMsg("DNSServiceQueryRecord(\"%s\", %d, %d) failed: %s (%ld)", fullname, rrtype, rrclass, errormsg, err);
680	return(err);
681	}
682
683//*************************************************************************************************************
684// DNSServiceGetAddrInfo
685
686static 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
693static 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
720DNSServiceErrorType 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
754fail:
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
767DNSServiceErrorType 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