1140 lines
30 KiB
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 */
|