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