diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2014-11-03 15:53:46 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2014-11-04 13:02:56 +0100 |
commit | 7ba9b7f24c9cdee4a59a0f3dc0d6441732ec1094 (patch) | |
tree | b083ad15a4d1b3eaf8e9a9ce95dbea5e925b2d7c /rtemsbsd | |
parent | NSDISPATCH(3): Add rtems_nss_register_module() (diff) | |
download | rtems-libbsd-7ba9b7f24c9cdee4a59a0f3dc0d6441732ec1094.tar.bz2 |
Add mDNS support for name service dispatcher
Diffstat (limited to 'rtemsbsd')
-rw-r--r-- | rtemsbsd/include/rtems/mdns.h | 74 | ||||
-rw-r--r-- | rtemsbsd/mdns/mdns.c | 321 |
2 files changed, 395 insertions, 0 deletions
diff --git a/rtemsbsd/include/rtems/mdns.h b/rtemsbsd/include/rtems/mdns.h new file mode 100644 index 00000000..ecf9242b --- /dev/null +++ b/rtemsbsd/include/rtems/mdns.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _RTEMS_MDNS_H_ +#define _RTEMS_MDNS_H_ + +#include <mDNSEmbeddedAPI.h> + +#include <rtems.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @brief Initializes an mDNS resolver instance. + * + * Calling this function multiple times leads to unpredictable results. + * + * @param[in] daemon_priority The task priority of the mDNS daemon. + * @param[in] rrcachestorage The resource record cache storage. Use + * mDNS_Init_NoCache in case no cache is desired. + * @param[in] rrcachesize The resource record cache entity count of the + * provided storage. Use mDNS_Init_ZeroCacheSize in case no cache is desired. + * + * @retval RTEMS_SUCCESSFUL Successful operation. + * @retval RTEMS_UNSATISFIED Initialization is incomplete. + */ +rtems_status_code rtems_mdns_initialize(rtems_task_priority daemon_priority, + CacheEntity *rrcachestorage, mDNSu32 rrcachesize); + +/** + * @brief Returns the mDNS resolver instance. + * + * Using of this instance is only allowed after a successful call to + * rtems_mdns_initialize(). + * + * @retval instance The mDNS resolver instance. + */ +mDNS *rtems_mdns_get_instance(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _RTEMS_MDNS_H_ */ diff --git a/rtemsbsd/mdns/mdns.c b/rtemsbsd/mdns/mdns.c new file mode 100644 index 00000000..3cdcfe61 --- /dev/null +++ b/rtemsbsd/mdns/mdns.c @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <mDNSEmbeddedAPI.h> +#include <mDNSPosix.h> + +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/stat.h> + +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> + +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <netdb.h> +#include <nsswitch.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <rtems/bsd/util.h> +#include <rtems/mdns.h> + +static rtems_id daemon_id; + +static mDNS mDNSStorage; + +static mDNS_PlatformSupport PlatformStorage; + +typedef struct { + mDNSu16 rrtype; + struct hostent *he; + rtems_id task_id; +} query_context; + +static void +query_callback(mDNS *m, DNSQuestion *q, const ResourceRecord *answer, + QC_result add_record) +{ + query_context *ctx = q->QuestionContext; + struct hostent *he = ctx->he; + bool stop = false; + rtems_id task_id = ctx->task_id; + + (void)m; + (void)add_record; + + if (ctx->rrtype == kDNSType_A && answer->rrtype == kDNSType_A) { + const mDNSv4Addr *ipv4 = &answer->rdata->u.ipv4; + + memcpy(he->h_addr_list[0], ipv4, sizeof(*ipv4)); + stop = true; + } else if (ctx->rrtype == kDNSType_AAAA + && answer->rrtype == kDNSType_AAAA) { + const mDNSv6Addr *ipv6 = &answer->rdata->u.ipv6; + + memcpy(he->h_addr_list[0], ipv6, sizeof(*ipv6)); + stop = true; + } + + if (stop && task_id != 0) { + rtems_status_code sc; + + ctx->task_id = 0; + + sc = rtems_event_transient_send(task_id); + assert(sc == RTEMS_SUCCESSFUL); + } +} + +static bool is_local_name(const char *name) +{ + size_t len = strlen(name); + const char local[] = "local"; + size_t locallen = sizeof(local) - 1; + + if (len == 0) { + return (false); + } + + if (name[len - 1] == '.') { + --len; + } + + if (len < locallen) { + return (false); + } + + return strncasecmp(name + len - locallen, &local[0], locallen) == 0; +} + +static int +mdns_gethostbyname(void *rval, void *cb_data, va_list ap) +{ + const char *name; + int af; + char *buffer; + size_t buflen; + size_t len; + size_t namelen; + int *errnop; + int *h_errnop; + struct hostent *hep; + struct hostent **resultp; + DNSQuestion q; + query_context ctx; + mDNSu8 *qname; + rtems_status_code sc; + + memset(&q, 0, sizeof(q)); + memset(&ctx, 0, sizeof(ctx)); + + name = va_arg(ap, const char *); + af = va_arg(ap, int); + hep = va_arg(ap, struct hostent *); + buffer = va_arg(ap, char *); + buflen = va_arg(ap, size_t); + errnop = va_arg(ap, int *); + h_errnop = va_arg(ap, int *); + resultp = (struct hostent **)rval; + + *resultp = NULL; + + if (!is_local_name(name)) { + *h_errnop = NETDB_INTERNAL; + *errnop = EINVAL; + return (NS_NOTFOUND); + } + + hep->h_addrtype = af; + switch (af) { + case AF_INET: + hep->h_length = NS_INADDRSZ; + ctx.rrtype = kDNSType_A; + break; + case AF_INET6: + hep->h_length = NS_IN6ADDRSZ; + ctx.rrtype = kDNSType_AAAA; + break; + default: + *h_errnop = NETDB_INTERNAL; + *errnop = EAFNOSUPPORT; + return (NS_UNAVAIL); + } + + len = (char *)ALIGN(buffer) - buffer; + len += 3 * sizeof(char *); + len += ALIGN(hep->h_length); + namelen = strlen(name) + 1; + len += namelen; + + if (len > buflen) { + *h_errnop = NETDB_INTERNAL; + *errnop = ERANGE; + return (NS_UNAVAIL); + } + + buffer = (char *)ALIGN(buffer); + + hep->h_aliases = (char **)buffer; + buffer += sizeof(char *); + hep->h_aliases[0] = NULL; + + hep->h_addr_list = (char **)buffer; + buffer += 2 * sizeof(char *); + hep->h_addr_list[0] = buffer; + buffer += ALIGN(hep->h_length); + hep->h_addr_list[1] = NULL; + + hep->h_name = buffer; + memcpy(buffer, name, namelen); + + qname = MakeDomainNameFromDNSNameString(&q.qname, name); + if (qname == NULL) { + *h_errnop = NETDB_INTERNAL; + *errnop = ERANGE; + return (NS_UNAVAIL); + } + + q.TargetPort = MulticastDNSPort; + q.qtype = kDNSQType_ANY; + q.qclass = kDNSClass_IN; + q.ForceMCast = mDNStrue; + q.ReturnIntermed = mDNStrue; + q.QuestionCallback = query_callback; + q.QuestionContext = &ctx; + + ctx.rrtype = kDNSType_A; + ctx.he = hep; + ctx.task_id = rtems_task_self(); + + mDNS_StartQuery(&mDNSStorage, &q); + rtems_bsd_force_select_timeout(daemon_id); + + sc = rtems_event_transient_receive(RTEMS_WAIT, + 10 * rtems_clock_get_ticks_per_second()); + + mDNS_StopQuery(&mDNSStorage, &q); + + if (sc != RTEMS_SUCCESSFUL) { + *h_errnop = NETDB_INTERNAL; + *errnop = ETIMEDOUT; + return (NS_NOTFOUND); + } + + *resultp = hep; + return (NS_SUCCESS); +} + +static ns_mtab mdns_mtab[] = { + { + .database = NSDB_HOSTS, + .name = "gethostbyname2_r", + .method = mdns_gethostbyname + } +}; + +static void +mdns_daemon(rtems_task_argument arg) +{ + while (true) { + struct timeval timeout = { .tv_sec = 0x1, .tv_usec = 0 }; + sigset_t signals; + mDNSBool got_something; + + mDNSPosixRunEventLoopOnce(&mDNSStorage, &timeout, &signals, + &got_something); + } +} + +rtems_status_code +rtems_mdns_initialize(rtems_task_priority daemon_priority, + CacheEntity *rrcachestorage, mDNSu32 rrcachesize) +{ + mStatus status; + int rv; + int fd; + rtems_status_code sc; + + status = mDNS_Init(&mDNSStorage, &PlatformStorage, rrcachestorage, + rrcachesize, mDNS_Init_AdvertiseLocalAddresses, + mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext); + if (status != mStatus_NoError) { + return (RTEMS_UNSATISFIED); + } + + sc = rtems_task_create(rtems_build_name('m', 'D', 'N', 'S'), + daemon_priority, 16 * 1024, RTEMS_DEFAULT_MODES, + RTEMS_DEFAULT_ATTRIBUTES, &daemon_id); + if (sc != RTEMS_SUCCESSFUL) { + return (RTEMS_UNSATISFIED); + } + + sc = rtems_task_start(daemon_id, mdns_daemon, 0); + if (sc != RTEMS_SUCCESSFUL) { + return (RTEMS_UNSATISFIED); + } + + rv = rtems_nss_register_module("mdns", &mdns_mtab[0], + RTEMS_ARRAY_SIZE(mdns_mtab)); + if (rv != 0) { + return (RTEMS_UNSATISFIED); + } + + fd = open(_PATH_NS_CONF, O_WRONLY | O_CREAT | O_EXCL, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fd >= 0) { + static const char nsconf[] = "hosts: files mdns dns\n"; + ssize_t n; + + n = write(fd, &nsconf[0], sizeof(nsconf) - 1); + + rv = close(fd); + assert(rv == 0); + + if (n != (ssize_t) (sizeof(nsconf) - 1)) { + return (RTEMS_UNSATISFIED); + } + } + + return (RTEMS_SUCCESSFUL); +} + +mDNS * +rtems_mdns_get_instance(void) +{ + return (&mDNSStorage); +} |