Module Name:    src
Committed By:   tsarna
Date:           Mon Oct  5 03:54:17 UTC 2009

Modified Files:
        src/distrib/sets/lists/base: shl.mi
        src/external/apache2/mDNSResponder: Makefile
Added Files:
        src/external/apache2/mDNSResponder/nss: Makefile nss_mdns.c

Log Message:
Add nss_mdns, a nsswitch plugin for host lookups vis mDNS ("Bonjour"),
eg "hostname.local".  This is a work in progress, but basically
functional. (note: this requires mdnsd to be running.)


To generate a diff of this commit:
cvs rdiff -u -r1.495 -r1.496 src/distrib/sets/lists/base/shl.mi
cvs rdiff -u -r1.1 -r1.2 src/external/apache2/mDNSResponder/Makefile
cvs rdiff -u -r0 -r1.1 src/external/apache2/mDNSResponder/nss/Makefile \
    src/external/apache2/mDNSResponder/nss/nss_mdns.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/distrib/sets/lists/base/shl.mi
diff -u src/distrib/sets/lists/base/shl.mi:1.495 src/distrib/sets/lists/base/shl.mi:1.496
--- src/distrib/sets/lists/base/shl.mi:1.495	Sun Oct  4 22:06:34 2009
+++ src/distrib/sets/lists/base/shl.mi	Mon Oct  5 03:54:17 2009
@@ -1,4 +1,4 @@
-# $NetBSD: shl.mi,v 1.495 2009/10/04 22:06:34 christos Exp $
+# $NetBSD: shl.mi,v 1.496 2009/10/05 03:54:17 tsarna Exp $
 #
 # Note:	Don't delete entries from here - mark them as "obsolete" instead,
 #	unless otherwise stated below.
@@ -166,6 +166,7 @@
 ./usr/lib/libutil.so.7.17			base-sys-shlib
 ./usr/lib/libwrap.so.1.0			base-net-shlib
 ./usr/lib/libz.so.1.0				base-sys-shlib
+./usr/lib/nss_mdns.so.0				base-mdns-shlib		mdns
 ./usr/lib/security/pam_afslog.so.3		base-sys-shlib		kerberos,pam
 ./usr/lib/security/pam_chroot.so.3		base-sys-shlib		pam
 ./usr/lib/security/pam_deny.so.3		base-sys-shlib		pam

Index: src/external/apache2/mDNSResponder/Makefile
diff -u src/external/apache2/mDNSResponder/Makefile:1.1 src/external/apache2/mDNSResponder/Makefile:1.2
--- src/external/apache2/mDNSResponder/Makefile:1.1	Tue Sep 29 23:56:27 2009
+++ src/external/apache2/mDNSResponder/Makefile	Mon Oct  5 03:54:17 2009
@@ -1,5 +1,5 @@
-#	$NetBSD: Makefile,v 1.1 2009/09/29 23:56:27 tsarna Exp $
+#	$NetBSD: Makefile,v 1.2 2009/10/05 03:54:17 tsarna Exp $
 
-SUBDIR=	usr.bin usr.sbin
+SUBDIR=	usr.bin usr.sbin nss
 
 .include <bsd.subdir.mk>

Added files:

