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