Bonjour/Zerconf library

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
dirkx
Date:
Sat Jul 24 20:59:52 2010 +0000
Parent:
1:59820ca5c83a
Child:
3:e1d86543ec50
Commit message:

Changed in this revision

lwip/core/ipv4/igmp.c Show annotated file Show diff for this revision Revisions of this file
lwip/core/ipv4/ip.c Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
netCfg.h Show annotated file Show diff for this revision Revisions of this file
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
--- a/lwip/core/ipv4/igmp.c	Thu Jul 22 00:08:38 2010 +0000
+++ b/lwip/core/ipv4/igmp.c	Sat Jul 24 20:59:52 2010 +0000
@@ -326,7 +326,7 @@
   }
 
   /* Group doesn't exist yet, create a new one */
-  group = memp_malloc(MEMP_IGMP_GROUP);
+  group = (struct igmp_group *) memp_malloc(MEMP_IGMP_GROUP);
   if (group != NULL) {
     group->netif              = ifp;
     ip_addr_set(&(group->group_address), addr);
@@ -397,7 +397,7 @@
   IGMP_STATS_INC(igmp.recv);
 
   /* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */    
-  iphdr = p->payload;
+  iphdr = (struct ip_hdr *) p->payload;
   if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) {
     pbuf_free(p);
     IGMP_STATS_INC(igmp.lenerr);
@@ -715,7 +715,7 @@
 static void
 igmp_stop_timer(struct igmp_group *group)
 {
-	  group->timer = 0;
+      group->timer = 0;
 }
 
 /**
@@ -783,7 +783,7 @@
   p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM);
   
   if (p) {
-    igmp = p->payload;
+    igmp = (struct igmp_msg*) p->payload;
     LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg",
                (p->len >= sizeof(struct igmp_msg)));
     ip_addr_copy(src, group->netif->ip_addr);
--- a/lwip/core/ipv4/ip.c	Thu Jul 22 00:08:38 2010 +0000
+++ b/lwip/core/ipv4/ip.c	Sat Jul 24 20:59:52 2010 +0000
@@ -295,11 +295,13 @@
       /* interface is up and configured? */
       if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) {
         /* unicast to this interface address? */
-        if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)) ||
+        if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr))
             /* or broadcast on this interface network address? */
-            ip_addr_isbroadcast(&(iphdr->dest), netif) ||
+            || ip_addr_isbroadcast(&(iphdr->dest), netif) 
+            #if 0
             /* or is this to our multicast interface? DIRKX */
-            ip_addr_ismulticast(&(iphdr->dest))
+            || ip_addr_ismulticast(&(iphdr->dest))
+            #endif
            ) {
           LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n",
               netif->name[0], netif->name[1]));
--- a/main.cpp	Thu Jul 22 00:08:38 2010 +0000
+++ b/main.cpp	Sat Jul 24 20:59:52 2010 +0000
@@ -9,7 +9,7 @@
 DigitalOut myled(LED1);
 EthernetNetIf eth;
 HTTPServer srv;
-mDNSResponder mdns;
+mDNSResponder mdns; // make sure LWIP_IGMP is set in netCfg.h !
 
 int main() {
     EthernetErr ethErr = eth.setup();
--- a/netCfg.h	Thu Jul 22 00:08:38 2010 +0000
+++ b/netCfg.h	Sat Jul 24 20:59:52 2010 +0000
@@ -1,12 +1,21 @@
-#ifndef NET_CFG_H
-#define NET_TELIT_STACK 0
-#define NET_GPRS 0
-#define NET_PPP 0
-#define NET_ZG2100 0
-#define NET_ETH 1
-#define NET_USB_SERIAL 0
-#define NET_TELIT 0
-#define NET_CFG_H 0
-#define NET_USB 0
-#define NET_LWIP_STACK 1
-#endif
+#ifndef NET_CFG_H
+#define NET_TELIT_STACK 0
+#define NET_GPRS 0
+#define NET_PPP 0
+#define NET_ZG2100 0
+#define NET_ETH 1
+#define NET_USB_SERIAL 0
+#define NET_TELIT 0
+#define NET_CFG_H 0
+#define NET_USB 0
+#define NET_LWIP_STACK 1
+
+// Enable Multicast on above IP stack(s).
+//
+#ifndef LWIP_RAND
+#include "mbed.h"
+#define LWIP_RAND() rand()
+#endif
+#define LWIP_IGMP 1
+
+#endif
--- a/services/http/server/impl/RPCHandler.cpp	Thu Jul 22 00:08:38 2010 +0000
+++ b/services/http/server/impl/RPCHandler.cpp	Sat Jul 24 20:59:52 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])))
     {
       memset((void*) p, ' ', strlen(lGarbage[i]));
     }
