Browse Source

Take 2: Add regular sends to mdns. Check for (some) buffer overflows. Make it handle unicast

Merging as suggested by @TerryE (and squashing at the same time. Turns out that this feature is enabled for this repo).

* Squashed commit of the following:

commit f985f10d9d2ee035f5a6ee6245c60d9904d98cc1
Author: philip <philip@gladstonefamily.net>
Date:   Sun Mar 27 21:52:46 2016 -0400

    Better mdns code

commit 6ee49ee106274bc63f6309047e57f7bc9828523e
Author: philip <philip@gladstonefamily.net>
Date:   Fri Mar 25 23:25:11 2016 -0400

    Update the docs

commit 7e455541c6f2531824cfb2419d051f1306935fdf
Author: philip <philip@gladstonefamily.net>
Date:   Thu Mar 24 21:58:16 2016 -0400

    Add retries and buffer checking to mdns

    Get the length right

    Now it seems to work

* Might work for combined mode

* Fix crash

* Simplified various bits of code. Changed the LUA interface

Added checking (to some degree) incoming quyery types

Move the defaults to the right place

Added reference to the RFC`
Philip Gladstone 8 years ago
parent
commit
3a5e5f10e2
8 changed files with 1151 additions and 104 deletions
  1. 2 0
      app/Makefile
  2. 16 0
      app/include/nodemcu_mdns.h
  3. 113 0
      app/libc/c_string.c
  4. 6 0
      app/libc/c_string.h
  5. 36 99
      app/modules/mdns.c
  6. 44 0
      app/net/Makefile
  7. 919 0
      app/net/nodemcu_mdns.c
  8. 15 5
      docs/en/modules/mdns.md

+ 2 - 0
app/Makefile

@@ -41,6 +41,7 @@ SUBDIRS= 					\
 	crypto 					\
 	dhtlib					\
 	tsl2561					\
+	net					\
 	http
 
 endif # } PDIR
@@ -86,6 +87,7 @@ COMPONENTS_eagle.app.v6 = 			\
 	dhtlib/libdhtlib.a 			\
 	tsl2561/tsl2561lib.a			\
 	http/libhttp.a				\
+	net/libnodemcu_net.a			\
 	modules/libmodules.a			\
 
 # Inspect the modules library and work out which modules need to be linked.

+ 16 - 0
app/include/nodemcu_mdns.h

@@ -0,0 +1,16 @@
+#ifndef _NODEMCU_MDNS_H
+#define _NODEMCU_MDNS_H
+
+struct nodemcu_mdns_info {
+	const char *host_name;
+	const char *host_desc;
+	const char *service_name;
+	uint16 service_port;
+	const char *txt_data[10];
+};
+
+void nodemcu_mdns_close(void);
+bool nodemcu_mdns_init(struct nodemcu_mdns_info *);
+
+
+#endif

+ 113 - 0
app/libc/c_string.c

@@ -1,4 +1,5 @@
 #include "c_string.h"
+#include "c_stdlib.h"
 
 // const char *c_strstr(const char * __s1, const char * __s2){
 // }
@@ -14,3 +15,115 @@
 
 // int c_strcoll(const char * s1, const char * s2){
 // }
+//
+char *c_strdup(const char *c) {
+  int len = os_strlen(c) + 1;
+  char *ret = os_malloc(len);
+  if (ret) {
+    memcpy(ret, c, len);
+  }
+  return ret;
+}
+
+/*	$OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $	*/
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copy src to string dst of size siz.  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+c_strlcpy(char *dst, const char *src, size_t siz)
+{
+	register char *d = dst;
+	register const char *s = src;
+	register size_t n = siz;
+
+	/* Copy as many bytes as will fit */
+	if (n != 0 && --n != 0) {
+		do {
+			if ((*d++ = *s++) == 0)
+				break;
+		} while (--n != 0);
+	}
+
+	/* Not enough room in dst, add NUL and traverse rest of src */
+	if (n == 0) {
+		if (siz != 0)
+			*d = '\0';		/* NUL-terminate dst */
+		while (*s++)
+			;
+	}
+
+	return(s - src - 1);	/* count does not include NUL */
+}
+
+/*	$OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $	*/
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left).  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz <= strlen(dst)).
+ * Returns strlen(src) + MIN(siz, strlen(initial dst)).
+ * If retval >= siz, truncation occurred.
+ */
+size_t
+c_strlcat(char *dst, const char *src, size_t siz)
+{
+	register char *d = dst;
+	register const char *s = src;
+	register size_t n = siz;
+	size_t dlen;
+
+	/* Find the end of dst and adjust bytes left but don't go past end */
+	while (n-- != 0 && *d != '\0')
+		d++;
+	dlen = d - dst;
+	n = siz - dlen;
+
+	if (n == 0)
+		return(dlen + strlen(s));
+	while (*s != '\0') {
+		if (n != 1) {
+			*d++ = *s;
+			n--;
+		}
+		s++;
+	}
+	*d = '\0';
+
+	return(dlen + (s - src));	/* count does not include NUL */
+}
+

+ 6 - 0
app/libc/c_string.h

@@ -39,5 +39,11 @@
 // size_t c_strcspn(const char * s1, const char * s2);
 // const char *c_strpbrk(const char * /*s1*/, const char * /*s2*/);
 // int c_strcoll(const char * /*s1*/, const char * /*s2*/);
+//
+
+extern size_t c_strlcpy(char *dst, const char *src, size_t siz);
+extern size_t c_strlcat(char *dst, const char *src, size_t siz);
+extern char *c_strdup(const char *src);
+
 
 #endif /* _C_STRING_H_ */

+ 36 - 99
app/modules/mdns.c

@@ -1,4 +1,4 @@
-// Module for access to the espconn_mdns functions
+// Module for access to the nodemcu_mdns functions
 
 #include "module.h"
 #include "lauxlib.h"
@@ -9,115 +9,59 @@
 #include "c_types.h"
 #include "mem.h"
 #include "lwip/ip_addr.h"
-#include "espconn.h"
+#include "nodemcu_mdns.h"
 #include "user_interface.h"
 
-typedef struct wrapper {
-  struct mdns_info mdns_info;
-  char data;
-} wrapper_t;
-
-static wrapper_t *info;
-
-typedef enum phase {
-  PHASE_CALCULATE_LENGTH,
-  PHASE_COPY_DATA
-} phase_t;
-
-static char *advance_over_string(char *s)
-{
-  while (*s++) {
-  }
-  // s now points after the null
-  return s;
-}
-
 //
 // mdns.close()
 // 
 static int mdns_close(lua_State *L)
 {
-  if (info) {
-    espconn_mdns_close();
-    c_free(info);
-    info = NULL;
-  }
+  nodemcu_mdns_close();
   return 0;
 }
 
-// 
-// this handles all the arguments. Two passes are necessary -- 
-// one to calculate the size of the block, and the other to 
-// copy the data. It is vitally important that these two
-// passes are kept in step.
 //
-static wrapper_t *process_args(lua_State *L, phase_t phase, size_t *sizep)
+// mdns.register(hostname [, { attributes} ])
+//
+static int mdns_register(lua_State *L)
 {
-  wrapper_t *result = NULL;
-  char *p = NULL;
+  struct nodemcu_mdns_info info;
 
-  if (phase == PHASE_COPY_DATA) {
-    result = (wrapper_t *) c_zalloc(sizeof(wrapper_t) + *sizep);
-    if (!result) {
-      return NULL;
-    }
-    p = &result->data;
-  }
-
-  if (phase == PHASE_CALCULATE_LENGTH) {
-    luaL_checktype(L, 1, LUA_TSTRING);
-    luaL_checktype(L, 2, LUA_TSTRING);
-    (void) luaL_checkinteger(L, 3);
-    *sizep += c_strlen(luaL_checkstring(L, 1)) + 1;
-    *sizep += c_strlen(luaL_checkstring(L, 2)) + 1;
-  } else {
-    c_strcpy(p, luaL_checkstring(L, 1)); 
-    result->mdns_info.host_name = p;
-    p = advance_over_string(p);
-
-    c_strcpy(p, luaL_checkstring(L, 2));
-    result->mdns_info.server_name = p;
-    p = advance_over_string(p);
-
-    result->mdns_info.server_port = luaL_checkinteger(L, 3);
-  }
+  memset(&info, 0, sizeof(info));
+  
+  info.host_name = luaL_checkstring(L, 1);
+  info.service_name = "http";
+  info.service_port = 80;
+  info.host_desc = info.host_name;
 
-  if (lua_gettop(L) >= 4) {
-    luaL_checktype(L, 4, LUA_TTABLE);
+  if (lua_gettop(L) >= 2) {
+    luaL_checktype(L, 2, LUA_TTABLE);
     lua_pushnil(L); // first key
     int slot = 0;
-    while (lua_next(L, 4) != 0 && slot < sizeof(result->mdns_info.txt_data) / sizeof(result->mdns_info.txt_data[0])) {
-      if (phase == PHASE_CALCULATE_LENGTH) {
-        luaL_checktype(L, -2, LUA_TSTRING);
-        *sizep += c_strlen(luaL_checkstring(L, -2)) + 1;
-        *sizep += c_strlen(luaL_checkstring(L, -1)) + 1;
+    while (lua_next(L, 2) != 0 && slot < sizeof(info.txt_data) / sizeof(info.txt_data[0])) {
+      luaL_checktype(L, -2, LUA_TSTRING);
+      const char *key = luaL_checkstring(L, -2);
+
+      if (c_strcmp(key, "port") == 0) {
+	info.service_port = luaL_checknumber(L, -1);
+      } else if (c_strcmp(key, "service") == 0) {
+	info.service_name = luaL_checkstring(L, -1);
+      } else if (c_strcmp(key, "description") == 0) {
+	info.host_desc = luaL_checkstring(L, -1);
       } else {
-        // put in the key
-	c_strcpy(p, luaL_checkstring(L, -2));
-        result->mdns_info.txt_data[slot] = p;
-	p = advance_over_string(p);
-
-	// now smash in the value
+	int len = c_strlen(key) + 1;
 	const char *value = luaL_checkstring(L, -1);
-	p[-1] = '=';
-	c_strcpy(p, value);
-	p = advance_over_string(p);
+	char *p = alloca(len + c_strlen(value) + 1);
+	strcpy(p, key);
+	strcat(p, "=");
+	strcat(p, value);
+	info.txt_data[slot++] = p;
       }
       lua_pop(L, 1);
     }
   }
 
-  return result;
-}
-
-//
-// mdns.register(hostname, servicename, port [, attributes])
-//
-static int mdns_register(lua_State *L)
-{
-  size_t len = 0;
-
-  (void) process_args(L, PHASE_CALCULATE_LENGTH, &len);
 
   struct ip_info ipconfig;
 
@@ -127,25 +71,18 @@ static int mdns_register(lua_State *L)
     return luaL_error(L, "No network connection");
   }
 
-  wrapper_t *result = process_args(L, PHASE_COPY_DATA, &len);
-
-  if (!result) {
-    return luaL_error( L, "failed to allocate info block" );
-  }
-
-  result->mdns_info.ipAddr = ipconfig.ip.addr;
-
   // Close up the old session (if any). This cannot fail
   // so no chance of losing the memory in 'result'
   
   mdns_close(L);
 
-  // Save the result as it appears that espconn_mdns_init needs
+  // Save the result as it appears that nodemcu_mdns_init needs
   // to have the data valid while it is running.
 
-  info = result;
-
-  espconn_mdns_init(&(info->mdns_info));
+  if (!nodemcu_mdns_init(&info)) {
+    mdns_close(L);
+    return luaL_error(L, "Unable to start mDns daemon");
+  }
 
   return 0;
 }

+ 44 - 0
app/net/Makefile

@@ -0,0 +1,44 @@
+
+#############################################################
+# Required variables for each makefile
+# Discard this section from all parent makefiles
+# Expected variables (with automatic defaults):
+#   CSRCS (all "C" files in the dir)
+#   SUBDIRS (all subdirs with a Makefile)
+#   GEN_LIBS - list of libs to be generated ()
+#   GEN_IMAGES - list of images to be generated ()
+#   COMPONENTS_xxx - a list of libs/objs in the form
+#     subdir/lib to be extracted and rolled up into
+#     a generated lib/image xxx.a ()
+#
+ifndef PDIR
+GEN_LIBS = libnodemcu_net.a
+endif
+
+#############################################################
+# Configuration i.e. compile options etc.
+# Target specific stuff (defines etc.) goes in here!
+# Generally values applying to a tree are captured in the
+#   makefile at its root level - these are then overridden
+#   for a subtree within the makefile rooted therein
+#
+#DEFINES += 
+
+#############################################################
+# Recursion Magic - Don't touch this!!
+#
+# Each subtree potentially has an include directory
+#   corresponding to the common APIs applicable to modules
+#   rooted at that subtree. Accordingly, the INCLUDE PATH
+#   of a module can only contain the include directories up
+#   its parent path, and not its siblings
+#
+# Required for each makefile to inherit from the parent
+#
+
+INCLUDES := $(INCLUDES) -I $(PDIR)include
+INCLUDES += -I ./
+INCLUDES += -I ../libc
+PDIR := ../$(PDIR)
+sinclude $(PDIR)Makefile
+

+ 919 - 0
app/net/nodemcu_mdns.c

@@ -0,0 +1,919 @@
+/**
+ * lwip MDNS resolver file.
+ *
+ * Created on: Jul 29, 2010
+ * Author: Daniel Toma
+ *
+
+ * ported from uIP resolv.c Copyright (c) 2002-2003, Adam Dunkels.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+
+ * This file implements a MDNS host name and PUCK service registration.
+
+ *-----------------------------------------------------------------------------
+ * Includes
+ *----------------------------------------------------------------------------*/
+#include "lwip/opt.h"
+#if LWIP_MDNS /* don't build if not configured for use in lwipopts.h */
+#include "lwip/mdns.h"
+#include "lwip/udp.h"
+#include "lwip/mem.h"
+#include "lwip/igmp.h"
+#include "osapi.h"
+#include "os_type.h"
+#include "user_interface.h"
+#include "c_string.h"
+#include "nodemcu_mdns.h"
+
+#if 0
+#define MDNS_DBG(...)  os_printf(...)
+#else
+#define MDNS_DBG(...)  do {} while (0)
+#endif
+
+#define MDNS_NAME_LENGTH     68 //68
+
+static const char* service_name_with_suffix    = NULL;
+#define DNS_SD_SERVICE       "_services._dns-sd._udp.local"
+#define PUCK_SERVICE_LENGTH  30
+
+#define PUCK_DATASHEET_SIZE   	96
+
+#ifdef MEMLEAK_DEBUG
+static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;
+#endif
+
+/** DNS server IP address */
+#ifndef DNS_MULTICAST_ADDRESS
+#define DNS_MULTICAST_ADDRESS        ipaddr_addr("224.0.0.251") /* resolver1.opendns.com */
+#endif
+
+/** DNS server IP address */
+#ifndef MDNS_LOCAL
+#define MDNS_LOCAL                "local" /* resolver1.opendns.com */
+#endif
+
+/** DNS server port address */
+#ifndef DNS_MDNS_PORT
+#define DNS_MDNS_PORT           5353
+#endif
+
+/** DNS maximum number of retries when asking for a name, before "timeout". */
+#ifndef DNS_MAX_RETRIES
+#define DNS_MAX_RETRIES           4
+#endif
+
+/** DNS resource record max. TTL (one week as default) */
+#ifndef DNS_MAX_TTL
+#define DNS_MAX_TTL               604800
+#endif
+
+/* DNS protocol flags */
+#define DNS_FLAG1_RESPONSE        0x84
+#define DNS_FLAG1_OPCODE_STATUS   0x10
+#define DNS_FLAG1_OPCODE_INVERSE  0x08
+#define DNS_FLAG1_OPCODE_STANDARD 0x00
+#define DNS_FLAG1_AUTHORATIVE     0x04
+#define DNS_FLAG1_TRUNC           0x02
+#define DNS_FLAG1_RD              0x01
+#define DNS_FLAG2_RA              0x80
+#define DNS_FLAG2_ERR_MASK        0x0f
+#define DNS_FLAG2_ERR_NONE        0x00
+#define DNS_FLAG2_ERR_NAME        0x03
+
+/* DNS protocol states */
+#define DNS_STATE_UNUSED          0
+#define DNS_STATE_NEW             1
+#define DNS_STATE_ASKING          2
+#define DNS_STATE_DONE            3
+
+/* MDNS registration type */
+#define MDNS_HOSTNAME_REG         0
+#define MDNS_SERVICE_REG          1
+
+/* MDNS registration type */
+#define MDNS_REG_ANSWER           1
+#define MDNS_SD_ANSWER            2
+#define MDNS_SERVICE_REG_ANSWER   3
+
+/* MDNS registration time */
+#define MDNS_HOST_TIME            120
+#define MDNS_SERVICE_TIME         3600
+
+/** MDNS name length with "." at the beginning and end of name*/
+#ifndef MDNS_LENGTH_ADD
+#define MDNS_LENGTH_ADD           2
+#endif
+
+#ifdef MDNS_MAX_NAME_LENGTH
+#undef MDNS_MAX_NAME_LENGTH
+#endif
+#define MDNS_MAX_NAME_LENGTH      (256)
+
+PACK_STRUCT_BEGIN
+/** DNS message header */
+struct mdns_hdr {
+	PACK_STRUCT_FIELD(u16_t id);
+	PACK_STRUCT_FIELD(u8_t flags1);
+	PACK_STRUCT_FIELD(u8_t flags2);
+	PACK_STRUCT_FIELD(u16_t numquestions);
+	PACK_STRUCT_FIELD(u16_t numanswers);
+	PACK_STRUCT_FIELD(u16_t numauthrr);
+	PACK_STRUCT_FIELD(u16_t numextrarr);
+}PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+
+#define SIZEOF_DNS_HDR 12
+
+PACK_STRUCT_BEGIN
+/** MDNS query message structure */
+struct mdns_query {
+	/* MDNS query record starts with either a domain name or a pointer
+	 to a name already present somewhere in the packet. */PACK_STRUCT_FIELD(u16_t type);
+	PACK_STRUCT_FIELD(u16_t class);
+}PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+
+#define SIZEOF_DNS_QUERY 4
+
+PACK_STRUCT_BEGIN
+/** MDNS answer message structure */
+struct mdns_answer {
+	/* MDNS answer record starts with either a domain name or a pointer
+	 to a name already present somewhere in the packet. */PACK_STRUCT_FIELD(u16_t type);
+	PACK_STRUCT_FIELD(u16_t class);
+	PACK_STRUCT_FIELD(u32_t ttl);
+	PACK_STRUCT_FIELD(u16_t len);
+}PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+#define SIZEOF_DNS_ANSWER 10
+
+PACK_STRUCT_BEGIN
+/** MDNS answer message structure */
+struct mdns_auth {
+	PACK_STRUCT_FIELD(u32_t src);
+}PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+
+#define SIZEOF_MDNS_AUTH 4
+PACK_STRUCT_BEGIN
+/** MDNS service registration message structure */
+struct mdns_service {
+	PACK_STRUCT_FIELD(u16_t prior);
+	PACK_STRUCT_FIELD(u16_t weight);
+	PACK_STRUCT_FIELD(u16_t port);
+}PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
+
+#define SIZEOF_MDNS_SERVICE 6
+
+static os_timer_t mdns_timer;
+/* forward declarations */
+static void mdns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p,
+		struct ip_addr *addr, u16_t port);
+
+/*-----------------------------------------------------------------------------
+ * Globales
+ *----------------------------------------------------------------------------*/
+
+/* MDNS variables */
+//static char puck_datasheet[PUCK_DATASHEET_SIZE];
+static struct udp_pcb *mdns_pcb = NULL;
+static struct nodemcu_mdns_info * ms_info = NULL;
+static struct ip_addr multicast_addr;
+static uint8 register_flag = 0;
+static uint8 mdns_flag = 0;
+static u8_t *mdns_payload;
+
+/**
+ * Compare the "dotted" name "query" with the encoded name "response"
+ * to make sure an answer from the DNS server matches the current mdns_table
+ * entry (otherwise, answers might arrive late for hostname not on the list
+ * any more).
+ *
+ * @param query hostname (not encoded) from the mdns_table
+ * @param response encoded hostname in the DNS response
+ * @return 0: names equal; 1: names differ
+ */
+static u8_t ICACHE_FLASH_ATTR
+mdns_compare_name(unsigned char *query, unsigned char *response) {
+	unsigned char n;
+
+	do {
+		n = *response++;
+		/** @see RFC 1035 - 4.1.4. Message compression */
+		if ((n & 0xc0) == 0xc0) {
+			/* Compressed name */
+			break;
+		} else {
+			/* Not compressed name */
+			while (n > 0) {
+				if ((*query) != (*response)) {
+					return 1;
+				}
+				++response;
+				++query;
+				--n;
+			};
+			++query;
+		}
+	} while (*response != 0);
+
+	return 0;
+}
+
+static int 
+mdns_namelen(u8_t *p, unsigned int maxlen) {
+  u8_t *orig = p;
+
+  while (*p && *p <= 63) {
+    if (p - orig > maxlen) {
+      return -1;
+    }
+    p += *p + 1;
+  }
+
+  if (*p >= 0xc0) {
+    p += 2;	// advance over the two byte pointer
+  } else {
+    p++;	// advance over the final 0
+  }
+
+  if (p - orig > maxlen) {
+    return -1;
+  }
+
+  return p - orig;
+}
+
+static err_t send_packet(struct pbuf *p, struct ip_addr *dst_addr, u16_t dst_port, u8_t *addr_ptr) {
+  err_t err;
+  /* send dns packet */
+  struct netif *sta_netif = (struct netif *)eagle_lwip_getif(0x00);
+  struct netif *ap_netif =  (struct netif *)eagle_lwip_getif(0x01);
+
+  if (addr_ptr) {
+    if (wifi_get_opmode() == 0x02) {
+      if (!ap_netif) {
+	return;
+      }
+      memcpy(addr_ptr, &ap_netif->ip_addr, sizeof(ap_netif->ip_addr));
+    } else {
+      if (!sta_netif) {
+	return;
+      }
+      memcpy(addr_ptr, &sta_netif->ip_addr, sizeof(sta_netif->ip_addr));
+    }
+  }
+
+  if (dst_addr) {
+    err = udp_sendto(mdns_pcb, p, dst_addr, dst_port);
+  } else {
+    err = udp_sendto(mdns_pcb, p, &multicast_addr, DNS_MDNS_PORT);
+    if(wifi_get_opmode() == 0x03 && wifi_get_broadcast_if() == 0x03 &&\
+		    sta_netif != NULL && ap_netif != NULL) {
+      if(netif_is_up(sta_netif) && netif_is_up(ap_netif)) {
+	netif_set_default(sta_netif);
+	if (addr_ptr) {
+	  memcpy(addr_ptr, &ap_netif->ip_addr, sizeof(ap_netif->ip_addr));
+	}
+	err = udp_sendto(mdns_pcb, p, &multicast_addr, DNS_MDNS_PORT);
+	netif_set_default(ap_netif);
+      }
+    }
+  }
+
+  /* free pbuf */
+  pbuf_free(p);
+
+  return err;
+}
+/**
+ * Send a mDNS packet for the service type
+ *
+ * @param id transaction ID in the DNS query packet
+ * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise
+ */
+static err_t ICACHE_FLASH_ATTR
+mdns_send_service_type(u16_t id, struct ip_addr *dst_addr, u16_t dst_port) {
+	err_t err;
+	struct mdns_hdr *hdr;
+	struct mdns_answer ans;
+	struct mdns_auth auth;
+	struct mdns_service serv;
+	struct pbuf *p ,*p_sta;
+	char *query, *nptr;
+	const char *pHostname;
+	struct netif * sta_netif = NULL;
+	struct netif * ap_netif = NULL;
+	char tmpBuf[PUCK_DATASHEET_SIZE + PUCK_SERVICE_LENGTH];
+	u8_t n;
+	u16_t length = 0;
+	/* if here, we have either a new query or a retry on a previous query to process */
+	p = pbuf_alloc(PBUF_TRANSPORT,
+			SIZEOF_DNS_HDR + MDNS_MAX_NAME_LENGTH * 2 + SIZEOF_DNS_QUERY, PBUF_RAM);
+	if (p != NULL) {
+		LWIP_ASSERT("pbuf must be in one piece", p->next == NULL);
+		/* fill dns header */
+		hdr = (struct mdns_hdr*) p->payload;
+		os_memset(hdr, 0, SIZEOF_DNS_HDR);
+		hdr->id = htons(id);
+		hdr->flags1 = DNS_FLAG1_RESPONSE;
+
+		pHostname = DNS_SD_SERVICE;
+		hdr->numanswers = htons(1);
+		query = (char*) hdr + SIZEOF_DNS_HDR;
+		--pHostname;
+		/* convert hostname into suitable query format. */
+		do {
+			++pHostname;
+			nptr = query;
+			++query;
+			for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {
+				*query = *pHostname;
+				++query;
+				++n;
+			}
+			*nptr = n;
+		} while (*pHostname != 0);
+		*query++ = '\0';
+		/* fill dns query */
+
+
+		ans.type = htons(DNS_RRTYPE_PTR);
+		ans.class = htons(DNS_RRCLASS_IN);
+		ans.ttl = htonl(3600);
+		ans.len = htons(os_strlen(service_name_with_suffix) + 1 +1 );
+		length = 0;
+
+		MEMCPY( query, &ans, SIZEOF_DNS_ANSWER);
+
+		/* resize the query */
+		query = query + SIZEOF_DNS_ANSWER;
+		pHostname = service_name_with_suffix;
+		--pHostname;
+
+		/* convert hostname into suitable query format. */
+		do {
+			++pHostname;
+			nptr = query;
+			++query;
+			for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {
+				*query = *pHostname;
+				++query;
+				++n;
+			}
+			*nptr = n;
+		} while (*pHostname != 0);
+		*query++ = '\0';
+
+		/* resize pbuf to the exact dns query */
+		pbuf_realloc(p, (query + length) - ((char*) (p->payload)));
+
+		err = send_packet(p, dst_addr, dst_port, 0);
+
+	} else {
+		err = ERR_MEM;
+	}
+
+	return err;
+}
+
+/**
+ * Send a mDNS service answer packet.
+ *
+ * @param name service name to query
+ * @param id transaction ID in the DNS query packet
+ * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise
+ */
+static err_t ICACHE_FLASH_ATTR
+mdns_send_service(struct nodemcu_mdns_info *info, u16_t id, struct ip_addr *dst_addr, u16_t dst_port) {
+	err_t err;
+	struct mdns_hdr *hdr;
+	struct mdns_answer ans;
+	struct mdns_service serv;
+	struct mdns_auth auth;
+	struct pbuf *p ,*p_sta;
+	char *query, *nptr;
+	char *query_end;
+	const char *pHostname;
+	const char *name = info->host_name;
+	u8_t n;
+	u8_t i = 0;
+	u16_t length = 0;
+	u8_t addr1 = 12, addr2 = 12;
+	struct netif * sta_netif = NULL;
+	struct netif * ap_netif = NULL;
+	char tmpBuf[PUCK_DATASHEET_SIZE + PUCK_SERVICE_LENGTH];
+	u16_t dns_class = dst_addr ? DNS_RRCLASS_IN : DNS_RRCLASS_FLUSH_IN;
+	/* if here, we have either a new query or a retry on a previous query to process */
+	p = pbuf_alloc(PBUF_TRANSPORT,
+			SIZEOF_DNS_HDR + MDNS_MAX_NAME_LENGTH * 2 + SIZEOF_DNS_QUERY, PBUF_RAM);
+	if (p != NULL) {
+		LWIP_ASSERT("pbuf must be in one piece", p->next == NULL);
+		/* fill dns header */
+		hdr = (struct mdns_hdr*) p->payload;
+		os_memset(hdr, 0, SIZEOF_DNS_HDR);
+		hdr->id = htons(id);
+		hdr->flags1 = DNS_FLAG1_RESPONSE;
+		hdr->numanswers = htons(4);
+		query = (char*) hdr + SIZEOF_DNS_HDR;
+		query_end = (char *) p->payload + p->tot_len;
+		c_strlcpy(tmpBuf, service_name_with_suffix, sizeof(tmpBuf));
+
+		pHostname = tmpBuf;
+		--pHostname;
+
+		/* convert hostname into suitable query format. */
+		do {
+			++pHostname;
+			nptr = query;
+			++query;
+			++addr1;
+			++addr2;
+			for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {
+				*query = *pHostname;
+				++query;
+				++addr1;
+				++addr2;
+				++n;
+			}
+			*nptr = n;
+		} while (*pHostname != 0);
+		*query++ = '\0';
+		length = sizeof(MDNS_LOCAL);
+		addr1 -= length;
+		length = os_strlen(service_name_with_suffix) + 1;
+		addr2 -= length;
+
+		ans.type = htons(DNS_RRTYPE_PTR);
+		ans.class = htons(DNS_RRCLASS_IN);
+		ans.ttl = htonl(300);
+		length = os_strlen(ms_info->host_desc) + MDNS_LENGTH_ADD + 1;
+		ans.len = htons(length);
+		length = 0;
+
+		MEMCPY( query, &ans, SIZEOF_DNS_ANSWER);
+		/* resize the query */
+		query = query + SIZEOF_DNS_ANSWER;
+
+		int name_offset = query - (const char *) hdr;
+
+		pHostname = ms_info->host_desc;
+		--pHostname;
+		/* convert hostname into suitable query format. */
+		do {
+			++pHostname;
+			nptr = query;
+			++query;
+			for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {
+				*query = *pHostname;
+				++query;
+				++n;
+			}
+			*nptr = n;
+		} while (*pHostname != 0);
+		*query++ = DNS_OFFSET_FLAG;
+		*query++ = DNS_DEFAULT_OFFSET;
+
+		*query++ = 0xc0 + (name_offset >> 8);
+		*query++ = name_offset & 0xff;
+
+		/* fill the answer */
+		ans.type = htons(DNS_RRTYPE_TXT);
+		ans.class = htons(dns_class);
+		ans.ttl = htonl(300);
+//		length = os_strlen(TXT_DATA) + MDNS_LENGTH_ADD + 1;
+		const char *attributes[12];
+		int attr_count = 0;
+		for(i = 0; i < 10 && (info->txt_data[i] != NULL); i++) {
+		  length += os_strlen(info->txt_data[i]);
+		  length++;
+		  attributes[attr_count++] = info->txt_data[i];
+		}
+		//MDNS_DBG("Found %d user attributes\n", i);
+		static const char *defaults[] = { "platform=nodemcu", NULL };
+		for(i = 0; defaults[i] != NULL; i++) {
+		  // See if this is a duplicate
+		  int j;
+		  int len = strchr(defaults[i], '=') + 1 - defaults[i];
+		  for (j = 0; j < attr_count; j++) {
+		    if (strncmp(attributes[j], defaults[i], len) == 0) {
+		      break;
+		    }
+		  }
+		  if (j == attr_count) {
+		    length += os_strlen(defaults[i]);
+		    length++;
+		    attributes[attr_count++] = defaults[i];
+		  }
+		}
+		//MDNS_DBG("Found %d total attributes\n", attr_count);
+
+		ans.len = htons(length);
+		MEMCPY( query, &ans, SIZEOF_DNS_ANSWER);
+		query = query + SIZEOF_DNS_ANSWER;
+		// Check enough space in the packet
+	        const char *end_of_packet = query + length + 2 + SIZEOF_DNS_ANSWER + SIZEOF_MDNS_SERVICE +
+		    os_strlen(ms_info->host_name) + 7 + 1 + 2 + SIZEOF_DNS_ANSWER + SIZEOF_MDNS_AUTH;
+
+	        if (query_end <= end_of_packet) {
+		  MDNS_DBG("Too much data to send\n");
+		  pbuf_free(p);
+		  return ERR_MEM;
+		}
+		//MDNS_DBG("Query=%x, query_end=%x, end_ofpacket=%x, length=%x\n", query, query_end, end_of_packet, length);
+
+		i = 0;
+		while(attributes[i] != NULL && i < attr_count) {
+			pHostname = attributes[i];
+			--pHostname;
+			/* convert hostname into suitable query format. */
+			do {
+				++pHostname;
+				nptr = query;
+				++query;
+				for (n = 0;  *pHostname != 0; ++pHostname) {
+					*query = *pHostname;
+					++query;
+					++n;
+				}
+				*nptr = n;
+			} while (*pHostname != 0);
+			i++;
+		}
+//		*query++ = '\0';
+		// Increment by length
+		*query++ = 0xc0 + (name_offset >> 8);
+		*query++ = name_offset & 0xff;
+
+		// Increment by 2
+
+		ans.type = htons(DNS_RRTYPE_SRV);
+		ans.class = htons(dns_class);
+		ans.ttl = htonl(300);
+		c_strlcpy(tmpBuf,ms_info->host_name, sizeof(tmpBuf));
+		c_strlcat(tmpBuf, ".", sizeof(tmpBuf));
+		c_strlcat(tmpBuf, MDNS_LOCAL, sizeof(tmpBuf));
+		length = os_strlen(tmpBuf) + MDNS_LENGTH_ADD;
+		ans.len = htons(SIZEOF_MDNS_SERVICE + length);
+		length = 0;
+		MEMCPY( query, &ans, SIZEOF_DNS_ANSWER);
+
+		/* resize the query */
+		query = query + SIZEOF_DNS_ANSWER;
+
+		serv.prior = htons(0);
+		serv.weight = htons(0);
+		serv.port = htons(ms_info->service_port);
+		MEMCPY( query, &serv, SIZEOF_MDNS_SERVICE);
+		/* resize the query */
+		query = query + SIZEOF_MDNS_SERVICE;
+
+		int hostname_offset = query - (const char *) hdr;
+
+		pHostname = tmpBuf;
+		--pHostname;
+		do {
+			++pHostname;
+			nptr = query;
+			++query;
+			for (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {
+				*query = *pHostname;
+				++query;
+				++n;
+			}
+			*nptr = n;
+		} while (*pHostname != 0);
+		*query++ = '\0';
+
+		// increment by strlen(service_name) + 1 + 7 + sizeof_dns_answer + sizeof_mdns_service
+		
+		*query++ = 0xc0 + (hostname_offset >> 8);
+		*query++ = hostname_offset & 0xff;
+
+		ans.type = htons(DNS_RRTYPE_A);
+		ans.class = htons(dns_class);
+		ans.ttl = htonl(300);
+		ans.len = htons(DNS_IP_ADDR_LEN);
+
+		MEMCPY( query, &ans, SIZEOF_DNS_ANSWER);
+
+		/* resize the query */
+		query = query + SIZEOF_DNS_ANSWER;
+		
+		// increment by strlen(service_name) + 1 + 7 + sizeof_dns_answer 
+		
+
+		/* fill the payload of the mDNS message */
+		/* set the local IP address */
+		auth.src = 0;
+		MEMCPY( query, &auth, SIZEOF_MDNS_AUTH);
+		u8_t *addr_ptr = query + ((char *) &auth.src - (char *) &auth);
+		/* resize the query */
+		query = query + SIZEOF_MDNS_AUTH;
+
+		//MDNS_DBG("Final ptr=%x\n", query);
+
+		// increment by sizeof_mdns_auth
+
+		/* set the name of the authority field.
+		 * The same name as the Query using the offset address*/
+
+		/* resize pbuf to the exact dns query */
+		pbuf_realloc(p, (query) - ((char*) (p->payload)));
+
+		err = send_packet(p, dst_addr, dst_port, addr_ptr);
+	} else {
+		MDNS_DBG("ERR_MEM \n");
+		err = ERR_MEM;
+	}
+
+	return err;
+}
+
+/**
+ * Receive input function for DNS response packets arriving for the dns UDP pcb.
+ *
+ * @params see udp.h
+ */
+static void ICACHE_FLASH_ATTR
+mdns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr,
+		u16_t port) {
+	u16_t i;
+	struct mdns_hdr *hdr;
+	u8_t nquestions;
+	LWIP_UNUSED_ARG(arg);
+	LWIP_UNUSED_ARG(pcb);
+	struct nodemcu_mdns_info *info = (struct nodemcu_mdns_info *)arg;
+	/* is the dns message too big ? */
+	if (p->tot_len > DNS_MSG_SIZE) {
+		LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too big\n"));
+		/* free pbuf and return */
+		goto memerr1;
+	}
+
+	/* is the dns message big enough ? */
+	if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + SIZEOF_DNS_ANSWER)) {
+		LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n"));
+		/* free pbuf and return */
+		goto memerr1;
+	}
+	/* copy dns payload inside static buffer for processing */
+	if (pbuf_copy_partial(p, mdns_payload, p->tot_len, 0) == p->tot_len) {
+		/* The ID in the DNS header should be our entry into the name table. */
+		hdr = (struct mdns_hdr*) mdns_payload;
+
+		i = htons(hdr->id);
+
+		nquestions = htons(hdr->numquestions);
+		//nanswers   = htons(hdr->numanswers);
+		/* if we have a question send an answer if necessary */
+		if (nquestions > 0) {
+		  struct mdns_query qry;
+
+		  int namelen = mdns_namelen((u8_t *) (hdr + 1), p->tot_len);
+
+		  memcpy(&qry, namelen + (u8_t *) (hdr + 1), sizeof(qry));
+
+		  u16_t qry_type = ntohs(qry.type);
+
+		  /* MDNS_DS_DOES_NAME_CHECK */
+		  /* Check if the name in the "question" part match with the name of the MDNS DS service. */
+		  if (mdns_compare_name((unsigned char *) DNS_SD_SERVICE,
+				  (unsigned char *) mdns_payload + SIZEOF_DNS_HDR) == 0) {
+			  if (qry_type == DNS_RRTYPE_PTR || qry_type == DNS_RRTYPE_ANY) {
+			    mdns_send_service_type(i, addr, port);
+			  }
+		  } else if (mdns_compare_name((unsigned char *) service_name_with_suffix,
+				  (unsigned char *) mdns_payload + SIZEOF_DNS_HDR) == 0) {
+
+			  if (qry_type == DNS_RRTYPE_PTR || qry_type == DNS_RRTYPE_ANY) {
+			    mdns_send_service(info, i, addr, port);
+			  }
+		  } else {
+		    
+		    char tmpBuf[PUCK_DATASHEET_SIZE + PUCK_SERVICE_LENGTH];
+		    c_strlcpy(tmpBuf,ms_info->host_name, sizeof(tmpBuf));
+		    c_strlcat(tmpBuf, ".", sizeof(tmpBuf));
+		    c_strlcat(tmpBuf, MDNS_LOCAL, sizeof(tmpBuf));
+
+		    if (mdns_compare_name((unsigned char *) tmpBuf,
+				  (unsigned char *) mdns_payload + SIZEOF_DNS_HDR) == 0) {
+			  if (qry_type == DNS_RRTYPE_A || qry_type == DNS_RRTYPE_ANY) {
+			    mdns_send_service(info, i, addr, port);
+			  }
+		    } else {
+		      c_strlcpy(tmpBuf,ms_info->host_desc, sizeof(tmpBuf));
+		      c_strlcat(tmpBuf, ".", sizeof(tmpBuf));
+		      c_strlcat(tmpBuf, service_name_with_suffix, sizeof(tmpBuf));
+		      if (mdns_compare_name((unsigned char *) tmpBuf,
+				  (unsigned char *) mdns_payload + SIZEOF_DNS_HDR) == 0) {
+			  if (qry_type == DNS_RRTYPE_TXT || qry_type == DNS_RRTYPE_SRV || qry_type == DNS_RRTYPE_ANY) {
+			    mdns_send_service(info, i, addr, port);
+			  }
+		      }
+		    }
+		  }
+		}
+	}
+memerr1:
+	/* free pbuf */
+	pbuf_free(p);
+	return;
+}
+
+static void
+mdns_free_info(struct nodemcu_mdns_info *info) {
+  os_free((void *) info);
+}
+
+/**
+ * close the UDP pcb .
+ */
+void ICACHE_FLASH_ATTR
+nodemcu_mdns_close(void)
+{
+  os_timer_disarm(&mdns_timer);
+
+  if (mdns_pcb != NULL) {
+    udp_remove(mdns_pcb);
+  }
+  if (mdns_payload) {
+    os_free(mdns_payload);
+  }
+  mdns_payload = NULL;
+  mdns_pcb = NULL;
+  mdns_free_info(ms_info);
+  ms_info = NULL;
+}
+
+static void ICACHE_FLASH_ATTR
+mdns_set_servicename(const char *name) {
+	char tmpBuf[128];
+	os_sprintf(tmpBuf, "_%s._tcp.local", name);
+	if (service_name_with_suffix) {
+	  os_free(service_name_with_suffix);
+	}
+	service_name_with_suffix = c_strdup(tmpBuf);
+}
+
+static u8_t reg_counter;
+
+static void
+mdns_reg_handler_restart(void) {
+  reg_counter = 99;
+}
+
+static void ICACHE_FLASH_ATTR
+mdns_reg(struct nodemcu_mdns_info *info) {
+  mdns_send_service(info,0,0,0);
+  if (reg_counter++ > 10) {
+    mdns_send_service_type(0,0,0);
+    reg_counter = 0;
+  }
+}
+
+static struct nodemcu_mdns_info *
+mdns_dup_info(const struct nodemcu_mdns_info *info) {
+  struct nodemcu_mdns_info *result;
+
+  // calculate length
+  int len = sizeof(struct nodemcu_mdns_info);
+
+  len += c_strlen(info->host_name) + 1;
+  len += c_strlen(info->host_desc) + 1;
+  len += c_strlen(info->service_name) + 1;
+  int i;
+  for (i = 0; i < sizeof(info->txt_data) / sizeof(info->txt_data[0]) && info->txt_data[i]; i++) {
+    len += c_strlen(info->txt_data[i]) + 1;
+  }
+
+#define COPY_OVER(dest, src, p)  len = c_strlen(src) + 1; memcpy(p, src, len); dest = p; p += len
+
+  result = (struct nodemcu_mdns_info *) os_zalloc(len);
+  if (result) {
+    char *p = (char *) (result + 1);
+    result->service_port = info->service_port;
+    COPY_OVER(result->host_name, info->host_name, p);
+    COPY_OVER(result->host_desc, info->host_desc, p);
+    COPY_OVER(result->service_name, info->service_name, p);
+    for (i = 0; i < sizeof(info->txt_data) / sizeof(info->txt_data[0]) && info->txt_data[i]; i++) {
+      COPY_OVER(result->txt_data[i], info->txt_data[i], p);
+    }
+  }
+
+#undef COPY_OVER
+
+  return result;
+}
+
+/**
+ * Initialize the resolver: set up the UDP pcb and configure the default server
+ * (NEW IP).
+ * 
+ * returns TRUE if it worked, FALSE if it failed.
+ */
+bool ICACHE_FLASH_ATTR
+nodemcu_mdns_init(struct nodemcu_mdns_info *info) {
+  /* initialize default DNS server address */
+  multicast_addr.addr = DNS_MULTICAST_ADDRESS;
+  struct ip_info ipconfig;
+  mdns_free_info(ms_info);
+  ms_info = mdns_dup_info(info);		// Save the passed block. We need all the data forever
+
+  if (!ms_info) {
+    return FALSE;
+  }
+
+  if (mdns_payload) {
+    os_free(mdns_payload);
+  }
+  mdns_payload = (u8_t *) os_malloc(DNS_MSG_SIZE);
+  if (!mdns_payload) {
+    MDNS_DBG("Alloc fail\n");
+    return FALSE;
+  }
+
+  LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n"));
+
+  mdns_set_servicename(ms_info->service_name);
+
+  // get the host name as instrumentName_serialNumber for MDNS
+  // set the name of the service, the same as host name
+  MDNS_DBG("host_name = %s\n", ms_info->host_name);
+  MDNS_DBG("server_name = %s\n", service_name_with_suffix);
+
+  /* initialize mDNS */
+  mdns_pcb = udp_new();
+
+  if (!mdns_pcb) {
+    return FALSE;
+  }
+  /* join to the multicast address 224.0.0.251 */
+  if(wifi_get_opmode() & 0x01) {
+    struct netif *sta_netif = (struct netif *)eagle_lwip_getif(0x00);
+    if (sta_netif && sta_netif->ip_addr.addr && igmp_joingroup(&sta_netif->ip_addr, &multicast_addr) != ERR_OK) {
+      MDNS_DBG("sta udp_join_multigrup failed!\n");
+      return FALSE;
+    };
+  }
+  if(wifi_get_opmode() & 0x02) {
+    struct netif *ap_netif = (struct netif *)eagle_lwip_getif(0x01);
+    if (ap_netif && ap_netif->ip_addr.addr && igmp_joingroup(&ap_netif->ip_addr, &multicast_addr) != ERR_OK) {
+      MDNS_DBG("ap udp_join_multigrup failed!\n");
+      return FALSE;
+    };
+  }
+  register_flag = 1;
+  /* join to any IP address at the port 5353 */
+  if (udp_bind(mdns_pcb, IP_ADDR_ANY, DNS_MDNS_PORT) != ERR_OK) {
+	  MDNS_DBG("udp_bind failed!\n");
+	  return FALSE;
+  };
+
+  /*loopback function for the multicast(224.0.0.251) messages received at port 5353*/
+  udp_recv(mdns_pcb, mdns_recv, ms_info);
+  mdns_flag = 1;
+  /*
+   * Register the name of the instrument
+   */
+
+  //MDNS_DBG("About to start timer\n");
+  os_timer_disarm(&mdns_timer);
+  os_timer_setfn(&mdns_timer, (os_timer_func_t *)mdns_reg,ms_info);
+  os_timer_arm(&mdns_timer, 1000 * 120, 1);
+  /* kick off the first one right away */
+  mdns_reg_handler_restart();
+  mdns_reg(ms_info);
+
+  return TRUE;
+}
+
+#endif /* LWIP_MDNS */

+ 15 - 5
docs/en/modules/mdns.md

@@ -9,13 +9,21 @@
 Register a hostname and start the mDNS service. If the service is already running, then it will be restarted with the new parameters.
 
 #### Syntax
-`mdns.register(hostname, servicename, port [, attributes])`
+`mdns.register(hostname [, attributes])`
 
 #### Parameters
 - `hostname` The hostname for this device. Alphanumeric characters are best.
-- `servicename` The service name for this device. Alphanumeric characters are best. This will get prefixed with `_` and suffixed with `._tcp`
-- `port` The port number for the primary service.
-- `attributes` A optional table of up to 10 attributes to be exposed. The keys must all be strings.
+- `attributes` A optional table of options. The keys must all be strings.
+
+The `attributes` contains two sorts of attributes -- those with specific names, and those that are service specific. [RFC 6763](https://tools.ietf.org/html/rfc6763#page-13} 
+defines how extra, service specific, attributes are encoded into the DNS. One example is that if the device supports printing, then the queue name can 
+be specified as an additional attribute. This module supports up to 10 such attributes.
+
+The specific names are:
+
+- `port` The port number for the service. Default value is 80.
+- `service` The name of the service. Default value is 'http'.
+- `dscription` A short phrase (under 63 characters) describing the service. Default is the hostname.
 
 #### Returns
 `nil`
@@ -25,10 +33,12 @@ Various errors can be generated during argument validation. The NodeMCU must hav
 
 #### Example
 
-    mdns.register("fishtank", "http", 80, { hardware='NodeMCU'})
+    mdns.register("fishtank", {hardware='NodeMCU'})
 
 Using `dns-sd` on OS X, you can see `fishtank.local` as providing the `_http._tcp` service. You can also browse directly to `fishtank.local`. In Safari you can get all the mDNS web pages as part of your bookmarks menu.
 
+    mdns.register("fishtank", { description="Top Fishtank", service="http", port=80, location='Living Room' })
+
 ## mdns.close()
 Shut down the mDNS service. This is not normally needed.