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 commit6ee49ee106
Author: philip <philip@gladstonefamily.net> Date: Fri Mar 25 23:25:11 2016 -0400 Update the docs commit7e455541c6
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`
This commit is contained in:
parent
eccb2e4a53
commit
3a5e5f10e2
|
@ -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.
|
||||
|
|
|
@ -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
|
|
@ -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 */
|
||||
}
|
||||
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
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 (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);
|
||||
}
|
||||
|
||||
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;
|
||||
} else {
|
||||
// put in the key
|
||||
c_strcpy(p, luaL_checkstring(L, -2));
|
||||
result->mdns_info.txt_data[slot] = p;
|
||||
p = advance_over_string(p);
|
||||
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);
|
||||
|
||||
// now smash in the value
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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 */
|
|
@ -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.
|
||||
|
||||
|
|
Loading…
Reference in New Issue