Index: src/external/apache2/mDNSResponder/nss/Makefile
diff -u /dev/null src/external/apache2/mDNSResponder/nss/Makefile:1.1
--- /dev/null	Mon Oct  5 03:54:17 2009
+++ src/external/apache2/mDNSResponder/nss/Makefile	Mon Oct  5 03:54:17 2009
@@ -0,0 +1,36 @@
+#	$NetBSD: Makefile,v 1.1 2009/10/05 03:54:17 tsarna Exp $
+
+LIB=		nss_mdns
+SHLIB_MAJOR=	0
+
+NOLINT=		# don't build a lint library
+NOPROFILE=	# don't build a profile library
+NOPICINSTALL=	# don't install _pic.a library
+
+.include <bsd.own.mk>
+
+.include "${.CURDIR}/../Makefile.inc"
+
+SRCS=		nss_mdns.c
+LDADD+= 	-ldns_sd
+DPADD+= 	${LIBDNS_SD}
+
+.if ${MKPIC} != "no"
+.PRECIOUS: ${DESTDIR}${LIBDIR}/${LIB}.so.${SHLIB_MAJOR}
+libinstall:: ${DESTDIR}${LIBDIR}/${LIB}.so.${SHLIB_MAJOR}
+.else
+libinstall::
+.endif
+
+.include <bsd.lib.mk>
+
+${DESTDIR}${LIBDIR}/${LIB}.so.${SHLIB_MAJOR}: lib${LIB}.so.${SHLIB_FULLVERSION}
+	${_MKTARGET_INSTALL}
+	${INSTALL_FILE} -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} \
+	    ${.ALLSRC} ${.TARGET}
+
+#.if defined(LD32DIR)
+#LIBDIR=/usr/lib/${LD32DIR}
+#.else
+#LIBDIR=/usr/lib
+#.endif
Index: src/external/apache2/mDNSResponder/nss/nss_mdns.c
diff -u /dev/null src/external/apache2/mDNSResponder/nss/nss_mdns.c:1.1
--- /dev/null	Mon Oct  5 03:54:17 2009
+++ src/external/apache2/mDNSResponder/nss/nss_mdns.c	Mon Oct  5 03:54:17 2009
@@ -0,0 +1,673 @@
+/*	$NetBSD: nss_mdns.c,v 1.1 2009/10/05 03:54:17 tsarna Exp $	*/
+
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Tyler C. Sarna
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * Multicast DNS ("Bonjour") hosts name service switch
+ *
+ * Documentation links:
+ *
+ * http://developer.apple.com/bonjour/
+ * http://www.multicastdns.org/
+ * http://www.dns-sd.org/
+ */
+
+#include <nsswitch.h>
+#include <stdarg.h>  
+#include <stdlib.h>  
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <netdb.h>
+#include <arpa/nameser.h>
+#include <dns_sd.h>
+#include <poll.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifndef lint
+#define UNUSED(a)       (void)&a
+#else
+#define UNUSED(a)       a = a
+#endif
+
+#if defined(__NetBSD__) && (__NetBSD_Version__ < 599002000)
+static struct addrinfo *
+allocaddrinfo(socklen_t addrlen)
+{
+    struct addrinfo *ai;
+    
+    ai = calloc(sizeof(struct addrinfo) + addrlen, 1);
+    if (ai) {
+        ai->ai_addrlen = addrlen;
+        ai->ai_addr = (void *)(ai+1);
+    }
+    
+    return ai;
+}
+#endif
+
+#define MAXALIASES      35 
+#define MAXADDRS        35
+
+typedef struct callback_ctx {
+    int done;
+} callback_ctx;
+
+typedef struct hostent_ctx {
+    callback_ctx cb_ctx;    /* must come first */
+    struct hostent host;
+    char *h_addr_ptrs[MAXADDRS + 1];
+    char *host_aliases[MAXALIASES];
+    char addrs[MAXADDRS * 16];
+    char buf[8192], *next;
+    int done, naliases, naddrs;
+} hostent_ctx;
+
+typedef struct addrinfo_ctx {
+    callback_ctx cb_ctx;    /* must come first */
+    struct addrinfo start, *last;
+} addrinfo_ctx;
+
+#define HCTX_BUFLEFT(c) (sizeof((c)->buf) - ((c)->next - (c)->buf))
+
+static hostent_ctx h_ctx;
+
+
+static int _mdns_getaddrinfo(void *cbrv, void *cbdata, va_list ap);
+static int _mdns_gethtbyaddr(void *cbrv, void *cbdata, va_list ap);
+static int _mdns_gethtbyname(void *cbrv, void *cbdata, va_list ap);
+
+static void _mdns_addrinfo_init(addrinfo_ctx *ctx, const struct addrinfo *ai);
+static void _mdns_addrinfo_add_ai(addrinfo_ctx *ctx, struct addrinfo *ai);
+static struct addrinfo *_mdns_addrinfo_done(addrinfo_ctx *ctx);
+
+static void _mdns_hostent_init(hostent_ctx *ctx, int af, int addrlen);
+static void _mdns_hostent_add_host(hostent_ctx *ctx, const char *name);
+static void _mdns_hostent_add_addr(hostent_ctx *ctx, const void *addr, uint16_t len);
+static struct hostent *_mdns_hostent_done(hostent_ctx *ctx);
+
+static void _mdns_addrinfo_cb(DNSServiceRef sdRef, DNSServiceFlags flags,
+    uint32_t interfaceIndex, DNSServiceErrorType errorCode,
+    const char *hostname, const struct sockaddr *address, uint32_t ttl,
+    void *context);
+static void _mdns_hostent_cb(DNSServiceRef sdRef, DNSServiceFlags flags,
+    uint32_t interfaceIndex, DNSServiceErrorType errorCode,
+    const char *fullname, uint16_t rrtype, uint16_t rrclass,
+    uint16_t rdlen, const void *rdata, uint32_t ttl, void *context);
+static void _mdns_eventloop(DNSServiceRef sdRef, callback_ctx *ctx);
+
+static char *_mdns_rdata2name(const unsigned char *rdata, uint16_t rdlen,
+    char *buf, size_t buflen);
+
+
+static ns_mtab mtab[] = {
+    { NSDB_HOSTS, "getaddrinfo",    _mdns_getaddrinfo, NULL },
+    { NSDB_HOSTS, "gethostbyaddr",  _mdns_gethtbyaddr, NULL },
+    { NSDB_HOSTS, "gethostbyname",  _mdns_gethtbyname, NULL },
+};
+
+
+
+ns_mtab *
+nss_module_register(const char *source, u_int *nelems,
+                    nss_module_unregister_fn *unreg)
+{
+    UNUSED(source);
+    UNUSED(unreg);
+    
+    *nelems = sizeof(mtab) / sizeof(mtab[0]);
+    *unreg = NULL;
+
+    return mtab;
+}
+
+
+
+static int
+_mdns_getaddrinfo(void *cbrv, void *cbdata, va_list ap)
+{
+    const struct addrinfo *pai;
+    const char *name;
+    addrinfo_ctx ctx;
+    DNSServiceProtocol proto;
+    DNSServiceErrorType err;
+    DNSServiceRef sdRef;
+    
+    UNUSED(cbdata);
+    
+    name = va_arg(ap, char *);
+    pai = va_arg(ap, struct addrinfo *);
+    
+    //XXX check valid name space
+    
+    switch (pai->ai_family) {
+    case AF_UNSPEC:
+        proto = kDNSServiceProtocol_IPv6 | kDNSServiceProtocol_IPv4;
+        break;
+
+    case AF_INET6:
+        proto = kDNSServiceProtocol_IPv6;
+        break;
+
+    case AF_INET:
+        proto = kDNSServiceProtocol_IPv4;
+        break;
+        
+    default:
+        return NS_UNAVAIL;
+    }
+
+    _mdns_addrinfo_init(&ctx, pai);
+
+    err = DNSServiceGetAddrInfo(
+        &sdRef,
+        kDNSServiceFlagsForceMulticast,
+        kDNSServiceInterfaceIndexAny,
+        proto,
+        name,
+        _mdns_addrinfo_cb,
+        &ctx
+    );
+
+    if (err) {
+        h_errno = NETDB_INTERNAL;
+        return NS_UNAVAIL;
+    }
+    
+    _mdns_eventloop(sdRef, (void *)&h_ctx);
+
+    DNSServiceRefDeallocate(sdRef);
+
+    if (ctx.start.ai_next) {
+        *(struct addrinfo **)cbrv = _mdns_addrinfo_done(&ctx);
+    
+        return NS_SUCCESS;
+    } else {
+        return NS_NOTFOUND;
+    }
+}
+
+
+
+static int
+_mdns_gethtbyaddr(void *cbrv, void *cbdata, va_list ap)
+{
+    const unsigned char *addr;
+    int addrlen, af;
+    char qbuf[NS_MAXDNAME + 1], *qp, *ep;
+    int advance, n;
+    DNSServiceErrorType err;
+    DNSServiceRef sdRef;
+
+    UNUSED(cbdata);
+    
+    addr = va_arg(ap, unsigned char *);
+    addrlen = va_arg(ap, int);
+    af = va_arg(ap, int);
+
+    //XXX Check if in valid address space
+    
+    switch (af) {
+    case AF_INET:
+        (void)snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u.in-addr.arpa",
+            (addr[3] & 0xff), (addr[2] & 0xff),
+            (addr[1] & 0xff), (addr[0] & 0xff));
+        break;
+    
+    case AF_INET6:
+        qp = qbuf;
+        ep = qbuf + sizeof(qbuf) - 1;
+        for (n = IN6ADDRSZ - 1; n >= 0; n--) {
+            advance = snprintf(qp, (size_t)(ep - qp), "%x.%x.",
+                addr[n] & 0xf,
+                ((unsigned int)addr[n] >> 4) & 0xf);
+            if (advance > 0 && qp + advance < ep)
+                qp += advance;
+            else {
+                h_errno = NETDB_INTERNAL;
+                return NS_NOTFOUND;
+            }
+        }
+        if (strlcat(qbuf, "ip6.arpa", sizeof(qbuf)) >= sizeof(qbuf)) {
+            h_errno = NETDB_INTERNAL;
+            return NS_NOTFOUND;
+        }
+        break;
+
+    default:
+        h_errno = NETDB_INTERNAL;
+        return NS_NOTFOUND;
+    }
+
+    _mdns_hostent_init(&h_ctx, af, addrlen);
+    _mdns_hostent_add_addr(&h_ctx, addr, addrlen);
+
+    err = DNSServiceQueryRecord(
+        &sdRef,
+        kDNSServiceFlagsForceMulticast,
+        kDNSServiceInterfaceIndexAny,
+        qbuf,
+        kDNSServiceType_PTR,
+        kDNSServiceClass_IN,
+        _mdns_hostent_cb,
+        &h_ctx
+    );
+
+    if (err) {
+        h_errno = NETDB_INTERNAL;
+        return NS_UNAVAIL;
+    }
+    
+    _mdns_eventloop(sdRef, (void *)&h_ctx);
+
+    DNSServiceRefDeallocate(sdRef);
+
+    if (h_ctx.naliases) {
+        *(struct hostent **)cbrv = _mdns_hostent_done(&h_ctx);
+    
+        return NS_SUCCESS;
+    } else {
+        return NS_NOTFOUND;
+    }
+}
+
+
+
+static int
+_mdns_gethtbyname(void *cbrv, void *cbdata, va_list ap)
+{
+    const char *name;
+    int namelen, af, addrlen, rrtype;
+    DNSServiceErrorType err;
+    DNSServiceRef sdRef;
+
+    UNUSED(cbdata);
+    
+    name = va_arg(ap, char *);
+    namelen = va_arg(ap, int);
+    af = va_arg(ap, int);
+
+    UNUSED(namelen);
+    
+    //XXX Check if in valid name space
+    
+    switch (af) {
+    case AF_INET:
+        rrtype = kDNSServiceType_A;
+        addrlen = 4;
+        break;
+    
+    case AF_INET6:
+        rrtype = kDNSServiceType_AAAA;
+        addrlen = 16;
+        break;
+
+    default:
+        h_errno = NETDB_INTERNAL;
+        return NS_NOTFOUND;
+    }
+
+    _mdns_hostent_init(&h_ctx, af, addrlen);
+    _mdns_hostent_add_host(&h_ctx, name);
+
+    err = DNSServiceQueryRecord(
+        &sdRef,
+        kDNSServiceFlagsForceMulticast,
+        kDNSServiceInterfaceIndexAny,
+        name,
+        rrtype,
+        kDNSServiceClass_IN,
+        _mdns_hostent_cb,
+        &h_ctx
+    );
+
+    if (err) {
+        h_errno = NETDB_INTERNAL;
+        return NS_UNAVAIL;
+    }
+    
+    _mdns_eventloop(sdRef, (void *)&h_ctx);
+
+    DNSServiceRefDeallocate(sdRef);
+
+    if (h_ctx.naddrs) {
+        *(struct hostent **)cbrv = _mdns_hostent_done(&h_ctx);
+    
+        return NS_SUCCESS;
+    } else {
+        return NS_NOTFOUND;
+    }
+}
+
+
+
+static void
+_mdns_addrinfo_init(addrinfo_ctx *ctx, const struct addrinfo *ai)
+{
+    ctx->cb_ctx.done = 0;
+    ctx->start = *ai;
+    ctx->start.ai_next = NULL;
+    ctx->start.ai_canonname = NULL;
+    ctx->last = &(ctx->start);
+}
+
+
+
+static void
+_mdns_addrinfo_add_ai(addrinfo_ctx *ctx, struct addrinfo *ai)
+{
+    ctx->last->ai_next = ai;
+    while (ctx->last->ai_next)
+        ctx->last = ctx->last->ai_next;
+}
+
+
+
+static struct addrinfo *
+_mdns_addrinfo_done(addrinfo_ctx *ctx)
+{
+    struct addrinfo head, *t, *p;
+            
+    /* sort v6 up */
+
+    t = &head;
+    p = &(ctx->start);
+
+    while (p->ai_next) {
+        if (p->ai_next->ai_family == AF_INET6) {
+            t->ai_next = p->ai_next;
+            t = t->ai_next;
+            p->ai_next = p->ai_next->ai_next;
+        } else {
+            p = p->ai_next;
+        }
+    }
+
+    /* add rest of list and reset start to the new list*/
+    t->ai_next = ctx->start.ai_next;
+    ctx->start.ai_next = head.ai_next;
+    
+    return ctx->start.ai_next;
+}
+
+
+
+static void
+_mdns_hostent_init(hostent_ctx *ctx, int af, int addrlen)
+{
+    int i;
+    
+    ctx->cb_ctx.done = ctx->naliases = ctx->naddrs = 0;
+    ctx->next = ctx->buf;
+
+    ctx->host.h_aliases = ctx->host_aliases;
+    ctx->host.h_addr_list = ctx->h_addr_ptrs;
+    ctx->host.h_name = ctx->host.h_aliases[0] = NULL;
+    ctx->host.h_addrtype = af;
+    ctx->host.h_length = addrlen;
+    
+    for (i = 0; i < MAXADDRS; i++) {
+        ctx->host.h_addr_list[i] = &(ctx->addrs[i * 16]);
+    }
+}
+
+
+
+static void
+_mdns_hostent_add_host(hostent_ctx *ctx, const char *name)
+{
+    size_t len = strlen(name);
+    
+    if (name && (HCTX_BUFLEFT(ctx) > len) && (ctx->naliases < MAXALIASES)) {
+        /* skip dupe names */
+        if ((ctx->host.h_name) && !strcmp(ctx->host.h_name, name)) {
+            return;
+        }
+    
+        strcpy(ctx->next, name);
+        if (ctx->naliases == 0) {
+            ctx->host.h_name = ctx->next;
+        } else {
+            ctx->host.h_aliases[ctx->naliases - 1] = ctx->next;
+        }
+        
+        ctx->next += (len + 1);
+        ctx->naliases++;
+    } /* else silently ignore */
+}
+
+
+
+static void
+_mdns_hostent_add_addr(hostent_ctx *ctx, const void *addr, uint16_t len)
+{
+    if ((len == ctx->host.h_length) && (ctx->naddrs < MAXADDRS)) {
+        memcpy(ctx->host.h_addr_list[ctx->naddrs++], addr, (size_t)len);
+    } /* else wrong address type or out of room... silently skip */
+}
+
+
+
+static struct hostent *
+_mdns_hostent_done(hostent_ctx *ctx)
+{
+    if (ctx->naliases) {
+        /* terminate array */
+        ctx->host.h_aliases[ctx->naliases - 1] = NULL;
+        ctx->host.h_addr_list[ctx->naddrs] = NULL;
+    }
+    
+    return &(ctx->host);
+}
+
+
+
+static void
+_mdns_addrinfo_cb(
+    DNSServiceRef           sdRef,
+    DNSServiceFlags         flags,
+    uint32_t                interfaceIndex,
+    DNSServiceErrorType     errorCode,
+    const char             *hostname,
+    const struct sockaddr  *address,
+    uint32_t                ttl,
+    void                   *context
+) {
+    addrinfo_ctx *ctx = context;
+    struct addrinfo *ai;
+
+    UNUSED(sdRef);
+    UNUSED(interfaceIndex);
+    UNUSED(hostname);
+    UNUSED(ttl);
+
+    if (errorCode == kDNSServiceErr_NoError) {
+        if (! (flags & kDNSServiceFlagsMoreComing)) {
+            ctx->cb_ctx.done = 1;
+        }
+
+        ai = allocaddrinfo((socklen_t)(address->sa_len));
+        if (ai) {
+            ai->ai_flags = ctx->start.ai_flags;
+            ai->ai_family = address->sa_family;
+            ai->ai_socktype = ctx->start.ai_socktype;
+            ai->ai_protocol = ctx->start.ai_protocol;
+            memcpy(ai->ai_addr, address, (size_t)(address->sa_len));
+            
+            //XXX canonname?
+            _mdns_addrinfo_add_ai(ctx, ai);
+        }
+    }
+}
+
+
+
+static void
+_mdns_hostent_cb(
+    DNSServiceRef           sdRef,
+    DNSServiceFlags         flags,
+    uint32_t                interfaceIndex,
+    DNSServiceErrorType     errorCode,
+    const char             *fullname,
+    uint16_t                rrtype,
+    uint16_t                rrclass,
+    uint16_t                rdlen,
+    const void             *rdata,
+    uint32_t                ttl,
+    void                   *context
+) {
+    hostent_ctx *ctx = (hostent_ctx *)context;
+    char buf[NS_MAXDNAME+1];
+
+    UNUSED(sdRef);
+    UNUSED(interfaceIndex);
+    UNUSED(rrclass);
+    UNUSED(ttl);
+
+    if (! (flags & kDNSServiceFlagsMoreComing)) {
+        ctx->cb_ctx.done = 1;
+    }
+
+    if (errorCode == kDNSServiceErr_NoError) {
+        switch (rrtype) {
+        case kDNSServiceType_PTR:
+            if (!_mdns_rdata2name(rdata, rdlen, buf, sizeof(buf))) {
+                /* corrupt response -- skip */
+                return;
+            }
+        
+            _mdns_hostent_add_host(ctx, buf);
+            break;
+
+        case kDNSServiceType_A:
+            if (ctx->host.h_addrtype == AF_INET) {
+                _mdns_hostent_add_host(ctx, fullname);
+                _mdns_hostent_add_addr(ctx, rdata, rdlen);
+            }
+            break;
+
+        case kDNSServiceType_AAAA:
+            if (ctx->host.h_addrtype == AF_INET6) {
+                _mdns_hostent_add_host(ctx, fullname);
+                _mdns_hostent_add_addr(ctx, rdata, rdlen);
+            }
+            break;
+        }
+    }
+}
+
+
+
+static void
+_mdns_eventloop(DNSServiceRef sdRef, callback_ctx *ctx)
+{
+    struct pollfd fds;
+    int fd, ret;
+
+    fd = DNSServiceRefSockFD(sdRef);
+    fds.fd = fd;
+    fds.events = POLLRDNORM;
+
+    while (!ctx->done) {
+        ret = poll(&fds, 1, 500);
+        if (ret > 0) {
+            DNSServiceProcessResult(sdRef);
+        } else {
+            break;
+        }
+    }
+}
+
+
+
+static char *
+_mdns_rdata2name(const unsigned char *rdata, uint16_t rdlen, char *buf, size_t buflen)
+{
+    unsigned char l;
+    char *r = buf;
+
+    /* illegal 0-size answer or not enough room for even "." */
+    if ((!rdlen) || (rdlen < 2)) {
+        return NULL;
+    }
+    
+    buflen--; /* reserve space for terminating NUL now */
+    
+    /* special case empty as "." */
+    if ((rdlen == 1) && (!*rdata)) {
+        strcpy(buf, ".");
+            
+        return r;
+    }
+    
+    while (rdlen && *rdata) {
+        /* label length byte */
+        l = *rdata++; rdlen--;
+        
+        if (l > 63) {
+            /* compression or bitstrings -- shouldn't happen */
+            return NULL;
+        } else if (l > buflen) {
+            /* not enough space */
+            return NULL;
+        } else if (l > rdlen) {
+            /* label shouldn't be longer than remaining rdata */
+            return NULL;
+        } else if (!l) {
+            /* empty label -- should be done */
+            if (rdlen) {
+                /* but more left!? */
+                return NULL;
+            } else {
+                break;
+            }
+        }
+        
+        memcpy(buf, rdata, (size_t)l);
+        rdata += l; buf += l;
+        rdlen -= l; buflen -= l;
+        
+        /* Another label to come? add a separator */
+        if (rdlen && *rdata) {
+            if (!buflen) {
+                return NULL;
+            }
+
+            *buf++ = '.'; buflen--;
+        }
+    }
+
+    /* we reserved space above, so we know we have space
+       to add this termination */
+       
+    *buf = '\0';
+
+    return r;
+}

Reply via email to