From 5935a30f031da3237648b1548d912cdbb2c794bc Mon Sep 17 00:00:00 2001 From: Benjamin Runnels Date: Thu, 26 Nov 2015 06:41:29 -0600 Subject: [PATCH] Started adding in standalone mdns implementation --- esp-link.vcxproj | 2 + esp-link/cgiwifi.c | 22 ++- esp-link/mdns.c | 335 ++++++++++++++++++++++++++++++++++++++++++ esp-link/mdns.h | 52 +++++++ include/user_config.h | 1 + 5 files changed, 404 insertions(+), 8 deletions(-) create mode 100644 esp-link/mdns.c create mode 100644 esp-link/mdns.h diff --git a/esp-link.vcxproj b/esp-link.vcxproj index 27d9fcc..c753fd6 100644 --- a/esp-link.vcxproj +++ b/esp-link.vcxproj @@ -23,6 +23,7 @@ + @@ -57,6 +58,7 @@ + diff --git a/esp-link/cgiwifi.c b/esp-link/cgiwifi.c index 1000c17..8032833 100644 --- a/esp-link/cgiwifi.c +++ b/esp-link/cgiwifi.c @@ -20,6 +20,7 @@ Cgi/template routines for the /wifi url. #include "status.h" #include "config.h" #include "log.h" +#include "mdns.h" #ifdef CGIWIFI_DBG #define DBG(format, ...) os_printf(format, ## __VA_ARGS__) @@ -114,19 +115,24 @@ wifiAddStateChangeCb(WifiStateChangeCb cb) { } static bool mdns_started = false; -static struct mdns_info mdns_info; +//static struct mdns_info mdns_info; // cannot allocate the info struct on the stack, it crashes! static ICACHE_FLASH_ATTR void wifiStartMDNS(struct ip_addr ip) { if (!mdns_started) { - os_memset(&mdns_info, 0, sizeof(struct mdns_info)); - mdns_info.host_name = flashConfig.hostname, - mdns_info.server_name = "http", // service name - mdns_info.server_port = 80, // service port - mdns_info.ipAddr = ip.addr, - mdns_info.txt_data[0] = (char *) "version = now", - espconn_mdns_init(&mdns_info); +// struct mdns_info *ard_mdns_info = (struct mdns_info *)os_zalloc(sizeof(struct mdns_info)); +// ard_mdns_info->host_name = flashConfig.hostname; +// ard_mdns_info->server_name = "arduino"; // service name +// ard_mdns_info->server_port = 2323; // service port +// ard_mdns_info->ipAddr = ip.addr; +// ard_mdns_info->txt_data[0] = (char *) "version = now"; +// espconn_mdns_init(ard_mdns_info); +// espconn_mdns_server_register(); + + mdns_init(60, 3600); + mdns_addhost(flashConfig.hostname, &ip); + //mdns_addhost("arduino", &ip); mdns_started = true; } } diff --git a/esp-link/mdns.c b/esp-link/mdns.c new file mode 100644 index 0000000..1cd504f --- /dev/null +++ b/esp-link/mdns.c @@ -0,0 +1,335 @@ +/* +* mdns.h +* +* Simple mDNS responder. +* It replys to mDNS IP (IPv4/A) queries and optionally broadcasts ip advertisements +* using the mDNS protocol +* Created on: Apr 10, 2015 +* Author: Kevin Uhlir (n0bel) +* +*/ + +#include +#include "mdns.h" + +#ifdef MDNS_DBG +#define DBG(format, ...) os_printf(format, ## __VA_ARGS__) +#else +#define DBG(format, ...) do { } while(0) +#endif + +static int mdns_initialized = 0; +static int ttl = 0; +static os_timer_t bc_timer; + +static struct espconn mdns_conn; + +#define MAX_HOSTS 5 +static struct _host { + char *hostname; + unsigned char *mdns; + struct ip_addr ip; + int len; +} hosts[MAX_HOSTS] = { { NULL } }; + +int nhosts = 0; + +struct ip_addr mdns_multicast; +struct ip_addr ipaddr_any; + +#ifdef MDNS_DBG +void ICACHE_FLASH_ATTR hexdump(char *desc, void *addr, int len) { + int i; + unsigned char buff[17]; + unsigned char *pc = (unsigned char*)addr; + + // Output description if given. + if (desc != NULL) + DBG("%s:\n", desc); + + // Process every byte in the data. + for (i = 0; i < len; i++) { + // Multiple of 16 means new line (with line offset). + + if ((i % 16) == 0) { + // Just don't print ASCII for the zeroth line. + if (i != 0) + DBG(" %s\n", buff); + + // Output the offset. + DBG(" %04x ", i); + } + + // Now the hex code for the specific character. + DBG(" %02x", pc[i]); + + // And store a printable ASCII character for later. + if ((pc[i] < 0x20) || (pc[i] > 0x7e)) + buff[i % 16] = '.'; + else + buff[i % 16] = pc[i]; + buff[(i % 16) + 1] = '\0'; + } + + // Pad out last line if not exactly 16 characters. + while ((i % 16) != 0) { + DBG(" "); + i++; + } + + // And print the final ASCII bit. + DBG(" %s\n", buff); +} +#endif + +unsigned ICACHE_FLASH_ATTR char * encodeResp(struct ip_addr * addr, char *name, int *len) +{ + *len = 12 + strlen(name) + 16; + unsigned char *data = (unsigned char *)os_zalloc(*len); + + data[2] = 0x84; + data[7] = 1; + + unsigned char *p = data + 12; + char *np = name; + char *i; + while ((i = strchr(np, '.'))) + { + *p = i - np; + p++; + memcpy(p, np, i - np); + p += i - np; + np = i + 1; + } + *p = strlen(np); + p++; + memcpy(p, np, strlen(np)); + p += strlen(np); + *p++ = 0; // terminate string sequence + + *p++ = 0; *p++ = 1; // type 0001 (A) + + *p++ = 0x80; *p++ = 1; // class code (IPV4) + + *p++ = ttl >> 24; + *p++ = ttl >> 16; + *p++ = ttl >> 8; + *p++ = ttl; + + *p++ = 0; *p++ = 4; // length (of ip) + + memcpy(p, addr, 4); + + return data; +} + +char ICACHE_FLASH_ATTR *decode_name_strings(unsigned char *p, int *len) +{ + unsigned char *s = p; + int c; + *len = 0; + while ((c = *s++)) + { + *len += c + 1; + s += c; + } + char *name = (char *)os_zalloc(*len + 1); + char *np = name; + s = p; + while ((c = *s++)) + { + memcpy(np, s, c); + np += c; + *np++ = '.'; + s += c; + } + np--; *np = 0; + return name; +} + +void ICACHE_FLASH_ATTR sendOne(struct _host *h) +{ + mdns_conn.proto.udp->remote_ip[0] = 224; + mdns_conn.proto.udp->remote_ip[1] = 0; + mdns_conn.proto.udp->remote_ip[2] = 0; + mdns_conn.proto.udp->remote_ip[3] = 251; + mdns_conn.proto.udp->remote_port = 5353; + mdns_conn.proto.udp->local_port = 5353; +#ifdef MDNS_DBG + hexdump("sending", h->mdns, h->len); +#endif + espconn_sent(&mdns_conn, h->mdns, h->len); + +} +void ICACHE_FLASH_ATTR decodeQuery(unsigned char *data) +{ + if (data[0] != 0 || data[1] != 0 || data[2] != 0 || data[3] != 0) return; // only queries + + int qcount = data[5]; // purposely ignore qcount > 255 + unsigned char *p = data + 12; + char *name; + int len; + while (qcount-- > 0) + { + if (*p == 0xc0) // pointer + { + name = decode_name_strings(data + p[1], &len); + p += 2; + } + else + { + name = decode_name_strings(p, &len); + p += len + 1; + } + int qtype = p[0] * 256 + p[1]; + int qclass = p[2] * 256 + p[3]; + p += 4; + DBG("decoded name %s qtype=%d qclass=%d\n", name, qtype, qclass); + + if (qtype == 1 && (qclass & 0x7fff) == 1) + { + struct _host *h; + int i; + for (h = hosts, i = 0; i < nhosts; i++, h++) + { + if (h->hostname && strcmp(name, h->hostname) == 0) + { + DBG("its %s!\n", h->hostname); + sendOne(h); + } + } + os_free(name); + } + } + + return; +} + +static void ICACHE_FLASH_ATTR broadcast(void *arg) +{ + struct _host *h; + int i; + for (h = hosts, i = 0; i < nhosts; i++, h++) + { + DBG("broadcast for %s\n", h->hostname); + sendOne(h); + } +} + +static void ICACHE_FLASH_ATTR mdns_udp_recv(void *arg, char *pusrdata, unsigned short length) { + unsigned char *data = (unsigned char *)pusrdata; + + + DBG("remote port=%d remoteip=%d.%d.%d.%d\n", mdns_conn.proto.udp->remote_port, + mdns_conn.proto.udp->remote_ip[0], + mdns_conn.proto.udp->remote_ip[1], + mdns_conn.proto.udp->remote_ip[2], + mdns_conn.proto.udp->remote_ip[3] + ); +#ifdef MDNS_DBG +// hexdump("rec mNDS:", data, length); +#endif + decodeQuery(data); +} + +int ICACHE_FLASH_ATTR mdns_addhost(char *hn, struct ip_addr* ip) +{ + struct _host *h = &hosts[nhosts]; + if (nhosts >= MAX_HOSTS) + { + int i; + for (h = hosts, i = 0; i < MAX_HOSTS; i++, h++) + { + if (!h->hostname) break; + } + if (i >= MAX_HOSTS) return -1; + } + else + { + nhosts++; + } + h->hostname = (char *)os_zalloc(os_strlen(hn) + 1); + os_strcpy(h->hostname, hn); + h->ip.addr = ip->addr; + h->mdns = encodeResp(ip, hn, &(h->len)); +#ifdef MDNS_DBG + hexdump("addhost", hosts, sizeof(hosts)); +#endif + return(0); +} + +int ICACHE_FLASH_ATTR mdns_delhost(char *hn, struct ip_addr* ip) +{ + if (nhosts < 1) return -1; + struct _host *h; + int i; + for (h = hosts, i = 0; i < MAX_HOSTS; i++, h++) + { + if ((hn && strcmp(hn, h->hostname) == 0) + || (ip && h->ip.addr == ip->addr)) + { + if (h->hostname) os_free(h->hostname); + if (h->mdns) os_free(h->mdns); + h->hostname = NULL; + h->mdns = NULL; + h->ip.addr = 0; + } + } +#ifdef MDNS_DBG +// hexdump("delhost", hosts, sizeof(hosts)); +#endif + return(0); +} + +int ICACHE_FLASH_ATTR mdns_init(int bctime, int sttl) +{ + if (mdns_initialized) mdns_stop(); + mdns_initialized = 1; + ttl = sttl; + + IP4_ADDR(&mdns_multicast, 224, 0, 0, 251); + ipaddr_any.addr = IPADDR_ANY; + + espconn_igmp_join(&ipaddr_any, &mdns_multicast); + + static esp_udp mdns_udp; + mdns_conn.type = ESPCONN_UDP; + mdns_conn.state = ESPCONN_NONE; + mdns_conn.proto.udp = &mdns_udp; + mdns_udp.local_port = 5353; + mdns_conn.reverse = NULL; + + espconn_regist_recvcb(&mdns_conn, mdns_udp_recv); + espconn_create(&mdns_conn); + + os_timer_disarm(&bc_timer); + if (bctime > 0) + { + os_timer_setfn(&bc_timer, (os_timer_func_t *)broadcast, (void *)0); + os_timer_arm(&bc_timer, bctime * 1000, 1); + } + + return 0; +} + +int ICACHE_FLASH_ATTR mdns_stop() +{ + if (!mdns_initialized) return(0); + os_timer_disarm(&bc_timer); + espconn_disconnect(&mdns_conn); + espconn_delete(&mdns_conn); + espconn_igmp_leave(&ipaddr_any, &mdns_multicast); + mdns_initialized = 0; + struct _host *h; + int i; + for (h = hosts, i = 0; i < MAX_HOSTS; i++, h++) + { + if (h->hostname) os_free(h->hostname); + if (h->mdns) os_free(h->mdns); + h->hostname = NULL; + h->mdns = NULL; + h->ip.addr = 0; + } + nhosts = 0; + return(0); +} \ No newline at end of file diff --git a/esp-link/mdns.h b/esp-link/mdns.h new file mode 100644 index 0000000..49273a1 --- /dev/null +++ b/esp-link/mdns.h @@ -0,0 +1,52 @@ +/* +* mdns.h +* +* Simple mDNS responder. +* It replys to mDNS IP (IPv4/A) queries and optionally broadcasts ip advertisements +* using the mDNS protocol +* Created on: Apr 10, 2015 +* Author: Kevin Uhlir (n0bel) +* +*/ + +#ifndef MDNS_H +#define MDNS_H + +/****************************************************************************** +* FunctionName : mdns_init +* Description : Initialize the module +* done once after the system is up and ready to run +* Parameters : bctime -- broadcast timer (seconds) can be 0 for no broadcasting +* ttl -- Time To Live must be > 0, should be a reasonable DNS ttl +* Returns : 0 success, -1 failed +*******************************************************************************/ +int mdns_init(int bctime, int ttl); +/****************************************************************************** +* FunctionName : mdns_stop +* Description : Stop the module. +* Parameters : None +* Returns : 0 success, -1 failed +*******************************************************************************/ +int mdns_stop(void); +/****************************************************************************** +* FunctionName : mdns_addhost +* Description : Add a host to be resolved by mDNS +* Parameters : hostname -- the hostname to add (must end in .local) +* for most clients to function +* ip -- the ip address of the host +* Returns : 0 success, -1 failed +*******************************************************************************/ +int mdns_addhost(char *hostname, struct ip_addr* ip); +/****************************************************************************** +* FunctionName : mdns_delhost +* Description : Delete a host to be resolved by mDNS +* Parameters : hostname -- the hostname to delete +* if NULL, hostname won't be used +* ip -- the ip address of the host to delete +* if NULL, ip won't be used +* Returns : 0 success, -1 failed +*******************************************************************************/ +int mdns_delhost(char *hostname, struct ip_addr* ip); + + +#endif /* MDNS_H */ \ No newline at end of file diff --git a/include/user_config.h b/include/user_config.h index 06d19eb..2fa067a 100644 --- a/include/user_config.h +++ b/include/user_config.h @@ -29,6 +29,7 @@ #define SERLED_DBG #undef SLIP_DBG #define UART_DBG +#define MDNS_DBG // If defined, the default hostname for DHCP will include the chip ID to make it unique #undef CHIP_IN_HOSTNAME