2 * Copyright (c) 2003-2019 Apple Inc. All rights reserved.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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
14 * limitations under the License.
16 * This file defines a simple shim layer between a client calling the "/usr/include/dns_sd.h" APIs
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
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.
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
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 extern mDNS mDNSStorage
; // We need to pass the address of this storage to the lower-layer functions
31 #if MDNS_BUILDINGSHAREDLIBRARY || MDNS_BUILDINGSTUBLIBRARY
35 //*************************************************************************************************************
36 // General Utility Functions
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
45 typedef struct mDNS_DirectOP_struct mDNS_DirectOP
;
46 typedef void mDNS_DirectOP_Dispose (mDNS_DirectOP
*op
);
47 struct mDNS_DirectOP_struct
49 mDNS_DirectOP_Dispose
*disposefn
;
54 mDNS_DirectOP_Dispose
*disposefn
;
55 DNSServiceRegisterReply callback
;
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
62 } mDNS_DirectOP_Register
;
66 mDNS_DirectOP_Dispose
*disposefn
;
67 DNSServiceBrowseReply callback
;
70 } mDNS_DirectOP_Browse
;
74 mDNS_DirectOP_Dispose
*disposefn
;
75 DNSServiceResolveReply callback
;
77 const ResourceRecord
*SRV
;
78 const ResourceRecord
*TXT
;
81 } mDNS_DirectOP_Resolve
;
85 mDNS_DirectOP_Dispose
*disposefn
;
86 DNSServiceQueryRecordReply callback
;
89 } mDNS_DirectOP_QueryRecord
;
93 mDNS_DirectOP_Dispose
*disposefn
;
94 DNSServiceGetAddrInfoReply callback
;
96 mDNSu32 interfaceIndex
;
99 } mDNS_DirectOP_GetAddrInfo
;
101 dnssd_sock_t
DNSServiceRefSockFD(DNSServiceRef sdRef
)
103 (void)sdRef
; // Unused
107 DNSServiceErrorType
DNSServiceProcessResult(DNSServiceRef sdRef
)
109 (void)sdRef
; // Unused
110 return(kDNSServiceErr_NoError
);
113 void DNSServiceRefDeallocate(DNSServiceRef sdRef
)
115 mDNS_DirectOP
*op
= (mDNS_DirectOP
*)sdRef
;
116 //LogMsg("DNSServiceRefDeallocate");
120 static mDNSInterfaceID
DNSServiceInterfaceIndexToID(mDNSu32 interfaceIndex
, DNSServiceFlags
*flags
)
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
)
126 LogOperation("handle_resolve_request: mapping kDNSServiceInterfaceIndexP2P to kDNSServiceInterfaceIndexAny + kDNSServiceFlagsIncludeP2P");
127 if (flags
!= mDNSNULL
) *flags
|= kDNSServiceFlagsIncludeP2P
;
128 interfaceIndex
= kDNSServiceInterfaceIndexAny
;
130 return mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage
, interfaceIndex
);
133 //*************************************************************************************************************
134 // Domain Enumeration
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
141 DNSServiceErrorType DNSServiceEnumerateDomains
143 DNSServiceRef
*sdRef
,
144 DNSServiceFlags flags
,
145 uint32_t interfaceIndex
,
146 DNSServiceDomainEnumReply callback
,
147 void *context
/* may be NULL */
150 (void)sdRef
; // Unused
151 (void)flags
; // Unused
152 (void)interfaceIndex
; // Unused
153 (void)callback
; // Unused
154 (void)context
; // Unused
155 return(kDNSServiceErr_Unsupported
);
159 //*************************************************************************************************************
162 mDNSlocal
void FreeDNSServiceRegistration(mDNS_DirectOP_Register
*x
)
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
);
173 if (x
->s
.RR_TXT
.resrec
.rdata
!= &x
->s
.RR_TXT
.rdatastorage
)
174 mDNSPlatformMemFree(x
->s
.RR_TXT
.resrec
.rdata
);
176 if (x
->s
.SubTypes
) mDNSPlatformMemFree(x
->s
.SubTypes
);
178 mDNSPlatformMemFree(x
);
181 static void DNSServiceRegisterDispose(mDNS_DirectOP
*op
)
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
);
193 mDNSlocal
void RegCallback(mDNS
*const m
, ServiceRecordSet
*const sr
, mStatus result
)
195 mDNS_DirectOP_Register
*x
= (mDNS_DirectOP_Register
*)sr
->ServiceContext
;
198 domainname type
, dom
;
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
];
202 if (!DeconstructServiceName(sr
->RR_SRV
.resrec
.name
, &name
, &type
, &dom
)) return;
203 if (!ConvertDomainLabelToCString_unescaped(&name
, namestr
)) return;
204 if (!ConvertDomainNameToCString(&type
, typestr
)) return;
205 if (!ConvertDomainNameToCString(&dom
, domstr
)) return;
207 if (result
== mStatus_NoError
)
210 x
->callback((DNSServiceRef
)x
, 0, result
, namestr
, typestr
, domstr
, x
->context
);
212 else if (result
== mStatus_NameConflict
)
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
);
218 else if (result
== mStatus_MemFree
)
222 x
->autorename
= mDNSfalse
;
223 x
->name
= mDNSStorage
.nicelabel
;
224 mDNS_RenameAndReregisterService(m
, &x
->s
, &x
->name
);
227 FreeDNSServiceRegistration(x
);
231 DNSServiceErrorType DNSServiceRegister
233 DNSServiceRef
*sdRef
,
234 DNSServiceFlags flags
,
235 uint32_t interfaceIndex
,
236 const char *name
, /* may be NULL */
238 const char *domain
, /* may be NULL */
239 const char *host
, /* may be NULL */
240 uint16_t notAnIntPort
,
242 const void *txtRecord
, /* may be NULL */
243 DNSServiceRegisterReply callback
, /* may be NULL */
244 void *context
/* may be NULL */
247 mStatus err
= mStatus_NoError
;
248 const char *errormsg
= "Unknown";
250 domainname t
, d
, h
, srv
;
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
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
;
269 // Allocate memory, and handle failure
272 x
= (mDNS_DirectOP_Register
*) mDNSPlatformMemAllocateClear(sizeof(*x
) - sizeof(RDataBody
) + size
);
273 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
276 x
->disposefn
= DNSServiceRegisterDispose
;
277 x
->callback
= callback
;
278 x
->context
= context
;
279 x
->autoname
= (!name
[0]);
280 x
->autorename
= mDNSfalse
;
285 err
= mDNS_RegisterService(&mDNSStorage
, &x
->s
,
286 &x
->name
, &t
, &d
, // Name, type, domain
287 &x
->host
, port
, // Host and port
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
; }
295 // Succeeded: Wrap up and return
296 *sdRef
= (DNSServiceRef
)x
;
297 return(mStatus_NoError
);
300 err
= mStatus_BadParamErr
;
302 LogMsg("DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", regtype
, domain
, errormsg
, err
);
306 //*************************************************************************************************************
307 // Add / Update / Remove records from existing Registration
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
314 DNSServiceErrorType DNSServiceAddRecord
317 DNSRecordRef
*RecordRef
,
318 DNSServiceFlags flags
,
325 (void)sdRef
; // Unused
326 (void)RecordRef
; // Unused
327 (void)flags
; // Unused
328 (void)rrtype
; // Unused
329 (void)rdlen
; // Unused
330 (void)rdata
; // Unused
332 return(kDNSServiceErr_Unsupported
);
335 DNSServiceErrorType DNSServiceUpdateRecord
338 DNSRecordRef RecordRef
, /* may be NULL */
339 DNSServiceFlags flags
,
345 (void)sdRef
; // Unused
346 (void)RecordRef
; // Unused
347 (void)flags
; // Unused
348 (void)rdlen
; // Unused
349 (void)rdata
; // Unused
351 return(kDNSServiceErr_Unsupported
);
354 DNSServiceErrorType DNSServiceRemoveRecord
357 DNSRecordRef RecordRef
,
358 DNSServiceFlags flags
361 (void)sdRef
; // Unused
362 (void)RecordRef
; // Unused
363 (void)flags
; // Unused
364 return(kDNSServiceErr_Unsupported
);
368 //*************************************************************************************************************
369 // Browse for services
371 static void DNSServiceBrowseDispose(mDNS_DirectOP
*op
)
373 mDNS_DirectOP_Browse
*x
= (mDNS_DirectOP_Browse
*)op
;
374 //LogMsg("DNSServiceBrowseDispose");
375 mDNS_StopBrowse(&mDNSStorage
, &x
->q
);
376 mDNSPlatformMemFree(x
);
379 mDNSlocal
void FoundInstance(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
381 DNSServiceFlags flags
= AddRecord
? kDNSServiceFlagsAdd
: (DNSServiceFlags
)0;
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
;
390 if (answer
->rrtype
!= kDNSType_PTR
)
391 { LogMsg("FoundInstance: Should not be called with rrtype %d (not a PTR record)", answer
->rrtype
); return; }
393 if (!DeconstructServiceName(&answer
->rdata
->u
.name
, &name
, &type
, &domain
))
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
);
400 ConvertDomainLabelToCString_unescaped(&name
, cname
);
401 ConvertDomainNameToCString(&type
, ctype
);
402 ConvertDomainNameToCString(&domain
, cdom
);
404 x
->callback((DNSServiceRef
)x
, flags
, 0, 0, cname
, ctype
, cdom
, x
->context
);
407 DNSServiceErrorType DNSServiceBrowse
409 DNSServiceRef
*sdRef
,
410 DNSServiceFlags flags
,
411 uint32_t interfaceIndex
,
413 const char *domain
, /* may be NULL */
414 DNSServiceBrowseReply callback
,
415 void *context
/* may be NULL */
418 mStatus err
= mStatus_NoError
;
419 const char *errormsg
= "Unknown";
421 mDNS_DirectOP_Browse
*x
;
422 (void)flags
; // Unused
423 (void)interfaceIndex
; // Unused
426 if (!regtype
[0] || !MakeDomainNameFromDNSNameString(&t
, regtype
)) { errormsg
= "Illegal regtype"; goto badparam
; }
427 if (!MakeDomainNameFromDNSNameString(&d
, *domain
? domain
: "local.")) { errormsg
= "Illegal domain"; goto badparam
; }
429 // Allocate memory, and handle failure
430 x
= (mDNS_DirectOP_Browse
*) mDNSPlatformMemAllocateClear(sizeof(*x
));
431 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
434 x
->disposefn
= DNSServiceBrowseDispose
;
435 x
->callback
= callback
;
436 x
->context
= context
;
437 x
->q
.QuestionContext
= x
;
440 err
= mDNS_StartBrowse(&mDNSStorage
, &x
->q
, &t
, &d
, mDNSInterface_Any
, flags
, (flags
& kDNSServiceFlagsForceMulticast
) != 0, (flags
& kDNSServiceFlagsBackgroundTrafficClass
) != 0, FoundInstance
, x
);
441 if (err
) { mDNSPlatformMemFree(x
); errormsg
= "mDNS_StartBrowse"; goto fail
; }
443 // Succeeded: Wrap up and return
444 *sdRef
= (DNSServiceRef
)x
;
445 return(mStatus_NoError
);
448 err
= mStatus_BadParamErr
;
450 LogMsg("DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", regtype
, domain
, errormsg
, err
);
454 //*************************************************************************************************************
455 // Resolve Service Info
457 static void DNSServiceResolveDispose(mDNS_DirectOP
*op
)
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
);
465 mDNSlocal
void FoundServiceInfo(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
467 mDNS_DirectOP_Resolve
*x
= (mDNS_DirectOP_Resolve
*)question
->QuestionContext
;
471 if (answer
->rrtype
== kDNSType_SRV
&& x
->SRV
== answer
) x
->SRV
= mDNSNULL
;
472 if (answer
->rrtype
== kDNSType_TXT
&& x
->TXT
== answer
) x
->TXT
= mDNSNULL
;
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
)
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
);
489 DNSServiceErrorType DNSServiceResolve
491 DNSServiceRef
*sdRef
,
492 DNSServiceFlags flags
,
493 uint32_t interfaceIndex
,
497 DNSServiceResolveReply callback
,
498 void *context
/* may be NULL */
501 mStatus err
= mStatus_NoError
;
502 const char *errormsg
= "Unknown";
504 domainname t
, d
, srv
;
505 mDNS_DirectOP_Resolve
*x
;
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
; }
513 // Allocate memory, and handle failure
514 x
= (mDNS_DirectOP_Resolve
*) mDNSPlatformMemAllocateClear(sizeof(*x
));
515 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
518 x
->disposefn
= DNSServiceResolveDispose
;
519 x
->callback
= callback
;
520 x
->context
= context
;
524 x
->qSRV
.ThisQInterval
= -1; // So that DNSServiceResolveDispose() knows whether to cancel this question
525 x
->qSRV
.InterfaceID
= DNSServiceInterfaceIndexToID(interfaceIndex
, &flags
);
526 x
->qSRV
.flags
= flags
;
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
;
535 x
->qSRV
.AppendSearchDomains
= 0;
536 x
->qSRV
.TimeoutQuestion
= 0;
537 x
->qSRV
.WakeOnResolve
= 0;
538 x
->qSRV
.UseBackgroundTraffic
= (flags
& kDNSServiceFlagsBackgroundTrafficClass
) != 0;
539 x
->qSRV
.ValidationRequired
= 0;
540 x
->qSRV
.ValidatingResponse
= 0;
541 x
->qSRV
.ProxyQuestion
= 0;
542 x
->qSRV
.pid
= mDNSPlatformGetPID();
543 x
->qSRV
.QuestionCallback
= FoundServiceInfo
;
544 x
->qSRV
.QuestionContext
= x
;
546 x
->qTXT
.ThisQInterval
= -1; // So that DNSServiceResolveDispose() knows whether to cancel this question
547 x
->qTXT
.InterfaceID
= DNSServiceInterfaceIndexToID(interfaceIndex
, mDNSNULL
);
548 x
->qTXT
.flags
= flags
;
549 AssignDomainName(&x
->qTXT
.qname
, &srv
);
550 x
->qTXT
.qtype
= kDNSType_TXT
;
551 x
->qTXT
.qclass
= kDNSClass_IN
;
552 x
->qTXT
.LongLived
= mDNSfalse
;
553 x
->qTXT
.ExpectUnique
= mDNStrue
;
554 x
->qTXT
.ForceMCast
= mDNSfalse
;
555 x
->qTXT
.ReturnIntermed
= mDNSfalse
;
556 x
->qTXT
.SuppressUnusable
= mDNSfalse
;
557 x
->qTXT
.AppendSearchDomains
= 0;
558 x
->qTXT
.TimeoutQuestion
= 0;
559 x
->qTXT
.WakeOnResolve
= 0;
560 x
->qTXT
.UseBackgroundTraffic
= (flags
& kDNSServiceFlagsBackgroundTrafficClass
) != 0;
561 x
->qTXT
.ValidationRequired
= 0;
562 x
->qTXT
.ValidatingResponse
= 0;
563 x
->qTXT
.ProxyQuestion
= 0;
564 x
->qTXT
.pid
= mDNSPlatformGetPID();
565 x
->qTXT
.QuestionCallback
= FoundServiceInfo
;
566 x
->qTXT
.QuestionContext
= x
;
568 err
= mDNS_StartQuery(&mDNSStorage
, &x
->qSRV
);
569 if (err
) { DNSServiceResolveDispose((mDNS_DirectOP
*)x
); errormsg
= "mDNS_StartQuery qSRV"; goto fail
; }
570 err
= mDNS_StartQuery(&mDNSStorage
, &x
->qTXT
);
571 if (err
) { DNSServiceResolveDispose((mDNS_DirectOP
*)x
); errormsg
= "mDNS_StartQuery qTXT"; goto fail
; }
573 // Succeeded: Wrap up and return
574 *sdRef
= (DNSServiceRef
)x
;
575 return(mStatus_NoError
);
578 err
= mStatus_BadParamErr
;
580 LogMsg("DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%ld)", name
, regtype
, domain
, errormsg
, err
);
584 //*************************************************************************************************************
585 // Connection-oriented calls
587 // Not yet implemented, so don't include in stub library
588 // We DO include it in the actual Extension, so that if a later client compiled to use this
589 // is run against this Extension, it will get a reasonable error code instead of just
590 // failing to launch (Strong Link) or calling an unresolved symbol and crashing (Weak Link)
591 #if !MDNS_BUILDINGSTUBLIBRARY
592 DNSServiceErrorType
DNSServiceCreateConnection(DNSServiceRef
*sdRef
)
594 (void)sdRef
; // Unused
595 return(kDNSServiceErr_Unsupported
);
598 DNSServiceErrorType DNSServiceRegisterRecord
601 DNSRecordRef
*RecordRef
,
602 DNSServiceFlags flags
,
603 uint32_t interfaceIndex
,
604 const char *fullname
,
610 DNSServiceRegisterRecordReply callback
,
611 void *context
/* may be NULL */
614 (void)sdRef
; // Unused
615 (void)RecordRef
; // Unused
616 (void)flags
; // Unused
617 (void)interfaceIndex
; // Unused
618 (void)fullname
; // Unused
619 (void)rrtype
; // Unused
620 (void)rrclass
; // Unused
621 (void)rdlen
; // Unused
622 (void)rdata
; // Unused
624 (void)callback
; // Unused
625 (void)context
; // Unused
626 return(kDNSServiceErr_Unsupported
);
630 //*************************************************************************************************************
631 // DNSServiceQueryRecord
633 static void DNSServiceQueryRecordDispose(mDNS_DirectOP
*op
)
635 mDNS_DirectOP_QueryRecord
*x
= (mDNS_DirectOP_QueryRecord
*)op
;
636 if (x
->q
.ThisQInterval
>= 0) mDNS_StopQuery(&mDNSStorage
, &x
->q
);
637 mDNSPlatformMemFree(x
);
640 mDNSlocal
void DNSServiceQueryRecordResponse(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
642 mDNS_DirectOP_QueryRecord
*x
= (mDNS_DirectOP_QueryRecord
*)question
->QuestionContext
;
643 char fullname
[MAX_ESCAPED_DOMAIN_NAME
];
645 ConvertDomainNameToCString(answer
->name
, fullname
);
646 x
->callback((DNSServiceRef
)x
, AddRecord
? kDNSServiceFlagsAdd
: (DNSServiceFlags
)0, 0, kDNSServiceErr_NoError
,
647 fullname
, answer
->rrtype
, answer
->rrclass
, answer
->rdlength
, answer
->rdata
->u
.data
, answer
->rroriginalttl
, x
->context
);
650 DNSServiceErrorType DNSServiceQueryRecord
652 DNSServiceRef
*sdRef
,
653 DNSServiceFlags flags
,
654 uint32_t interfaceIndex
,
655 const char *fullname
,
658 DNSServiceQueryRecordReply callback
,
659 void *context
/* may be NULL */
662 mStatus err
= mStatus_NoError
;
663 const char *errormsg
= "Unknown";
664 mDNS_DirectOP_QueryRecord
*x
;
666 // Allocate memory, and handle failure
667 x
= (mDNS_DirectOP_QueryRecord
*) mDNSPlatformMemAllocateClear(sizeof(*x
));
668 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
671 x
->disposefn
= DNSServiceQueryRecordDispose
;
672 x
->callback
= callback
;
673 x
->context
= context
;
675 x
->q
.ThisQInterval
= -1; // So that DNSServiceResolveDispose() knows whether to cancel this question
676 x
->q
.InterfaceID
= DNSServiceInterfaceIndexToID(interfaceIndex
, &flags
);
678 MakeDomainNameFromDNSNameString(&x
->q
.qname
, fullname
);
680 x
->q
.qclass
= rrclass
;
681 x
->q
.LongLived
= (flags
& kDNSServiceFlagsLongLivedQuery
) != 0;
682 x
->q
.ExpectUnique
= mDNSfalse
;
683 x
->q
.ForceMCast
= (flags
& kDNSServiceFlagsForceMulticast
) != 0;
684 x
->q
.ReturnIntermed
= (flags
& kDNSServiceFlagsReturnIntermediates
) != 0;
685 x
->q
.SuppressUnusable
= (flags
& kDNSServiceFlagsSuppressUnusable
) != 0;
686 x
->q
.AppendSearchDomains
= 0;
687 x
->q
.TimeoutQuestion
= 0;
688 x
->q
.WakeOnResolve
= 0;
689 x
->q
.UseBackgroundTraffic
= (flags
& kDNSServiceFlagsBackgroundTrafficClass
) != 0;
690 x
->q
.ValidationRequired
= 0;
691 x
->q
.ValidatingResponse
= 0;
692 x
->q
.ProxyQuestion
= 0;
693 x
->q
.pid
= mDNSPlatformGetPID();
694 x
->q
.QuestionCallback
= DNSServiceQueryRecordResponse
;
695 x
->q
.QuestionContext
= x
;
697 err
= mDNS_StartQuery(&mDNSStorage
, &x
->q
);
698 if (err
) { DNSServiceResolveDispose((mDNS_DirectOP
*)x
); errormsg
= "mDNS_StartQuery"; goto fail
; }
700 // Succeeded: Wrap up and return
701 *sdRef
= (DNSServiceRef
)x
;
702 return(mStatus_NoError
);
705 LogMsg("DNSServiceQueryRecord(\"%s\", %d, %d) failed: %s (%ld)", fullname
, rrtype
, rrclass
, errormsg
, err
);
709 //*************************************************************************************************************
710 // DNSServiceGetAddrInfo
713 static void DNSServiceGetAddrInfoDispose(mDNS_DirectOP
*op
)
715 mDNS_DirectOP_GetAddrInfo
*x
= (mDNS_DirectOP_GetAddrInfo
*)op
;
716 if (x
->a
.ThisQInterval
>= 0) mDNS_StopQuery(&mDNSStorage
, &x
->a
);
717 if (x
->aaaa
.ThisQInterval
>= 0) mDNS_StopQuery(&mDNSStorage
, &x
->aaaa
);
718 mDNSPlatformMemFree(x
);
721 mDNSlocal
void DNSServiceGetAddrInfoResponse(mDNS
*const m
, DNSQuestion
*question
,
722 const ResourceRecord
*const answer
, QC_result addRecord
)
724 mDNS_DirectOP_GetAddrInfo
*x
= (mDNS_DirectOP_GetAddrInfo
*)question
->QuestionContext
;
725 char fullname
[MAX_ESCAPED_DOMAIN_NAME
];
727 struct sockaddr_storage sas
;
728 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&sas
;
729 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&sas
;
730 void *sa_ap
= mDNSNULL
;
732 mStatus err
= mStatus_NoError
;
736 mDNSPlatformMemZero(&sas
, sizeof sas
);
738 ConvertDomainNameToCString(answer
->name
, fullname
);
740 if (addRecord
== QC_suppressed
|| answer
->RecordType
== kDNSRecordTypePacketNegative
)
742 err
= mStatus_NoSuchRecord
;
745 // There are three checks here for bad data: class != IN, RRTYPE not in {A,AAAA} and wrong length.
746 // None of these should be possible, because the cache code wouldn't cache malformed data and wouldn't
747 // return records we didn't ask for, but it doesn't hurt to check.
748 if (answer
->rrclass
!= kDNSServiceClass_IN
)
750 LogMsg("DNSServiceGetAddrInfoResponse: response of class %d received, which is bogus", answer
->rrclass
);
752 if (x
->a
.ThisQInterval
>= 0)
754 sin
->sin_family
= AF_INET
;
755 #ifndef NOT_HAVE_SA_LEN
756 sin
->sin_len
= sizeof *sin
;
758 x
->callback((DNSServiceRef
)x
, 0, x
->interfaceIndex
, kDNSServiceErr_Invalid
, fullname
,
759 (const struct sockaddr
*)&sas
, 0, x
->context
);
761 if (x
->aaaa
.ThisQInterval
>= 0)
763 sin6
->sin6_family
= AF_INET6
;
764 #ifndef NOT_HAVE_SA_LEN
765 sin6
->sin6_len
= sizeof *sin6
;
767 x
->callback((DNSServiceRef
)x
, 0, x
->interfaceIndex
, kDNSServiceErr_Invalid
, fullname
,
768 (const struct sockaddr
*)&sas
, 0, x
->context
);
772 else if (answer
->rrtype
== kDNSServiceType_A
)
774 sin
->sin_family
= AF_INET
;
775 #ifndef NOT_HAVE_SA_LEN
776 sin
->sin_len
= sizeof *sin
;
778 sa_ap
= &sin
->sin_addr
;
779 sa_as
= sizeof sin
->sin_addr
.s_addr
;
781 else if (answer
->rrtype
== kDNSServiceType_AAAA
)
783 sin6
->sin6_family
= AF_INET6
;
784 #ifndef NOT_HAVE_SA_LEN
785 sin6
->sin6_len
= sizeof *sin6
;
787 sa_ap
= &sin6
->sin6_addr
;
788 sa_as
= sizeof sin6
->sin6_addr
.s6_addr
;
792 LogMsg("DNSServiceGetAddrInfoResponse: response of type %d received, which is bogus", answer
->rrtype
);
793 goto totally_invalid
;
796 if (err
== kDNSServiceErr_NoError
&& sa_ap
!= mDNSNULL
)
798 if (err
== mStatus_NoError
)
800 if (answer
->rdlength
== sa_as
)
802 mDNSPlatformMemCopy(sa_ap
, answer
->rdata
->u
.data
, answer
->rdlength
);
806 LogMsg("DNSServiceGetAddrInfoResponse: %s rrtype with length %d received",
807 answer
->rrtype
== kDNSServiceType_A
? "A" : "AAAA", answer
->rdlength
);
808 goto totally_invalid
;
813 x
->callback((DNSServiceRef
)x
, addRecord
? kDNSServiceFlagsAdd
: (DNSServiceFlags
)0, x
->interfaceIndex
, err
,
814 fullname
, (const struct sockaddr
*)&sas
, answer
->rroriginalttl
, x
->context
);
817 DNSServiceErrorType DNSSD_API
DNSServiceGetAddrInfo(
818 DNSServiceRef
*outRef
,
819 DNSServiceFlags inFlags
,
820 uint32_t inInterfaceIndex
,
821 DNSServiceProtocol inProtocol
,
822 const char *inHostName
,
823 DNSServiceGetAddrInfoReply inCallback
,
826 const char *errormsg
= "Unknown";
827 DNSServiceErrorType err
;
828 mDNS_DirectOP_GetAddrInfo
*x
;
830 // Allocate memory, and handle failure
831 x
= (mDNS_DirectOP_GetAddrInfo
*) mDNSPlatformMemAllocateClear(sizeof(*x
));
832 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
835 x
->disposefn
= DNSServiceGetAddrInfoDispose
;
836 x
->callback
= inCallback
;
837 x
->context
= inContext
;
838 x
->interfaceIndex
= inInterfaceIndex
;
840 // Validate and default the protocols.
841 if ((inProtocol
& ~(kDNSServiceProtocol_IPv4
| kDNSServiceProtocol_IPv6
)) != 0)
843 err
= mStatus_BadParamErr
;
844 errormsg
= "Unsupported protocol";
847 // In theory this API checks to see if we have a routable IPv6 address, but
848 if ((inProtocol
& (kDNSServiceProtocol_IPv4
| kDNSServiceProtocol_IPv6
)) == 0)
850 inProtocol
= kDNSServiceProtocol_IPv4
| kDNSServiceProtocol_IPv6
;
851 inFlags
|= kDNSServiceFlagsSuppressUnusable
;
854 x
->a
.ThisQInterval
= -1; // So we know whether to cancel this question
855 x
->a
.InterfaceID
= DNSServiceInterfaceIndexToID(inInterfaceIndex
, &inFlags
);
856 x
->a
.flags
= inFlags
;
857 MakeDomainNameFromDNSNameString(&x
->a
.qname
, inHostName
);
858 x
->a
.qtype
= kDNSType_A
;
859 x
->a
.qclass
= kDNSClass_IN
;
860 x
->a
.LongLived
= (inFlags
& kDNSServiceFlagsLongLivedQuery
) != 0;
861 x
->a
.ExpectUnique
= mDNSfalse
;
862 x
->a
.ForceMCast
= (inFlags
& kDNSServiceFlagsForceMulticast
) != 0;
863 x
->a
.ReturnIntermed
= (inFlags
& kDNSServiceFlagsReturnIntermediates
) != 0;
864 x
->a
.SuppressUnusable
= (inFlags
& kDNSServiceFlagsSuppressUnusable
) != 0;
865 x
->a
.AppendSearchDomains
= 0;
866 x
->a
.TimeoutQuestion
= 0;
867 x
->a
.WakeOnResolve
= 0;
868 x
->a
.UseBackgroundTraffic
= (inFlags
& kDNSServiceFlagsBackgroundTrafficClass
) != 0;
869 x
->a
.ValidationRequired
= 0;
870 x
->a
.ValidatingResponse
= 0;
871 x
->a
.ProxyQuestion
= 0;
872 x
->a
.pid
= mDNSPlatformGetPID();
873 x
->a
.QuestionCallback
= DNSServiceGetAddrInfoResponse
;
874 x
->a
.QuestionContext
= x
;
877 x
->aaaa
.qtype
= kDNSType_AAAA
;
879 if (inProtocol
& kDNSServiceProtocol_IPv4
)
881 err
= mDNS_StartQuery(&mDNSStorage
, &x
->a
);
882 if (err
) { DNSServiceResolveDispose((mDNS_DirectOP
*)x
); errormsg
= "mDNS_StartQuery"; goto fail
; }
884 if (inProtocol
& kDNSServiceProtocol_IPv6
)
886 err
= mDNS_StartQuery(&mDNSStorage
, &x
->aaaa
);
887 if (err
) { DNSServiceResolveDispose((mDNS_DirectOP
*)x
); errormsg
= "mDNS_StartQuery"; goto fail
; }
890 *outRef
= (DNSServiceRef
)x
;
891 return(mStatus_NoError
);
894 LogMsg("DNSServiceGetAddrInfo(\"%s\", %d) failed: %s (%ld)", inHostName
, inProtocol
, errormsg
, err
);
898 //*************************************************************************************************************
899 // DNSServiceReconfirmRecord
901 // Not yet implemented, so don't include in stub library
902 // We DO include it in the actual Extension, so that if a later client compiled to use this
903 // is run against this Extension, it will get a reasonable error code instead of just
904 // failing to launch (Strong Link) or calling an unresolved symbol and crashing (Weak Link)
905 #if !MDNS_BUILDINGSTUBLIBRARY
906 DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
908 DNSServiceFlags flags
,
909 uint32_t interfaceIndex
,
910 const char *fullname
,
917 (void)flags
; // Unused
918 (void)interfaceIndex
; // Unused
919 (void)fullname
; // Unused
920 (void)rrtype
; // Unused
921 (void)rrclass
; // Unused
922 (void)rdlen
; // Unused
923 (void)rdata
; // Unused
924 return(kDNSServiceErr_Unsupported
);
927 #endif // !MDNS_BUILDINGSTUBLIBRARY
932 // c-file-style: "bsd"
935 // indent-tabs-mode: nil