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