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