Bonjour/Zerconf library

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
dirkx
Date:
Sat Jul 31 14:30:45 2010 +0000
Parent:
3:e1d86543ec50
Child:
5:8e53abda9900
Commit message:

Changed in this revision

services/http/server/impl/RPCHandler.cpp Show annotated file Show diff for this revision Revisions of this file
services/mDNS/mDNSResponder.cpp Show annotated file Show diff for this revision Revisions of this file
services/mDNS/mDNSResponder.h Show annotated file Show diff for this revision Revisions of this file
services/ntp/NTPClient.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/services/http/server/impl/RPCHandler.cpp	Tue Jul 27 17:22:17 2010 +0000
+++ b/services/http/server/impl/RPCHandler.cpp	Sat Jul 31 14:30:45 2010 +0000
@@ -105,7 +105,7 @@
   static const char* lGarbage[2] = {"%20", "+"};
   for(int i = 0; i < 2; i++)
   {
-    while((p = strstr(data, lGarbage[i])))
+    while((p = strstr(data, lGarbage[i])) != NULL)
     {
       memset((void*) p, ' ', strlen(lGarbage[i]));
     }
--- a/services/mDNS/mDNSResponder.cpp	Tue Jul 27 17:22:17 2010 +0000
+++ b/services/mDNS/mDNSResponder.cpp	Sat Jul 31 14:30:45 2010 +0000
@@ -1,470 +1,498 @@
-/* Class: mDNSResponder
- * Copyright 1991, 2003, 2010 Dirk-Willem van Gulik <dirkx(at)apache(punto)org>
- *
- * License: Any BSD or ASF License.
- *
- * Rough and ready port of some mDNS code.
- *
- * Typical use is something like
- *
- * EthernetNetIf eth;
- * HTTPServer svr;
- * mDNSResponder mdns;
- *
- * int main()...
- *
- *   // get internet
- *   EthernetErr ethErr = eth.setup();
- *   ... etc ..
- *
- *   // set up some server
- *   svr.addHandler<SimpleHandler>("/"); //Default handler
- *   svr.bind(80); * *
-
- *  // Extract the IP address.
- *   IpAddr ip = eth.getIp();
- *   printf("mbed IP Address is %d.%d.%d.%d\r\n", ip[0], ip[1], ip[2], ip[3]);
- *
- *   // Announce ourselves.
- *   mdns.announce(ip, "fred", "_http._tcp", 80, "The Little Server that Could", "path=/demo");
- *
- *   while()... enter some run loop
- *   ...
- *
- *  This will cause http://fred.local./demo to be announced as 'The Little Server that Could'.
- *
- *  Or as another example: (http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt)
- *  and the various RFCs:
- *
- *     mdns.announce(ip, "_ssh._tcp", 22, SSH to Serial Gateway", NULL);
- *
- * CAVEAT - a lot of the buffer overrun and copy checks
- *          where removed; and this is not anywhere near
- *          threadsafve or sane. Not for production use.
- */
-#include "lwip/opt.h"
-#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
-
-#include "mDNSResponder.h"
-#include <stdio.h>
-
-#ifndef DNS_RRTYPE_SRV
-#define DNS_RRTYPE_SRV (33)
-#endif
-
-mDNSResponder::mDNSResponder() : NetService(false),
-        moi_txt(NULL), moi_port(0), moi_ip(0),
-        moi_name(NULL), moi_proto(NULL),
-        moi_local_proto(NULL), moi_local_name(NULL), moi_local_pglue(NULL),
-        announcer() {
-    // nothing yet...
-}
-
-mDNSResponder::~mDNSResponder() {
-    announcer.stop();
-    close();
-}
-
-void mDNSResponder::announce(IpAddr ip, const char * ldn, const char * proto, uint16_t port, const char * name, char ** txt) {
-    Host localhost(IpAddr(MCAST), MDNS_PORT, NULL /* fqdn */);
-
-    m_pUDPSocket = new UDPSocket;
-    m_pUDPSocket->bind(localhost);
-
-    m_pUDPSocket->setOnEvent(this, &mDNSResponder::onUDPSocketEvent);
-
-    moi_port = port;
-    moi_txt = txt;
-    moi_ip = ip;
-    moi_proto = proto;
-    moi_name = name;
-
-    moi_local_proto = (char *)malloc(128);
-    moi_local_name = (char *)malloc(128);
-    moi_local_pglue = (char *)malloc(128);
-
-#define LOCAL "local"
-    snprintf(moi_local_proto,128,"%s.%s.", moi_proto, LOCAL);
-    snprintf(moi_local_name,128,"%s.%s.", ldn, LOCAL);
-    snprintf(moi_local_pglue,128,"%s.%s.%s.", moi_name,moi_proto, LOCAL);
-
-    // Gratuis intro - and repeat such regularly..
-    //
-    mDNSResponder::sendReply(DNS_RRTYPE_PTR, 0, localhost);
-    announcer.start();
-}
-
-void mDNSResponder::close() {
-    m_pUDPSocket->resetOnEvent();
-    m_pUDPSocket->close();
-    delete m_pUDPSocket;
-}
-
-
-
-void mDNSResponder::poll() { //Called by NetServices
-    if (announcer.read_ms() > 1000  * MDNS_INTERVAL) {
-
-        Host mch(IpAddr(MCAST), MDNS_PORT, NULL);
-        mDNSResponder::sendReply(DNS_RRTYPE_PTR, 0, mch);
-
-        announcer.reset();
-    }
-}
-
-char * index(char * str, char c) {
-    for (;str && *str;str++) {
-        if (*str == c) return str;
-    };
-    return NULL;
-}
-
-#ifndef THREADINGCOMPRESS
-#ifndef MAXCACHEDNSLABELS
-#define MAXCACHEDNSLABELS (10)
-#endif
-static int labelCacheCnt = 0;
-static uint16_t _cache_off[MAXCACHEDNSLABELS];
-static char * _cache_och[MAXCACHEDNSLABELS];
-static char * labelCacheOffset = 0;
-
-void initLabelCache(char * off) {
-    labelCacheOffset = off;
-    labelCacheCnt = 0;
-    memset(_cache_off,0, sizeof(_cache_off)); // Rely on min value to be 12
-};
-
-uint16_t checkLabelCache(char * name) {
-    for (int i=0; i < MAXCACHEDNSLABELS; i++)
-        if (_cache_off[i] && !strcmp(_cache_och[i],name))
-            return _cache_off[i];
-    return 0;
-};
-
-void addLabelCache(char * p, char * name) {
-    _cache_off[labelCacheCnt] = p - labelCacheOffset;
-    _cache_och[labelCacheCnt] = name;
-
-    labelCacheCnt++;
-    // we intentionally do not wack the first entries - as they are the most
-    // likely ones to be used.
-    if (labelCacheCnt>=MAXCACHEDNSLABELS)
-        labelCacheCnt = MAXCACHEDNSLABELS / 3;
-};
-#else
-#define initLabelCache(x) {} /* Ignored */
-#define checkLabelCache(x) (0) /* never a hit */
-#define addLabelCache(x,y) {} /* Ignored */
-#endif
-
-char * breakname(char *p, char *name) {
-    int l = 0, de = 1;
-    char * q;
-    uint16_t off;
-
-    do {
-        if ((off = checkLabelCache(name))) {
-            *p++ = 192 + (off >> 8);
-            *p++ =       (off &  0xFF);
-            return p;
-        } else {
-            addLabelCache(p, name);
-        };
-
-        q = index(name,'.');
-        if (!q) {
-            q = name + strlen(name);
-            de = 0;
-        };
-        l = q - name;
-        *p++ = l;
-        memcpy(p, name, l);
-        p+=l;
-        name = q + 1;
-    } while (l && *name && de);
-
-    // terminating root field if any (not the case for
-    // things like TXTs).
-    if (de) *p++ = 0;
-    return p;
-}
-
-char * mRR(char *p, char * name, uint16_t tpe, uint16_t cls, uint32_t ttl) {
-    uint16_t i = 0;
-    uint32_t j = 0;
-
-    p = breakname(p, name);
-
-    // NOTE: Cannot assume proper byte boundaries.
-    //
-    i = htons(tpe); // Type
-    memcpy(p, &i,  2);
-    p+=2;
-
-    i = htons(cls); // Class
-    memcpy(p, &i, 2);
-    p+=2;
-
-    j = htonl(ttl); // TTL (4 bytes)
-    memcpy(p, &j, 4);
-    p+=4;
-
-    return p;
-}
-
-char * mRRLABEL(char *p, char * name, uint16_t tpe, char ** rr) {
-    uint16_t i;
-
-    p = mRR(p, name, tpe, DNS_RRCLASS_IN, MDNS_TTL); // Type, IN, TTL
-
-    // RR String
-    char * q = p + 2;
-
-    for (;*rr;rr++)
-        q = breakname(q, *rr);
-
-    i = htons(q - p - 2); // RDLEN
-    memcpy(p, &i, 2);
-    return q;
-}
-
-char * mPTR(char *p, char * name, char * r) {
-    char *rr[] = { r, NULL };
-    return mRRLABEL(p, name, DNS_RRTYPE_PTR, rr );
-}
-
-char * mTXT(char *p, char * name, char ** rr) {
-    return mRRLABEL(p, name, DNS_RRTYPE_TXT, rr);
-}
-
-char * mARR(char *p, char * name, IpAddr ip) {
-    uint16_t i;
-
-    p = mRR(p, name, DNS_RRTYPE_A, DNS_RRCLASS_IN, MDNS_TTL ); // A, IN
-
-    i = htons(4); // RDLEN - we're just doing a single IPv4 address - our primary link ?
-    memcpy(p, &i, 2);
-
-    // IP already in network order.
-    memcpy(p+2, &ip, 4);
-
-    return p + 2 + 4;
-}
-
-char * mSRV(char *p, char * name, uint16_t port, char * rr) {
-    uint16_t i = 0;
-    char * q;
-
-    p = mRR(p, name, DNS_RRTYPE_SRV, DNS_RRCLASS_IN, MDNS_TTL); // SRV, IN
-
-    // Keep space for RDLEN
-    q = p;
-    p+=2;
-
-    i = htons(1); // Priority
-    memcpy(p, &i, 2);
-    p+=2;
-
-    i = htons(0); // Weight (see rfc2782)
-    memcpy(p, &i, 2);
-    p+=2;
-
-    i = htons(port); // Port
-    memcpy(p, &i, 2);
-    p+=2;
-
-    p = breakname(p, rr);
-
-    i = htons(p - q - 2); // RDLEN
-    memcpy(q, &i, 2);
-
-    return p;
-}
-
-char * qANY(char *p, char * name, uint16_t tpe, uint16_t cls) {
-    uint16_t i = 0;
-    p = breakname(p, name); // QNAME
-
-    i = htons(tpe); // QTYPE
-    memcpy(p, &i, 2);
-    p+=2;
-
-    i = htons(cls); // QCLASS
-    memcpy(p, &i, 2);
-    p+=2;
-
-    return p;
-}
-
-char * qPTR(char *p, char *name) {
-    return qANY(p,name,DNS_RRTYPE_PTR,DNS_RRCLASS_IN);
-}
-
-char * qA(char *p, char *name) {
-    return qANY(p,name,DNS_RRTYPE_A,DNS_RRCLASS_IN);
-}
-
-char * qSRV(char *p, char *name) {
-    return qANY(p,name,DNS_RRTYPE_SRV,DNS_RRCLASS_IN);
-}
-
-void mDNSResponder::sendReply(uint16_t t, uint16_t tid, Host dst) {
-    // sent a reply - basically a precooked A/PTR/SRV with the TransactionID
-    // and my URI squeezed in.
-    char out[ 1500 ], *p;
-    DNSPacket * op = (DNSPacket *) out;
-
-    initLabelCache(out); // Offsets are relative to the ID header.
-
-    op->tid = ntohs(tid);
-    op->flags = ntohs(0x8000U); // Answer
-    op->question_count = ntohs(1); // Courtesy copy of the question.
-    op->answer_count = ntohs(1); // The record asked for
-    op->a_count = ntohs(0);
-    p = out + 12;
-
-    switch (t) {
-        case DNS_RRTYPE_PTR:    // PTR record, SRV, optional TXT and A with my own address.
-            op->aa_count = ntohs(moi_txt ? 3 : 2);
-            p = qPTR(p,moi_local_proto);
-
-            p = mPTR(p,moi_local_proto, moi_local_pglue);
-            if (moi_txt && * moi_txt)
-                p = mTXT(p,moi_local_pglue,moi_txt);
-
-            break;
-        case DNS_RRTYPE_A:    // A record (and nothing else)
-            op->aa_count = ntohs(1);
-            p = qA(p,moi_local_name);
-            break;
-
-        case DNS_RRTYPE_SRV:   // SRV record and a gratious A record to complete.
-            op->aa_count = ntohs(moi_txt ? 2 : 1);
-            p = qSRV(p,moi_local_pglue);
-
-            p = mPTR(p,moi_local_proto, moi_local_pglue);
-            if (moi_txt && * moi_txt)
-                p = mTXT(p,moi_local_pglue,moi_txt);
-            break;
-    }
-    p = mARR(p,moi_local_name,moi_ip);
-    m_pUDPSocket->sendto(out,p-out,&dst);
-}
-
-char * decodeQBlock(char * udp, int len, char *p, char  * fqdn, int fqdn_size, uint32_t *Qclass, uint32_t *Qtype) {
-    char * endp = udp + len;
-    int depth = 0;
-    int l, ll = 0;
-    char * q = 0;
-    char * ep = fqdn;
-
-    do {
-        while (((l = *p++) < 192) && (l > 0)) {
-            if (p + l >= endp) {
-                printf("RR longer than packet\r\n");
-                return NULL;
-            };
-
-            if (ll + l + 1 > fqdn_size) {
-                printf("FQDN too long\r\n");
-                return NULL;
-            }
-
-            memcpy(ep,p,l);
-            ep[l]='.';
-            ep += l + 1;
-            p += l;
-            ll += l + 1;
-        };
-
-        if (l >= 192) {
-            // construct an offset pointer by wiping the top 1 bits
-            // and then getting the remaining 8 bytes to make 14.
-            l -= 192;
-            l = l << 8;
-            l += *p++;
-
-            // rescue our reference; as we've not gotten the Qt's yet
-            // and these follow the last entry in our record (and not
-            // that from the compressed values.
-            //
-            if (!q) q = p;
-
-            // printf(" [->%d] ",l);
-            p = udp + l;
-
-            if (p >= udp + len || p < udp + 12) {
-                printf("Pointer to wrong place\r\n");
-                return NULL;
-            };
-        };
-
-        if (depth++ >= 128) {
-            printf("Far too deep\r\n");
-            return NULL;
-        };
-    } while (l);
-
-    // Terminate the FQDN string.
-    *ep = 0;
-
-    // in case no compression was used at all.
-    if (!q)
-        q = p;
-
-    *Qtype = htons(q[0] + q[1]*256);
-    *Qclass = htons(q[2] + q[3]*256);
-    return p;
-}
-
-void mDNSResponder::onUDPSocketEvent(UDPSocketEvent e) {
-    char udp[ 1500 ];
-    Host from;
-    int len;
-
-    //The only event for now
-    if (e != UDPSOCKET_READABLE)
-        return;
-        
-    // parse through the packet; find any PTR requests
-    // and respond to any for _http._tcp._local.
-    //
-    while ((len = m_pUDPSocket->recvfrom( (char*)&udp, sizeof(udp), &from ))) {
-        DNSPacket * dp = (DNSPacket *) udp;
-        
-        unsigned int tid = ntohs(dp->tid);
-        unsigned int flags = ntohs(dp->flags);
-        unsigned int nQ = ntohs(dp->question_count);
-
-        if (flags & 2 != 0 || nQ < 1)
-            continue; // we only want questions
-
-        // assume nQ NON terminated fields followed by Qtype & Qclass
-        //
-        char * p = udp + 12;
-        for (int i = 0; i < nQ; i++) {
-            char fqdn[ 256 ];
-            uint32_t Qt, Qc;
-
-            if (!((p = decodeQBlock(udp,len,p,fqdn,sizeof(fqdn),&Qc, &Qt))))
-                return;
-
-            // We only deal with INternet.
-            //
-            if (Qc != DNS_RRCLASS_IN)
-                continue;
-
-            printf("Q type %d for %s\r\n", Qt, fqdn);
-
-            // We want PTR records on the INternet of our type. Also do ANY.
-            //
-            if ((Qt == DNS_RRTYPE_PTR || Qt == 255) && !(strcmp(fqdn,moi_local_proto)))
-                sendReply(DNS_RRTYPE_PTR,tid,from);
-            else if ((Qt == DNS_RRTYPE_A || Qt == 255)  && !(strcmp(fqdn,moi_local_name)))
-                sendReply(DNS_RRTYPE_A,tid,from);
-            else if ((Qt == DNS_RRTYPE_SRV || Qt == 255)  && !(strcmp(fqdn,moi_local_pglue)))
-                sendReply(DNS_RRTYPE_SRV,tid,from);
-        };
-    }
-}
-#endif
+/* Class: mDNSResponder
+ * Copyright 1991, 2003, 2010 Dirk-Willem van Gulik <dirkx(at)apache(punto)org>
+ *
+ * License: Any BSD or ASF License.
+ *
+ * Rough and ready port of some mDNS code.
+ *
+ * Typical use is something like
+ *
+ * EthernetNetIf eth;
+ * HTTPServer svr;
+ * mDNSResponder mdns;
+ *
+ * int main()...
+ *
+ *   // get internet
+ *   EthernetErr ethErr = eth.setup();
+ *   ... etc ..
+ *
+ *   // set up some server
+ *   svr.addHandler<SimpleHandler>("/"); //Default handler
+ *   svr.bind(80); * *
+
+ *  // Extract the IP address.
+ *   IpAddr ip = eth.getIp();
+ *   printf("mbed IP Address is %d.%d.%d.%d\r\n", ip[0], ip[1], ip[2], ip[3]);
+ *
+ *   // Announce ourselves.
+ *   mdns.announce(ip, "fred", "_http._tcp", 80, "The Little Server that Could", "path=/demo");
+ *
+ *   while()... enter some run loop
+ *   ...
+ *
+ *  This will cause http://fred.local./demo to be announced as 'The Little Server that Could'.
+ *
+ *  Or as another example: (http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt)
+ *  and the various RFCs:
+ *
+ *     mdns.announce(ip, "_ssh._tcp", 22, SSH to Serial Gateway", NULL);
+ *
+ * CAVEAT - a lot of the buffer overrun and copy checks
+ *          where removed; and this is not anywhere near
+ *          threadsafve or sane. Not for production use.
+ */
+#include "lwip/opt.h"
+#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
+
+#define __DEBUG
+#include "dbg/dbg.h"
+
+#include "mDNSResponder.h"
+#include <stdio.h>
+
+#ifndef DNS_RRTYPE_SRV
+#define DNS_RRTYPE_SRV (33)
+#endif
+
+#ifndef DNS_LOCAL
+#define DNS_LOCAL "local"
+#endif
+
+mDNSResponder::mDNSResponder() : NetService(false),
+        moi_txt(NULL), moi_port(0), moi_ip(0),
+        moi_name(NULL), moi_proto(NULL),
+        moi_local_proto(NULL), moi_local_name(NULL), moi_local_pglue(NULL),
+#ifdef MDNS_QCACHE
+        labelCacheCnt(0), labelCacheOffset(0),
+#endif
+        announcer() 
+{
+    initLabelCache(0);
+}
+
+mDNSResponder::~mDNSResponder() {
+    announcer.stop();
+    close();
+}
+
+void mDNSResponder::announce(IpAddr ip, const char * ldn, const char * proto, uint16_t port, const char * name, char ** txt) {
+    Host localhost(IpAddr(MCAST), MDNS_PORT, NULL /* fqdn */);
+
+    m_pUDPSocket = new UDPSocket;
+    m_pUDPSocket->bind(localhost);
+
+    m_pUDPSocket->setOnEvent(this, &mDNSResponder::onUDPSocketEvent);
+
+    moi_port = port;
+    moi_txt = txt;
+    moi_ip = ip;
+    moi_proto = proto;
+    moi_name = name;
+
+    moi_local_proto = (char *)malloc(128);
+    moi_local_name = (char *)malloc(128);
+    moi_local_pglue = (char *)malloc(128);
+
+    snprintf(moi_local_proto,128,"%s.%s.", moi_proto, DNS_LOCAL);
+    snprintf(moi_local_name,128,"%s.%s.", ldn, DNS_LOCAL);
+    snprintf(moi_local_pglue,128,"%s.%s.%s.", moi_name,moi_proto, DNS_LOCAL);
+
+    // Gratuis intro - and repeat such regularly.. taking some
+    // care to not go beyond DHCP limits - but not more often
+    // than makes sense for our TTL. See the .h file for the
+    // various tradeoffs.
+    //
+    mDNSResponder::sendReply(DNS_RRTYPE_PTR, 0, localhost);
+    announcer.start();
+}
+
+void mDNSResponder::close() {
+    m_pUDPSocket->resetOnEvent();
+    m_pUDPSocket->close();
+    delete m_pUDPSocket;
+}
+
+void mDNSResponder::poll() { //Called by NetServices
+    if (announcer.read_ms() > 1000  * MDNS_INTERVAL) {
+
+        Host mch(IpAddr(MCAST), MDNS_PORT, NULL);
+        mDNSResponder::sendReply(DNS_RRTYPE_PTR, 0, mch);
+
+        announcer.reset();
+    }
+}
+
+char * index(char * str, char c) {
+    for (;str && *str;str++) {
+        if (*str == c) return str;
+    };
+    return NULL;
+}
+
+#ifdef MDNS_QCACHE
+void mDNSResponder::initLabelCache(char * off) {
+    labelCacheOffset = off;
+    labelCacheCnt = 0;
+    memset(_cache_off,0, sizeof(_cache_off)); // Rely on min value to be 12
+};
+
+uint16_t mDNSResponder::checkLabelCache(char * name) {
+    // Bail out if not initialized with a valid (>12) offset.
+    //
+    if (!labelCacheOffset)
+        return 0;
+    
+    for (int i=0; i < MDNS_MAXCACHEDNSLABELS; i++)
+        if (_cache_off[i] && !strcmp(_cache_och[i],name))
+            return _cache_off[i];
+    return 0;
+};
+
+void mDNSResponder::addLabelCache(char * p, char * name) {
+    // Bail out if not initialized with a valid (>12) offset.
+    //
+    if (!labelCacheOffset)
+        return;
+        
+    _cache_off[labelCacheCnt] = p - labelCacheOffset;
+    _cache_och[labelCacheCnt] = name;
+
+    labelCacheCnt++;
+    // we intentionally do not wack the first entries - as they are the most
+    // likely ones to be used.
+    if (labelCacheCnt>= MDNS_MAXCACHEDNSLABELS)
+        labelCacheCnt = MDNS_MAXCACHEDNSLABELS / 3;
+};
+#else
+#define initLabelCache(x) {} /* Ignored */
+#define checkLabelCache(x) (0) /* never a hit */
+#define addLabelCache(x,y) {} /* Ignored */
+#endif
+
+char * mDNSResponder::breakname(char *p, char *name) {
+    int l = 0, de = 1;
+    char * q;
+    uint16_t off;
+
+    do {
+        if ((off = checkLabelCache(name)) != 0) {
+            *p++ = 192 + (off >> 8);
+            *p++ =       (off &  0xFF);
+            return p;
+        } else {
+            addLabelCache(p, name);
+        };
+
+        q = index(name,'.');
+        if (!q) {
+            q = name + strlen(name);
+            de = 0;
+        };
+        l = q - name;
+        *p++ = l;
+        memcpy(p, name, l);
+        p+=l;
+        name = q + 1;
+    } while (l && *name && de);
+
+    // terminating root field if any (not the case for
+    // things like TXTs).
+    if (de) *p++ = 0;
+    return p;
+}
+
+char * mDNSResponder::mRR(char *p, char * name, uint16_t tpe, uint16_t cls, uint32_t ttl) {
+    uint16_t i = 0;
+    uint32_t j = 0;
+
+    p = breakname(p, name);
+
+    // NOTE: Cannot assume proper byte boundaries; so
+    // we assume the compiler does not allow that for
+    // casts - and write it out with memcpy's
+    //
+    i = htons(tpe); // Type
+    memcpy(p, &i,  2);
+    p+=2;
+
+    i = htons(cls); // Class
+    memcpy(p, &i, 2);
+    p+=2;
+
+    j = htonl(ttl); // TTL (4 bytes)
+    memcpy(p, &j, 4);
+    p+=4;
+
+    return p;
+}
+
+char * mDNSResponder::mRRLABEL(char *p, char * name, uint16_t tpe, char ** rr) {
+    uint16_t i = 0;
+
+    p = mRR(p, name, tpe, DNS_RRCLASS_IN, MDNS_TTL); // Type, IN, TTL
+
+    // RR String
+    char * q = p + 2;
+
+    for (;*rr;rr++)
+        q = breakname(q, *rr);
+
+    i = htons(q - p - 2); // RDLEN
+    memcpy(p, &i, 2);
+    return q;
+}
+
+char * mDNSResponder::mPTR(char *p, char * name, char * r) {
+    char *rr[] = { r, NULL };
+    return mRRLABEL(p, name, DNS_RRTYPE_PTR, rr );
+}
+
+char * mDNSResponder::mTXT(char *p, char * name, char ** rr) {
+    return mRRLABEL(p, name, DNS_RRTYPE_TXT, rr);
+}
+
+char * mDNSResponder::mARR(char *p, char * name, IpAddr ip) {
+    uint16_t i = 0;
+
+    p = mRR(p, name, DNS_RRTYPE_A, DNS_RRCLASS_IN, MDNS_TTL ); // A, IN
+
+    i = htons(4); // RDLEN - we're just doing a single IPv4 address - our primary link ?
+    memcpy(p, &i, 2);
+
+    // IP already in network order.
+    memcpy(p+2, &ip, 4);
+
+    return p + 2 + 4;
+}
+
+char * mDNSResponder::mSRV(char *p, char * name, uint16_t port, char * rr) {
+    uint16_t i = 0;
+    char * q;
+
+    p = mRR(p, name, DNS_RRTYPE_SRV, DNS_RRCLASS_IN, MDNS_TTL); // SRV, IN
+
+    // Keep space for RDLEN
+    q = p;
+    p+=2;
+
+    i = htons(1); // Priority
+    memcpy(p, &i, 2);
+    p+=2;
+
+    i = htons(0); // Weight (see rfc2782)
+    memcpy(p, &i, 2);
+    p+=2;
+
+    i = htons(port); // Port
+    memcpy(p, &i, 2);
+    p+=2;
+
+    p = breakname(p, rr);
+
+    i = htons(p - q - 2); // RDLEN
+    memcpy(q, &i, 2);
+
+    return p;
+}
+
+char * mDNSResponder::qANY(char *p, char * name, uint16_t tpe, uint16_t cls) {
+    uint16_t i = 0;
+    p = breakname(p, name); // QNAME
+
+    i = htons(tpe); // QTYPE
+    memcpy(p, &i, 2);
+    p+=2;
+
+    i = htons(cls); // QCLASS
+    memcpy(p, &i, 2);
+    p+=2;
+
+    return p;
+}
+
+char * mDNSResponder::qPTR(char *p, char *name) {
+    return qANY(p,name,DNS_RRTYPE_PTR,DNS_RRCLASS_IN);
+}
+
+char * mDNSResponder::qA(char *p, char *name) {
+    return qANY(p,name,DNS_RRTYPE_A,DNS_RRCLASS_IN);
+}
+
+char * mDNSResponder::qSRV(char *p, char *name) {
+    return qANY(p,name,DNS_RRTYPE_SRV,DNS_RRCLASS_IN);
+}
+
+void mDNSResponder::mDNSResponder::sendReply(uint16_t t, uint16_t tid, Host dst) {
+    // sent a reply - basically a precooked A/PTR/SRV with the TransactionID
+    // and my URI squeezed in.
+    char out[ 1500 ], *p;
+    DNSPacket * op = (DNSPacket *) out;
+
+    initLabelCache(out); // Offsets are relative to the ID header.
+
+    op->tid = ntohs(tid);
+    op->flags = ntohs(0x8000U); // Answer
+    op->question_count = ntohs(1); // Courtesy copy of the question.
+    op->answer_count = ntohs(1); // The record asked for
+    op->a_count = ntohs(0);
+    p = out + 12;
+
+    switch (t) {
+        case DNS_RRTYPE_PTR:    // PTR record, SRV, optional TXT and A with my own address.
+            op->aa_count = ntohs(moi_txt ? 3 : 2);
+            p = qPTR(p,moi_local_proto);
+
+            p = mPTR(p,moi_local_proto, moi_local_pglue);
+            if (moi_txt && * moi_txt)
+                p = mTXT(p,moi_local_pglue,moi_txt);
+
+            break;
+        case DNS_RRTYPE_A:    // A record (and nothing else)
+            op->aa_count = ntohs(1);
+            p = qA(p,moi_local_name);
+            break;
+
+        case DNS_RRTYPE_SRV:   // SRV record and a gratious A record to complete.
+            op->aa_count = ntohs(moi_txt ? 2 : 1);
+            p = qSRV(p,moi_local_pglue);
+
+            p = mPTR(p,moi_local_proto, moi_local_pglue);
+            if (moi_txt && * moi_txt)
+                p = mTXT(p,moi_local_pglue,moi_txt);
+            break;
+    }
+    p = mARR(p,moi_local_name,moi_ip);
+    m_pUDPSocket->sendto(out,p-out,&dst);
+    DBG("Reply type %d sent to %s\r\n",t,dst);
+}
+
+char * mDNSResponder::decodeQBlock(char * udp, int len, char *p, char  * fqdn, int fqdn_size, uint32_t *Qclass, uint32_t *Qtype) {
+    char * endp = udp + len;
+    int depth = 0;
+    int l, ll = 0;
+    char * q = 0;
+    char * ep = fqdn;
+
+    do {
+        while (((l = *p++) < 192) && (l > 0)) {
+            if (p + l >= endp) {
+                DBG("Malformed packet or bug, RR field larger than packet itself\n\r");
+                return NULL;
+            };
+
+            if (ll + l + 1 > fqdn_size) {
+                DBG("Malformed packet or bug, FQDN exceeds %d bytes\n\r", fqdn_size);
+                return NULL;
+            }
+
+            memcpy(ep,p,l);
+            ep[l]='.';
+            ep += l + 1;
+            p += l;
+            ll += l + 1;
+        };
+
+        if (l >= 192) {
+            // construct an offset pointer by wiping the top 1 bits
+            // and then getting the remaining 8 bytes to make 14.
+            l -= 192;
+            l = l << 8;
+            l += *p++;
+
+            // rescue our reference; as we've not gotten the Qt's yet
+            // and these follow the last entry in our record (and not
+            // that from the compressed values.
+            //
+            if (!q) q = p;
+
+            // printf(" [->%d] ",l);
+            p = udp + l;
+
+            if (p >= udp + len || p < udp + 12) {
+                DBG("Malformed packet or bug, pointer outside UDP packet\n\r");
+                return NULL;
+            };
+        };
+
+        if (depth++ >= 128) {
+            DBG("Malformed packet or bug, depth too high\n\r");
+            return NULL;
+        };
+    } while (l);
+
+    // Terminate the FQDN string.
+    *ep = 0;
+
+    // in case no compression was used at all.
+    if (!q)
+        q = p;
+
+    *Qtype = htons(q[0] + q[1]*256);
+    *Qclass = htons(q[2] + q[3]*256);
+    return p;
+}
+
+void mDNSResponder::onUDPSocketEvent(UDPSocketEvent e) {
+    char udp[ 1500 ];
+    Host from;
+    int len;
+
+    //The only event for now
+    if (e != UDPSOCKET_READABLE)
+        return;
+        
+    // parse through the packet; find any PTR requests
+    // and respond to any for _http._tcp._local.
+    //
+    while ((len = m_pUDPSocket->recvfrom( (char*)&udp, sizeof(udp), &from )) != 0) {
+        DNSPacket * dp = (DNSPacket *) udp;
+        
+        unsigned int tid = ntohs(dp->tid);
+        unsigned int flags = ntohs(dp->flags);
+        unsigned int nQ = ntohs(dp->question_count);
+
+        if (flags & 2 != 0 || nQ < 1)
+            continue; // we only want questions
+
+        // assume nQ NON terminated fields followed by Qtype & Qclass
+        //
+        char * p = udp + 12;
+        for (int i = 0; i < nQ; i++) {
+            char fqdn[ 256 ];
+            uint32_t Qt, Qc;
+
+            if ( (p = decodeQBlock(udp,len,p,fqdn,sizeof(fqdn),&Qc, &Qt)) == 0)
+                return;
+
+            // We only deal with INternet.
+            //
+            if (Qc != DNS_RRCLASS_IN)
+                continue;
+
+           DBG("IN query %x for %s\n\r", Qt, fqdn);
+            
+            // Normally we'll respond to a mCast query for the PTR of our conceptual
+            // service; to which we reply with the services we run; and then the A
+            // records for our actual endpoint. However if one of the requistors their
+            // cashing is not up to scratch - we may (also) get hit up a bit later for
+            // the secondary records under their logical names. So we respond to
+            // all 3. As this is likely to happen due to resource constraints on the
+            // side of the requestor; we are careful and reply as 'narrow' as possible.
+            //
+            // Note that we also respond to the ANY query - as to make a quick 'dig'
+            // testing command easier.
+            //
+            if ((Qt == DNS_RRTYPE_PTR || Qt == 255) && !(strcmp(fqdn,moi_local_proto)))
+                sendReply(DNS_RRTYPE_PTR,tid,from);
+            else if ((Qt == DNS_RRTYPE_A || Qt == 255)  && !(strcmp(fqdn,moi_local_name)))
+                sendReply(DNS_RRTYPE_A,tid,from);
+            else if ((Qt == DNS_RRTYPE_SRV || Qt == 255)  && !(strcmp(fqdn,moi_local_pglue)))
+                sendReply(DNS_RRTYPE_SRV,tid,from);
+            else
+               DBG(".. which was ignored\n\r", Qt, fqdn);
+            
+        };
+    }
+}
+#endif
--- a/services/mDNS/mDNSResponder.h	Tue Jul 27 17:22:17 2010 +0000
+++ b/services/mDNS/mDNSResponder.h	Sat Jul 31 14:30:45 2010 +0000
@@ -34,23 +34,103 @@
 #define MDNS_INTERVAL ( MDNS_TTL * 2 / 3 )
 #endif
 
+#ifndef MDNS_QCACHE
+#define MDNS_QCACHE 1
+#endif
+
+#ifndef MDNS_MAXCACHEDNSLABELS
+#define MDNS_MAXCACHEDNSLABELS (10)
+#endif
+
 class mDNSResponder : protected NetService
 {
 public:
   mDNSResponder();
   virtual ~mDNSResponder();
   void close();
-void mDNSResponder::announce(IpAddr ip, const char * ldn, const char * proto, uint16_t port, const char * name, char ** txts);
+  void announce(IpAddr ip, const char * ldn, const char * proto, uint16_t port, const char * name, char ** txts);
   
 protected:
   virtual void poll(); //Called by NetServices - not actually needed.
   
 private:
-  void process(); //Main state-machine
+  void process(); // Needed for timer, to fire off regular updates.
+  
+  // Main inbound packet handler
   void onUDPSocketEvent(UDPSocketEvent e);
-  void sendReply(uint16_t Qtype,uint16_t tid, Host dst); // temp
+
+  // 3 functions to keep a QName chace. If enabled with MDNS_QCACHE
+  void initLabelCache(char * off);
+  uint16_t checkLabelCache(char * name);
+  void addLabelCache(char * p, char * name);
+  
+  // Handing functions
+  char * breakname(char *p, char *name); // Break FQDNs at the dots, understanding QCaching.
+  
+  // reply building functions; see RFC for names/defintion.
+  char * mRR(char *p, char * name, uint16_t tpe, uint16_t cls, uint32_t ttl);
+  char * mRRLABEL(char *p, char * name, uint16_t tpe, char ** rr); 
+  char * mPTR(char *p, char * name, char * r); 
+  char * mTXT(char *p, char * name, char ** rr);
+  char * mARR(char *p, char * name, IpAddr ip);
+  char * mSRV(char *p, char * name, uint16_t port, char * rr);
+  char * qANY(char *p, char * name, uint16_t tpe, uint16_t cls);
+
+  // build query part of a reply.
+  char * qPTR(char *p, char *name);
+  char * qA(char *p, char *name);
+  char * qSRV(char *p, char *name);
+  
+  // Sent out the actual DNS packet.
+  void sendReply(uint16_t t, uint16_t tid, Host dst);
   
+  // Decode the query part of a DNS inbound packet.
+  char * decodeQBlock(char * udp, int len, char *p, char  * fqdn, int fqdn_size, uint32_t *Qclass, uint32_t *Qtype);
+
+PACK_STRUCT_BEGIN
+struct DNSPacket
+  {
+    PACK_STRUCT_FIELD(uint16_t tid);
+    PACK_STRUCT_FIELD(uint16_t flags);
+    PACK_STRUCT_FIELD(uint16_t question_count);
+    PACK_STRUCT_FIELD(uint16_t answer_count);
+    PACK_STRUCT_FIELD(uint16_t a_count);
+    PACK_STRUCT_FIELD(uint16_t aa_count);
+    PACK_STRUCT_FIELD(char answers);
+  } PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+  
+  // Services
+  char ** moi_txt; /* Null terminated list */
+  
+  // Endpoint
+  uint16_t moi_port;
+  IpAddr moi_ip;
+  
+  // Local name construction.
+  const char * moi_name, * moi_proto;
+  char * moi_local_proto, * moi_local_name, * moi_local_pglue;
+  
+  Timer announcer;
+    
+  UDPSocket* m_pUDPSocket;
+
+  // For the QCache
+#ifdef MDNS_QCACHE
+  int labelCacheCnt;
+  char * labelCacheOffset;
+  
+  uint16_t _cache_off[MDNS_MAXCACHEDNSLABELS];
+  char * _cache_och[MDNS_MAXCACHEDNSLABELS];
+#endif
+};
+
+
+
+#endif
+
 // Just in case - there is prolly some nice ARM6 assembler already linked in.
+//
 #ifndef htons
 #define htons( x ) ( (( x << 8 ) & 0xFF00) | (( x >> 8 ) & 0x00FF) )
 #define ntohs( x ) (htons(x))
@@ -64,26 +144,4 @@
 #define ntohl( x ) (htonl(x))
 #endif
 
-  __packed struct DNSPacket
-  {
-    uint16_t tid;
-    uint16_t flags;
-    uint16_t question_count;
-    uint16_t answer_count;
-    uint16_t a_count;
-    uint16_t aa_count;
-    char answers;
-  };
-  const char * moi_name, * moi_proto;
-  char ** moi_txt; /* Null terminated list */
-  char * moi_local_proto, * moi_local_name, * moi_local_pglue;
-  uint16_t moi_port;
-  IpAddr moi_ip;
-  
-  Timer announcer;
-    
-  UDPSocket* m_pUDPSocket;
-};
-
 #endif
-#endif
--- a/services/ntp/NTPClient.cpp	Tue Jul 27 17:22:17 2010 +0000
+++ b/services/ntp/NTPClient.cpp	Sat Jul 31 14:30:45 2010 +0000
@@ -197,8 +197,7 @@
     break;
   
   case NTP_PONG:
-    DBG("\r\nPong\r\n");
-    while( len = m_pUDPSocket->recvfrom( (char*)&m_pkt, sizeof(NTPPacket), &host ) )
+    while((len = m_pUDPSocket->recvfrom( (char*)&m_pkt, sizeof(NTPPacket), &host )) != 0 )
     {
       if( len <= 0 )
         break;