source: rtems-libbsd/rtemsbsd/mdns/mdns.c @ 7ba9b7f

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 7ba9b7f was 7ba9b7f, checked in by Sebastian Huber <sebastian.huber@…>, on 11/03/14 at 14:53:46

Add mDNS support for name service dispatcher

  • Property mode set to 100644
File size: 7.3 KB
Line 
1/*
2 * Copyright (c) 2014 embedded brains GmbH.  All rights reserved.
3 *
4 *  embedded brains GmbH
5 *  Dornierstr. 4
6 *  82178 Puchheim
7 *  Germany
8 *  <rtems@embedded-brains.de>
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <mDNSEmbeddedAPI.h>
33#include <mDNSPosix.h>
34
35#include <sys/select.h>
36#include <sys/socket.h>
37#include <sys/stat.h>
38
39#include <netinet/in.h>
40#include <arpa/inet.h>
41#include <arpa/nameser.h>
42
43#include <assert.h>
44#include <errno.h>
45#include <fcntl.h>
46#include <netdb.h>
47#include <nsswitch.h>
48#include <stdbool.h>
49#include <stdio.h>
50#include <stdlib.h>
51#include <string.h>
52#include <unistd.h>
53
54#include <rtems/bsd/util.h>
55#include <rtems/mdns.h>
56
57static rtems_id daemon_id;
58
59static mDNS mDNSStorage;
60
61static mDNS_PlatformSupport PlatformStorage;
62
63typedef struct {
64        mDNSu16 rrtype;
65        struct hostent *he;
66        rtems_id task_id;
67} query_context;
68
69static void
70query_callback(mDNS *m, DNSQuestion *q, const ResourceRecord *answer,
71    QC_result add_record)
72{
73        query_context *ctx = q->QuestionContext;
74        struct hostent *he = ctx->he;
75        bool stop = false;
76        rtems_id task_id = ctx->task_id;
77
78        (void)m;
79        (void)add_record;
80
81        if (ctx->rrtype == kDNSType_A && answer->rrtype == kDNSType_A) {
82                const mDNSv4Addr *ipv4 = &answer->rdata->u.ipv4;
83
84                memcpy(he->h_addr_list[0], ipv4, sizeof(*ipv4));
85                stop = true;
86        } else if (ctx->rrtype == kDNSType_AAAA
87            && answer->rrtype == kDNSType_AAAA) {
88                const mDNSv6Addr *ipv6 = &answer->rdata->u.ipv6;
89
90                memcpy(he->h_addr_list[0], ipv6, sizeof(*ipv6));
91                stop = true;
92        }
93
94        if (stop && task_id != 0) {
95                rtems_status_code sc;
96
97                ctx->task_id = 0;
98
99                sc = rtems_event_transient_send(task_id);
100                assert(sc == RTEMS_SUCCESSFUL);
101        }
102}
103
104static bool is_local_name(const char *name)
105{
106        size_t len = strlen(name);
107        const char local[] = "local";
108        size_t locallen = sizeof(local) - 1;
109
110        if (len == 0) {
111                return (false);
112        }
113
114        if (name[len - 1] == '.') {
115                --len;
116        }
117
118        if (len < locallen) {
119                return (false);
120        }
121
122        return strncasecmp(name + len - locallen, &local[0], locallen) == 0;
123}
124
125static int
126mdns_gethostbyname(void *rval, void *cb_data, va_list ap)
127{
128        const char *name;
129        int af;
130        char *buffer;
131        size_t buflen;
132        size_t len;
133        size_t namelen;
134        int *errnop;
135        int *h_errnop;
136        struct hostent *hep;
137        struct hostent **resultp;
138        DNSQuestion q;
139        query_context ctx;
140        mDNSu8 *qname;
141        rtems_status_code sc;
142
143        memset(&q, 0, sizeof(q));
144        memset(&ctx, 0, sizeof(ctx));
145
146        name = va_arg(ap, const char *);
147        af = va_arg(ap, int);
148        hep = va_arg(ap, struct hostent *);
149        buffer = va_arg(ap, char *);
150        buflen = va_arg(ap, size_t);
151        errnop = va_arg(ap, int *);
152        h_errnop = va_arg(ap, int *);
153        resultp = (struct hostent **)rval;
154
155        *resultp = NULL;
156
157        if (!is_local_name(name)) {
158                *h_errnop = NETDB_INTERNAL;
159                *errnop = EINVAL;
160                return (NS_NOTFOUND);
161        }
162
163        hep->h_addrtype = af;
164        switch (af) {
165        case AF_INET:
166                hep->h_length = NS_INADDRSZ;
167                ctx.rrtype = kDNSType_A;
168                break;
169        case AF_INET6:
170                hep->h_length = NS_IN6ADDRSZ;
171                ctx.rrtype = kDNSType_AAAA;
172                break;
173        default:
174                *h_errnop = NETDB_INTERNAL;
175                *errnop = EAFNOSUPPORT;
176                return (NS_UNAVAIL);
177        }
178
179        len = (char *)ALIGN(buffer) - buffer;
180        len += 3 * sizeof(char *);
181        len += ALIGN(hep->h_length);
182        namelen = strlen(name) + 1;
183        len += namelen;
184
185        if (len > buflen) {
186                *h_errnop = NETDB_INTERNAL;
187                *errnop = ERANGE;
188                return (NS_UNAVAIL);
189        }
190
191        buffer = (char *)ALIGN(buffer);
192
193        hep->h_aliases = (char **)buffer;
194        buffer += sizeof(char *);
195        hep->h_aliases[0] = NULL;
196
197        hep->h_addr_list = (char **)buffer;
198        buffer += 2 * sizeof(char *);
199        hep->h_addr_list[0] = buffer;
200        buffer += ALIGN(hep->h_length);
201        hep->h_addr_list[1] = NULL;
202
203        hep->h_name = buffer;
204        memcpy(buffer, name, namelen);
205
206        qname = MakeDomainNameFromDNSNameString(&q.qname, name);
207        if (qname == NULL) {
208                *h_errnop = NETDB_INTERNAL;
209                *errnop = ERANGE;
210                return (NS_UNAVAIL);
211        }
212
213        q.TargetPort = MulticastDNSPort;
214        q.qtype = kDNSQType_ANY;
215        q.qclass = kDNSClass_IN;
216        q.ForceMCast = mDNStrue;
217        q.ReturnIntermed = mDNStrue;
218        q.QuestionCallback = query_callback;
219        q.QuestionContext = &ctx;
220
221        ctx.rrtype = kDNSType_A;
222        ctx.he = hep;
223        ctx.task_id = rtems_task_self();
224
225        mDNS_StartQuery(&mDNSStorage, &q);
226        rtems_bsd_force_select_timeout(daemon_id);
227
228        sc = rtems_event_transient_receive(RTEMS_WAIT,
229            10 * rtems_clock_get_ticks_per_second());
230
231        mDNS_StopQuery(&mDNSStorage, &q);
232
233        if (sc != RTEMS_SUCCESSFUL) {
234                *h_errnop = NETDB_INTERNAL;
235                *errnop = ETIMEDOUT;
236                return (NS_NOTFOUND);
237        }
238
239        *resultp = hep;
240        return (NS_SUCCESS);
241}
242
243static ns_mtab mdns_mtab[] = {
244        {
245                .database = NSDB_HOSTS,
246                .name = "gethostbyname2_r",
247                .method = mdns_gethostbyname
248        }
249};
250
251static void
252mdns_daemon(rtems_task_argument arg)
253{
254        while (true) {
255                struct timeval timeout = { .tv_sec = 0x1, .tv_usec = 0 };
256                sigset_t signals;
257                mDNSBool got_something;
258
259                mDNSPosixRunEventLoopOnce(&mDNSStorage, &timeout, &signals,
260                    &got_something);
261        }
262}
263
264rtems_status_code
265rtems_mdns_initialize(rtems_task_priority daemon_priority,
266    CacheEntity *rrcachestorage, mDNSu32 rrcachesize)
267{
268        mStatus status;
269        int rv;
270        int fd;
271        rtems_status_code sc;
272
273        status = mDNS_Init(&mDNSStorage, &PlatformStorage, rrcachestorage,
274            rrcachesize, mDNS_Init_AdvertiseLocalAddresses,
275            mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
276        if (status != mStatus_NoError) {
277                return (RTEMS_UNSATISFIED);
278        }
279
280        sc = rtems_task_create(rtems_build_name('m', 'D', 'N', 'S'),
281            daemon_priority, 16 * 1024, RTEMS_DEFAULT_MODES,
282            RTEMS_DEFAULT_ATTRIBUTES, &daemon_id);
283        if (sc != RTEMS_SUCCESSFUL) {
284                return (RTEMS_UNSATISFIED);
285        }
286
287        sc = rtems_task_start(daemon_id, mdns_daemon, 0);
288        if (sc != RTEMS_SUCCESSFUL) {
289                return (RTEMS_UNSATISFIED);
290        }
291
292        rv = rtems_nss_register_module("mdns", &mdns_mtab[0],
293            RTEMS_ARRAY_SIZE(mdns_mtab));
294        if (rv != 0) {
295                return (RTEMS_UNSATISFIED);
296        }
297
298        fd = open(_PATH_NS_CONF, O_WRONLY | O_CREAT | O_EXCL,
299            S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
300        if (fd >= 0) {
301                static const char nsconf[] = "hosts: files mdns dns\n";
302                ssize_t n;
303
304                n = write(fd, &nsconf[0], sizeof(nsconf) - 1);
305
306                rv = close(fd);
307                assert(rv == 0);
308
309                if (n != (ssize_t) (sizeof(nsconf) - 1)) {
310                        return (RTEMS_UNSATISFIED);
311                }
312        }
313
314        return (RTEMS_SUCCESSFUL);
315}
316
317mDNS *
318rtems_mdns_get_instance(void)
319{
320        return (&mDNSStorage);
321}
Note: See TracBrowser for help on using the repository browser.