nodemcu-firmware/app/lwip/core/mdns.c

1140 lines
30 KiB
C

/**
* 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/puck_def.h"
#include "lwip/udp.h"
#include "lwip/mem.h"
#include "lwip/igmp.h"
#include "osapi.h"
#include "os_type.h"
#include "user_interface.h"
#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
uint16 PUCK_PORT ;
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 host_name[MDNS_NAME_LENGTH];
static char service_name[MDNS_NAME_LENGTH];
static char server_name[MDNS_NAME_LENGTH];
//static char puck_datasheet[PUCK_DATASHEET_SIZE];
static struct udp_pcb *mdns_pcb = NULL;
static struct mdns_info * ms_info = NULL;
static struct ip_addr multicast_addr;
static struct ip_addr host_addr;
static uint8 register_flag = 0;
static uint8 mdns_flag = 0;
//#if (DNS_USES_STATIC_BUF == 1)
static u8_t mdns_payload[DNS_MSG_SIZE];
//#endif /* (MDNS_USES_STATIC_BUF == 1) */
/*
* Function to set the UDP pcb used to send the mDNS packages
*/
void ICACHE_FLASH_ATTR
getPcb(struct udp_pcb *pcb) {
mdns_pcb = pcb;
}
#if DNS_DOES_NAME_CHECK
/**
* 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;
}
#endif /* DNS_DOES_NAME_CHECK */
/**
* Send a mDNS answer packet.
*
* @param type of answer hostname and service registration or service
* @param 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_answer(u16_t type, const char* name, u8_t id) {
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;
static 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;
if (type == MDNS_SD_ANSWER) {
pHostname = DNS_SD_SERVICE;
hdr->numanswers = htons(1);
} else if (type == MDNS_SERVICE_REG_ANSWER) {
pHostname = PUCK_SERVICE;
hdr->numanswers = htons(type);
} else {
pHostname = name;
hdr->numanswers = htons(type);
}
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 */
if (type == MDNS_REG_ANSWER) {
ans.type = htons(DNS_RRTYPE_A);
ans.class = htons(DNS_RRCLASS_IN);
ans.ttl = htonl(MDNS_SERVICE_TIME);
ans.len = htons(DNS_IP_ADDR_LEN);
length = DNS_IP_ADDR_LEN;
MEMCPY( query, &ans, SIZEOF_DNS_ANSWER);
/* resize the query */
query = query + SIZEOF_DNS_ANSWER;
/* set the local IP address */
auth.src = host_addr.addr;
MEMCPY( query, &auth, SIZEOF_MDNS_AUTH);
}
if (type == MDNS_SD_ANSWER) {
ans.type = htons(DNS_RRTYPE_PTR);
ans.class = htons(DNS_RRCLASS_IN);
ans.ttl = htonl(300);
ans.len = htons(os_strlen(PUCK_SERVICE) + 1 +1 );
length = 0;
MEMCPY( query, &ans, SIZEOF_DNS_ANSWER);
/* resize the query */
query = query + SIZEOF_DNS_ANSWER;
pHostname = PUCK_SERVICE;
--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';
}
if (type == MDNS_SERVICE_REG_ANSWER) {
ans.type = htons(DNS_RRTYPE_PTR);
ans.class = htons(DNS_RRCLASS_IN);
ans.ttl = htonl(MDNS_SERVICE_TIME);
os_strcpy(tmpBuf, name);
os_strcat(tmpBuf, ".");
os_strcat(tmpBuf, PUCK_SERVICE);
length = os_strlen(tmpBuf) + MDNS_LENGTH_ADD;
ans.len = htons(length);
length = 0;
MEMCPY( query, &ans, SIZEOF_DNS_ANSWER);
/* resize the query */
query = query + SIZEOF_DNS_ANSWER;
pHostname = tmpBuf;
--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';
/* Service query*/
pHostname = name;
--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);
/* Add to the service name the service local
* pointing to the beginning of the mDNS message*/
*query++ = DNS_OFFSET_FLAG;
*query++ = DNS_DEFAULT_OFFSET;
/* fill the query */
ans.type = htons(DNS_RRTYPE_SRV);
ans.class = htons(DNS_RRCLASS_FLUSH_IN);
ans.ttl = htonl(MDNS_SERVICE_TIME);
os_strcpy(tmpBuf, host_name);
os_strcat(tmpBuf, ".");
os_strcat(tmpBuf, MDNS_LOCAL);
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;
/* fill the service properties */
serv.prior = htons(0);
serv.weight = htons(0);
serv.port = htons(PUCK_PORT);
MEMCPY( query, &serv, SIZEOF_MDNS_SERVICE);
/* resize the query */
query = query + SIZEOF_MDNS_SERVICE;
pHostname = tmpBuf;
--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';
/* TXT answer */
pHostname = name;
--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);
/* Add to the service name the service local
* pointing to the beginning of the mDNS message*/
*query++ = DNS_OFFSET_FLAG;
*query++ = DNS_DEFAULT_OFFSET;
/* fill the answer */
ans.type = htons(DNS_RRTYPE_TXT);
ans.class = htons(DNS_RRCLASS_IN);
ans.ttl = htonl(MDNS_SERVICE_TIME);
length = sizeof(SERVICE_DESCRIPTION);
ans.len = htons(length);
length = 0;
MEMCPY( query, &ans, SIZEOF_DNS_ANSWER);
/* resize the query */
query = query + SIZEOF_DNS_ANSWER;
pHostname = SERVICE_DESCRIPTION;
--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)));
/* send dns packet */
/*add by tzx for AP + STA MDNS begin------*/
sta_netif = (struct netif *)eagle_lwip_getif(0x00);
ap_netif = (struct netif *)eagle_lwip_getif(0x01);
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)) {
p_sta = pbuf_alloc(PBUF_TRANSPORT,
SIZEOF_DNS_HDR + MDNS_MAX_NAME_LENGTH * 2 + SIZEOF_DNS_QUERY, PBUF_RAM);
if (pbuf_copy (p_sta,p) != ERR_OK) {
os_printf("mdns_answer copying to new pbuf failed\n");
return -1;
}
netif_set_default(sta_netif);
err = udp_sendto(mdns_pcb, p_sta, &multicast_addr, DNS_MDNS_PORT);
pbuf_free(p_sta);
netif_set_default(ap_netif);
}
}
/*add by tzx for AP + STA MDNS end------*/
err = udp_sendto(mdns_pcb, p, &multicast_addr, DNS_MDNS_PORT);
/* free pbuf */
pbuf_free(p);
} 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 mdns_info *info, u8_t id) {
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;
const char *pHostname;
char *device_info;
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;
static char tmpBuf[PUCK_DATASHEET_SIZE + PUCK_SERVICE_LENGTH];
/* 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;
os_strcpy(tmpBuf, PUCK_SERVICE);
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(PUCK_SERVICE) + 1;
addr2 -= length;
ans.type = htons(DNS_RRTYPE_PTR);
ans.class = htons(DNS_RRCLASS_IN);
ans.ttl = htonl(300);
os_strcpy(tmpBuf, name);
length = os_strlen(tmpBuf) + MDNS_LENGTH_ADD + 1;
ans.len = htons(length);
length = 0;
MEMCPY( query, &ans, SIZEOF_DNS_ANSWER);
/* resize the query */
query = query + SIZEOF_DNS_ANSWER;
pHostname = tmpBuf;
--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;
pHostname = name;
--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';
*query++ = DNS_OFFSET_FLAG;
*query++ = DNS_DEFAULT_OFFSET;
/* fill the answer */
ans.type = htons(DNS_RRTYPE_TXT);
ans.class = htons(DNS_RRCLASS_FLUSH_IN);
ans.ttl = htonl(300);
// length = os_strlen(TXT_DATA) + MDNS_LENGTH_ADD + 1;
device_info = (char *)os_zalloc(50);
ets_sprintf(device_info,"vendor = %s","Espressif");
for(i = 0; i < 10 &&(info->txt_data[i] != NULL);i++) {
length += os_strlen(info->txt_data[i]);
length++;
}
length += os_strlen(device_info)+ 1 ;
ans.len = htons(length);
length = 0;
MEMCPY( query, &ans, SIZEOF_DNS_ANSWER);
query = query + SIZEOF_DNS_ANSWER;
pHostname = device_info;
--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 = 0;
while(info->txt_data[i] != NULL && i < 10) {
pHostname = info->txt_data[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';
os_free(device_info);
os_strcpy(tmpBuf, name);
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++ = DNS_OFFSET_FLAG;
*query++ = DNS_DEFAULT_OFFSET;
ans.type = htons(DNS_RRTYPE_SRV);
ans.class = htons(DNS_RRCLASS_FLUSH_IN);
ans.ttl = htonl(300);
os_strcpy(tmpBuf,service_name);
os_strcat(tmpBuf, ".");
os_strcat(tmpBuf, MDNS_LOCAL);
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(PUCK_PORT);
MEMCPY( query, &serv, SIZEOF_MDNS_SERVICE);
/* resize the query */
query = query + SIZEOF_MDNS_SERVICE;
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';
/* set the name of the authority field.
* The same name as the Query using the offset address*/
os_strcpy(tmpBuf,service_name);
os_strcat(tmpBuf, ".");
os_strcat(tmpBuf, MDNS_LOCAL);
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';
/* set the name of the authority field.
* The same name as the Query using the offset address*/
//*query++ = DNS_OFFSET_FLAG;
//*query++ = DNS_DEFAULT_OFFSET;
ans.type = htons(DNS_RRTYPE_A);
ans.class = htons(DNS_RRCLASS_FLUSH_IN);
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;
/* fill the payload of the mDNS message */
/* set the local IP address */
auth.src = host_addr.addr; //ipAddr;
MEMCPY( query, &auth, SIZEOF_MDNS_AUTH);
/* resize the query */
query = query + 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)));
/* send dns packet */
sta_netif = (struct netif *)eagle_lwip_getif(0x00);
ap_netif = (struct netif *)eagle_lwip_getif(0x01);
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)) {
p_sta = pbuf_alloc(PBUF_TRANSPORT,
SIZEOF_DNS_HDR + MDNS_MAX_NAME_LENGTH * 2 + SIZEOF_DNS_QUERY, PBUF_RAM);
if (pbuf_copy (p_sta,p) != ERR_OK) {
os_printf("mdns_send_service copying to new pbuf failed\n");
return -1;
}
netif_set_default(sta_netif);
err = udp_sendto(mdns_pcb, p_sta, &multicast_addr, DNS_MDNS_PORT);
pbuf_free(p_sta);
netif_set_default(ap_netif);
}
}
err = udp_sendto(mdns_pcb, p, &multicast_addr, DNS_MDNS_PORT);
/* free pbuf */
pbuf_free(p);
} else {
os_printf("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) {
u8_t i;
struct mdns_hdr *hdr;
u8_t nquestions;
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(pcb);
LWIP_UNUSED_ARG(addr);
LWIP_UNUSED_ARG(port);
struct mdns_info *info = (struct 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);
if (i < DNS_TABLE_SIZE) {
nquestions = htons(hdr->numquestions);
//nanswers = htons(hdr->numanswers);
/* if we have a question send an answer if necessary */
if (nquestions > 0) {
/* 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) {
/* respond with the puck service*/
mdns_answer(MDNS_SD_ANSWER, PUCK_SERVICE, 0);
} else if (mdns_compare_name((unsigned char *) PUCK_SERVICE,
(unsigned char *) mdns_payload + SIZEOF_DNS_HDR) == 0) {
/* respond with the puck service*/
mdns_send_service(info, 0);
} else
goto memerr2;
}
}
}
goto memerr2;
memerr2:
os_memset(mdns_payload , 0 ,DNS_MSG_SIZE);
memerr1:
/* free pbuf */
pbuf_free(p);
return;
}
/**
* close the UDP pcb .
*/
void ICACHE_FLASH_ATTR
mdns_close(void)
{
uint8 text_index = 0;
if (mdns_pcb != NULL && ms_info != NULL) {
udp_remove(mdns_pcb);
for(text_index = 0;text_index < 10;text_index++) {
if(ms_info->txt_data[text_index] != NULL) {
os_free(ms_info->txt_data[text_index]);
ms_info->txt_data[text_index] = NULL;
}
}
if (ms_info->host_name != NULL) {
os_free(ms_info->host_name);
ms_info->host_name = NULL;
}
if (ms_info->server_name != NULL) {
os_free(ms_info->server_name);
ms_info->server_name = NULL;
}
os_free(ms_info);
mdns_pcb = NULL;
ms_info = NULL;
}
}
void ICACHE_FLASH_ATTR
mdns_set_name(const char *name)
{
//strcpy(host_name, name);
os_strcpy(service_name, name);
}
void ICACHE_FLASH_ATTR
mdns_enable(void)
{
if(mdns_flag == 0) {
udp_recv(mdns_pcb, mdns_recv, NULL);
}
}
void ICACHE_FLASH_ATTR
mdns_disable(void)
{
if (mdns_flag == 1) {
udp_recv(mdns_pcb, NULL, NULL);
}
}
/**
* close the UDP pcb .
*/
char* ICACHE_FLASH_ATTR
mdns_get_hostname(void) {
//strcpy(host_name, name);
char *name = host_name;
if (host_name[0] != 0 ) {
return name;
} else {
return ("Espressif");
}
}
void ICACHE_FLASH_ATTR
mdns_set_hostname(char *name) {
if (name == NULL) {
os_strncpy(host_name, "Espressif", os_strlen("Espressif")+3);
return;
}
if (os_strlen(name) + 3 <= MDNS_NAME_LENGTH ){
os_strncpy(host_name, name, os_strlen(name) );
// os_memset(host_name + os_strlen(host_name) ,0x00,3);
} else {
os_strncpy(host_name, name, MDNS_NAME_LENGTH);
}
}
void ICACHE_FLASH_ATTR
mdns_set_servername(const char *name) {
if (name == NULL) {
PUCK_SERVICE = "_Espressif._tcp._local";
}else {
os_sprintf(server_name ,"_%s._tcp.local",name);
PUCK_SERVICE = server_name;
}
}
char* ICACHE_FLASH_ATTR
mdns_get_servername(void) {
char *name = PUCK_SERVICE;
if (name == NULL) {
PUCK_SERVICE = "_Espressif._tcp._local";
}
return name;
}
void ICACHE_FLASH_ATTR
mdns_server_unregister(void) {
struct ip_addr ap_host_addr;
struct ip_info ipconfig;
if(register_flag == 1){
if (igmp_leavegroup(&host_addr, &multicast_addr) != ERR_OK) {
os_printf("sta udp_leave_multigrup failed!\n");
return;
};
if(wifi_get_opmode() == 0x03 || wifi_get_opmode() == 0x02) {
wifi_get_ip_info(SOFTAP_IF, &ipconfig);
ap_host_addr.addr = ipconfig.ip.addr;
if (igmp_leavegroup(&ap_host_addr, &multicast_addr) != ERR_OK) {
os_printf("ap udp_join_multigrup failed!\n");
return;
};
}
register_flag = 0;
}
}
void ICACHE_FLASH_ATTR
mdns_server_register(void) {
if (register_flag == 1) {
os_printf("mdns server is already registered !\n");
return;
} else if (igmp_joingroup(&host_addr, &multicast_addr) != ERR_OK) {
os_printf("udp_join_multigrup failed!\n");
return;
};
register_flag = 1;
}
void ICACHE_FLASH_ATTR
mdns_reg(struct mdns_info *info) {
static uint8 i = 0;
if (i <= 3) {
mdns_send_service(info,0);
i++;
} else {
os_timer_disarm(&mdns_timer);
}
}
#include "pm/swtimer.h"
/**
* Initialize the resolver: set up the UDP pcb and configure the default server
* (NEW IP).
*/
void ICACHE_FLASH_ATTR
mdns_init(struct mdns_info *info) {
/* initialize default DNS server address */
multicast_addr.addr = DNS_MULTICAST_ADDRESS;
struct ip_addr ap_host_addr;
struct ip_info ipconfig;
uint8 text_index = 0;
ms_info = (struct mdns_info *)os_zalloc(sizeof(struct mdns_info));
if (ms_info != NULL) {
os_memcpy(ms_info,info,sizeof(struct mdns_info));
ms_info->host_name = (char *)os_zalloc(os_strlen(info->host_name)+1);
os_memcpy(ms_info->host_name,info->host_name,os_strlen(info->host_name));
ms_info->server_name = (char *)os_zalloc(os_strlen(info->server_name)+1);
os_memcpy(ms_info->server_name,info->server_name,os_strlen(info->server_name));
for(text_index = 0;text_index < 10;text_index++) {
if(info->txt_data[text_index] != NULL) {
ms_info->txt_data[text_index] = (char *)os_zalloc(os_strlen(info->txt_data[text_index])+1);
os_memcpy(ms_info->txt_data[text_index],info->txt_data[text_index],os_strlen(info->txt_data[text_index]));
} else {
break;
}
}
} else {
os_printf("ms_info alloc failed\n");
return;
}
if (ms_info->ipAddr == 0) {
os_printf("mdns ip error!\n ");
return;
}
host_addr.addr = ms_info->ipAddr ;
LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n"));
//get the datasheet from PUCK
mdns_set_hostname(ms_info->host_name);
mdns_set_servername(ms_info->server_name);
mdns_set_name(ms_info->host_name);
// get the host name as instrumentName_serialNumber for MDNS
// set the name of the service, the same as host name
os_printf("host_name = %s\n", host_name);
os_printf("server_name = %s\n", PUCK_SERVICE);
if (ms_info->server_port == 0)
{
PUCK_PORT = 80;
} else {
PUCK_PORT = ms_info->server_port;
}
/* initialize mDNS */
mdns_pcb = udp_new();
if (mdns_pcb != NULL) {
/* join to the multicast address 224.0.0.251 */
if(wifi_get_opmode() == 0x03 || wifi_get_opmode() == 0x01) {
if (igmp_joingroup(&host_addr, &multicast_addr) != ERR_OK) {
os_printf("sta udp_join_multigrup failed!\n");
return;
};
}
if(wifi_get_opmode() == 0x03 || wifi_get_opmode() == 0x02) {
wifi_get_ip_info(SOFTAP_IF, &ipconfig);
ap_host_addr.addr = ipconfig.ip.addr;
if (igmp_joingroup(&ap_host_addr, &multicast_addr) != ERR_OK) {
os_printf("ap udp_join_multigrup failed!\n");
return;
};
}
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) {
os_printf("udp_bind failed!\n");
return;
};
/*loopback function for the multicast(224.0.0.251) messages received at port 5353*/
// mdns_enable();
udp_recv(mdns_pcb, mdns_recv, ms_info);
mdns_flag = 1;
/*
* Register the name of the instrument
*/
os_timer_disarm(&mdns_timer);
os_timer_setfn(&mdns_timer, (os_timer_func_t *)mdns_reg,ms_info);
SWTIMER_REG_CB(mdns_reg, SWTIMER_RESTART);
//going on the above comment, it's probably a good idea to let mdns_reg run it's course. not sure if the 1 second timing is important, so lets restart it to be safe.
os_timer_arm(&mdns_timer, 1000, 1);
}
}
#endif /* LWIP_MDNS */