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
28extern mDNS mDNSStorage;        // We need to pass the address of this storage to the lower-layer functions
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
44typedef struct mDNS_DirectOP_struct mDNS_DirectOP;
45typedef void mDNS_DirectOP_Dispose (mDNS_DirectOP *op);
46struct mDNS_DirectOP_struct
47{
48    mDNS_DirectOP_Dispose  *disposefn;
49};
50
51typedef struct
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;
62
63typedef struct
64{
65    mDNS_DirectOP_Dispose  *disposefn;
66    DNSServiceBrowseReply callback;
67    void                   *context;
68    DNSQuestion q;
69} mDNS_DirectOP_Browse;
70
71typedef struct
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;
81
82typedef struct
83{
84    mDNS_DirectOP_Dispose      *disposefn;
85    DNSServiceQueryRecordReply callback;
86    void                       *context;
87    DNSQuestion q;
88} mDNS_DirectOP_QueryRecord;
89
90int DNSServiceRefSockFD(DNSServiceRef sdRef)
91{
92    (void)sdRef;    // Unused
93    return(0);
94}
95
96DNSServiceErrorType DNSServiceProcessResult(DNSServiceRef sdRef)
97{
98    (void)sdRef;    // Unused
99    return(kDNSServiceErr_NoError);
100}
101
102void DNSServiceRefDeallocate(DNSServiceRef sdRef)
103{
104    mDNS_DirectOP *op = (mDNS_DirectOP *)sdRef;
105    //LogMsg("DNSServiceRefDeallocate");
106    op->disposefn(op);
107}
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
117DNSServiceErrorType DNSServiceEnumerateDomains
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}
133#endif
134
135//*************************************************************************************************************
136// Register Service
137
138mDNSlocal void FreeDNSServiceRegistration(mDNS_DirectOP_Register *x)
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}
156
157static void DNSServiceRegisterDispose(mDNS_DirectOP *op)
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}
168
169mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus result)
170{
171    mDNS_DirectOP_Register *x = (mDNS_DirectOP_Register*)sr->ServiceContext;
172
173    domainlabel name;
174    domainname type, dom;
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];
178    if (!DeconstructServiceName(sr->RR_SRV.resrec.name, &name, &type, &dom)) return;
179    if (!ConvertDomainLabelToCString_unescaped(&name, namestr)) return;
180    if (!ConvertDomainNameToCString(&type, typestr)) return;
181    if (!ConvertDomainNameToCString(&dom, domstr)) return;
182
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}
206
207DNSServiceErrorType DNSServiceRegister
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);
273
274badparam:
275    err = mStatus_BadParamErr;
276fail:
277    LogMsg("DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", regtype, domain, errormsg, err);
278    return(err);
279}
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
289DNSServiceErrorType DNSServiceAddRecord
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}
309
310DNSServiceErrorType DNSServiceUpdateRecord
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}
328
329DNSServiceErrorType DNSServiceRemoveRecord
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}
341#endif
342
343//*************************************************************************************************************
344// Browse for services
345
346static void DNSServiceBrowseDispose(mDNS_DirectOP *op)
347{
348    mDNS_DirectOP_Browse *x = (mDNS_DirectOP_Browse*)op;
349    //LogMsg("DNSServiceBrowseDispose");
350    mDNS_StopBrowse(&mDNSStorage, &x->q);
351    mDNSPlatformMemFree(x);
352}
353
354mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
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}
381
382DNSServiceErrorType DNSServiceBrowse
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, mDNSNULL, 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);
421
422badparam:
423    err = mStatus_BadParamErr;
424fail:
425    LogMsg("DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", regtype, domain, errormsg, err);
426    return(err);
427}
428
429//*************************************************************************************************************
430// Resolve Service Info
431
432static void DNSServiceResolveDispose(mDNS_DirectOP *op)
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}
439
440mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
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}
463
464DNSServiceErrorType DNSServiceResolve
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.UseBackgroundTrafficClass = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
520    x->qSRV.ValidationRequired  = 0;
521    x->qSRV.ValidatingResponse  = 0;
522    x->qSRV.ProxyQuestion       = 0;
523    x->qSRV.qnameOrig           = mDNSNULL;
524    x->qSRV.AnonInfo            = mDNSNULL;
525    x->qSRV.pid                 = mDNSPlatformGetPID();
526    x->qSRV.QuestionCallback    = FoundServiceInfo;
527    x->qSRV.QuestionContext     = x;
528
529    x->qTXT.ThisQInterval       = -1;       // So that DNSServiceResolveDispose() knows whether to cancel this question
530    x->qTXT.InterfaceID         = mDNSInterface_Any;
531    x->qTXT.flags               = 0;
532    x->qTXT.Target              = zeroAddr;
533    AssignDomainName(&x->qTXT.qname, &srv);
534    x->qTXT.qtype               = kDNSType_TXT;
535    x->qTXT.qclass              = kDNSClass_IN;
536    x->qTXT.LongLived           = mDNSfalse;
537    x->qTXT.ExpectUnique        = mDNStrue;
538    x->qTXT.ForceMCast          = mDNSfalse;
539    x->qTXT.ReturnIntermed      = mDNSfalse;
540    x->qTXT.SuppressUnusable    = mDNSfalse;
541    x->qTXT.SearchListIndex     = 0;
542    x->qTXT.AppendSearchDomains = 0;
543    x->qTXT.RetryWithSearchDomains = mDNSfalse;
544    x->qTXT.TimeoutQuestion     = 0;
545    x->qTXT.WakeOnResolve       = 0;
546    x->qTXT.UseBackgroundTrafficClass = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
547    x->qTXT.ValidationRequired  = 0;
548    x->qTXT.ValidatingResponse  = 0;
549    x->qTXT.ProxyQuestion       = 0;
550    x->qTXT.qnameOrig           = mDNSNULL;
551    x->qTXT.AnonInfo            = mDNSNULL;
552    x->qTXT.pid                 = mDNSPlatformGetPID();
553    x->qTXT.QuestionCallback    = FoundServiceInfo;
554    x->qTXT.QuestionContext     = x;
555
556    err = mDNS_StartQuery(&mDNSStorage, &x->qSRV);
557    if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery qSRV"; goto fail; }
558    err = mDNS_StartQuery(&mDNSStorage, &x->qTXT);
559    if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery qTXT"; goto fail; }
560
561    // Succeeded: Wrap up and return
562    *sdRef = (DNSServiceRef)x;
563    return(mStatus_NoError);
564
565badparam:
566    err = mStatus_BadParamErr;
567fail:
568    LogMsg("DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%ld)", name, regtype, domain, errormsg, err);
569    return(err);
570}
571
572//*************************************************************************************************************
573// Connection-oriented calls
574
575// Not yet implemented, so don't include in stub library
576// We DO include it in the actual Extension, so that if a later client compiled to use this
577// is run against this Extension, it will get a reasonable error code instead of just
578// failing to launch (Strong Link) or calling an unresolved symbol and crashing (Weak Link)
579#if !MDNS_BUILDINGSTUBLIBRARY
580DNSServiceErrorType DNSServiceCreateConnection(DNSServiceRef *sdRef)
581{
582    (void)sdRef;    // Unused
583    return(kDNSServiceErr_Unsupported);
584}
585
586DNSServiceErrorType DNSServiceRegisterRecord
587(
588    DNSServiceRef sdRef,
589    DNSRecordRef                        *RecordRef,
590    DNSServiceFlags flags,
591    uint32_t interfaceIndex,
592    const char                          *fullname,
593    uint16_t rrtype,
594    uint16_t rrclass,
595    uint16_t rdlen,
596    const void                          *rdata,
597    uint32_t ttl,
598    DNSServiceRegisterRecordReply callback,
599    void                                *context    /* may be NULL */
600)
601{
602    (void)sdRef;            // Unused
603    (void)RecordRef;        // Unused
604    (void)flags;            // Unused
605    (void)interfaceIndex;   // Unused
606    (void)fullname;         // Unused
607    (void)rrtype;           // Unused
608    (void)rrclass;          // Unused
609    (void)rdlen;            // Unused
610    (void)rdata;            // Unused
611    (void)ttl;              // Unused
612    (void)callback;         // Unused
613    (void)context;          // Unused
614    return(kDNSServiceErr_Unsupported);
615}
616#endif
617
618//*************************************************************************************************************
619// DNSServiceQueryRecord
620
621static void DNSServiceQueryRecordDispose(mDNS_DirectOP *op)
622{
623    mDNS_DirectOP_QueryRecord *x = (mDNS_DirectOP_QueryRecord*)op;
624    if (x->q.ThisQInterval >= 0) mDNS_StopQuery(&mDNSStorage, &x->q);
625    mDNSPlatformMemFree(x);
626}
627
628mDNSlocal void DNSServiceQueryRecordResponse(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
629{
630    mDNS_DirectOP_QueryRecord *x = (mDNS_DirectOP_QueryRecord*)question->QuestionContext;
631    char fullname[MAX_ESCAPED_DOMAIN_NAME];
632    (void)m;    // Unused
633    ConvertDomainNameToCString(answer->name, fullname);
634    x->callback((DNSServiceRef)x, AddRecord ? kDNSServiceFlagsAdd : (DNSServiceFlags)0, 0, kDNSServiceErr_NoError,
635                fullname, answer->rrtype, answer->rrclass, answer->rdlength, answer->rdata->u.data, answer->rroriginalttl, x->context);
636}
637
638DNSServiceErrorType DNSServiceQueryRecord
639(
640    DNSServiceRef                       *sdRef,
641    DNSServiceFlags flags,
642    uint32_t interfaceIndex,
643    const char                          *fullname,
644    uint16_t rrtype,
645    uint16_t rrclass,
646    DNSServiceQueryRecordReply callback,
647    void                                *context  /* may be NULL */
648)
649{
650    mStatus err = mStatus_NoError;
651    const char *errormsg = "Unknown";
652    mDNS_DirectOP_QueryRecord *x;
653
654    (void)flags;            // Unused
655    (void)interfaceIndex;   // Unused
656
657    // Allocate memory, and handle failure
658    x = (mDNS_DirectOP_QueryRecord *)mDNSPlatformMemAllocate(sizeof(*x));
659    if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
660
661    // Set up object
662    x->disposefn = DNSServiceQueryRecordDispose;
663    x->callback  = callback;
664    x->context   = context;
665
666    x->q.ThisQInterval       = -1;      // So that DNSServiceResolveDispose() knows whether to cancel this question
667    x->q.InterfaceID         = mDNSInterface_Any;
668    x->q.flags               = flags;
669    x->q.Target              = zeroAddr;
670    MakeDomainNameFromDNSNameString(&x->q.qname, fullname);
671    x->q.qtype               = rrtype;
672    x->q.qclass              = rrclass;
673    x->q.LongLived           = (flags & kDNSServiceFlagsLongLivedQuery) != 0;
674    x->q.ExpectUnique        = mDNSfalse;
675    x->q.ForceMCast          = (flags & kDNSServiceFlagsForceMulticast) != 0;
676    x->q.ReturnIntermed      = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
677    x->q.SuppressUnsable     = (flags & kDNSServiceFlagsSuppressUnusable) != 0;
678    x->q.SearchListIndex     = 0;
679    x->q.AppendSearchDomains = 0;
680    x->q.RetryWithSearchDomains = mDNSfalse;
681    x->q.TimeoutQuestion     = 0;
682    x->q.WakeOnResolve       = 0;
683    x->q.UseBackgroundTrafficClass = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
684    x->q.ValidationRequired  = 0;
685    x->q.ValidatingResponse  = 0;
686    x->q.ProxyQuestion       = 0;
687    x->q.qnameOrig           = mDNSNULL;
688    x->q.AnonInfo            = mDNSNULL;
689    x->q.pid                 = mDNSPlatformGetPID();
690    x->q.QuestionCallback    = DNSServiceQueryRecordResponse;
691    x->q.QuestionContext     = x;
692
693    err = mDNS_StartQuery(&mDNSStorage, &x->q);
694    if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery"; goto fail; }
695
696    // Succeeded: Wrap up and return
697    *sdRef = (DNSServiceRef)x;
698    return(mStatus_NoError);
699
700fail:
701    LogMsg("DNSServiceQueryRecord(\"%s\", %d, %d) failed: %s (%ld)", fullname, rrtype, rrclass, errormsg, err);
702    return(err);
703}
704
705//*************************************************************************************************************
706// DNSServiceGetAddrInfo
707
708static void DNSServiceGetAddrInfoDispose(mDNS_DirectOP *op)
709{
710    mDNS_DirectOP_GetAddrInfo *x = (mDNS_DirectOP_GetAddrInfo*)op;
711    if (x->aQuery) DNSServiceRefDeallocate(x->aQuery);
712    mDNSPlatformMemFree(x);
713}
714
715static void DNSSD_API DNSServiceGetAddrInfoResponse(
716    DNSServiceRef inRef,
717    DNSServiceFlags inFlags,
718    uint32_t inInterfaceIndex,
719    DNSServiceErrorType inErrorCode,
720    const char *        inFullName,
721    uint16_t inRRType,
722    uint16_t inRRClass,
723    uint16_t inRDLen,
724    const void *        inRData,
725    uint32_t inTTL,
726    void *              inContext )
727{
728    mDNS_DirectOP_GetAddrInfo *     x = (mDNS_DirectOP_GetAddrInfo*)inContext;
729    struct sockaddr_in sa4;
730
731    mDNSPlatformMemZero(&sa4, sizeof(sa4));
732    if (inErrorCode == kDNSServiceErr_NoError && inRRType == kDNSServiceType_A)
733    {
734        sa4.sin_family = AF_INET;
735        mDNSPlatformMemCopy(&sa4.sin_addr.s_addr, inRData, 4);
736    }
737
738    x->callback((DNSServiceRef)x, inFlags, inInterfaceIndex, inErrorCode, inFullName,
739                (const struct sockaddr *) &sa4, inTTL, x->context);
740}
741
742DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo(
743    DNSServiceRef *             outRef,
744    DNSServiceFlags inFlags,
745    uint32_t inInterfaceIndex,
746    DNSServiceProtocol inProtocol,
747    const char *                inHostName,
748    DNSServiceGetAddrInfoReply inCallback,
749    void *                      inContext )
750{
751    const char *                    errormsg = "Unknown";
752    DNSServiceErrorType err;
753    mDNS_DirectOP_GetAddrInfo *     x;
754
755    // Allocate memory, and handle failure
756    x = (mDNS_DirectOP_GetAddrInfo *)mDNSPlatformMemAllocate(sizeof(*x));
757    if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
758
759    // Set up object
760    x->disposefn = DNSServiceGetAddrInfoDispose;
761    x->callback  = inCallback;
762    x->context   = inContext;
763    x->aQuery    = mDNSNULL;
764
765    // Start the query.
766    // (It would probably be more efficient to code this using mDNS_StartQuery directly,
767    // instead of wrapping DNSServiceQueryRecord, which then unnecessarily allocates
768    // more memory and then just calls through to mDNS_StartQuery. -- SC June 2010)
769    err = DNSServiceQueryRecord(&x->aQuery, inFlags, inInterfaceIndex, inHostName, kDNSServiceType_A,
770                                kDNSServiceClass_IN, DNSServiceGetAddrInfoResponse, x);
771    if (err) { DNSServiceGetAddrInfoDispose((mDNS_DirectOP*)x); errormsg = "DNSServiceQueryRecord"; goto fail; }
772
773    *outRef = (DNSServiceRef)x;
774    return(mStatus_NoError);
775
776fail:
777    LogMsg("DNSServiceGetAddrInfo(\"%s\", %d) failed: %s (%ld)", inHostName, inProtocol, errormsg, err);
778    return(err);
779}
780
781//*************************************************************************************************************
782// DNSServiceReconfirmRecord
783
784// Not yet implemented, so don't include in stub library
785// We DO include it in the actual Extension, so that if a later client compiled to use this
786// is run against this Extension, it will get a reasonable error code instead of just
787// failing to launch (Strong Link) or calling an unresolved symbol and crashing (Weak Link)
788#if !MDNS_BUILDINGSTUBLIBRARY
789DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
790(
791    DNSServiceFlags flags,
792    uint32_t interfaceIndex,
793    const char                         *fullname,
794    uint16_t rrtype,
795    uint16_t rrclass,
796    uint16_t rdlen,
797    const void                         *rdata
798)
799{
800    (void)flags;            // Unused
801    (void)interfaceIndex;   // Unused
802    (void)fullname;         // Unused
803    (void)rrtype;           // Unused
804    (void)rrclass;          // Unused
805    (void)rdlen;            // Unused
806    (void)rdata;            // Unused
807    return(kDNSServiceErr_Unsupported);
808}
809
810
811#endif  // !MDNS_BUILDINGSTUBLIBRARY
812