--- a/services/mDNS/mDNSResponder.cpp	Thu Jul 22 00:08:38 2010 +0000
+++ b/services/mDNS/mDNSResponder.cpp	Sat Jul 24 20:59:52 2010 +0000
@@ -1,408 +1,471 @@
-/* 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 "mDNSResponder.h"
-#include <stdio.h>
-
-// #define MCAST 192,168,1,71
-
-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(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(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);
-    
-    // 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;
-    uint32_t j;
-
-    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, 1, 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, 12 /* PTR */, rr );
-}
-    
-char * mTXT(char *p, char * name, char ** rr) {
-    return mRRLABEL(p, name, 16 /* TXT */, rr);
-}
-
-char * mARR(char *p, char * name, IpAddr ip) {
-    uint16_t i;
-
-    p = mRR(p, name, 1, 1, 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;
-    char * q;
-    
-    p = mRR(p, name, 33, 1, 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;
-    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,12 /* PTR */,1);
-}
-
-    
-void mDNSResponder::sendReply(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 PTR record asked for
-    op->a_count = ntohs(0);
-    
-    // The 2 or 3 extra records (A, SRV and optional TXT) we know will be needed next
-    op->aa_count = ntohs(moi_txt ? 3 : 2);
-    
-    p = out + 12;
-    
-    p = qPTR(p,moi_local_proto);
-    p = mPTR(p,moi_local_proto, moi_local_pglue);
-    p = mSRV(p,moi_local_pglue,80, moi_local_name);
-    if (moi_txt && * moi_txt)
-         p = mTXT(p,moi_local_pglue,moi_txt);
-    p = mARR(p,moi_local_name,moi_ip); // fill out my own IP address.
-
-    m_pUDPSocket->sendto(out,p-out,&dst);
-}
-
-void mDNSResponder::onUDPSocketEvent(UDPSocketEvent e) {
-    char udp[ 1500 ];
-    Host from;
-    int len;
-
-    switch (e) {
-        case UDPSOCKET_READABLE: //The only event for now
-            // 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);
-                unsigned int nA = ntohs(dp->answer_count);
-
-                if (flags & 2 != 0 || nQ == 0)
-                    continue; // we only want questions
-
-                #define MAXDEPTH 64
-                #define MAXRR 192 /* including dot */
-                
-                // assume nQ zero terminated fields followed by Qtype & Qclass
-                char * p = udp + 12;
-                for (int i = 0; i < nQ; i++) {
-                    char buff[ MAXDEPTH * MAXRR ], * ep = buff;
-                    int depth = 0;
-                    int l;
-                    char * q = 0;
-
-                    do {
-                        while (((l = *p++) < 192) && (l > 0)) {
-                            if (p + l >= udp + len) {
-                                printf("RR longer than packet\r\n");
-                                return;
-                            };
-
-                            memcpy(ep,p,l);
-                            ep[l]='.';
-                            ep += l + 1;
-                            // printf("%d:%s.", p-udp-12,buff);
-                            p += l;
-                        };
-                        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.
-                            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;
-                            };
-                        };
-                        if (depth++ >= MAXDEPTH) {
-                            printf("Too deep\r\n");
-                            return;
-                        };
-                    } while (l);
-                    *ep = 0;
-                    // in case no compression was used at all.
-                    if (!q) q = p;
-
-                    unsigned int Qt = htons(q[0] + q[1]*256);
-                    unsigned int Qc = htons(q[2] + q[3]*256);
-                    p = q + 4;
-                    
-                    printf("Q for %s\r\n", buff);
-                    // We want PTR records on the INternet of our type
-                    if ((Qt == 12) && (Qc == 1) && !(strcmp(buff,moi_local_proto))) 
-                        sendReply(tid,from);                        
-                };
-            }
-            break;
-    }
-}
-
-
+/* 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;
+
+    switch (e) {
+        case UDPSOCKET_READABLE: //The only event for now
+            // 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);
+                // unsigned int nA = ntohs(dp->answer_count);
+
+                if (flags & 2 != 0 || nQ == 0)
+                    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);
+                };
+            }
+            break;
+    }
+}
+#endif
--- a/services/mDNS/mDNSResponder.h	Thu Jul 22 00:08:38 2010 +0000
+++ b/services/mDNS/mDNSResponder.h	Sat Jul 24 20:59:52 2010 +0000
@@ -1,12 +1,21 @@
-
 #ifndef MDNS_RESPONDER_H
 #define MDNS_RESPONDER_H
 
+
+#include "lwip/opt.h"
+
+#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
+
 #include "if/net/net.h"
 #include "api/UDPSocket.h"
 #include "api/DNSRequest.h"
 #include "mbed.h"
 
+#include "lwip/udp.h"
+#include "lwip/mem.h"
+#include "lwip/memp.h"
+#include "lwip/dns.h"
+
 // As defined by IANA.
 //
 #define MDNS_PORT (5353)
@@ -39,7 +48,7 @@
 private:
   void process(); //Main state-machine
   void onUDPSocketEvent(UDPSocketEvent e);
-  void sendReply(uint16_t tid, Host dst); // temp
+  void sendReply(uint16_t Qtype,uint16_t tid, Host dst); // temp
   
 // Just in case - there is prolly some nice ARM6 assembler already linked in.
 #ifndef htons
@@ -77,3 +86,4 @@
 };
 
 #endif
+#endif