]> git.saurik.com Git - apple/mdnsresponder.git/blame - mDNSShared/dnssd_clientshim.c
mDNSResponder-1310.80.1.tar.gz
[apple/mdnsresponder.git] / mDNSShared / dnssd_clientshim.c
CommitLineData
f0cc3e7b
A
1/*
2 * Copyright (c) 2003-2019 Apple Inc. All rights reserved.
83fb1e36 3 *
67c8f8a1
A
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
83fb1e36 7 *
67c8f8a1 8 * http://www.apache.org/licenses/LICENSE-2.0
83fb1e36 9 *
67c8f8a1
A
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
8e92c31c 14 * limitations under the License.
8e92c31c
A
15
16 * This file defines a simple shim layer between a client calling the "/usr/include/dns_sd.h" APIs
7f0064bd
A
17 * and an implementation of mDNSCore ("mDNSEmbeddedAPI.h" APIs) in the same address space.
18 * When the client calls a dns_sd.h function, the shim calls the corresponding mDNSEmbeddedAPI.h
8e92c31c
A
19 * function, and when mDNSCore calls the shim's callback, we call through to the client's callback.
20 * The shim is responsible for two main things:
21 * - converting string parameters between C string format and native DNS format,
22 * - and for allocating and freeing memory.
8e92c31c
A
23 */
24
83fb1e36
A
25#include "dns_sd.h" // Defines the interface to the client layer above
26#include "mDNSEmbeddedAPI.h" // The interface we're building on top of
f0cc3e7b
A
27#include <sys/socket.h>
28#include <netinet/in.h>
83fb1e36 29extern mDNS mDNSStorage; // We need to pass the address of this storage to the lower-layer functions
8e92c31c
A
30
31#if MDNS_BUILDINGSHAREDLIBRARY || MDNS_BUILDINGSTUBLIBRARY
32#pragma export on
33#endif
34
35//*************************************************************************************************************
36// General Utility Functions
37
38// All mDNS_DirectOP structures start with the pointer to the type-specific disposal function.
39// Optional type-specific data follows these three fields
40// When the client starts an operation, we return the address of the corresponding mDNS_DirectOP
41// as the DNSServiceRef for the operation
42// We stash the value in core context fields so we can get it back to recover our state in our callbacks,
43// and pass it though to the client for it to recover its state
44
45typedef struct mDNS_DirectOP_struct mDNS_DirectOP;
83fb1e36 46typedef void mDNS_DirectOP_Dispose (mDNS_DirectOP *op);
8e92c31c 47struct mDNS_DirectOP_struct
83fb1e36
A
48{
49 mDNS_DirectOP_Dispose *disposefn;
50};
8e92c31c
A
51
52typedef struct
83fb1e36
A
53{
54 mDNS_DirectOP_Dispose *disposefn;
55 DNSServiceRegisterReply callback;
56 void *context;
57 mDNSBool autoname; // Set if this name is tied to the Computer Name
58 mDNSBool autorename; // Set if we just got a name conflict and now need to automatically pick a new name
59 domainlabel name;
60 domainname host;
61 ServiceRecordSet s;
62} mDNS_DirectOP_Register;
8e92c31c
A
63
64typedef struct
83fb1e36
A
65{
66 mDNS_DirectOP_Dispose *disposefn;
67 DNSServiceBrowseReply callback;
68 void *context;
69 DNSQuestion q;
70} mDNS_DirectOP_Browse;
8e92c31c
A
71
72typedef struct
83fb1e36
A
73{
74 mDNS_DirectOP_Dispose *disposefn;
75 DNSServiceResolveReply callback;
76 void *context;
77 const ResourceRecord *SRV;
78 const ResourceRecord *TXT;
79 DNSQuestion qSRV;
80 DNSQuestion qTXT;
81} mDNS_DirectOP_Resolve;
8e92c31c
A
82
83typedef struct
83fb1e36
A
84{
85 mDNS_DirectOP_Dispose *disposefn;
86 DNSServiceQueryRecordReply callback;
87 void *context;
88 DNSQuestion q;
89} mDNS_DirectOP_QueryRecord;
8e92c31c 90
f0cc3e7b
A
91typedef struct
92{
93 mDNS_DirectOP_Dispose *disposefn;
94 DNSServiceGetAddrInfoReply callback;
95 void *context;
96 mDNSu32 interfaceIndex;
97 DNSQuestion a;
98 DNSQuestion aaaa;
99} mDNS_DirectOP_GetAddrInfo;
100
9f221bca 101dnssd_sock_t DNSServiceRefSockFD(DNSServiceRef sdRef)
83fb1e36
A
102{
103 (void)sdRef; // Unused
104 return(0);
105}
8e92c31c
A
106
107DNSServiceErrorType DNSServiceProcessResult(DNSServiceRef sdRef)
83fb1e36
A
108{
109 (void)sdRef; // Unused
110 return(kDNSServiceErr_NoError);
111}
8e92c31c
A
112
113void DNSServiceRefDeallocate(DNSServiceRef sdRef)
83fb1e36
A
114{
115 mDNS_DirectOP *op = (mDNS_DirectOP *)sdRef;
116 //LogMsg("DNSServiceRefDeallocate");
117 op->disposefn(op);
118}
8e92c31c 119
f0cc3e7b
A
120static mDNSInterfaceID DNSServiceInterfaceIndexToID(mDNSu32 interfaceIndex, DNSServiceFlags *flags)
121{
122 // Map kDNSServiceInterfaceIndexP2P to kDNSServiceInterfaceIndexAny with the kDNSServiceFlagsIncludeP2P
123 // flag set so that the resolve will run over P2P interfaces that are not yet created.
124 if (interfaceIndex == kDNSServiceInterfaceIndexP2P)
125 {
126 LogOperation("handle_resolve_request: mapping kDNSServiceInterfaceIndexP2P to kDNSServiceInterfaceIndexAny + kDNSServiceFlagsIncludeP2P");
127 if (flags != mDNSNULL) *flags |= kDNSServiceFlagsIncludeP2P;
128 interfaceIndex = kDNSServiceInterfaceIndexAny;
129 }
130 return mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
131}
132
8e92c31c
A
133//*************************************************************************************************************
134// Domain Enumeration
135
136// Not yet implemented, so don't include in stub library
137// We DO include it in the actual Extension, so that if a later client compiled to use this
138// is run against this Extension, it will get a reasonable error code instead of just
139// failing to launch (Strong Link) or calling an unresolved symbol and crashing (Weak Link)
140#if !MDNS_BUILDINGSTUBLIBRARY
141DNSServiceErrorType DNSServiceEnumerateDomains
83fb1e36
A
142(
143 DNSServiceRef *sdRef,
144 DNSServiceFlags flags,
145 uint32_t interfaceIndex,
146 DNSServiceDomainEnumReply callback,
147 void *context /* may be NULL */
148)
149{
150 (void)sdRef; // Unused
151 (void)flags; // Unused
152 (void)interfaceIndex; // Unused
153 (void)callback; // Unused
154 (void)context; // Unused
155 return(kDNSServiceErr_Unsupported);
156}
8e92c31c
A
157#endif
158
159//*************************************************************************************************************
160// Register Service
161
162mDNSlocal void FreeDNSServiceRegistration(mDNS_DirectOP_Register *x)
83fb1e36
A
163{
164 while (x->s.Extras)
165 {
166 ExtraResourceRecord *extras = x->s.Extras;
167 x->s.Extras = x->s.Extras->next;
168 if (extras->r.resrec.rdata != &extras->r.rdatastorage)
169 mDNSPlatformMemFree(extras->r.resrec.rdata);
170 mDNSPlatformMemFree(extras);
171 }
172
173 if (x->s.RR_TXT.resrec.rdata != &x->s.RR_TXT.rdatastorage)
174 mDNSPlatformMemFree(x->s.RR_TXT.resrec.rdata);
175
176 if (x->s.SubTypes) mDNSPlatformMemFree(x->s.SubTypes);
177
178 mDNSPlatformMemFree(x);
179}
8e92c31c
A
180
181static void DNSServiceRegisterDispose(mDNS_DirectOP *op)
83fb1e36
A
182{
183 mDNS_DirectOP_Register *x = (mDNS_DirectOP_Register*)op;
184 x->autorename = mDNSfalse;
185 // If mDNS_DeregisterService() returns mStatus_NoError, that means that the service was found in the list,
186 // is sending its goodbye packet, and we'll get an mStatus_MemFree message when we can free the memory.
187 // If mDNS_DeregisterService() returns an error, it means that the service had already been removed from
188 // the list, so we should go ahead and free the memory right now
189 if (mDNS_DeregisterService(&mDNSStorage, &x->s) != mStatus_NoError)
190 FreeDNSServiceRegistration(x);
191}
8e92c31c
A
192
193mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus result)
83fb1e36
A
194{
195 mDNS_DirectOP_Register *x = (mDNS_DirectOP_Register*)sr->ServiceContext;
8e92c31c
A
196
197 domainlabel name;
198 domainname type, dom;
83fb1e36
A
199 char namestr[MAX_DOMAIN_LABEL+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
200 char typestr[MAX_ESCAPED_DOMAIN_NAME];
201 char domstr [MAX_ESCAPED_DOMAIN_NAME];
283ee3ff 202 if (!DeconstructServiceName(sr->RR_SRV.resrec.name, &name, &type, &dom)) return;
8e92c31c
A
203 if (!ConvertDomainLabelToCString_unescaped(&name, namestr)) return;
204 if (!ConvertDomainNameToCString(&type, typestr)) return;
205 if (!ConvertDomainNameToCString(&dom, domstr)) return;
206
83fb1e36
A
207 if (result == mStatus_NoError)
208 {
209 if (x->callback)
210 x->callback((DNSServiceRef)x, 0, result, namestr, typestr, domstr, x->context);
211 }
212 else if (result == mStatus_NameConflict)
213 {
214 if (x->autoname) mDNS_RenameAndReregisterService(m, sr, mDNSNULL);
215 else if (x->callback)
216 x->callback((DNSServiceRef)x, 0, result, namestr, typestr, domstr, x->context);
217 }
218 else if (result == mStatus_MemFree)
219 {
220 if (x->autorename)
221 {
222 x->autorename = mDNSfalse;
223 x->name = mDNSStorage.nicelabel;
224 mDNS_RenameAndReregisterService(m, &x->s, &x->name);
225 }
226 else
227 FreeDNSServiceRegistration(x);
228 }
229}
8e92c31c
A
230
231DNSServiceErrorType DNSServiceRegister
83fb1e36
A
232(
233 DNSServiceRef *sdRef,
234 DNSServiceFlags flags,
235 uint32_t interfaceIndex,
236 const char *name, /* may be NULL */
237 const char *regtype,
238 const char *domain, /* may be NULL */
239 const char *host, /* may be NULL */
240 uint16_t notAnIntPort,
241 uint16_t txtLen,
242 const void *txtRecord, /* may be NULL */
243 DNSServiceRegisterReply callback, /* may be NULL */
244 void *context /* may be NULL */
245)
246{
247 mStatus err = mStatus_NoError;
248 const char *errormsg = "Unknown";
249 domainlabel n;
250 domainname t, d, h, srv;
251 mDNSIPPort port;
252 unsigned int size = sizeof(RDataBody);
253 AuthRecord *SubTypes = mDNSNULL;
254 mDNSu32 NumSubTypes = 0;
255 mDNS_DirectOP_Register *x;
256 (void)flags; // Unused
257 (void)interfaceIndex; // Unused
258
259 // Check parameters
260 if (!name) name = "";
261 if (!name[0]) n = mDNSStorage.nicelabel;
262 else if (!MakeDomainLabelFromLiteralString(&n, name)) { errormsg = "Bad Instance Name"; goto badparam; }
263 if (!regtype || !*regtype || !MakeDomainNameFromDNSNameString(&t, regtype)) { errormsg = "Bad Service Type"; goto badparam; }
264 if (!MakeDomainNameFromDNSNameString(&d, (domain && *domain) ? domain : "local.")) { errormsg = "Bad Domain"; goto badparam; }
265 if (!MakeDomainNameFromDNSNameString(&h, (host && *host ) ? host : "")) { errormsg = "Bad Target Host"; goto badparam; }
266 if (!ConstructServiceName(&srv, &n, &t, &d)) { errormsg = "Bad Name"; goto badparam; }
267 port.NotAnInteger = notAnIntPort;
268
269 // Allocate memory, and handle failure
270 if (size < txtLen)
271 size = txtLen;
f0cc3e7b 272 x = (mDNS_DirectOP_Register *) mDNSPlatformMemAllocateClear(sizeof(*x) - sizeof(RDataBody) + size);
83fb1e36
A
273 if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
274
275 // Set up object
276 x->disposefn = DNSServiceRegisterDispose;
277 x->callback = callback;
278 x->context = context;
279 x->autoname = (!name[0]);
280 x->autorename = mDNSfalse;
281 x->name = n;
282 x->host = h;
283
284 // Do the operation
285 err = mDNS_RegisterService(&mDNSStorage, &x->s,
286 &x->name, &t, &d, // Name, type, domain
287 &x->host, port, // Host and port
f0cc3e7b 288 mDNSNULL,
83fb1e36
A
289 txtRecord, txtLen, // TXT data, length
290 SubTypes, NumSubTypes, // Subtypes
291 mDNSInterface_Any, // Interface ID
292 RegCallback, x, 0); // Callback, context, flags
293 if (err) { mDNSPlatformMemFree(x); errormsg = "mDNS_RegisterService"; goto fail; }
294
295 // Succeeded: Wrap up and return
296 *sdRef = (DNSServiceRef)x;
297 return(mStatus_NoError);
8e92c31c
A
298
299badparam:
83fb1e36 300 err = mStatus_BadParamErr;
8e92c31c 301fail:
83fb1e36
A
302 LogMsg("DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", regtype, domain, errormsg, err);
303 return(err);
304}
8e92c31c
A
305
306//*************************************************************************************************************
307// Add / Update / Remove records from existing Registration
308
309// Not yet implemented, so don't include in stub library
310// We DO include it in the actual Extension, so that if a later client compiled to use this
311// is run against this Extension, it will get a reasonable error code instead of just
312// failing to launch (Strong Link) or calling an unresolved symbol and crashing (Weak Link)
313#if !MDNS_BUILDINGSTUBLIBRARY
314DNSServiceErrorType DNSServiceAddRecord
83fb1e36
A
315(
316 DNSServiceRef sdRef,
317 DNSRecordRef *RecordRef,
318 DNSServiceFlags flags,
319 uint16_t rrtype,
320 uint16_t rdlen,
321 const void *rdata,
322 uint32_t ttl
323)
324{
325 (void)sdRef; // Unused
326 (void)RecordRef; // Unused
327 (void)flags; // Unused
328 (void)rrtype; // Unused
329 (void)rdlen; // Unused
330 (void)rdata; // Unused
331 (void)ttl; // Unused
332 return(kDNSServiceErr_Unsupported);
333}
8e92c31c
A
334
335DNSServiceErrorType DNSServiceUpdateRecord
83fb1e36
A
336(
337 DNSServiceRef sdRef,
338 DNSRecordRef RecordRef, /* may be NULL */
339 DNSServiceFlags flags,
340 uint16_t rdlen,
341 const void *rdata,
342 uint32_t ttl
343)
344{
345 (void)sdRef; // Unused
346 (void)RecordRef; // Unused
347 (void)flags; // Unused
348 (void)rdlen; // Unused
349 (void)rdata; // Unused
350 (void)ttl; // Unused
351 return(kDNSServiceErr_Unsupported);
352}
8e92c31c
A
353
354DNSServiceErrorType DNSServiceRemoveRecord
83fb1e36
A
355(
356 DNSServiceRef sdRef,
357 DNSRecordRef RecordRef,
358 DNSServiceFlags flags
359)
360{
361 (void)sdRef; // Unused
362 (void)RecordRef; // Unused
363 (void)flags; // Unused
364 return(kDNSServiceErr_Unsupported);
365}
8e92c31c
A
366#endif
367
368//*************************************************************************************************************
369// Browse for services
370
371static void DNSServiceBrowseDispose(mDNS_DirectOP *op)
83fb1e36
A
372{
373 mDNS_DirectOP_Browse *x = (mDNS_DirectOP_Browse*)op;
374 //LogMsg("DNSServiceBrowseDispose");
375 mDNS_StopBrowse(&mDNSStorage, &x->q);
376 mDNSPlatformMemFree(x);
377}
8e92c31c 378
67c8f8a1 379mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
83fb1e36
A
380{
381 DNSServiceFlags flags = AddRecord ? kDNSServiceFlagsAdd : (DNSServiceFlags)0;
382 domainlabel name;
383 domainname type, domain;
384 char cname[MAX_DOMAIN_LABEL+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
385 char ctype[MAX_ESCAPED_DOMAIN_NAME];
386 char cdom [MAX_ESCAPED_DOMAIN_NAME];
387 mDNS_DirectOP_Browse *x = (mDNS_DirectOP_Browse*)question->QuestionContext;
388 (void)m; // Unused
389
390 if (answer->rrtype != kDNSType_PTR)
391 { LogMsg("FoundInstance: Should not be called with rrtype %d (not a PTR record)", answer->rrtype); return; }
392
393 if (!DeconstructServiceName(&answer->rdata->u.name, &name, &type, &domain))
394 {
395 LogMsg("FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
396 answer->name->c, answer->rdata->u.name.c);
397 return;
398 }
399
400 ConvertDomainLabelToCString_unescaped(&name, cname);
401 ConvertDomainNameToCString(&type, ctype);
402 ConvertDomainNameToCString(&domain, cdom);
403 if (x->callback)
404 x->callback((DNSServiceRef)x, flags, 0, 0, cname, ctype, cdom, x->context);
405}
8e92c31c
A
406
407DNSServiceErrorType DNSServiceBrowse
83fb1e36
A
408(
409 DNSServiceRef *sdRef,
410 DNSServiceFlags flags,
411 uint32_t interfaceIndex,
412 const char *regtype,
413 const char *domain, /* may be NULL */
414 DNSServiceBrowseReply callback,
415 void *context /* may be NULL */
416)
417{
418 mStatus err = mStatus_NoError;
419 const char *errormsg = "Unknown";
420 domainname t, d;
421 mDNS_DirectOP_Browse *x;
422 (void)flags; // Unused
423 (void)interfaceIndex; // Unused
424
425 // Check parameters
426 if (!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype)) { errormsg = "Illegal regtype"; goto badparam; }
427 if (!MakeDomainNameFromDNSNameString(&d, *domain ? domain : "local.")) { errormsg = "Illegal domain"; goto badparam; }
428
429 // Allocate memory, and handle failure
f0cc3e7b 430 x = (mDNS_DirectOP_Browse *) mDNSPlatformMemAllocateClear(sizeof(*x));
83fb1e36
A
431 if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
432
433 // Set up object
434 x->disposefn = DNSServiceBrowseDispose;
435 x->callback = callback;
436 x->context = context;
437 x->q.QuestionContext = x;
438
439 // Do the operation
f0cc3e7b 440 err = mDNS_StartBrowse(&mDNSStorage, &x->q, &t, &d, mDNSInterface_Any, flags, (flags & kDNSServiceFlagsForceMulticast) != 0, (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0, FoundInstance, x);
83fb1e36
A
441 if (err) { mDNSPlatformMemFree(x); errormsg = "mDNS_StartBrowse"; goto fail; }
442
443 // Succeeded: Wrap up and return
444 *sdRef = (DNSServiceRef)x;
445 return(mStatus_NoError);
8e92c31c
A
446
447badparam:
83fb1e36 448 err = mStatus_BadParamErr;
8e92c31c 449fail:
83fb1e36
A
450 LogMsg("DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", regtype, domain, errormsg, err);
451 return(err);
452}
8e92c31c
A
453
454//*************************************************************************************************************
455// Resolve Service Info
456
457static void DNSServiceResolveDispose(mDNS_DirectOP *op)
83fb1e36
A
458{
459 mDNS_DirectOP_Resolve *x = (mDNS_DirectOP_Resolve*)op;
460 if (x->qSRV.ThisQInterval >= 0) mDNS_StopQuery(&mDNSStorage, &x->qSRV);
461 if (x->qTXT.ThisQInterval >= 0) mDNS_StopQuery(&mDNSStorage, &x->qTXT);
462 mDNSPlatformMemFree(x);
463}
8e92c31c 464
67c8f8a1 465mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
83fb1e36
A
466{
467 mDNS_DirectOP_Resolve *x = (mDNS_DirectOP_Resolve*)question->QuestionContext;
468 (void)m; // Unused
469 if (!AddRecord)
470 {
471 if (answer->rrtype == kDNSType_SRV && x->SRV == answer) x->SRV = mDNSNULL;
472 if (answer->rrtype == kDNSType_TXT && x->TXT == answer) x->TXT = mDNSNULL;
473 }
474 else
475 {
476 if (answer->rrtype == kDNSType_SRV) x->SRV = answer;
477 if (answer->rrtype == kDNSType_TXT) x->TXT = answer;
478 if (x->SRV && x->TXT && x->callback)
479 {
480 char fullname[MAX_ESCAPED_DOMAIN_NAME], targethost[MAX_ESCAPED_DOMAIN_NAME];
481 ConvertDomainNameToCString(answer->name, fullname);
482 ConvertDomainNameToCString(&x->SRV->rdata->u.srv.target, targethost);
483 x->callback((DNSServiceRef)x, 0, 0, kDNSServiceErr_NoError, fullname, targethost,
484 x->SRV->rdata->u.srv.port.NotAnInteger, x->TXT->rdlength, (unsigned char*)x->TXT->rdata->u.txt.c, x->context);
485 }
486 }
487}
8e92c31c
A
488
489DNSServiceErrorType DNSServiceResolve
83fb1e36
A
490(
491 DNSServiceRef *sdRef,
492 DNSServiceFlags flags,
493 uint32_t interfaceIndex,
494 const char *name,
495 const char *regtype,
496 const char *domain,
497 DNSServiceResolveReply callback,
498 void *context /* may be NULL */
499)
500{
501 mStatus err = mStatus_NoError;
502 const char *errormsg = "Unknown";
503 domainlabel n;
504 domainname t, d, srv;
505 mDNS_DirectOP_Resolve *x;
506
83fb1e36
A
507 // Check parameters
508 if (!name[0] || !MakeDomainLabelFromLiteralString(&n, name )) { errormsg = "Bad Instance Name"; goto badparam; }
509 if (!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype)) { errormsg = "Bad Service Type"; goto badparam; }
510 if (!domain[0] || !MakeDomainNameFromDNSNameString(&d, domain )) { errormsg = "Bad Domain"; goto badparam; }
511 if (!ConstructServiceName(&srv, &n, &t, &d)) { errormsg = "Bad Name"; goto badparam; }
512
513 // Allocate memory, and handle failure
f0cc3e7b 514 x = (mDNS_DirectOP_Resolve *) mDNSPlatformMemAllocateClear(sizeof(*x));
83fb1e36
A
515 if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
516
517 // Set up object
518 x->disposefn = DNSServiceResolveDispose;
519 x->callback = callback;
520 x->context = context;
521 x->SRV = mDNSNULL;
522 x->TXT = mDNSNULL;
523
524 x->qSRV.ThisQInterval = -1; // So that DNSServiceResolveDispose() knows whether to cancel this question
f0cc3e7b
A
525 x->qSRV.InterfaceID = DNSServiceInterfaceIndexToID(interfaceIndex, &flags);
526 x->qSRV.flags = flags;
83fb1e36
A
527 AssignDomainName(&x->qSRV.qname, &srv);
528 x->qSRV.qtype = kDNSType_SRV;
529 x->qSRV.qclass = kDNSClass_IN;
530 x->qSRV.LongLived = mDNSfalse;
531 x->qSRV.ExpectUnique = mDNStrue;
532 x->qSRV.ForceMCast = mDNSfalse;
533 x->qSRV.ReturnIntermed = mDNSfalse;
534 x->qSRV.SuppressUnusable = mDNSfalse;
83fb1e36 535 x->qSRV.AppendSearchDomains = 0;
83fb1e36
A
536 x->qSRV.TimeoutQuestion = 0;
537 x->qSRV.WakeOnResolve = 0;
f0cc3e7b 538 x->qSRV.UseBackgroundTraffic = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
51601d48 539 x->qSRV.ProxyQuestion = 0;
51601d48 540 x->qSRV.pid = mDNSPlatformGetPID();
83fb1e36
A
541 x->qSRV.QuestionCallback = FoundServiceInfo;
542 x->qSRV.QuestionContext = x;
543
544 x->qTXT.ThisQInterval = -1; // So that DNSServiceResolveDispose() knows whether to cancel this question
f0cc3e7b
A
545 x->qTXT.InterfaceID = DNSServiceInterfaceIndexToID(interfaceIndex, mDNSNULL);
546 x->qTXT.flags = flags;
83fb1e36
A
547 AssignDomainName(&x->qTXT.qname, &srv);
548 x->qTXT.qtype = kDNSType_TXT;
549 x->qTXT.qclass = kDNSClass_IN;
550 x->qTXT.LongLived = mDNSfalse;
551 x->qTXT.ExpectUnique = mDNStrue;
552 x->qTXT.ForceMCast = mDNSfalse;
553 x->qTXT.ReturnIntermed = mDNSfalse;
554 x->qTXT.SuppressUnusable = mDNSfalse;
83fb1e36 555 x->qTXT.AppendSearchDomains = 0;
83fb1e36
A
556 x->qTXT.TimeoutQuestion = 0;
557 x->qTXT.WakeOnResolve = 0;
f0cc3e7b 558 x->qTXT.UseBackgroundTraffic = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
51601d48 559 x->qTXT.ProxyQuestion = 0;
51601d48 560 x->qTXT.pid = mDNSPlatformGetPID();
83fb1e36
A
561 x->qTXT.QuestionCallback = FoundServiceInfo;
562 x->qTXT.QuestionContext = x;
563
564 err = mDNS_StartQuery(&mDNSStorage, &x->qSRV);
565 if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery qSRV"; goto fail; }
566 err = mDNS_StartQuery(&mDNSStorage, &x->qTXT);
567 if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery qTXT"; goto fail; }
568
569 // Succeeded: Wrap up and return
570 *sdRef = (DNSServiceRef)x;
571 return(mStatus_NoError);
8e92c31c
A
572
573badparam:
83fb1e36 574 err = mStatus_BadParamErr;
8e92c31c 575fail:
83fb1e36
A
576 LogMsg("DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%ld)", name, regtype, domain, errormsg, err);
577 return(err);
578}
8e92c31c
A
579
580//*************************************************************************************************************
581// Connection-oriented calls
582
583// Not yet implemented, so don't include in stub library
584// We DO include it in the actual Extension, so that if a later client compiled to use this
585// is run against this Extension, it will get a reasonable error code instead of just
586// failing to launch (Strong Link) or calling an unresolved symbol and crashing (Weak Link)
587#if !MDNS_BUILDINGSTUBLIBRARY
588DNSServiceErrorType DNSServiceCreateConnection(DNSServiceRef *sdRef)
83fb1e36
A
589{
590 (void)sdRef; // Unused
591 return(kDNSServiceErr_Unsupported);
592}
8e92c31c
A
593
594DNSServiceErrorType DNSServiceRegisterRecord
83fb1e36
A
595(
596 DNSServiceRef sdRef,
597 DNSRecordRef *RecordRef,
598 DNSServiceFlags flags,
599 uint32_t interfaceIndex,
600 const char *fullname,
601 uint16_t rrtype,
602 uint16_t rrclass,
603 uint16_t rdlen,
604 const void *rdata,
605 uint32_t ttl,
606 DNSServiceRegisterRecordReply callback,
607 void *context /* may be NULL */
608)
609{
610 (void)sdRef; // Unused
611 (void)RecordRef; // Unused
612 (void)flags; // Unused
613 (void)interfaceIndex; // Unused
614 (void)fullname; // Unused
615 (void)rrtype; // Unused
616 (void)rrclass; // Unused
617 (void)rdlen; // Unused
618 (void)rdata; // Unused
619 (void)ttl; // Unused
620 (void)callback; // Unused
621 (void)context; // Unused
622 return(kDNSServiceErr_Unsupported);
623}
8e92c31c
A
624#endif
625
626//*************************************************************************************************************
627// DNSServiceQueryRecord
628
629static void DNSServiceQueryRecordDispose(mDNS_DirectOP *op)
83fb1e36
A
630{
631 mDNS_DirectOP_QueryRecord *x = (mDNS_DirectOP_QueryRecord*)op;
632 if (x->q.ThisQInterval >= 0) mDNS_StopQuery(&mDNSStorage, &x->q);
633 mDNSPlatformMemFree(x);
634}
8e92c31c 635
67c8f8a1 636mDNSlocal void DNSServiceQueryRecordResponse(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
83fb1e36
A
637{
638 mDNS_DirectOP_QueryRecord *x = (mDNS_DirectOP_QueryRecord*)question->QuestionContext;
639 char fullname[MAX_ESCAPED_DOMAIN_NAME];
640 (void)m; // Unused
641 ConvertDomainNameToCString(answer->name, fullname);
642 x->callback((DNSServiceRef)x, AddRecord ? kDNSServiceFlagsAdd : (DNSServiceFlags)0, 0, kDNSServiceErr_NoError,
643 fullname, answer->rrtype, answer->rrclass, answer->rdlength, answer->rdata->u.data, answer->rroriginalttl, x->context);
644}
8e92c31c
A
645
646DNSServiceErrorType DNSServiceQueryRecord
83fb1e36 647(
f0cc3e7b
A
648 DNSServiceRef *sdRef,
649 DNSServiceFlags flags,
650 uint32_t interfaceIndex,
651 const char *fullname,
652 uint16_t rrtype,
653 uint16_t rrclass,
83fb1e36 654 DNSServiceQueryRecordReply callback,
f0cc3e7b 655 void *context /* may be NULL */
83fb1e36
A
656)
657{
658 mStatus err = mStatus_NoError;
659 const char *errormsg = "Unknown";
660 mDNS_DirectOP_QueryRecord *x;
661
83fb1e36 662 // Allocate memory, and handle failure
f0cc3e7b 663 x = (mDNS_DirectOP_QueryRecord *) mDNSPlatformMemAllocateClear(sizeof(*x));
83fb1e36
A
664 if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
665
666 // Set up object
667 x->disposefn = DNSServiceQueryRecordDispose;
668 x->callback = callback;
669 x->context = context;
670
f0cc3e7b
A
671 x->q.ThisQInterval = -1; // So that DNSServiceResolveDispose() knows whether to cancel this question
672 x->q.InterfaceID = DNSServiceInterfaceIndexToID(interfaceIndex, &flags);
673 x->q.flags = flags;
83fb1e36 674 MakeDomainNameFromDNSNameString(&x->q.qname, fullname);
f0cc3e7b
A
675 x->q.qtype = rrtype;
676 x->q.qclass = rrclass;
677 x->q.LongLived = (flags & kDNSServiceFlagsLongLivedQuery) != 0;
678 x->q.ExpectUnique = mDNSfalse;
679 x->q.ForceMCast = (flags & kDNSServiceFlagsForceMulticast) != 0;
680 x->q.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
681 x->q.SuppressUnusable = (flags & kDNSServiceFlagsSuppressUnusable) != 0;
682 x->q.AppendSearchDomains = 0;
683 x->q.TimeoutQuestion = 0;
684 x->q.WakeOnResolve = 0;
685 x->q.UseBackgroundTraffic = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
f0cc3e7b
A
686 x->q.ProxyQuestion = 0;
687 x->q.pid = mDNSPlatformGetPID();
688 x->q.QuestionCallback = DNSServiceQueryRecordResponse;
689 x->q.QuestionContext = x;
83fb1e36
A
690
691 err = mDNS_StartQuery(&mDNSStorage, &x->q);
692 if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery"; goto fail; }
693
694 // Succeeded: Wrap up and return
695 *sdRef = (DNSServiceRef)x;
696 return(mStatus_NoError);
8e92c31c 697
8e92c31c 698fail:
83fb1e36
A
699 LogMsg("DNSServiceQueryRecord(\"%s\", %d, %d) failed: %s (%ld)", fullname, rrtype, rrclass, errormsg, err);
700 return(err);
701}
8e92c31c
A
702
703//*************************************************************************************************************
263eeeab 704// DNSServiceGetAddrInfo
f0cc3e7b 705//
263eeeab
A
706
707static void DNSServiceGetAddrInfoDispose(mDNS_DirectOP *op)
83fb1e36
A
708{
709 mDNS_DirectOP_GetAddrInfo *x = (mDNS_DirectOP_GetAddrInfo*)op;
f0cc3e7b
A
710 if (x->a.ThisQInterval >= 0) mDNS_StopQuery(&mDNSStorage, &x->a);
711 if (x->aaaa.ThisQInterval >= 0) mDNS_StopQuery(&mDNSStorage, &x->aaaa);
83fb1e36
A
712 mDNSPlatformMemFree(x);
713}
263eeeab 714
f0cc3e7b
A
715mDNSlocal void DNSServiceGetAddrInfoResponse(mDNS *const m, DNSQuestion *question,
716 const ResourceRecord *const answer, QC_result addRecord)
717{
718 mDNS_DirectOP_GetAddrInfo *x = (mDNS_DirectOP_GetAddrInfo*)question->QuestionContext;
719 char fullname[MAX_ESCAPED_DOMAIN_NAME];
720
721 struct sockaddr_storage sas;
722 struct sockaddr_in *sin = (struct sockaddr_in *)&sas;
723 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sas;
724 void *sa_ap = mDNSNULL;
725 int sa_as = 0;
726 mStatus err = mStatus_NoError;
727
728 (void)m; // Unused
729
730 mDNSPlatformMemZero(&sas, sizeof sas);
731
732 ConvertDomainNameToCString(answer->name, fullname);
733
734 if (addRecord == QC_suppressed || answer->RecordType == kDNSRecordTypePacketNegative)
83fb1e36 735 {
f0cc3e7b
A
736 err = mStatus_NoSuchRecord;
737 }
738
739 // There are three checks here for bad data: class != IN, RRTYPE not in {A,AAAA} and wrong length.
740 // None of these should be possible, because the cache code wouldn't cache malformed data and wouldn't
741 // return records we didn't ask for, but it doesn't hurt to check.
742 if (answer->rrclass != kDNSServiceClass_IN)
743 {
744 LogMsg("DNSServiceGetAddrInfoResponse: response of class %d received, which is bogus", answer->rrclass);
745 totally_invalid:
746 if (x->a.ThisQInterval >= 0)
747 {
748 sin->sin_family = AF_INET;
749#ifndef NOT_HAVE_SA_LEN
750 sin->sin_len = sizeof *sin;
751#endif
752 x->callback((DNSServiceRef)x, 0, x->interfaceIndex, kDNSServiceErr_Invalid, fullname,
753 (const struct sockaddr *)&sas, 0, x->context);
754 }
755 if (x->aaaa.ThisQInterval >= 0)
756 {
757 sin6->sin6_family = AF_INET6;
758#ifndef NOT_HAVE_SA_LEN
759 sin6->sin6_len = sizeof *sin6;
760#endif
761 x->callback((DNSServiceRef)x, 0, x->interfaceIndex, kDNSServiceErr_Invalid, fullname,
762 (const struct sockaddr *)&sas, 0, x->context);
763 }
764 return;
765 }
766 else if (answer->rrtype == kDNSServiceType_A)
767 {
768 sin->sin_family = AF_INET;
769#ifndef NOT_HAVE_SA_LEN
770 sin->sin_len = sizeof *sin;
771#endif
772 sa_ap = &sin->sin_addr;
773 sa_as = sizeof sin->sin_addr.s_addr;
774 }
775 else if (answer->rrtype == kDNSServiceType_AAAA)
776 {
777 sin6->sin6_family = AF_INET6;
778#ifndef NOT_HAVE_SA_LEN
779 sin6->sin6_len = sizeof *sin6;
780#endif
781 sa_ap = &sin6->sin6_addr;
782 sa_as = sizeof sin6->sin6_addr.s6_addr;
783 }
784 else
785 {
786 LogMsg("DNSServiceGetAddrInfoResponse: response of type %d received, which is bogus", answer->rrtype);
787 goto totally_invalid;
788 }
789
790 if (err == kDNSServiceErr_NoError && sa_ap != mDNSNULL)
791 {
792 if (err == mStatus_NoError)
793 {
794 if (answer->rdlength == sa_as)
795 {
796 mDNSPlatformMemCopy(sa_ap, answer->rdata->u.data, answer->rdlength);
797 }
798 else
799 {
800 LogMsg("DNSServiceGetAddrInfoResponse: %s rrtype with length %d received",
801 answer->rrtype == kDNSServiceType_A ? "A" : "AAAA", answer->rdlength);
802 goto totally_invalid;
803 }
804 }
83fb1e36
A
805 }
806
f0cc3e7b
A
807 x->callback((DNSServiceRef)x, addRecord ? kDNSServiceFlagsAdd : (DNSServiceFlags)0, x->interfaceIndex, err,
808 fullname, (const struct sockaddr *)&sas, answer->rroriginalttl, x->context);
83fb1e36 809}
263eeeab
A
810
811DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo(
f0cc3e7b
A
812 DNSServiceRef *outRef,
813 DNSServiceFlags inFlags,
814 uint32_t inInterfaceIndex,
815 DNSServiceProtocol inProtocol,
816 const char *inHostName,
83fb1e36 817 DNSServiceGetAddrInfoReply inCallback,
f0cc3e7b 818 void *inContext )
83fb1e36 819{
f0cc3e7b
A
820 const char *errormsg = "Unknown";
821 DNSServiceErrorType err;
822 mDNS_DirectOP_GetAddrInfo *x;
83fb1e36
A
823
824 // Allocate memory, and handle failure
f0cc3e7b 825 x = (mDNS_DirectOP_GetAddrInfo *) mDNSPlatformMemAllocateClear(sizeof(*x));
83fb1e36
A
826 if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
827
828 // Set up object
f0cc3e7b
A
829 x->disposefn = DNSServiceGetAddrInfoDispose;
830 x->callback = inCallback;
831 x->context = inContext;
832 x->interfaceIndex = inInterfaceIndex;
833
834 // Validate and default the protocols.
835 if ((inProtocol & ~(kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6)) != 0)
836 {
837 err = mStatus_BadParamErr;
838 errormsg = "Unsupported protocol";
839 goto fail;
840 }
841 // In theory this API checks to see if we have a routable IPv6 address, but
842 if ((inProtocol & (kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6)) == 0)
843 {
844 inProtocol = kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6;
845 inFlags |= kDNSServiceFlagsSuppressUnusable;
846 }
847
848 x->a.ThisQInterval = -1; // So we know whether to cancel this question
849 x->a.InterfaceID = DNSServiceInterfaceIndexToID(inInterfaceIndex, &inFlags);
850 x->a.flags = inFlags;
851 MakeDomainNameFromDNSNameString(&x->a.qname, inHostName);
852 x->a.qtype = kDNSType_A;
853 x->a.qclass = kDNSClass_IN;
854 x->a.LongLived = (inFlags & kDNSServiceFlagsLongLivedQuery) != 0;
855 x->a.ExpectUnique = mDNSfalse;
856 x->a.ForceMCast = (inFlags & kDNSServiceFlagsForceMulticast) != 0;
857 x->a.ReturnIntermed = (inFlags & kDNSServiceFlagsReturnIntermediates) != 0;
858 x->a.SuppressUnusable = (inFlags & kDNSServiceFlagsSuppressUnusable) != 0;
859 x->a.AppendSearchDomains = 0;
860 x->a.TimeoutQuestion = 0;
861 x->a.WakeOnResolve = 0;
862 x->a.UseBackgroundTraffic = (inFlags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
f0cc3e7b
A
863 x->a.ProxyQuestion = 0;
864 x->a.pid = mDNSPlatformGetPID();
865 x->a.QuestionCallback = DNSServiceGetAddrInfoResponse;
866 x->a.QuestionContext = x;
867
868 x->aaaa = x->a;
869 x->aaaa.qtype = kDNSType_AAAA;
870
871 if (inProtocol & kDNSServiceProtocol_IPv4)
872 {
873 err = mDNS_StartQuery(&mDNSStorage, &x->a);
874 if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery"; goto fail; }
875 }
876 if (inProtocol & kDNSServiceProtocol_IPv6)
877 {
878 err = mDNS_StartQuery(&mDNSStorage, &x->aaaa);
879 if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery"; goto fail; }
880 }
83fb1e36
A
881
882 *outRef = (DNSServiceRef)x;
883 return(mStatus_NoError);
884
263eeeab 885fail:
83fb1e36
A
886 LogMsg("DNSServiceGetAddrInfo(\"%s\", %d) failed: %s (%ld)", inHostName, inProtocol, errormsg, err);
887 return(err);
888}
263eeeab
A
889
890//*************************************************************************************************************
8e92c31c
A
891// DNSServiceReconfirmRecord
892
893// Not yet implemented, so don't include in stub library
894// We DO include it in the actual Extension, so that if a later client compiled to use this
895// is run against this Extension, it will get a reasonable error code instead of just
896// failing to launch (Strong Link) or calling an unresolved symbol and crashing (Weak Link)
897#if !MDNS_BUILDINGSTUBLIBRARY
67c8f8a1 898DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
83fb1e36
A
899(
900 DNSServiceFlags flags,
901 uint32_t interfaceIndex,
902 const char *fullname,
903 uint16_t rrtype,
904 uint16_t rrclass,
905 uint16_t rdlen,
906 const void *rdata
907)
908{
909 (void)flags; // Unused
910 (void)interfaceIndex; // Unused
911 (void)fullname; // Unused
912 (void)rrtype; // Unused
913 (void)rrclass; // Unused
914 (void)rdlen; // Unused
915 (void)rdata; // Unused
916 return(kDNSServiceErr_Unsupported);
917}
509d285a 918
f0cc3e7b 919#endif // !MDNS_BUILDINGSTUBLIBRARY
b8d5688b 920
f0cc3e7b
A
921// Local Variables:
922// mode: C
923// tab-width: 4
924// c-file-style: "bsd"
925// c-basic-offset: 4
926// fill-column: 108
927// indent-tabs-mode: nil
928// End: