Dirk-Willem van Gulik (NXP/mbed)
/
Bonjour
Bonjour/Zerconf library
Revision 2:816cbd922d3e, committed 2010-07-24
- Comitter:
- dirkx
- Date:
- Sat Jul 24 20:59:52 2010 +0000
- Parent:
- 1:59820ca5c83a
- Child:
- 3:e1d86543ec50
- Commit message:
Changed in this revision
--- 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