1/* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002 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
18// Suppress "warning: 'DNSServiceDiscoveryMachPort' is deprecated" messages -- we already know this code is building the deprecated API
19// Since we compile with all warnings treated as errors, we have to turn off the warnings here or the project won't compile
20#include <AvailabilityMacros.h>
21#undef AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED
22#define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED
23#undef AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3
24#define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3
25
26#include "../mDNSMacOSX/DNSServiceDiscovery.h"
27#include "DNSServiceDiscoveryDefines.h"
28#include "DNSServiceDiscoveryReplyServer.h"
29
30#include <stdlib.h>
31#include <stdio.h>
32#include <servers/bootstrap.h>
33#include <mach/mach.h>
34#include <mach/mach_error.h>
35#include <pthread.h>
36
37#include <netinet/in.h>
38
39extern boolean_t DNSServiceDiscoveryReply_server(
40    mach_msg_header_t *InHeadP,
41    mach_msg_header_t *OutHeadP);
42
43extern
44kern_return_t DNSServiceBrowserCreate_rpc
45(
46    mach_port_t server,
47    mach_port_t client,
48    DNSCString regtype,
49    DNSCString domain
50);
51
52extern
53kern_return_t DNSServiceDomainEnumerationCreate_rpc
54(
55    mach_port_t server,
56    mach_port_t client,
57    int registrationDomains
58);
59
60extern
61kern_return_t DNSServiceRegistrationCreate_rpc
62(
63    mach_port_t server,
64    mach_port_t client,
65    DNSCString name,
66    DNSCString regtype,
67    DNSCString domain,
68    IPPort port,
69    DNSCString txtRecord
70);
71
72extern
73kern_return_t DNSServiceResolverResolve_rpc
74(
75    mach_port_t server,
76    mach_port_t client,
77    DNSCString name,
78    DNSCString regtype,
79    DNSCString domain
80);
81
82extern
83kern_return_t DNSServiceRegistrationAddRecord_rpc
84(
85    mach_port_t server,
86    mach_port_t client,
87    int type,
88    record_data_t data,
89    mach_msg_type_number_t record_dataCnt,
90    uint32_t ttl,
91    natural_t *reference
92);
93
94extern
95int DNSServiceRegistrationUpdateRecord_rpc
96(
97    mach_port_t server,
98    mach_port_t client,
99    natural_t reference,
100    record_data_t data,
101    mach_msg_type_number_t record_dataCnt,
102    uint32_t ttl
103);
104
105extern
106kern_return_t DNSServiceRegistrationRemoveRecord_rpc
107(
108    mach_port_t server,
109    mach_port_t client,
110    natural_t reference
111);
112
113struct a_requests {
114    struct a_requests       *next;
115    mach_port_t client_port;
116    union {
117        DNSServiceBrowserReply browserCallback;
118        DNSServiceDomainEnumerationReply enumCallback;
119        DNSServiceRegistrationReply regCallback;
120        DNSServiceResolverReply resolveCallback;
121    } callout;
122    void                    *context;
123};
124
125static struct a_requests    *a_requests = NULL;
126static pthread_mutex_t a_requests_lock = PTHREAD_MUTEX_INITIALIZER;
127
128typedef struct _dns_service_discovery_t {
129    mach_port_t port;
130} dns_service_discovery_t;
131
132static mach_port_t DNSServiceDiscoveryLookupServer(void)
133{
134    static mach_port_t sndPort  = MACH_PORT_NULL;
135    kern_return_t result;
136
137    if (sndPort != MACH_PORT_NULL) {
138        return sndPort;
139    }
140
141    result = bootstrap_look_up(bootstrap_port, DNS_SERVICE_DISCOVERY_SERVER, &sndPort);
142    if (result != KERN_SUCCESS) {
143        printf("%s(): {%s:%d} bootstrap_look_up() failed: $%x\n", __FUNCTION__, __FILE__, __LINE__, (int) result);
144        sndPort = MACH_PORT_NULL;
145    }
146
147
148    return sndPort;
149}
150
151static void _increaseQueueLengthOnPort(mach_port_t port)
152{
153    mach_port_limits_t qlimits;
154    kern_return_t result;
155
156    qlimits.mpl_qlimit = 16;
157    result = mach_port_set_attributes(mach_task_self(), port, MACH_PORT_LIMITS_INFO, (mach_port_info_t)&qlimits, MACH_PORT_LIMITS_INFO_COUNT);
158
159    if (result != KERN_SUCCESS) {
160        printf("%s(): {%s:%d} mach_port_set_attributes() failed: $%x %s\n", __FUNCTION__, __FILE__, __LINE__, (int) result, mach_error_string(result));
161    }
162}
163
164dns_service_discovery_ref DNSServiceBrowserCreate (const char *regtype, const char *domain, DNSServiceBrowserReply callBack,void *context)
165{
166    mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
167    mach_port_t clientPort;
168    kern_return_t result;
169    dns_service_discovery_ref return_t;
170    struct a_requests   *request;
171
172    if (!serverPort) {
173        return NULL;
174    }
175
176    result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort);
177    if (result != KERN_SUCCESS) {
178        printf("Mach port receive creation failed, %s\n", mach_error_string(result));
179        return NULL;
180    }
181    result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND);
182    if (result != KERN_SUCCESS) {
183        printf("Mach port send creation failed, %s\n", mach_error_string(result));
184        mach_port_destroy(mach_task_self(), clientPort);
185        return NULL;
186    }
187    _increaseQueueLengthOnPort(clientPort);
188
189    return_t = malloc(sizeof(dns_service_discovery_t));
190    return_t->port = clientPort;
191
192    request = malloc(sizeof(struct a_requests));
193    request->client_port = clientPort;
194    request->context = context;
195    request->callout.browserCallback = callBack;
196
197    result = DNSServiceBrowserCreate_rpc(serverPort, clientPort, (char *)regtype, (char *)domain);
198
199    if (result != KERN_SUCCESS) {
200        printf("There was an error creating a browser, %s\n", mach_error_string(result));
201        free(request);
202        return NULL;
203    }
204
205    pthread_mutex_lock(&a_requests_lock);
206    request->next = a_requests;
207    a_requests = request;
208    pthread_mutex_unlock(&a_requests_lock);
209
210    return return_t;
211}
212
213/* Service Enumeration */
214
215dns_service_discovery_ref DNSServiceDomainEnumerationCreate (int registrationDomains, DNSServiceDomainEnumerationReply callBack, void *context)
216{
217    mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
218    mach_port_t clientPort;
219    kern_return_t result;
220    dns_service_discovery_ref return_t;
221    struct a_requests   *request;
222
223    if (!serverPort) {
224        return NULL;
225    }
226
227    result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort);
228    if (result != KERN_SUCCESS) {
229        printf("Mach port receive creation failed, %s\n", mach_error_string(result));
230        return NULL;
231    }
232    result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND);
233    if (result != KERN_SUCCESS) {
234        printf("Mach port send creation failed, %s\n", mach_error_string(result));
235        mach_port_destroy(mach_task_self(), clientPort);
236        return NULL;
237    }
238    _increaseQueueLengthOnPort(clientPort);
239
240    return_t = malloc(sizeof(dns_service_discovery_t));
241    return_t->port = clientPort;
242
243    request = malloc(sizeof(struct a_requests));
244    request->client_port = clientPort;
245    request->context = context;
246    request->callout.enumCallback = callBack;
247
248    result = DNSServiceDomainEnumerationCreate_rpc(serverPort, clientPort, registrationDomains);
249
250    if (result != KERN_SUCCESS) {
251        printf("There was an error creating an enumerator, %s\n", mach_error_string(result));
252        free(request);
253        return NULL;
254    }
255
256    pthread_mutex_lock(&a_requests_lock);
257    request->next = a_requests;
258    a_requests = request;
259    pthread_mutex_unlock(&a_requests_lock);
260
261    return return_t;
262}
263
264
265/* Service Registration */
266
267dns_service_discovery_ref DNSServiceRegistrationCreate
268    (const char *name, const char *regtype, const char *domain, uint16_t port, const char *txtRecord, DNSServiceRegistrationReply callBack, void *context)
269{
270    mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
271    mach_port_t clientPort;
272    kern_return_t result;
273    dns_service_discovery_ref return_t;
274    struct a_requests   *request;
275    IPPort IpPort;
276    char *portptr = (char *)&port;
277
278    if (!serverPort) {
279        return NULL;
280    }
281
282    if (!txtRecord) {
283        txtRecord = "";
284    }
285
286    result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort);
287    if (result != KERN_SUCCESS) {
288        printf("Mach port receive creation failed, %s\n", mach_error_string(result));
289        return NULL;
290    }
291    result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND);
292    if (result != KERN_SUCCESS) {
293        printf("Mach port send creation failed, %s\n", mach_error_string(result));
294        mach_port_destroy(mach_task_self(), clientPort);
295        return NULL;
296    }
297    _increaseQueueLengthOnPort(clientPort);
298
299    return_t = malloc(sizeof(dns_service_discovery_t));
300    return_t->port = clientPort;
301
302    request = malloc(sizeof(struct a_requests));
303    request->client_port = clientPort;
304    request->context = context;
305    request->callout.regCallback = callBack;
306
307    // older versions of this code passed the port via mach IPC as an int.
308    // we continue to pass it as 4 bytes to maintain binary compatibility,
309    // but now ensure that the network byte order is preserved by using a struct
310    IpPort.bytes[0] = 0;
311    IpPort.bytes[1] = 0;
312    IpPort.bytes[2] = portptr[0];
313    IpPort.bytes[3] = portptr[1];
314
315    result = DNSServiceRegistrationCreate_rpc(serverPort, clientPort, (char *)name, (char *)regtype, (char *)domain, IpPort, (char *)txtRecord);
316
317    if (result != KERN_SUCCESS) {
318        printf("There was an error creating a resolve, %s\n", mach_error_string(result));
319        free(request);
320        return NULL;
321    }
322
323    pthread_mutex_lock(&a_requests_lock);
324    request->next = a_requests;
325    a_requests = request;
326    pthread_mutex_unlock(&a_requests_lock);
327
328    return return_t;
329}
330
331/* Resolver requests */
332
333dns_service_discovery_ref DNSServiceResolverResolve(const char *name, const char *regtype, const char *domain, DNSServiceResolverReply callBack, void *context)
334{
335    mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
336    mach_port_t clientPort;
337    kern_return_t result;
338    dns_service_discovery_ref return_t;
339    struct a_requests   *request;
340
341    if (!serverPort) {
342        return NULL;
343    }
344
345    result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort);
346    if (result != KERN_SUCCESS) {
347        printf("Mach port receive creation failed, %s\n", mach_error_string(result));
348        return NULL;
349    }
350    result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND);
351    if (result != KERN_SUCCESS) {
352        printf("Mach port send creation failed, %s\n", mach_error_string(result));
353        mach_port_destroy(mach_task_self(), clientPort);
354        return NULL;
355    }
356    _increaseQueueLengthOnPort(clientPort);
357
358    return_t = malloc(sizeof(dns_service_discovery_t));
359    return_t->port = clientPort;
360
361    request = malloc(sizeof(struct a_requests));
362    request->client_port = clientPort;
363    request->context = context;
364    request->callout.resolveCallback = callBack;
365
366    DNSServiceResolverResolve_rpc(serverPort, clientPort, (char *)name, (char *)regtype, (char *)domain);
367
368    pthread_mutex_lock(&a_requests_lock);
369    request->next = a_requests;
370    a_requests = request;
371    pthread_mutex_unlock(&a_requests_lock);
372
373    return return_t;
374}
375
376DNSRecordReference DNSServiceRegistrationAddRecord(dns_service_discovery_ref ref, uint16_t rrtype, uint16_t rdlen, const char *rdata, uint32_t ttl)
377{
378    mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
379    mach_port_t clientPort;
380    natural_t reference = 0;
381    kern_return_t result = KERN_SUCCESS;
382
383    if (!serverPort) {
384        return kDNSServiceDiscoveryUnknownErr;
385    }
386
387    clientPort = DNSServiceDiscoveryMachPort(ref);
388
389    if (!clientPort) {
390        return kDNSServiceDiscoveryUnknownErr;
391    }
392
393    result = DNSServiceRegistrationAddRecord_rpc(serverPort, clientPort, rrtype, (record_data_t)rdata, rdlen, ttl, &reference);
394
395    if (result != KERN_SUCCESS) {
396        printf("The result of the registration was not successful.  Error %d, result %s\n", result, mach_error_string(result));
397    }
398
399    return reference;
400}
401
402DNSServiceRegistrationReplyErrorType DNSServiceRegistrationUpdateRecord(dns_service_discovery_ref ref, DNSRecordReference reference, uint16_t rdlen, const char *rdata, uint32_t ttl)
403{
404    mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
405    mach_port_t clientPort;
406    kern_return_t result = KERN_SUCCESS;
407
408    if (!serverPort) {
409        return kDNSServiceDiscoveryUnknownErr;
410    }
411
412    clientPort = DNSServiceDiscoveryMachPort(ref);
413
414    if (!clientPort) {
415        return kDNSServiceDiscoveryUnknownErr;
416    }
417
418    result = DNSServiceRegistrationUpdateRecord_rpc(serverPort, clientPort, (natural_t)reference, (record_data_t)rdata, rdlen, ttl);
419    if (result != KERN_SUCCESS) {
420        printf("The result of the registration was not successful.  Error %d, result %s\n", result, mach_error_string(result));
421        return result;
422    }
423
424    return kDNSServiceDiscoveryNoError;
425}
426
427
428DNSServiceRegistrationReplyErrorType DNSServiceRegistrationRemoveRecord(dns_service_discovery_ref ref, DNSRecordReference reference)
429{
430    mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
431    mach_port_t clientPort;
432    kern_return_t result = KERN_SUCCESS;
433
434    if (!serverPort) {
435        return kDNSServiceDiscoveryUnknownErr;
436    }
437
438    clientPort = DNSServiceDiscoveryMachPort(ref);
439
440    if (!clientPort) {
441        return kDNSServiceDiscoveryUnknownErr;
442    }
443
444    result = DNSServiceRegistrationRemoveRecord_rpc(serverPort, clientPort, (natural_t)reference);
445
446    if (result != KERN_SUCCESS) {
447        printf("The result of the registration was not successful.  Error %d, result %s\n", result, mach_error_string(result));
448        return result;
449    }
450
451    return kDNSServiceDiscoveryNoError;
452}
453
454void DNSServiceDiscovery_handleReply(void *replyMsg)
455{
456    unsigned long result = 0xFFFFFFFF;
457    mach_msg_header_t *     msgSendBufPtr;
458    mach_msg_header_t *     receivedMessage;
459    unsigned msgSendBufLength;
460
461    msgSendBufLength = internal_DNSServiceDiscoveryReply_subsystem.maxsize;
462    msgSendBufPtr = (mach_msg_header_t *) malloc(msgSendBufLength);
463
464
465    receivedMessage = ( mach_msg_header_t * ) replyMsg;
466
467    // Call DNSServiceDiscoveryReply_server to change mig-generated message into a
468    // genuine mach message. It will then cause the callback to get called.
469    result = DNSServiceDiscoveryReply_server ( receivedMessage, msgSendBufPtr );
470    ( void ) mach_msg_send ( msgSendBufPtr );
471    free(msgSendBufPtr);
472}
473
474mach_port_t DNSServiceDiscoveryMachPort(dns_service_discovery_ref dnsServiceDiscovery)
475{
476    return dnsServiceDiscovery->port;
477}
478
479void DNSServiceDiscoveryDeallocate(dns_service_discovery_ref dnsServiceDiscovery)
480{
481    struct a_requests   *request0, *request;
482    mach_port_t reply = dnsServiceDiscovery->port;
483
484    if (dnsServiceDiscovery->port) {
485        pthread_mutex_lock(&a_requests_lock);
486        request0 = NULL;
487        request  = a_requests;
488        while (request) {
489            if (request->client_port == reply) {
490                /* request info found, remove from list */
491                if (request0) {
492                    request0->next = request->next;
493                } else {
494                    a_requests = request->next;
495                }
496                break;
497            } else {
498                /* not info for this request, skip to next */
499                request0 = request;
500                request  = request->next;
501            }
502
503        }
504        pthread_mutex_unlock(&a_requests_lock);
505
506        free(request);
507
508        mach_port_destroy(mach_task_self(), dnsServiceDiscovery->port);
509
510        free(dnsServiceDiscovery);
511    }
512    return;
513}
514
515// reply functions, calls the users setup callbacks with function pointers
516
517kern_return_t internal_DNSServiceDomainEnumerationReply_rpc
518(
519    mach_port_t reply,
520    int resultType,
521    DNSCString replyDomain,
522    int flags
523)
524{
525    struct a_requests   *request;
526    void *requestContext = NULL;
527    DNSServiceDomainEnumerationReply callback = NULL;
528
529    pthread_mutex_lock(&a_requests_lock);
530    request  = a_requests;
531    while (request) {
532        if (request->client_port == reply) {
533            break;
534        }
535        request = request->next;
536    }
537
538    if (request != NULL) {
539        callback = (*request->callout.enumCallback);
540        requestContext = request->context;
541    }
542    pthread_mutex_unlock(&a_requests_lock);
543
544    if (request != NULL) {
545        (callback)(resultType, replyDomain, flags, requestContext);
546    }
547
548    return KERN_SUCCESS;
549
550}
551
552kern_return_t internal_DNSServiceBrowserReply_rpc
553(
554    mach_port_t reply,
555    int resultType,
556    DNSCString replyName,
557    DNSCString replyType,
558    DNSCString replyDomain,
559    int flags
560)
561{
562    struct a_requests   *request;
563    void *requestContext = NULL;
564    DNSServiceBrowserReply callback = NULL;
565
566    pthread_mutex_lock(&a_requests_lock);
567    request  = a_requests;
568    while (request) {
569        if (request->client_port == reply) {
570            break;
571        }
572        request = request->next;
573    }
574    if (request != NULL) {
575        callback = (*request->callout.browserCallback);
576        requestContext = request->context;
577    }
578
579    pthread_mutex_unlock(&a_requests_lock);
580
581    if (request != NULL) {
582        (callback)(resultType, replyName, replyType, replyDomain, flags, requestContext);
583    }
584
585    return KERN_SUCCESS;
586}
587
588
589kern_return_t internal_DNSServiceRegistrationReply_rpc
590(
591    mach_port_t reply,
592    int resultType
593)
594{
595    struct a_requests   *request;
596    void *requestContext = NULL;
597    DNSServiceRegistrationReply callback = NULL;
598
599    pthread_mutex_lock(&a_requests_lock);
600    request  = a_requests;
601    while (request) {
602        if (request->client_port == reply) {
603            break;
604        }
605        request = request->next;
606    }
607    if (request != NULL) {
608        callback = (*request->callout.regCallback);
609        requestContext = request->context;
610    }
611
612    pthread_mutex_unlock(&a_requests_lock);
613    if (request != NULL) {
614        (callback)(resultType, requestContext);
615    }
616    return KERN_SUCCESS;
617}
618
619
620kern_return_t internal_DNSServiceResolverReply_rpc
621(
622    mach_port_t reply,
623    sockaddr_t interface,
624    sockaddr_t address,
625    DNSCString txtRecord,
626    int flags
627)
628{
629    struct sockaddr  *interface_storage = NULL;
630    struct sockaddr  *address_storage = NULL;
631    struct a_requests   *request;
632    void *requestContext = NULL;
633    DNSServiceResolverReply callback = NULL;
634
635    if (interface) {
636        int len = ((struct sockaddr *)interface)->sa_len;
637        interface_storage = (struct sockaddr *)malloc(len);
638        memcpy(interface_storage, interface, len);
639    }
640
641    if (address) {
642        int len = ((struct sockaddr *)address)->sa_len;
643        address_storage = (struct sockaddr *)malloc(len);
644        memcpy(address_storage, address, len);
645    }
646
647    pthread_mutex_lock(&a_requests_lock);
648    request  = a_requests;
649    while (request) {
650        if (request->client_port == reply) {
651            break;
652        }
653        request = request->next;
654    }
655
656    if (request != NULL) {
657        callback = (*request->callout.resolveCallback);
658        requestContext = request->context;
659    }
660    pthread_mutex_unlock(&a_requests_lock);
661
662    if (request != NULL) {
663        (callback)(interface_storage, address_storage, txtRecord, flags, requestContext);
664    }
665
666    if (interface) {
667        free(interface_storage);
668    }
669    if (address) {
670        free(address_storage);
671    }
672
673    return KERN_SUCCESS;
674}
675