source: rtems-libbsd/rtemsbsd/mdns/mdns.c @ f0aaa04

55-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since f0aaa04 was 026abfb, checked in by Sebastian Huber <sebastian.huber@…>, on 11/10/14 at 07:27:32

Add rtems_mdns_gethostname()

  • Property mode set to 100644
File size: 8.2 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#include <DNSCommon.h>
35
36#include <sys/select.h>
37#include <sys/socket.h>
38#include <sys/stat.h>
39
40#include <netinet/in.h>
41#include <arpa/inet.h>
42#include <arpa/nameser.h>
43
44#include <assert.h>
45#include <errno.h>
46#include <fcntl.h>
47#include <netdb.h>
48#include <nsswitch.h>
49#include <stdbool.h>
50#include <stdio.h>
51#include <stdlib.h>
52#include <string.h>
53#include <unistd.h>
54
55#include <rtems/bsd/util.h>
56#include <rtems/mdns.h>
57
58static rtems_id mdns_daemon_id;
59
60static mDNS mDNSStorage;
61
62static mDNS_PlatformSupport PlatformStorage;
63
64typedef struct {
65        mDNSu16 rrtype;
66        struct hostent *he;
67        rtems_id task_id;
68} query_context;
69
70static void
71query_callback(mDNS *m, DNSQuestion *q, const ResourceRecord *answer,
72    QC_result add_record)
73{
74        query_context *ctx = q->QuestionContext;
75        struct hostent *he = ctx->he;
76        bool stop = false;
77        rtems_id task_id = ctx->task_id;
78
79        (void)m;
80        (void)add_record;
81
82        if (ctx->rrtype == kDNSType_A && answer->rrtype == kDNSType_A) {
83                const mDNSv4Addr *ipv4 = &answer->rdata->u.ipv4;
84
85                memcpy(he->h_addr_list[0], ipv4, sizeof(*ipv4));
86                stop = true;
87        } else if (ctx->rrtype == kDNSType_AAAA
88            && answer->rrtype == kDNSType_AAAA) {
89                const mDNSv6Addr *ipv6 = &answer->rdata->u.ipv6;
90
91                memcpy(he->h_addr_list[0], ipv6, sizeof(*ipv6));
92                stop = true;
93        }
94
95        if (stop && task_id != 0) {
96                rtems_status_code sc;
97
98                ctx->task_id = 0;
99
100                sc = rtems_event_transient_send(task_id);
101                assert(sc == RTEMS_SUCCESSFUL);
102        }
103}
104
105static bool is_local_name(const char *name)
106{
107        size_t len = strlen(name);
108        const char local[] = "local";
109        size_t locallen = sizeof(local) - 1;
110
111        if (len == 0) {
112                return (false);
113        }
114
115        if (name[len - 1] == '.') {
116                --len;
117        }
118
119        if (len < locallen) {
120                return (false);
121        }
122
123        return strncasecmp(name + len - locallen, &local[0], locallen) == 0;
124}
125
126static int
127mdns_gethostbyname(void *rval, void *cb_data, va_list ap)
128{
129        const char *name;
130        int af;
131        char *buffer;
132        size_t buflen;
133        size_t len;
134        size_t namelen;
135        int *errnop;
136        int *h_errnop;
137        struct hostent *hep;
138        struct hostent **resultp;
139        DNSQuestion q;
140        query_context ctx;
141        mDNSu8 *qname;
142        rtems_status_code sc;
143
144        memset(&q, 0, sizeof(q));
145        memset(&ctx, 0, sizeof(ctx));
146
147        name = va_arg(ap, const char *);
148        af = va_arg(ap, int);
149        hep = va_arg(ap, struct hostent *);
150        buffer = va_arg(ap, char *);
151        buflen = va_arg(ap, size_t);
152        errnop = va_arg(ap, int *);
153        h_errnop = va_arg(ap, int *);
154        resultp = (struct hostent **)rval;
155
156        *resultp = NULL;
157
158        if (!is_local_name(name)) {
159                *h_errnop = NETDB_INTERNAL;
160                *errnop = EINVAL;
161                return (NS_NOTFOUND);
162        }
163
164        hep->h_addrtype = af;
165        switch (af) {
166        case AF_INET:
167                hep->h_length = NS_INADDRSZ;
168                ctx.rrtype = kDNSType_A;
169                break;
170        case AF_INET6:
171                hep->h_length = NS_IN6ADDRSZ;
172                ctx.rrtype = kDNSType_AAAA;
173                break;
174        default:
175                *h_errnop = NETDB_INTERNAL;
176                *errnop = EAFNOSUPPORT;
177                return (NS_UNAVAIL);
178        }
179
180        len = (char *)ALIGN(buffer) - buffer;
181        len += 3 * sizeof(char *);
182        len += ALIGN(hep->h_length);
183        namelen = strlen(name) + 1;
184        len += namelen;
185
186        if (len > buflen) {
187                *h_errnop = NETDB_INTERNAL;
188                *errnop = ERANGE;
189                return (NS_UNAVAIL);
190        }
191
192        buffer = (char *)ALIGN(buffer);
193
194        hep->h_aliases = (char **)buffer;
195        buffer += sizeof(char *);
196        hep->h_aliases[0] = NULL;
197
198        hep->h_addr_list = (char **)buffer;
199        buffer += 2 * sizeof(char *);
200        hep->h_addr_list[0] = buffer;
201        buffer += ALIGN(hep->h_length);
202        hep->h_addr_list[1] = NULL;
203
204        hep->h_name = buffer;
205        memcpy(buffer, name, namelen);
206
207        qname = MakeDomainNameFromDNSNameString(&q.qname, name);
208        if (qname == NULL) {
209                *h_errnop = NETDB_INTERNAL;
210                *errnop = ERANGE;
211                return (NS_UNAVAIL);
212        }
213
214        q.TargetPort = MulticastDNSPort;
215        q.qtype = kDNSQType_ANY;
216        q.qclass = kDNSClass_IN;
217        q.ForceMCast = mDNStrue;
218        q.ReturnIntermed = mDNStrue;
219        q.QuestionCallback = query_callback;
220        q.QuestionContext = &ctx;
221
222        ctx.rrtype = kDNSType_A;
223        ctx.he = hep;
224        ctx.task_id = rtems_task_self();
225
226        mDNS_StartQuery(&mDNSStorage, &q);
227        rtems_bsd_force_select_timeout(mdns_daemon_id);
228
229        sc = rtems_event_transient_receive(RTEMS_WAIT,
230            10 * rtems_clock_get_ticks_per_second());
231
232        mDNS_StopQuery(&mDNSStorage, &q);
233
234        if (sc != RTEMS_SUCCESSFUL) {
235                *h_errnop = NETDB_INTERNAL;
236                *errnop = ETIMEDOUT;
237                return (NS_NOTFOUND);
238        }
239
240        *resultp = hep;
241        return (NS_SUCCESS);
242}
243
244static ns_mtab mdns_mtab[] = {
245        {
246                .database = NSDB_HOSTS,
247                .name = "gethostbyname2_r",
248                .method = mdns_gethostbyname
249        }
250};
251
252static void
253mdns_daemon(rtems_task_argument arg)
254{
255        while (true) {
256                struct timeval timeout = { .tv_sec = 0x1, .tv_usec = 0 };
257                sigset_t signals;
258                mDNSBool got_something;
259
260                mDNSPosixRunEventLoopOnce(&mDNSStorage, &timeout, &signals,
261                    &got_something);
262        }
263}
264
265static void
266truncate_at_first_dot(domainlabel *name)
267{
268        int c = name->c[0];
269        int n = 0;
270
271        while (n < c && name->c[n + 1] != '.') {
272                ++n;
273        }
274
275        name->c[0] = n;
276}
277
278static int
279mdns_sethostname(const char *hostname)
280{
281        mDNS *m = &mDNSStorage;
282
283        mDNS_Lock(m);
284
285        MakeDomainLabelFromLiteralString(&m->hostlabel, hostname);
286        truncate_at_first_dot(&m->hostlabel);
287
288        mDNS_Unlock(m);
289
290        mDNS_SetFQDN(m);
291
292        rtems_bsd_force_select_timeout(mdns_daemon_id);
293
294        return (0);
295}
296
297static int
298mdns_gethostname(char *hostname, size_t size)
299{
300        mDNS *m = &mDNSStorage;
301
302        if (size < MAX_ESCAPED_DOMAIN_LABEL) {
303                errno = ERANGE;
304
305                return (-1);
306        }
307
308        mDNS_Lock(m);
309
310        ConvertDomainLabelToCString(&m->hostlabel, hostname);
311
312        mDNS_Unlock(m);
313
314        return (0);
315}
316
317rtems_status_code
318rtems_mdns_initialize(rtems_task_priority daemon_priority,
319    CacheEntity *rrcachestorage, mDNSu32 rrcachesize)
320{
321        mStatus status;
322        int rv;
323        int fd;
324        rtems_status_code sc;
325
326        status = mDNS_Init(&mDNSStorage, &PlatformStorage, rrcachestorage,
327            rrcachesize, mDNS_Init_AdvertiseLocalAddresses,
328            mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
329        if (status != mStatus_NoError) {
330                return (RTEMS_UNSATISFIED);
331        }
332
333        sc = rtems_task_create(rtems_build_name('m', 'D', 'N', 'S'),
334            daemon_priority, 16 * 1024, RTEMS_DEFAULT_MODES,
335            RTEMS_DEFAULT_ATTRIBUTES, &mdns_daemon_id);
336        if (sc != RTEMS_SUCCESSFUL) {
337                return (RTEMS_UNSATISFIED);
338        }
339
340        sc = rtems_task_start(mdns_daemon_id, mdns_daemon, 0);
341        if (sc != RTEMS_SUCCESSFUL) {
342                return (RTEMS_UNSATISFIED);
343        }
344
345        rv = rtems_nss_register_module("mdns", &mdns_mtab[0],
346            RTEMS_ARRAY_SIZE(mdns_mtab));
347        if (rv != 0) {
348                return (RTEMS_UNSATISFIED);
349        }
350
351        fd = open(_PATH_NS_CONF, O_WRONLY | O_CREAT | O_EXCL,
352            S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
353        if (fd >= 0) {
354                static const char nsconf[] = "hosts: files mdns dns\n";
355                ssize_t n;
356
357                n = write(fd, &nsconf[0], sizeof(nsconf) - 1);
358
359                rv = close(fd);
360                assert(rv == 0);
361
362                if (n != (ssize_t) (sizeof(nsconf) - 1)) {
363                        return (RTEMS_UNSATISFIED);
364                }
365        }
366
367        rtems_mdns_sethostname_handler = mdns_sethostname;
368        rtems_mdns_gethostname_handler = mdns_gethostname;
369
370        return (RTEMS_SUCCESSFUL);
371}
372
373mDNS *
374rtems_mdns_get_instance(void)
375{
376        return (&mDNSStorage);
377}
Note: See TracBrowser for help on using the repository browser.