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
.ProxyQuestion
= 0;
540 x
->qSRV
.pid
= mDNSPlatformGetPID();
541 x
->qSRV
.QuestionCallback
= FoundServiceInfo
;
542 x
->qSRV
.QuestionContext
= x
;
544 x
->qTXT
.ThisQInterval
= -1; // So that DNSServiceResolveDispose() knows whether to cancel this question
545 x
->qTXT
.InterfaceID
= DNSServiceInterfaceIndexToID(interfaceIndex
, mDNSNULL
);
546 x
->qTXT
.flags
= flags
;
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
;
555 x
->qTXT
.AppendSearchDomains
= 0;
556 x
->qTXT
.TimeoutQuestion
= 0;
557 x
->qTXT
.WakeOnResolve
= 0;
558 x
->qTXT
.UseBackgroundTraffic
= (flags
& kDNSServiceFlagsBackgroundTrafficClass
) != 0;
559 x
->qTXT
.ProxyQuestion
= 0;
560 x
->qTXT
.pid
= mDNSPlatformGetPID();
561 x
->qTXT
.QuestionCallback
= FoundServiceInfo
;
562 x
->qTXT
.QuestionContext
= x
;
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
; }
569 // Succeeded: Wrap up and return
570 *sdRef
= (DNSServiceRef
)x
;
571 return(mStatus_NoError
);
574 err
= mStatus_BadParamErr
;
576 LogMsg("DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%ld)", name
, regtype
, domain
, errormsg
, err
);
580 //*************************************************************************************************************
581 // Connection-oriented calls
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
588 DNSServiceErrorType
DNSServiceCreateConnection(DNSServiceRef
*sdRef
)
590 (void)sdRef
; // Unused
591 return(kDNSServiceErr_Unsupported
);
594 DNSServiceErrorType DNSServiceRegisterRecord
597 DNSRecordRef
*RecordRef
,
598 DNSServiceFlags flags
,
599 uint32_t interfaceIndex
,
600 const char *fullname
,
606 DNSServiceRegisterRecordReply callback
,
607 void *context
/* may be NULL */
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
620 (void)callback
; // Unused
621 (void)context
; // Unused
622 return(kDNSServiceErr_Unsupported
);
626 //*************************************************************************************************************
627 // DNSServiceQueryRecord
629 static void DNSServiceQueryRecordDispose(mDNS_DirectOP
*op
)
631 mDNS_DirectOP_QueryRecord
*x
= (mDNS_DirectOP_QueryRecord
*)op
;
632 if (x
->q
.ThisQInterval
>= 0) mDNS_StopQuery(&mDNSStorage
, &x
->q
);
633 mDNSPlatformMemFree(x
);
636 mDNSlocal
void DNSServiceQueryRecordResponse(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
638 mDNS_DirectOP_QueryRecord
*x
= (mDNS_DirectOP_QueryRecord
*)question
->QuestionContext
;
639 char fullname
[MAX_ESCAPED_DOMAIN_NAME
];
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
);
646 DNSServiceErrorType DNSServiceQueryRecord
648 DNSServiceRef
*sdRef
,
649 DNSServiceFlags flags
,
650 uint32_t interfaceIndex
,
651 const char *fullname
,
654 DNSServiceQueryRecordReply callback
,
655 void *context
/* may be NULL */
658 mStatus err
= mStatus_NoError
;
659 const char *errormsg
= "Unknown";
660 mDNS_DirectOP_QueryRecord
*x
;
662 // Allocate memory, and handle failure
663 x
= (mDNS_DirectOP_QueryRecord
*) mDNSPlatformMemAllocateClear(sizeof(*x
));
664 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
667 x
->disposefn
= DNSServiceQueryRecordDispose
;
668 x
->callback
= callback
;
669 x
->context
= context
;
671 x
->q
.ThisQInterval
= -1; // So that DNSServiceResolveDispose() knows whether to cancel this question
672 x
->q
.InterfaceID
= DNSServiceInterfaceIndexToID(interfaceIndex
, &flags
);
674 MakeDomainNameFromDNSNameString(&x
->q
.qname
, fullname
);
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;
686 x
->q
.ProxyQuestion
= 0;
687 x
->q
.pid
= mDNSPlatformGetPID();
688 x
->q
.QuestionCallback
= DNSServiceQueryRecordResponse
;
689 x
->q
.QuestionContext
= x
;
691 err
= mDNS_StartQuery(&mDNSStorage
, &x
->q
);
692 if (err
) { DNSServiceResolveDispose((mDNS_DirectOP
*)x
); errormsg
= "mDNS_StartQuery"; goto fail
; }
694 // Succeeded: Wrap up and return
695 *sdRef
= (DNSServiceRef
)x
;
696 return(mStatus_NoError
);
699 LogMsg("DNSServiceQueryRecord(\"%s\", %d, %d) failed: %s (%ld)", fullname
, rrtype
, rrclass
, errormsg
, err
);
703 //*************************************************************************************************************
704 // DNSServiceGetAddrInfo
707 static void DNSServiceGetAddrInfoDispose(mDNS_DirectOP
*op
)
709 mDNS_DirectOP_GetAddrInfo
*x
= (mDNS_DirectOP_GetAddrInfo
*)op
;
710 if (x
->a
.ThisQInterval
>= 0) mDNS_StopQuery(&mDNSStorage
, &x
->a
);
711 if (x
->aaaa
.ThisQInterval
>= 0) mDNS_StopQuery(&mDNSStorage
, &x
->aaaa
);
712 mDNSPlatformMemFree(x
);
715 mDNSlocal
void DNSServiceGetAddrInfoResponse(mDNS
*const m
, DNSQuestion
*question
,
716 const ResourceRecord
*const answer
, QC_result addRecord
)
718 mDNS_DirectOP_GetAddrInfo
*x
= (mDNS_DirectOP_GetAddrInfo
*)question
->QuestionContext
;
719 char fullname
[MAX_ESCAPED_DOMAIN_NAME
];
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
;
726 mStatus err
= mStatus_NoError
;
730 mDNSPlatformMemZero(&sas
, sizeof sas
);
732 ConvertDomainNameToCString(answer
->name
, fullname
);
734 if (addRecord
== QC_suppressed
|| answer
->RecordType
== kDNSRecordTypePacketNegative
)
736 err
= mStatus_NoSuchRecord
;
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
)
744 LogMsg("DNSServiceGetAddrInfoResponse: response of class %d received, which is bogus", answer
->rrclass
);
746 if (x
->a
.ThisQInterval
>= 0)
748 sin
->sin_family
= AF_INET
;
749 #ifndef NOT_HAVE_SA_LEN
750 sin
->sin_len
= sizeof *sin
;
752 x
->callback((DNSServiceRef
)x
, 0, x
->interfaceIndex
, kDNSServiceErr_Invalid
, fullname
,
753 (const struct sockaddr
*)&sas
, 0, x
->context
);
755 if (x
->aaaa
.ThisQInterval
>= 0)
757 sin6
->sin6_family
= AF_INET6
;
758 #ifndef NOT_HAVE_SA_LEN
759 sin6
->sin6_len
= sizeof *sin6
;
761 x
->callback((DNSServiceRef
)x
, 0, x
->interfaceIndex
, kDNSServiceErr_Invalid
, fullname
,
762 (const struct sockaddr
*)&sas
, 0, x
->context
);
766 else if (answer
->rrtype
== kDNSServiceType_A
)
768 sin
->sin_family
= AF_INET
;
769 #ifndef NOT_HAVE_SA_LEN
770 sin
->sin_len
= sizeof *sin
;
772 sa_ap
= &sin
->sin_addr
;
773 sa_as
= sizeof sin
->sin_addr
.s_addr
;
775 else if (answer
->rrtype
== kDNSServiceType_AAAA
)
777 sin6
->sin6_family
= AF_INET6
;
778 #ifndef NOT_HAVE_SA_LEN
779 sin6
->sin6_len
= sizeof *sin6
;
781 sa_ap
= &sin6
->sin6_addr
;
782 sa_as
= sizeof sin6
->sin6_addr
.s6_addr
;
786 LogMsg("DNSServiceGetAddrInfoResponse: response of type %d received, which is bogus", answer
->rrtype
);
787 goto totally_invalid
;
790 if (err
== kDNSServiceErr_NoError
&& sa_ap
!= mDNSNULL
)
792 if (err
== mStatus_NoError
)
794 if (answer
->rdlength
== sa_as
)
796 mDNSPlatformMemCopy(sa_ap
, answer
->rdata
->u
.data
, answer
->rdlength
);
800 LogMsg("DNSServiceGetAddrInfoResponse: %s rrtype with length %d received",
801 answer
->rrtype
== kDNSServiceType_A
? "A" : "AAAA", answer
->rdlength
);
802 goto totally_invalid
;
807 x
->callback((DNSServiceRef
)x
, addRecord
? kDNSServiceFlagsAdd
: (DNSServiceFlags
)0, x
->interfaceIndex
, err
,
808 fullname
, (const struct sockaddr
*)&sas
, answer
->rroriginalttl
, x
->context
);
811 DNSServiceErrorType DNSSD_API
DNSServiceGetAddrInfo(
812 DNSServiceRef
*outRef
,
813 DNSServiceFlags inFlags
,
814 uint32_t inInterfaceIndex
,
815 DNSServiceProtocol inProtocol
,
816 const char *inHostName
,
817 DNSServiceGetAddrInfoReply inCallback
,
820 const char *errormsg
= "Unknown";
821 DNSServiceErrorType err
;
822 mDNS_DirectOP_GetAddrInfo
*x
;
824 // Allocate memory, and handle failure
825 x
= (mDNS_DirectOP_GetAddrInfo
*) mDNSPlatformMemAllocateClear(sizeof(*x
));
826 if (!x
) { err
= mStatus_NoMemoryErr
; errormsg
= "No memory"; goto fail
; }
829 x
->disposefn
= DNSServiceGetAddrInfoDispose
;
830 x
->callback
= inCallback
;
831 x
->context
= inContext
;
832 x
->interfaceIndex
= inInterfaceIndex
;
834 // Validate and default the protocols.
835 if ((inProtocol
& ~(kDNSServiceProtocol_IPv4
| kDNSServiceProtocol_IPv6
)) != 0)
837 err
= mStatus_BadParamErr
;
838 errormsg
= "Unsupported protocol";
841 // In theory this API checks to see if we have a routable IPv6 address, but
842 if ((inProtocol
& (kDNSServiceProtocol_IPv4
| kDNSServiceProtocol_IPv6
)) == 0)
844 inProtocol
= kDNSServiceProtocol_IPv4
| kDNSServiceProtocol_IPv6
;
845 inFlags
|= kDNSServiceFlagsSuppressUnusable
;
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;
863 x
->a
.ProxyQuestion
= 0;
864 x
->a
.pid
= mDNSPlatformGetPID();
865 x
->a
.QuestionCallback
= DNSServiceGetAddrInfoResponse
;
866 x
->a
.QuestionContext
= x
;
869 x
->aaaa
.qtype
= kDNSType_AAAA
;
871 if (inProtocol
& kDNSServiceProtocol_IPv4
)
873 err
= mDNS_StartQuery(&mDNSStorage
, &x
->a
);
874 if (err
) { DNSServiceResolveDispose((mDNS_DirectOP
*)x
); errormsg
= "mDNS_StartQuery"; goto fail
; }
876 if (inProtocol
& kDNSServiceProtocol_IPv6
)
878 err
= mDNS_StartQuery(&mDNSStorage
, &x
->aaaa
);
879 if (err
) { DNSServiceResolveDispose((mDNS_DirectOP
*)x
); errormsg
= "mDNS_StartQuery"; goto fail
; }
882 *outRef
= (DNSServiceRef
)x
;
883 return(mStatus_NoError
);
886 LogMsg("DNSServiceGetAddrInfo(\"%s\", %d) failed: %s (%ld)", inHostName
, inProtocol
, errormsg
, err
);
890 //*************************************************************************************************************
891 // DNSServiceReconfirmRecord
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
898 DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
900 DNSServiceFlags flags
,
901 uint32_t interfaceIndex
,
902 const char *fullname
,
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
);
919 #endif // !MDNS_BUILDINGSTUBLIBRARY
924 // c-file-style: "bsd"
927 // indent-tabs-mode: nil