[rtems-libbsd commit] Add mDNS support for name service dispatcher

Sebastian Huber sebh at rtems.org
Tue Nov 4 12:02:23 UTC 2014


Module:    rtems-libbsd
Branch:    master
Commit:    7ba9b7f24c9cdee4a59a0f3dc0d6441732ec1094
Changeset: http://git.rtems.org/rtems-libbsd/commit/?id=7ba9b7f24c9cdee4a59a0f3dc0d6441732ec1094

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Mon Nov  3 15:53:46 2014 +0100

Add mDNS support for name service dispatcher

---

 Makefile                      |    1 +
 freebsd-to-rtems.py           |    1 +
 rtemsbsd/include/rtems/mdns.h |   74 ++++++++++
 rtemsbsd/mdns/mdns.c          |  321 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 397 insertions(+), 0 deletions(-)

diff --git a/Makefile b/Makefile
index 658973e..739fef4 100644
--- a/Makefile
+++ b/Makefile
@@ -101,6 +101,7 @@ LIB_C_FILES += rtemsbsd/rtems/rtems_mii_ioctl_kern.c
 LIB_C_FILES += rtemsbsd/rtems/rtems-syslog-initialize.c
 LIB_C_FILES += rtemsbsd/rtems/syslog.c
 LIB_C_FILES += rtemsbsd/ftpd/ftpd.c
+LIB_C_FILES += rtemsbsd/mdns/mdns.c
 LIB_C_FILES += rtemsbsd/pppd/auth.c
 LIB_C_FILES += rtemsbsd/pppd/ccp.c
 LIB_C_FILES += rtemsbsd/pppd/chap.c
diff --git a/freebsd-to-rtems.py b/freebsd-to-rtems.py
index a6618a7..bdb0dda 100755
--- a/freebsd-to-rtems.py
+++ b/freebsd-to-rtems.py
@@ -699,6 +699,7 @@ rtems.addRTEMSSourceFiles(
 		'rtems/rtems-syslog-initialize.c',
 		'rtems/syslog.c',
 		'ftpd/ftpd.c',
+		'mdns/mdns.c',
 		'pppd/auth.c',
 		'pppd/ccp.c',
 		'pppd/chap.c',
diff --git a/rtemsbsd/include/rtems/mdns.h b/rtemsbsd/include/rtems/mdns.h
new file mode 100644
index 0000000..ecf9242
--- /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 at 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 0000000..3cdcfe6
--- /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 at 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);
+}



More information about the vc mailing list