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