]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSShared/dnssd_clientshim.c
121b0df237cd01fc1a7cb53e843c363fd0360df8
[apple/mdnsresponder.git] / mDNSShared / dnssd_clientshim.c
1 /*
2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22
23 * This file defines a simple shim layer between a client calling the "/usr/include/dns_sd.h" APIs
24 * and an implementation of mDNSCore ("mDNSEmbeddedAPI.h" APIs) in the same address space.
25 * When the client calls a dns_sd.h function, the shim calls the corresponding mDNSEmbeddedAPI.h
26 * function, and when mDNSCore calls the shim's callback, we call through to the client's callback.
27 * The shim is responsible for two main things:
28 * - converting string parameters between C string format and native DNS format,
29 * - and for allocating and freeing memory.
30
31 Change History (most recent first):
32
33 $Log: dnssd_clientshim.c,v $
34 Revision 1.7 2004/12/10 04:08:43 cheshire
35 Added comments about autoname and autorename
36
37 Revision 1.6 2004/10/19 21:33:22 cheshire
38 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
39 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
40 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
41
42 Revision 1.5 2004/09/21 23:29:51 cheshire
43 <rdar://problem/3680045> DNSServiceResolve should delay sending packets
44
45 Revision 1.4 2004/09/17 01:08:55 cheshire
46 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
47 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
48 declared in that file are ONLY appropriate to single-address-space embedded applications.
49 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
50
51 Revision 1.3 2004/05/27 06:26:31 cheshire
52 Add shim for DNSServiceQueryRecord()
53
54 Revision 1.2 2004/05/20 18:41:24 cheshire
55 Fix build broken by removal of 'kDNSServiceFlagsRemove' from dns_sd.h
56
57 Revision 1.1 2004/03/12 21:30:29 cheshire
58 Build a System-Context Shared Library from mDNSCore, for the benefit of developers
59 like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
60
61 */
62
63 #include "dns_sd.h" // Defines the interface to the client layer above
64 #include "mDNSEmbeddedAPI.h" // The interface we're building on top of
65 extern mDNS mDNSStorage; // We need to pass the address of this storage to the lower-layer functions
66
67 #if MDNS_BUILDINGSHAREDLIBRARY || MDNS_BUILDINGSTUBLIBRARY
68 #pragma export on
69 #endif
70
71 //*************************************************************************************************************
72 // General Utility Functions
73
74 // All mDNS_DirectOP structures start with the pointer to the type-specific disposal function.
75 // Optional type-specific data follows these three fields
76 // When the client starts an operation, we return the address of the corresponding mDNS_DirectOP
77 // as the DNSServiceRef for the operation
78 // We stash the value in core context fields so we can get it back to recover our state in our callbacks,
79 // and pass it though to the client for it to recover its state
80
81 typedef struct mDNS_DirectOP_struct mDNS_DirectOP;
82 typedef void mDNS_DirectOP_Dispose(mDNS_DirectOP *op);
83 struct mDNS_DirectOP_struct
84 {
85 mDNS_DirectOP_Dispose *disposefn;
86 };
87
88 typedef struct
89 {
90 mDNS_DirectOP_Dispose *disposefn;
91 DNSServiceRegisterReply callback;
92 void *context;
93 mDNSBool autoname; // Set if this name is tied to the Computer Name
94 mDNSBool autorename; // Set if we just got a name conflict and now need to automatically pick a new name
95 domainlabel name;
96 ServiceRecordSet s;
97 } mDNS_DirectOP_Register;
98
99 typedef struct
100 {
101 mDNS_DirectOP_Dispose *disposefn;
102 DNSServiceBrowseReply callback;
103 void *context;
104 DNSQuestion q;
105 } mDNS_DirectOP_Browse;
106
107 typedef struct
108 {
109 mDNS_DirectOP_Dispose *disposefn;
110 DNSServiceResolveReply callback;
111 void *context;
112 const ResourceRecord *SRV;
113 const ResourceRecord *TXT;
114 DNSQuestion qSRV;
115 DNSQuestion qTXT;
116 } mDNS_DirectOP_Resolve;
117
118 typedef struct
119 {
120 mDNS_DirectOP_Dispose *disposefn;
121 DNSServiceQueryRecordReply callback;
122 void *context;
123 DNSQuestion q;
124 } mDNS_DirectOP_QueryRecord;
125
126 int DNSServiceRefSockFD(DNSServiceRef sdRef)
127 {
128 (void)sdRef; // Unused
129 return(0);
130 }
131
132 DNSServiceErrorType DNSServiceProcessResult(DNSServiceRef sdRef)
133 {
134 (void)sdRef; // Unused
135 return(kDNSServiceErr_NoError);
136 }
137
138 void DNSServiceRefDeallocate(DNSServiceRef sdRef)
139 {
140 mDNS_DirectOP *op = (mDNS_DirectOP *)sdRef;
141 //LogMsg("DNSServiceRefDeallocate");
142 op->disposefn(op);
143 }
144
145 //*************************************************************************************************************
146 // Domain Enumeration
147
148 // Not yet implemented, so don't include in stub library
149 // We DO include it in the actual Extension, so that if a later client compiled to use this
150 // is run against this Extension, it will get a reasonable error code instead of just
151 // failing to launch (Strong Link) or calling an unresolved symbol and crashing (Weak Link)
152 #if !MDNS_BUILDINGSTUBLIBRARY
153 DNSServiceErrorType DNSServiceEnumerateDomains
154 (
155 DNSServiceRef *sdRef,
156 DNSServiceFlags flags,
157 uint32_t interfaceIndex,
158 DNSServiceDomainEnumReply callback,
159 void *context /* may be NULL */
160 )
161 {
162 (void)sdRef; // Unused
163 (void)flags; // Unused
164 (void)interfaceIndex; // Unused
165 (void)callback; // Unused
166 (void)context; // Unused
167 return(kDNSServiceErr_Unsupported);
168 }
169 #endif
170
171 //*************************************************************************************************************
172 // Register Service
173
174 mDNSlocal void FreeDNSServiceRegistration(mDNS_DirectOP_Register *x)
175 {
176 while (x->s.Extras)
177 {
178 ExtraResourceRecord *extras = x->s.Extras;
179 x->s.Extras = x->s.Extras->next;
180 if (extras->r.resrec.rdata != &extras->r.rdatastorage)
181 mDNSPlatformMemFree(extras->r.resrec.rdata);
182 mDNSPlatformMemFree(extras);
183 }
184
185 if (x->s.RR_TXT.resrec.rdata != &x->s.RR_TXT.rdatastorage)
186 mDNSPlatformMemFree(x->s.RR_TXT.resrec.rdata);
187
188 if (x->s.SubTypes) mDNSPlatformMemFree(x->s.SubTypes);
189
190 mDNSPlatformMemFree(x);
191 }
192
193 static void DNSServiceRegisterDispose(mDNS_DirectOP *op)
194 {
195 mDNS_DirectOP_Register *x = (mDNS_DirectOP_Register*)op;
196 x->autorename = mDNSfalse;
197 // If mDNS_DeregisterService() returns mStatus_NoError, that means that the service was found in the list,
198 // is sending its goodbye packet, and we'll get an mStatus_MemFree message when we can free the memory.
199 // If mDNS_DeregisterService() returns an error, it means that the service had already been removed from
200 // the list, so we should go ahead and free the memory right now
201 if (mDNS_DeregisterService(&mDNSStorage, &x->s) != mStatus_NoError)
202 FreeDNSServiceRegistration(x);
203 }
204
205 mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus result)
206 {
207 mDNS_DirectOP_Register *x = (mDNS_DirectOP_Register*)sr->ServiceContext;
208
209 domainlabel name;
210 domainname type, dom;
211 char namestr[MAX_DOMAIN_LABEL+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
212 char typestr[MAX_ESCAPED_DOMAIN_NAME];
213 char domstr [MAX_ESCAPED_DOMAIN_NAME];
214 if (!DeconstructServiceName(&sr->RR_SRV.resrec.name, &name, &type, &dom)) return;
215 if (!ConvertDomainLabelToCString_unescaped(&name, namestr)) return;
216 if (!ConvertDomainNameToCString(&type, typestr)) return;
217 if (!ConvertDomainNameToCString(&dom, domstr)) return;
218
219 if (result == mStatus_NoError)
220 {
221 if (x->callback)
222 x->callback((DNSServiceRef)x, 0, result, namestr, typestr, domstr, x->context);
223 }
224 else if (result == mStatus_NameConflict)
225 {
226 if (x->autoname) mDNS_RenameAndReregisterService(m, sr, mDNSNULL);
227 else if (x->callback)
228 x->callback((DNSServiceRef)x, 0, result, namestr, typestr, domstr, x->context);
229 }
230 else if (result == mStatus_MemFree)
231 {
232 if (x->autorename)
233 {
234 x->autorename = mDNSfalse;
235 x->name = mDNSStorage.nicelabel;
236 mDNS_RenameAndReregisterService(m, &x->s, &x->name);
237 }
238 else
239 FreeDNSServiceRegistration(x);
240 }
241 }
242
243 DNSServiceErrorType DNSServiceRegister
244 (
245 DNSServiceRef *sdRef,
246 DNSServiceFlags flags,
247 uint32_t interfaceIndex,
248 const char *name, /* may be NULL */
249 const char *regtype,
250 const char *domain, /* may be NULL */
251 const char *host, /* may be NULL */
252 uint16_t notAnIntPort,
253 uint16_t txtLen,
254 const void *txtRecord, /* may be NULL */
255 DNSServiceRegisterReply callback, /* may be NULL */
256 void *context /* may be NULL */
257 )
258 {
259 mStatus err = mStatus_NoError;
260 const char *errormsg = "Unknown";
261 domainlabel n;
262 domainname t, d, h, srv;
263 mDNSIPPort port;
264 unsigned int size = sizeof(RDataBody);
265 AuthRecord *SubTypes = mDNSNULL;
266 mDNSu32 NumSubTypes = 0;
267 mDNS_DirectOP_Register *x;
268 (void)flags; // Unused
269 (void)interfaceIndex; // Unused
270
271 // Check parameters
272 if (!name[0]) n = mDNSStorage.nicelabel;
273 else if (!MakeDomainLabelFromLiteralString(&n, name)) { errormsg = "Bad Instance Name"; goto badparam; }
274 if (!regtype || !*regtype || !MakeDomainNameFromDNSNameString(&t, regtype)) { errormsg = "Bad Service Type"; goto badparam; }
275 if (!MakeDomainNameFromDNSNameString(&d, (domain && *domain) ? domain : "local.")) { errormsg = "Bad Domain"; goto badparam; }
276 if (!MakeDomainNameFromDNSNameString(&h, (host && *host ) ? host : "")) { errormsg = "Bad Target Host"; goto badparam; }
277 if (!ConstructServiceName(&srv, &n, &t, &d)) { errormsg = "Bad Name"; goto badparam; }
278 port.NotAnInteger = notAnIntPort;
279
280 // Allocate memory, and handle failure
281 if (size < txtLen)
282 size = txtLen;
283 x = (mDNS_DirectOP_Register *)mDNSPlatformMemAllocate(sizeof(*x) - sizeof(RDataBody) + size);
284 if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
285
286 // Set up object
287 x->disposefn = DNSServiceRegisterDispose;
288 x->callback = callback;
289 x->context = context;
290 x->autoname = (!name[0]);
291 x->autorename = mDNSfalse;
292 x->name = n;
293
294 // Do the operation
295 err = mDNS_RegisterService(&mDNSStorage, &x->s,
296 &x->name, &t, &d, // Name, type, domain
297 &h, port, // Host and port
298 txtRecord, txtLen, // TXT data, length
299 SubTypes, NumSubTypes, // Subtypes
300 mDNSInterface_Any, // Interface ID
301 RegCallback, x); // Callback and context
302 if (err) { mDNSPlatformMemFree(x); errormsg = "mDNS_RegisterService"; goto fail; }
303
304 // Succeeded: Wrap up and return
305 *sdRef = (DNSServiceRef)x;
306 return(mStatus_NoError);
307
308 badparam:
309 err = mStatus_BadParamErr;
310 fail:
311 LogMsg("DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", regtype, domain, errormsg, err);
312 return(err);
313 }
314
315 //*************************************************************************************************************
316 // Add / Update / Remove records from existing Registration
317
318 // Not yet implemented, so don't include in stub library
319 // We DO include it in the actual Extension, so that if a later client compiled to use this
320 // is run against this Extension, it will get a reasonable error code instead of just
321 // failing to launch (Strong Link) or calling an unresolved symbol and crashing (Weak Link)
322 #if !MDNS_BUILDINGSTUBLIBRARY
323 DNSServiceErrorType DNSServiceAddRecord
324 (
325 DNSServiceRef sdRef,
326 DNSRecordRef *RecordRef,
327 DNSServiceFlags flags,
328 uint16_t rrtype,
329 uint16_t rdlen,
330 const void *rdata,
331 uint32_t ttl
332 )
333 {
334 (void)sdRef; // Unused
335 (void)RecordRef; // Unused
336 (void)flags; // Unused
337 (void)rrtype; // Unused
338 (void)rdlen; // Unused
339 (void)rdata; // Unused
340 (void)ttl; // Unused
341 return(kDNSServiceErr_Unsupported);
342 }
343
344 DNSServiceErrorType DNSServiceUpdateRecord
345 (
346 DNSServiceRef sdRef,
347 DNSRecordRef RecordRef, /* may be NULL */
348 DNSServiceFlags flags,
349 uint16_t rdlen,
350 const void *rdata,
351 uint32_t ttl
352 )
353 {
354 (void)sdRef; // Unused
355 (void)RecordRef; // Unused
356 (void)flags; // Unused
357 (void)rdlen; // Unused
358 (void)rdata; // Unused
359 (void)ttl; // Unused
360 return(kDNSServiceErr_Unsupported);
361 }
362
363 DNSServiceErrorType DNSServiceRemoveRecord
364 (
365 DNSServiceRef sdRef,
366 DNSRecordRef RecordRef,
367 DNSServiceFlags flags
368 )
369 {
370 (void)sdRef; // Unused
371 (void)RecordRef; // Unused
372 (void)flags; // Unused
373 return(kDNSServiceErr_Unsupported);
374 }
375 #endif
376
377 //*************************************************************************************************************
378 // Browse for services
379
380 static void DNSServiceBrowseDispose(mDNS_DirectOP *op)
381 {
382 mDNS_DirectOP_Browse *x = (mDNS_DirectOP_Browse*)op;
383 //LogMsg("DNSServiceBrowseDispose");
384 mDNS_StopBrowse(&mDNSStorage, &x->q);
385 mDNSPlatformMemFree(x);
386 }
387
388 mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
389 {
390 DNSServiceFlags flags = AddRecord ? kDNSServiceFlagsAdd : (DNSServiceFlags)0;
391 domainlabel name;
392 domainname type, domain;
393 char cname[MAX_DOMAIN_LABEL+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
394 char ctype[MAX_ESCAPED_DOMAIN_NAME];
395 char cdom [MAX_ESCAPED_DOMAIN_NAME];
396 mDNS_DirectOP_Browse *x = (mDNS_DirectOP_Browse*)question->QuestionContext;
397 (void)m; // Unused
398
399 if (answer->rrtype != kDNSType_PTR)
400 { LogMsg("FoundInstance: Should not be called with rrtype %d (not a PTR record)", answer->rrtype); return; }
401
402 if (!DeconstructServiceName(&answer->rdata->u.name, &name, &type, &domain))
403 {
404 LogMsg("FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
405 answer->name.c, answer->rdata->u.name.c);
406 return;
407 }
408
409 ConvertDomainLabelToCString_unescaped(&name, cname);
410 ConvertDomainNameToCString(&type, ctype);
411 ConvertDomainNameToCString(&domain, cdom);
412 if (x->callback)
413 x->callback((DNSServiceRef)x, flags, 0, 0, cname, ctype, cdom, x->context);
414 }
415
416 DNSServiceErrorType DNSServiceBrowse
417 (
418 DNSServiceRef *sdRef,
419 DNSServiceFlags flags,
420 uint32_t interfaceIndex,
421 const char *regtype,
422 const char *domain, /* may be NULL */
423 DNSServiceBrowseReply callback,
424 void *context /* may be NULL */
425 )
426 {
427 mStatus err = mStatus_NoError;
428 const char *errormsg = "Unknown";
429 domainname t, d;
430 mDNS_DirectOP_Browse *x;
431 (void)flags; // Unused
432 (void)interfaceIndex; // Unused
433
434 // Check parameters
435 if (!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype)) { errormsg = "Illegal regtype"; goto badparam; }
436 if (!MakeDomainNameFromDNSNameString(&d, *domain ? domain : "local.")) { errormsg = "Illegal domain"; goto badparam; }
437
438 // Allocate memory, and handle failure
439 x = (mDNS_DirectOP_Browse *)mDNSPlatformMemAllocate(sizeof(*x));
440 if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
441
442 // Set up object
443 x->disposefn = DNSServiceBrowseDispose;
444 x->callback = callback;
445 x->context = context;
446 x->q.QuestionContext = x;
447
448 // Do the operation
449 err = mDNS_StartBrowse(&mDNSStorage, &x->q, &t, &d, mDNSInterface_Any, (flags & kDNSServiceFlagsForceMulticast) != 0, FoundInstance, x);
450 if (err) { mDNSPlatformMemFree(x); errormsg = "mDNS_StartBrowse"; goto fail; }
451
452 // Succeeded: Wrap up and return
453 *sdRef = (DNSServiceRef)x;
454 return(mStatus_NoError);
455
456 badparam:
457 err = mStatus_BadParamErr;
458 fail:
459 LogMsg("DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", regtype, domain, errormsg, err);
460 return(err);
461 }
462
463 //*************************************************************************************************************
464 // Resolve Service Info
465
466 static void DNSServiceResolveDispose(mDNS_DirectOP *op)
467 {
468 mDNS_DirectOP_Resolve *x = (mDNS_DirectOP_Resolve*)op;
469 if (x->qSRV.ThisQInterval >= 0) mDNS_StopQuery(&mDNSStorage, &x->qSRV);
470 if (x->qTXT.ThisQInterval >= 0) mDNS_StopQuery(&mDNSStorage, &x->qTXT);
471 mDNSPlatformMemFree(x);
472 }
473
474 mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
475 {
476 mDNS_DirectOP_Resolve *x = (mDNS_DirectOP_Resolve*)question->QuestionContext;
477 (void)m; // Unused
478 if (!AddRecord)
479 {
480 if (answer->rrtype == kDNSType_SRV && x->SRV == answer) x->SRV = mDNSNULL;
481 if (answer->rrtype == kDNSType_TXT && x->TXT == answer) x->TXT = mDNSNULL;
482 }
483 else
484 {
485 if (answer->rrtype == kDNSType_SRV) x->SRV = answer;
486 if (answer->rrtype == kDNSType_TXT) x->TXT = answer;
487 if (x->SRV && x->TXT && x->callback)
488 {
489 char fullname[MAX_ESCAPED_DOMAIN_NAME], targethost[MAX_ESCAPED_DOMAIN_NAME];
490 ConvertDomainNameToCString(&answer->name, fullname);
491 ConvertDomainNameToCString(&x->SRV->rdata->u.srv.target, targethost);
492 x->callback((DNSServiceRef)x, 0, 0, kDNSServiceErr_NoError, fullname, targethost,
493 x->SRV->rdata->u.srv.port.NotAnInteger, x->TXT->rdlength, (char*)x->TXT->rdata->u.txt.c, x->context);
494 }
495 }
496 }
497
498 DNSServiceErrorType DNSServiceResolve
499 (
500 DNSServiceRef *sdRef,
501 DNSServiceFlags flags,
502 uint32_t interfaceIndex,
503 const char *name,
504 const char *regtype,
505 const char *domain,
506 DNSServiceResolveReply callback,
507 void *context /* may be NULL */
508 )
509 {
510 mStatus err = mStatus_NoError;
511 const char *errormsg = "Unknown";
512 domainlabel n;
513 domainname t, d, srv;
514 mDNS_DirectOP_Resolve *x;
515
516 (void)flags; // Unused
517 (void)interfaceIndex; // Unused
518
519 // Check parameters
520 if (!name[0] || !MakeDomainLabelFromLiteralString(&n, name )) { errormsg = "Bad Instance Name"; goto badparam; }
521 if (!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype)) { errormsg = "Bad Service Type"; goto badparam; }
522 if (!domain[0] || !MakeDomainNameFromDNSNameString(&d, domain )) { errormsg = "Bad Domain"; goto badparam; }
523 if (!ConstructServiceName(&srv, &n, &t, &d)) { errormsg = "Bad Name"; goto badparam; }
524
525 // Allocate memory, and handle failure
526 x = (mDNS_DirectOP_Resolve *)mDNSPlatformMemAllocate(sizeof(*x));
527 if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
528
529 // Set up object
530 x->disposefn = DNSServiceResolveDispose;
531 x->callback = callback;
532 x->context = context;
533 x->SRV = mDNSNULL;
534 x->TXT = mDNSNULL;
535
536 x->qSRV.ThisQInterval = -1; // So that DNSServiceResolveDispose() knows whether to cancel this question
537 x->qSRV.InterfaceID = mDNSInterface_Any;
538 x->qSRV.Target = zeroAddr;
539 AssignDomainName(x->qSRV.qname, srv);
540 x->qSRV.qtype = kDNSType_SRV;
541 x->qSRV.qclass = kDNSClass_IN;
542 x->qSRV.LongLived = mDNSfalse;
543 x->qSRV.ExpectUnique = mDNStrue;
544 x->qSRV.ForceMCast = mDNSfalse;
545 x->qSRV.QuestionCallback = FoundServiceInfo;
546 x->qSRV.QuestionContext = x;
547
548 x->qTXT.ThisQInterval = -1; // So that DNSServiceResolveDispose() knows whether to cancel this question
549 x->qTXT.InterfaceID = mDNSInterface_Any;
550 x->qTXT.Target = zeroAddr;
551 AssignDomainName(x->qTXT.qname, srv);
552 x->qTXT.qtype = kDNSType_TXT;
553 x->qTXT.qclass = kDNSClass_IN;
554 x->qTXT.LongLived = mDNSfalse;
555 x->qTXT.ExpectUnique = mDNStrue;
556 x->qTXT.ForceMCast = mDNSfalse;
557 x->qTXT.QuestionCallback = FoundServiceInfo;
558 x->qTXT.QuestionContext = x;
559
560 err = mDNS_StartQuery(&mDNSStorage, &x->qSRV);
561 if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery qSRV"; goto fail; }
562 err = mDNS_StartQuery(&mDNSStorage, &x->qTXT);
563 if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery qTXT"; goto fail; }
564
565 // Succeeded: Wrap up and return
566 *sdRef = (DNSServiceRef)x;
567 return(mStatus_NoError);
568
569 badparam:
570 err = mStatus_BadParamErr;
571 fail:
572 LogMsg("DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%ld)", name, regtype, domain, errormsg, err);
573 return(err);
574 }
575
576 //*************************************************************************************************************
577 // Connection-oriented calls
578
579 // Not yet implemented, so don't include in stub library
580 // We DO include it in the actual Extension, so that if a later client compiled to use this
581 // is run against this Extension, it will get a reasonable error code instead of just
582 // failing to launch (Strong Link) or calling an unresolved symbol and crashing (Weak Link)
583 #if !MDNS_BUILDINGSTUBLIBRARY
584 DNSServiceErrorType DNSServiceCreateConnection(DNSServiceRef *sdRef)
585 {
586 (void)sdRef; // Unused
587 return(kDNSServiceErr_Unsupported);
588 }
589
590 DNSServiceErrorType DNSServiceRegisterRecord
591 (
592 DNSServiceRef sdRef,
593 DNSRecordRef *RecordRef,
594 DNSServiceFlags flags,
595 uint32_t interfaceIndex,
596 const char *fullname,
597 uint16_t rrtype,
598 uint16_t rrclass,
599 uint16_t rdlen,
600 const void *rdata,
601 uint32_t ttl,
602 DNSServiceRegisterRecordReply callback,
603 void *context /* may be NULL */
604 )
605 {
606 (void)sdRef; // Unused
607 (void)RecordRef; // Unused
608 (void)flags; // Unused
609 (void)interfaceIndex; // Unused
610 (void)fullname; // Unused
611 (void)rrtype; // Unused
612 (void)rrclass; // Unused
613 (void)rdlen; // Unused
614 (void)rdata; // Unused
615 (void)ttl; // Unused
616 (void)callback; // Unused
617 (void)context; // Unused
618 return(kDNSServiceErr_Unsupported);
619 }
620 #endif
621
622 //*************************************************************************************************************
623 // DNSServiceQueryRecord
624
625 static void DNSServiceQueryRecordDispose(mDNS_DirectOP *op)
626 {
627 mDNS_DirectOP_QueryRecord *x = (mDNS_DirectOP_QueryRecord*)op;
628 if (x->q.ThisQInterval >= 0) mDNS_StopQuery(&mDNSStorage, &x->q);
629 mDNSPlatformMemFree(x);
630 }
631
632 mDNSlocal void DNSServiceQueryRecordResponse(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
633 {
634 mDNS_DirectOP_QueryRecord *x = (mDNS_DirectOP_QueryRecord*)question->QuestionContext;
635 char fullname[MAX_ESCAPED_DOMAIN_NAME];
636 (void)m; // Unused
637 ConvertDomainNameToCString(&answer->name, fullname);
638 x->callback((DNSServiceRef)x, AddRecord ? kDNSServiceFlagsAdd : (DNSServiceFlags)0, 0, kDNSServiceErr_NoError,
639 fullname, answer->rrtype, answer->rrclass, answer->rdlength, answer->rdata->u.data, answer->rroriginalttl, x->context);
640 }
641
642 DNSServiceErrorType DNSServiceQueryRecord
643 (
644 DNSServiceRef *sdRef,
645 DNSServiceFlags flags,
646 uint32_t interfaceIndex,
647 const char *fullname,
648 uint16_t rrtype,
649 uint16_t rrclass,
650 DNSServiceQueryRecordReply callback,
651 void *context /* may be NULL */
652 )
653 {
654 mStatus err = mStatus_NoError;
655 const char *errormsg = "Unknown";
656 mDNS_DirectOP_QueryRecord *x;
657
658 (void)flags; // Unused
659 (void)interfaceIndex; // Unused
660
661 // Allocate memory, and handle failure
662 x = (mDNS_DirectOP_QueryRecord *)mDNSPlatformMemAllocate(sizeof(*x));
663 if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
664
665 // Set up object
666 x->disposefn = DNSServiceQueryRecordDispose;
667 x->callback = callback;
668 x->context = context;
669
670 x->q.ThisQInterval = -1; // So that DNSServiceResolveDispose() knows whether to cancel this question
671 x->q.InterfaceID = mDNSInterface_Any;
672 x->q.Target = zeroAddr;
673 MakeDomainNameFromDNSNameString(&x->q.qname, fullname);
674 x->q.qtype = rrtype;
675 x->q.qclass = rrclass;
676 x->q.LongLived = (flags & kDNSServiceFlagsLongLivedQuery) != 0;
677 x->q.ExpectUnique = mDNSfalse;
678 x->q.ForceMCast = (flags & kDNSServiceFlagsForceMulticast) != 0;
679 x->q.QuestionCallback = DNSServiceQueryRecordResponse;
680 x->q.QuestionContext = x;
681
682 err = mDNS_StartQuery(&mDNSStorage, &x->q);
683 if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery"; goto fail; }
684
685 // Succeeded: Wrap up and return
686 *sdRef = (DNSServiceRef)x;
687 return(mStatus_NoError);
688
689 badparam:
690 err = mStatus_BadParamErr;
691 fail:
692 LogMsg("DNSServiceQueryRecord(\"%s\", %d, %d) failed: %s (%ld)", fullname, rrtype, rrclass, errormsg, err);
693 return(err);
694 }
695
696 //*************************************************************************************************************
697 // DNSServiceReconfirmRecord
698
699 // Not yet implemented, so don't include in stub library
700 // We DO include it in the actual Extension, so that if a later client compiled to use this
701 // is run against this Extension, it will get a reasonable error code instead of just
702 // failing to launch (Strong Link) or calling an unresolved symbol and crashing (Weak Link)
703 #if !MDNS_BUILDINGSTUBLIBRARY
704 void DNSServiceReconfirmRecord
705 (
706 DNSServiceFlags flags,
707 uint32_t interfaceIndex,
708 const char *fullname,
709 uint16_t rrtype,
710 uint16_t rrclass,
711 uint16_t rdlen,
712 const void *rdata
713 )
714 {
715 (void)flags; // Unused
716 (void)interfaceIndex; // Unused
717 (void)fullname; // Unused
718 (void)rrtype; // Unused
719 (void)rrclass; // Unused
720 (void)rdlen; // Unused
721 (void)rdata; // Unused
722 }
723 #endif