mdns: add mdns delegation

This allows publishing mdns services for other devices.


* Original commit: espressif/esp-idf@401ff56cc1
This commit is contained in:
Jiacheng Guo
2021-03-30 13:19:01 +08:00
committed by suren-gabrielyan-espressif
parent b62b4b3e25
commit 1eb5df9780
4 changed files with 494 additions and 220 deletions

View File

@ -114,6 +114,10 @@ void mdns_free(void);
*/ */
esp_err_t mdns_hostname_set(const char * hostname); esp_err_t mdns_hostname_set(const char * hostname);
esp_err_t mdns_delegate_hostname_add(const char * hostname, const esp_ip_addr_t *address);
bool mdns_hostname_exists(const char *hostname);
/** /**
* @brief Set the default instance name for mDNS server * @brief Set the default instance name for mDNS server
* *
@ -145,6 +149,12 @@ esp_err_t mdns_instance_name_set(const char * instance_name);
*/ */
esp_err_t mdns_service_add(const char * instance_name, const char * service_type, const char * proto, uint16_t port, mdns_txt_item_t txt[], size_t num_items); esp_err_t mdns_service_add(const char * instance_name, const char * service_type, const char * proto, uint16_t port, mdns_txt_item_t txt[], size_t num_items);
esp_err_t mdns_service_add_custom_host(const char *instance_name, const char *service_type, const char *proto,
const char *hostname, uint16_t port, mdns_txt_item_t txt[], size_t num_items);
bool mdns_service_exists(const char *service_type, const char *proto, const char *hostname);
/** /**
* @brief Remove service from mDNS server * @brief Remove service from mDNS server
* *
@ -159,6 +169,8 @@ esp_err_t mdns_service_add(const char * instance_name, const char * service_type
*/ */
esp_err_t mdns_service_remove(const char * service_type, const char * proto); esp_err_t mdns_service_remove(const char * service_type, const char * proto);
esp_err_t mdns_service_remove_for_host(const char * service_type, const char * proto, const char *hostname);
/** /**
* @brief Set instance name for service * @brief Set instance name for service
* *
@ -174,6 +186,8 @@ esp_err_t mdns_service_remove(const char * service_type, const char * proto);
*/ */
esp_err_t mdns_service_instance_name_set(const char * service_type, const char * proto, const char * instance_name); esp_err_t mdns_service_instance_name_set(const char * service_type, const char * proto, const char * instance_name);
esp_err_t mdns_service_instance_name_set_for_host(const char * service_type, const char * proto, const char *hostname, const char * instance_name);
/** /**
* @brief Set service port * @brief Set service port
* *
@ -189,6 +203,10 @@ esp_err_t mdns_service_instance_name_set(const char * service_type, const char *
*/ */
esp_err_t mdns_service_port_set(const char * service_type, const char * proto, uint16_t port); esp_err_t mdns_service_port_set(const char * service_type, const char * proto, uint16_t port);
esp_err_t mdns_service_port_set_for_host(const char *service_type, const char *proto, const char *hostname,
uint16_t port);
/** /**
* @brief Replace all TXT items for service * @brief Replace all TXT items for service
* *
@ -205,6 +223,9 @@ esp_err_t mdns_service_port_set(const char * service_type, const char * proto, u
*/ */
esp_err_t mdns_service_txt_set(const char * service_type, const char * proto, mdns_txt_item_t txt[], uint8_t num_items); esp_err_t mdns_service_txt_set(const char * service_type, const char * proto, mdns_txt_item_t txt[], uint8_t num_items);
esp_err_t mdns_service_txt_set_for_host(const char *service_type, const char *proto, const char *hostname,
mdns_txt_item_t txt[], uint8_t num_items);
/** /**
* @brief Set/Add TXT item for service TXT record * @brief Set/Add TXT item for service TXT record
* *
@ -221,6 +242,10 @@ esp_err_t mdns_service_txt_set(const char * service_type, const char * proto, md
*/ */
esp_err_t mdns_service_txt_item_set(const char * service_type, const char * proto, const char * key, const char * value); esp_err_t mdns_service_txt_item_set(const char * service_type, const char * proto, const char * key, const char * value);
esp_err_t mdns_service_txt_item_set_for_host(const char *service_type, const char *proto, const char *hostname,
const char *key, const char *value);
/** /**
* @brief Remove TXT item for service TXT record * @brief Remove TXT item for service TXT record
* *
@ -236,6 +261,9 @@ esp_err_t mdns_service_txt_item_set(const char * service_type, const char * prot
*/ */
esp_err_t mdns_service_txt_item_remove(const char * service_type, const char * proto, const char * key); esp_err_t mdns_service_txt_item_remove(const char * service_type, const char * proto, const char * key);
esp_err_t mdns_service_txt_item_remove_for_host(const char *service_type, const char *proto, const char *hostname,
const char *key);
/** /**
* @brief Remove and free all services from mDNS server * @brief Remove and free all services from mDNS server
* *

View File

@ -31,6 +31,8 @@ static const char * MDNS_DEFAULT_DOMAIN = "local";
static const char * MDNS_SUB_STR = "_sub"; static const char * MDNS_SUB_STR = "_sub";
mdns_server_t * _mdns_server = NULL; mdns_server_t * _mdns_server = NULL;
static mdns_host_item_t *_mdns_host_list = NULL;
static mdns_host_item_t _mdns_self_host;
static const char *TAG = "MDNS"; static const char *TAG = "MDNS";
@ -43,6 +45,7 @@ static void _mdns_search_result_add_ip(mdns_search_once_t * search, const char *
static void _mdns_search_result_add_srv(mdns_search_once_t * search, const char * hostname, uint16_t port, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol); static void _mdns_search_result_add_srv(mdns_search_once_t * search, const char * hostname, uint16_t port, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol);
static void _mdns_search_result_add_txt(mdns_search_once_t * search, mdns_txt_item_t * txt, size_t txt_count, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol); static void _mdns_search_result_add_txt(mdns_search_once_t * search, mdns_txt_item_t * txt, size_t txt_count, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol);
static mdns_result_t * _mdns_search_result_add_ptr(mdns_search_once_t * search, const char * instance, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol); static mdns_result_t * _mdns_search_result_add_ptr(mdns_search_once_t * search, const char * instance, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol);
static bool _mdns_append_host_list(mdns_out_answer_t ** destination, bool flush, bool bye);
/* /*
* @brief Internal collection of mdns supported interfaces * @brief Internal collection of mdns supported interfaces
@ -143,6 +146,12 @@ static char * _mdns_mangle_name(char* in) {
return ret; return ret;
} }
static bool _mdns_service_match(const mdns_service_t *srv, const char *service, const char *proto, const char *hostname)
{
return !strcasecmp(srv->service, service) && !strcasecmp(srv->proto, proto) &&
(_str_null_or_empty(hostname) || !strcasecmp(srv->hostname, hostname));
}
/** /**
* @brief finds service from given service type * @brief finds service from given service type
* @param server the server * @param server the server
@ -151,11 +160,11 @@ static char * _mdns_mangle_name(char* in) {
* *
* @return the service item if found or NULL on error * @return the service item if found or NULL on error
*/ */
static mdns_srv_item_t * _mdns_get_service_item(const char * service, const char * proto) static mdns_srv_item_t * _mdns_get_service_item(const char * service, const char * proto, const char *hostname)
{ {
mdns_srv_item_t * s = _mdns_server->services; mdns_srv_item_t * s = _mdns_server->services;
while (s) { while (s) {
if (!strcasecmp(s->service->service, service) && !strcasecmp(s->service->proto, proto)) { if (_mdns_service_match(s->service, service, proto, hostname)) {
return s; return s;
} }
s = s->next; s = s->next;
@ -163,6 +172,21 @@ static mdns_srv_item_t * _mdns_get_service_item(const char * service, const char
return NULL; return NULL;
} }
static mdns_host_item_t *mdns_get_host_item(const char *hostname, uint8_t address_type)
{
if (hostname == NULL || strcasecmp(hostname, _mdns_server->hostname) == 0) {
return &_mdns_self_host;
}
mdns_host_item_t *host = _mdns_host_list;
while (host != NULL) {
if (strcasecmp(host->hostname, hostname) == 0 && host->address.type == address_type) {
return host;
}
host = host->next;
}
return NULL;
}
static bool _mdns_can_add_more_services(void) static bool _mdns_can_add_more_services(void)
{ {
mdns_srv_item_t * s = _mdns_server->services; mdns_srv_item_t * s = _mdns_server->services;
@ -704,7 +728,11 @@ static uint16_t _mdns_append_srv_record(uint8_t * packet, uint16_t * index, mdns
return 0; return 0;
} }
str[0] = _mdns_server->hostname; if (service->hostname) {
str[0] = service->hostname;
} else {
str[0] = _mdns_server->hostname;
}
str[1] = MDNS_DEFAULT_DOMAIN; str[1] = MDNS_DEFAULT_DOMAIN;
if (_str_null_or_empty(str[0])) { if (_str_null_or_empty(str[0])) {
@ -731,20 +759,19 @@ static uint16_t _mdns_append_srv_record(uint8_t * packet, uint16_t * index, mdns
* *
* @return length of added data: 0 on error or length on success * @return length of added data: 0 on error or length on success
*/ */
static uint16_t _mdns_append_a_record(uint8_t * packet, uint16_t * index, uint32_t ip, bool flush, bool bye) static uint16_t _mdns_append_a_record(uint8_t * packet, uint16_t * index, const char * hostname, uint32_t ip, bool flush, bool bye)
{ {
const char * str[2]; const char * str[2];
uint16_t record_length = 0; uint16_t record_length = 0;
uint8_t part_length; uint8_t part_length;
str[0] = _mdns_server->hostname; str[0] = hostname;
str[1] = MDNS_DEFAULT_DOMAIN; str[1] = MDNS_DEFAULT_DOMAIN;
if (_str_null_or_empty(str[0])) { if (_str_null_or_empty(str[0])) {
return 0; return 0;
} }
part_length = _mdns_append_fqdn(packet, index, str, 2); part_length = _mdns_append_fqdn(packet, index, str, 2);
if (!part_length) { if (!part_length) {
return 0; return 0;
@ -778,17 +805,18 @@ static uint16_t _mdns_append_a_record(uint8_t * packet, uint16_t * index, uint32
* *
* @param packet MDNS packet * @param packet MDNS packet
* @param index offset in the packet * @param index offset in the packet
* @param hostnamek the hostname address to add
* @param ipv6 the IPv6 address to add * @param ipv6 the IPv6 address to add
* *
* @return length of added data: 0 on error or length on success * @return length of added data: 0 on error or length on success
*/ */
static uint16_t _mdns_append_aaaa_record(uint8_t * packet, uint16_t * index, uint8_t * ipv6, bool flush, bool bye) static uint16_t _mdns_append_aaaa_record(uint8_t * packet, uint16_t * index, const char * hostname, uint8_t * ipv6, bool flush, bool bye)
{ {
const char * str[2]; const char * str[2];
uint16_t record_length = 0; uint16_t record_length = 0;
uint8_t part_length; uint8_t part_length;
str[0] = _mdns_server->hostname; str[0] = hostname;
str[1] = MDNS_DEFAULT_DOMAIN; str[1] = MDNS_DEFAULT_DOMAIN;
if (_str_null_or_empty(str[0])) { if (_str_null_or_empty(str[0])) {
@ -908,6 +936,7 @@ static bool _ipv6_address_is_zero(esp_ip6_addr_t ip6)
* @brief Append answer to packet * @brief Append answer to packet
* *
* @return number of answers added to the packet * @return number of answers added to the packet
* XXX: create the answers here
*/ */
static uint8_t _mdns_append_answer(uint8_t * packet, uint16_t * index, mdns_out_answer_t * answer, mdns_if_t tcpip_if) static uint8_t _mdns_append_answer(uint8_t * packet, uint16_t * index, mdns_out_answer_t * answer, mdns_if_t tcpip_if)
{ {
@ -930,54 +959,71 @@ static uint8_t _mdns_append_answer(uint8_t * packet, uint16_t * index, mdns_out_
} else if (answer->type == MDNS_TYPE_SDPTR) { } else if (answer->type == MDNS_TYPE_SDPTR) {
return _mdns_append_sdptr_record(packet, index, answer->service, answer->flush, answer->bye) > 0; return _mdns_append_sdptr_record(packet, index, answer->service, answer->flush, answer->bye) > 0;
} else if (answer->type == MDNS_TYPE_A) { } else if (answer->type == MDNS_TYPE_A) {
esp_netif_ip_info_t if_ip_info; if (answer->host == &_mdns_self_host) {
if (!_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].pcb && _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].state != PCB_DUP) { esp_netif_ip_info_t if_ip_info;
return 0; if (!_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].pcb && _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].state != PCB_DUP) {
} return 0;
if (esp_netif_get_ip_info(_mdns_get_esp_netif(tcpip_if), &if_ip_info)) { }
return 0; if (esp_netif_get_ip_info(_mdns_get_esp_netif(tcpip_if), &if_ip_info)) {
} return 0;
if (_mdns_append_a_record(packet, index, if_ip_info.ip.addr, answer->flush, answer->bye) <= 0) { }
return 0; if (_mdns_append_a_record(packet, index, _mdns_server->hostname, if_ip_info.ip.addr, answer->flush, answer->bye) <= 0) {
} return 0;
if (!_mdns_if_is_dup(tcpip_if)) { }
if (!_mdns_if_is_dup(tcpip_if)) {
return 1;
}
mdns_if_t other_if = _mdns_get_other_if (tcpip_if);
if (esp_netif_get_ip_info(_mdns_get_esp_netif(other_if), &if_ip_info)) {
return 1;
}
if (_mdns_append_a_record(packet, index, _mdns_server->hostname, if_ip_info.ip.addr, answer->flush, answer->bye) > 0) {
return 2;
}
return 1; return 1;
} else if (answer->host != NULL) {
if (_mdns_append_a_record(packet, index, answer->host->hostname, answer->host->address.u_addr.ip4.addr, answer->flush, answer->bye) <= 0) {
return 0;
} else {
return 1;
}
} }
mdns_if_t other_if = _mdns_get_other_if (tcpip_if);
if (esp_netif_get_ip_info(_mdns_get_esp_netif(other_if), &if_ip_info)) {
return 1;
}
if (_mdns_append_a_record(packet, index, if_ip_info.ip.addr, answer->flush, answer->bye) > 0) {
return 2;
}
return 1;
} }
#if CONFIG_LWIP_IPV6 #if CONFIG_LWIP_IPV6
else if (answer->type == MDNS_TYPE_AAAA) { else if (answer->type == MDNS_TYPE_AAAA) {
struct esp_ip6_addr if_ip6; if (answer->host == &_mdns_self_host) {
if (!_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].pcb && _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].state != PCB_DUP) { struct esp_ip6_addr if_ip6;
return 0; if (!_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].pcb && _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].state != PCB_DUP) {
} return 0;
if (esp_netif_get_ip6_linklocal(_mdns_get_esp_netif(tcpip_if), &if_ip6)) { }
return 0; if (esp_netif_get_ip6_linklocal(_mdns_get_esp_netif(tcpip_if), &if_ip6)) {
} return 0;
if (_ipv6_address_is_zero(if_ip6)) { }
return 0; if (_ipv6_address_is_zero(if_ip6)) {
} return 0;
if (_mdns_append_aaaa_record(packet, index, (uint8_t*)if_ip6.addr, answer->flush, answer->bye) <= 0) { }
return 0; if (_mdns_append_aaaa_record(packet, index, _mdns_server->hostname, (uint8_t*)if_ip6.addr, answer->flush, answer->bye) <= 0) {
} return 0;
if (!_mdns_if_is_dup(tcpip_if)) { }
if (!_mdns_if_is_dup(tcpip_if)) {
return 1;
}
mdns_if_t other_if = _mdns_get_other_if (tcpip_if);
if (esp_netif_get_ip6_linklocal(_mdns_get_esp_netif(other_if), &if_ip6)) {
return 1;
}
if (_mdns_append_aaaa_record(packet, index, _mdns_server->hostname, (uint8_t*)if_ip6.addr, answer->flush, answer->bye) > 0) {
return 2;
}
return 1; return 1;
} else if (answer->host != NULL) {
if (_mdns_append_aaaa_record(packet, index, answer->host->hostname, (uint8_t*)answer->host->address.u_addr.ip6.addr, answer->flush, answer->bye) <= 0) {
return 0;
} else {
return 1;
}
} }
mdns_if_t other_if = _mdns_get_other_if (tcpip_if);
if (esp_netif_get_ip6_linklocal(_mdns_get_esp_netif(other_if), &if_ip6)) {
return 1;
}
if (_mdns_append_aaaa_record(packet, index, (uint8_t*)if_ip6.addr, answer->flush, answer->bye) > 0) {
return 2;
}
return 1;
} }
#endif #endif
return 0; return 0;
@ -1232,11 +1278,11 @@ static void _mdns_dealloc_answer(mdns_out_answer_t ** destination, uint16_t type
/** /**
* @brief Allocate new answer and add it to answer list (destination) * @brief Allocate new answer and add it to answer list (destination)
*/ */
static bool _mdns_alloc_answer(mdns_out_answer_t ** destination, uint16_t type, mdns_service_t * service, bool flush, bool bye) static bool _mdns_alloc_answer(mdns_out_answer_t ** destination, uint16_t type, mdns_service_t * service, mdns_host_item_t *host, bool flush, bool bye)
{ {
mdns_out_answer_t * d = *destination; mdns_out_answer_t * d = *destination;
while (d) { while (d) {
if (d->type == type && d->service == service) { if (d->type == type && d->service == service && d->host == host) {
return true; return true;
} }
d = d->next; d = d->next;
@ -1249,6 +1295,7 @@ static bool _mdns_alloc_answer(mdns_out_answer_t ** destination, uint16_t type,
} }
a->type = type; a->type = type;
a->service = service; a->service = service;
a->host = host;
a->custom_service = NULL; a->custom_service = NULL;
a->bye = bye; a->bye = bye;
a->flush = flush; a->flush = flush;
@ -1283,10 +1330,58 @@ static mdns_tx_packet_t * _mdns_alloc_packet_default(mdns_if_t tcpip_if, mdns_ip
return packet; return packet;
} }
static bool _mdns_create_answer_from_service(mdns_tx_packet_t *packet, mdns_service_t *service,
mdns_parsed_question_t *question, bool shared, bool send_flush)
{
mdns_host_item_t *host4 = mdns_get_host_item(service->hostname, ESP_IPADDR_TYPE_V4);
mdns_host_item_t *host6 = mdns_get_host_item(service->hostname, ESP_IPADDR_TYPE_V6);
if (question->type == MDNS_TYPE_PTR || question->type == MDNS_TYPE_ANY) {
if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, service, NULL, false, false) ||
!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SRV, service, NULL, send_flush, false) ||
!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_TXT, service, NULL, send_flush, false) ||
!_mdns_alloc_answer(shared ? &packet->additional : &packet->answers, MDNS_TYPE_A, service, host4,
send_flush, false) ||
!_mdns_alloc_answer(shared ? &packet->additional : &packet->answers, MDNS_TYPE_AAAA, service, host6,
send_flush, false)) {
return false;
}
} else if (question->type == MDNS_TYPE_SRV) {
if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SRV, service, NULL, send_flush, false) ||
!_mdns_alloc_answer(&packet->additional, MDNS_TYPE_A, service, host4, send_flush, false) ||
!_mdns_alloc_answer(&packet->additional, MDNS_TYPE_AAAA, service, host6, send_flush, false)) {
return false;
}
} else if (question->type == MDNS_TYPE_TXT) {
if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_TXT, service, NULL, send_flush, false)) {
return false;
}
} else if (question->type == MDNS_TYPE_SDPTR) {
shared = true;
if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SDPTR, service, NULL, false, false)) {
return false;
}
}
return true;
}
static bool _mdns_create_answer_from_hostname(mdns_tx_packet_t *packet, const char *hostname, bool send_flush)
{
mdns_host_item_t *host4;
mdns_host_item_t *host6;
host4 = mdns_get_host_item(hostname, ESP_IPADDR_TYPE_V4);
host6 = mdns_get_host_item(hostname, ESP_IPADDR_TYPE_V6);
if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_A, NULL, host4, send_flush, false) ||
!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_AAAA, NULL, host6, send_flush, false)) {
return false;
}
return true;
}
/** /**
* @brief Create answer packet to questions from parsed packet * @brief Create answer packet to questions from parsed packet
* XXX: reply from here
*/ */
static void _mdns_create_answer_from_parsed_packet(mdns_parsed_packet_t * parsed_packet) static void _mdns_create_answer_from_parsed_packet(mdns_parsed_packet_t *parsed_packet)
{ {
if (!parsed_packet->questions) { if (!parsed_packet->questions) {
return; return;
@ -1294,7 +1389,7 @@ static void _mdns_create_answer_from_parsed_packet(mdns_parsed_packet_t * parsed
bool send_flush = parsed_packet->src_port == MDNS_SERVICE_PORT; bool send_flush = parsed_packet->src_port == MDNS_SERVICE_PORT;
bool unicast = false; bool unicast = false;
bool shared = false; bool shared = false;
mdns_tx_packet_t * packet = _mdns_alloc_packet_default(parsed_packet->tcpip_if, parsed_packet->ip_protocol); mdns_tx_packet_t *packet = _mdns_alloc_packet_default(parsed_packet->tcpip_if, parsed_packet->ip_protocol);
if (!packet) { if (!packet) {
return; return;
} }
@ -1302,82 +1397,60 @@ static void _mdns_create_answer_from_parsed_packet(mdns_parsed_packet_t * parsed
packet->distributed = parsed_packet->distributed; packet->distributed = parsed_packet->distributed;
packet->id = parsed_packet->id; packet->id = parsed_packet->id;
mdns_parsed_question_t * q = parsed_packet->questions; mdns_parsed_question_t *q = parsed_packet->questions;
while (q) { while (q) {
mdns_srv_item_t * service = NULL; shared = q->type == MDNS_TYPE_PTR || q->type == MDNS_TYPE_SDPTR || !parsed_packet->probe;
if (q->service && q->proto) { if (q->service && q->proto) {
service = _mdns_get_service_item(q->service, q->proto); mdns_srv_item_t *service = _mdns_server->services;
if (!service) { while (service) {
continue; if (_mdns_service_match(service->service, q->service, q->proto, q->host)) {
if (!_mdns_create_answer_from_service(packet, service->service, q, shared, send_flush)) {
_mdns_free_tx_packet(packet);
return;
}
}
service = service->next;
} }
} } else if (q->type == MDNS_TYPE_A || q->type == MDNS_TYPE_AAAA) {
if (q->unicast) { if (!_mdns_create_answer_from_hostname(packet, q->host, send_flush)) {
unicast = true;
}
if (service) {
if (q->type == MDNS_TYPE_PTR || q->type == MDNS_TYPE_ANY) {
if (q->type == MDNS_TYPE_PTR || !parsed_packet->probe) {
shared = true;
}
if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, service->service, false, false)
|| !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SRV, service->service, send_flush, false)
|| !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_TXT, service->service, send_flush, false)
|| !_mdns_alloc_answer(shared?&packet->additional:&packet->answers, MDNS_TYPE_A, NULL, send_flush, false)
|| !_mdns_alloc_answer(shared?&packet->additional:&packet->answers, MDNS_TYPE_AAAA, NULL, send_flush, false)) {
_mdns_free_tx_packet(packet);
return;
}
} else if (q->type == MDNS_TYPE_SRV) {
if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SRV, service->service, send_flush, false)
|| !_mdns_alloc_answer(&packet->additional, MDNS_TYPE_A, NULL, send_flush, false)
|| !_mdns_alloc_answer(&packet->additional, MDNS_TYPE_AAAA, NULL, send_flush, false)) {
_mdns_free_tx_packet(packet);
return;
}
} else if (q->type == MDNS_TYPE_TXT) {
if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_TXT, service->service, send_flush, false)) {
_mdns_free_tx_packet(packet);
return;
}
} else if (q->type == MDNS_TYPE_SDPTR) {
shared = true;
if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SDPTR, service->service, false, false)) {
_mdns_free_tx_packet(packet);
return;
}
}
} else {
if (q->type == MDNS_TYPE_ANY || q->type == MDNS_TYPE_A || q->type == MDNS_TYPE_AAAA) {
if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_A, NULL, send_flush, false)
|| !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_AAAA, NULL, send_flush, false)) {
_mdns_free_tx_packet(packet);
return;
}
#ifdef MDNS_REPEAT_QUERY_IN_RESPONSE
mdns_out_question_t * out_question = malloc(sizeof(mdns_out_question_t));
if (out_question == NULL) {
HOOK_MALLOC_FAILED;
_mdns_free_tx_packet(packet);
return;
}
out_question->type = q->type;
out_question->unicast = q->unicast;
out_question->host = q->host;
q->host = NULL;
out_question->service = q->service;
q->service = NULL;
out_question->proto = q->proto;
q->proto = NULL;
out_question->domain = q->domain;
q->domain = NULL;
out_question->next = NULL;
out_question->own_dynamic_memory = true;
queueToEnd(mdns_out_question_t, packet->questions, out_question);
#endif // MDNS_REPEAT_QUERY_IN_RESPONSE
} else if (!_mdns_alloc_answer(&packet->answers, q->type, NULL, send_flush, false)) {
_mdns_free_tx_packet(packet); _mdns_free_tx_packet(packet);
return; return;
} }
} else if (q->type == MDNS_TYPE_ANY) {
if (!_mdns_append_host_list(&packet->answers, send_flush, false)) {
_mdns_free_tx_packet(packet);
return;
}
} else if (!_mdns_alloc_answer(&packet->answers, q->type, NULL, NULL, send_flush, false)) {
_mdns_free_tx_packet(packet);
return;
}
#ifdef MDNS_REPEAT_QUERY_IN_RESPONSE
if (q->type == MDNS_TYPE_ANY || q->type == MDNS_TYPE_A || q->type == MDNS_TYPE_AAAA) {
mdns_out_question_t * out_question = malloc(sizeof(mdns_out_question_t));
if (out_question == NULL) {
HOOK_MALLOC_FAILED;
_mdns_free_tx_packet(packet);
return;
}
out_question->type = q->type;
out_question->unicast = q->unicast;
out_question->host = q->host;
q->host = NULL;
out_question->service = q->service;
q->service = NULL;
out_question->proto = q->proto;
q->proto = NULL;
out_question->domain = q->domain;
q->domain = NULL;
out_question->next = NULL;
out_question->own_dynamic_memory = true;
queueToEnd(mdns_out_question_t, packet->questions, out_question);
}
#endif // MDNS_REPEAT_QUERY_IN_RESPONSE
if (q->unicast) {
unicast = true;
} }
q = q->next; q = q->next;
} }
@ -1413,6 +1486,32 @@ static bool _mdns_question_exists(mdns_out_question_t * needle, mdns_out_questio
return false; return false;
} }
bool _mdns_append_host_list(mdns_out_answer_t ** destination, bool flush, bool bye) {
if (!_str_null_or_empty(_mdns_server->hostname)) {
mdns_host_item_t *self_host = mdns_get_host_item(_mdns_server->hostname, ESP_IPADDR_TYPE_ANY);
if (!_mdns_alloc_answer(destination, MDNS_TYPE_A, NULL, self_host, flush, bye)) {
return false;
}
if (!_mdns_alloc_answer(destination, MDNS_TYPE_AAAA, NULL, self_host, flush, bye)) {
return false;
}
}
mdns_host_item_t *host = _mdns_host_list;
while(host != NULL) {
if (host->address.type == ESP_IPADDR_TYPE_V4) {
if (!_mdns_alloc_answer(destination, MDNS_TYPE_A, NULL, host, flush, bye)) {
return false;
}
} else if (host->address.type == ESP_IPADDR_TYPE_V6) {
if (!_mdns_alloc_answer(destination, MDNS_TYPE_AAAA, NULL, host, flush, bye)) {
return false;
}
}
host = host->next;
}
return true;
}
/** /**
* @brief Create probe packet for particular services on particular PCB * @brief Create probe packet for particular services on particular PCB
*/ */
@ -1446,13 +1545,13 @@ static mdns_tx_packet_t * _mdns_create_probe_packet(mdns_if_t tcpip_if, mdns_ip_
queueToEnd(mdns_out_question_t, packet->questions, q); queueToEnd(mdns_out_question_t, packet->questions, q);
} }
if (!q->host || !_mdns_alloc_answer(&packet->servers, MDNS_TYPE_SRV, services[i]->service, false, false)) { if (!q->host || !_mdns_alloc_answer(&packet->servers, MDNS_TYPE_SRV, services[i]->service, NULL, false, false)) {
_mdns_free_tx_packet(packet); _mdns_free_tx_packet(packet);
return NULL; return NULL;
} }
} }
if (include_ip && !_str_null_or_empty(_mdns_server->hostname)) { if (include_ip) {
mdns_out_question_t * q = (mdns_out_question_t *)malloc(sizeof(mdns_out_question_t)); mdns_out_question_t * q = (mdns_out_question_t *)malloc(sizeof(mdns_out_question_t));
if (!q) { if (!q) {
HOOK_MALLOC_FAILED; HOOK_MALLOC_FAILED;
@ -1473,18 +1572,9 @@ static mdns_tx_packet_t * _mdns_create_probe_packet(mdns_if_t tcpip_if, mdns_ip_
queueToEnd(mdns_out_question_t, packet->questions, q); queueToEnd(mdns_out_question_t, packet->questions, q);
} }
if (_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].pcb) { if (!_mdns_append_host_list(&packet->servers, false, false)) {
if (!_mdns_alloc_answer(&packet->servers, MDNS_TYPE_A, NULL, false, false)) { _mdns_free_tx_packet(packet);
_mdns_free_tx_packet(packet); return NULL;
return NULL;
}
}
if (_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].pcb) {
if (!_mdns_alloc_answer(&packet->servers, MDNS_TYPE_AAAA, NULL, false, false)) {
_mdns_free_tx_packet(packet);
return NULL;
}
} }
} }
@ -1504,17 +1594,16 @@ static mdns_tx_packet_t * _mdns_create_announce_packet(mdns_if_t tcpip_if, mdns_
uint8_t i; uint8_t i;
for (i=0; i<len; i++) { for (i=0; i<len; i++) {
if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SDPTR, services[i]->service, false, false) if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SDPTR, services[i]->service, NULL, false, false)
|| !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, services[i]->service, false, false) || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, services[i]->service, NULL, false, false)
|| !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SRV, services[i]->service, true, false) || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SRV, services[i]->service, NULL, true, false)
|| !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_TXT, services[i]->service, true, false)) { || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_TXT, services[i]->service, NULL, true, false)) {
_mdns_free_tx_packet(packet); _mdns_free_tx_packet(packet);
return NULL; return NULL;
} }
} }
if (include_ip) { if (include_ip) {
if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_A, NULL, true, false) if (!_mdns_append_host_list(&packet->servers, true, false)) {
|| !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_AAAA, NULL, true, false)) {
_mdns_free_tx_packet(packet); _mdns_free_tx_packet(packet);
return NULL; return NULL;
} }
@ -1537,16 +1626,16 @@ static mdns_tx_packet_t * _mdns_create_announce_from_probe(mdns_tx_packet_t * pr
mdns_out_answer_t * s = probe->servers; mdns_out_answer_t * s = probe->servers;
while (s) { while (s) {
if (s->type == MDNS_TYPE_SRV) { if (s->type == MDNS_TYPE_SRV) {
if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SDPTR, s->service, false, false) if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SDPTR, s->service, NULL, false, false)
|| !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, s->service, false, false) || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, s->service, NULL, false, false)
|| !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SRV, s->service, true, false) || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SRV, s->service, NULL, true, false)
|| !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_TXT, s->service, true, false)) { || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_TXT, s->service, NULL, true, false)) {
_mdns_free_tx_packet(packet); _mdns_free_tx_packet(packet);
return NULL; return NULL;
} }
} else if (s->type == MDNS_TYPE_A || s->type == MDNS_TYPE_AAAA) { } else if (s->type == MDNS_TYPE_A || s->type == MDNS_TYPE_AAAA) {
if (!_mdns_alloc_answer(&packet->answers, s->type, NULL, true, false)) { if (!_mdns_alloc_answer(&packet->answers, s->type, NULL, s->host, true, false)) {
_mdns_free_tx_packet(packet); _mdns_free_tx_packet(packet);
return NULL; return NULL;
} }
@ -1569,14 +1658,13 @@ static void _mdns_pcb_send_bye(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protoco
packet->flags = MDNS_FLAGS_AUTHORITATIVE; packet->flags = MDNS_FLAGS_AUTHORITATIVE;
size_t i; size_t i;
for (i=0; i<len; i++) { for (i=0; i<len; i++) {
if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, services[i]->service, true, true)) { if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, services[i]->service, NULL, true, true)) {
_mdns_free_tx_packet(packet); _mdns_free_tx_packet(packet);
return; return;
} }
} }
if (include_ip && (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_A, NULL, true, true) || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_AAAA, NULL, true, true))) { if (include_ip) {
_mdns_free_tx_packet(packet); _mdns_append_host_list(&packet->answers, true, true);
return;
} }
_mdns_dispatch_tx_packet(packet); _mdns_dispatch_tx_packet(packet);
_mdns_free_tx_packet(packet); _mdns_free_tx_packet(packet);
@ -1732,18 +1820,17 @@ static void _mdns_announce_pcb(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protoco
mdns_tx_packet_t * p = _mdns_get_next_pcb_packet(tcpip_if, ip_protocol); mdns_tx_packet_t * p = _mdns_get_next_pcb_packet(tcpip_if, ip_protocol);
if (p) { if (p) {
for (i=0; i<len; i++) { for (i=0; i<len; i++) {
if (!_mdns_alloc_answer(&p->answers, MDNS_TYPE_SDPTR, services[i]->service, false, false) if (!_mdns_alloc_answer(&p->answers, MDNS_TYPE_SDPTR, services[i]->service, NULL, false, false)
|| !_mdns_alloc_answer(&p->answers, MDNS_TYPE_PTR, services[i]->service, false, false) || !_mdns_alloc_answer(&p->answers, MDNS_TYPE_PTR, services[i]->service, NULL, false, false)
|| !_mdns_alloc_answer(&p->answers, MDNS_TYPE_SRV, services[i]->service, true, false) || !_mdns_alloc_answer(&p->answers, MDNS_TYPE_SRV, services[i]->service, NULL, true, false)
|| !_mdns_alloc_answer(&p->answers, MDNS_TYPE_TXT, services[i]->service, true, false)) { || !_mdns_alloc_answer(&p->answers, MDNS_TYPE_TXT, services[i]->service, NULL, true, false)) {
break; break;
} }
} }
if (include_ip) { if (include_ip) {
_mdns_dealloc_answer(&p->additional, MDNS_TYPE_A, NULL); _mdns_dealloc_answer(&p->additional, MDNS_TYPE_A, NULL);
_mdns_dealloc_answer(&p->additional, MDNS_TYPE_AAAA, NULL); _mdns_dealloc_answer(&p->additional, MDNS_TYPE_AAAA, NULL);
_mdns_alloc_answer(&p->answers, MDNS_TYPE_A, NULL, true, false); _mdns_append_host_list(&p->answers, true, false);
_mdns_alloc_answer(&p->answers, MDNS_TYPE_AAAA, NULL, true, false);
} }
_pcb->state = PCB_ANNOUNCE_1; _pcb->state = PCB_ANNOUNCE_1;
} }
@ -1961,7 +2048,7 @@ static void _mdns_free_linked_txt(mdns_txt_linked_item_t *txt)
* *
* @return pointer to the service or NULL on error * @return pointer to the service or NULL on error
*/ */
static mdns_service_t * _mdns_create_service(const char * service, const char * proto, uint16_t port, const char * instance, size_t num_items, mdns_txt_item_t txt[]) static mdns_service_t * _mdns_create_service(const char * service, const char * proto, const char *hostname, uint16_t port, const char * instance, size_t num_items, mdns_txt_item_t txt[])
{ {
mdns_service_t * s = (mdns_service_t *)malloc(sizeof(mdns_service_t)); mdns_service_t * s = (mdns_service_t *)malloc(sizeof(mdns_service_t));
if (!s) { if (!s) {
@ -1981,6 +2068,17 @@ static mdns_service_t * _mdns_create_service(const char * service, const char *
s->txt = new_txt; s->txt = new_txt;
s->port = port; s->port = port;
assert(hostname != NULL);
if (hostname) {
s->hostname = strndup(hostname, MDNS_NAME_BUF_LEN - 1);
if (!s->hostname) {
free(s);
return NULL;
}
} else {
s->hostname = NULL;
}
s->service = strndup(service, MDNS_NAME_BUF_LEN - 1); s->service = strndup(service, MDNS_NAME_BUF_LEN - 1);
if (!s->service) { if (!s->service) {
free(s); free(s);
@ -2341,6 +2439,39 @@ static int _mdns_check_aaaa_collision(esp_ip6_addr_t * ip, mdns_if_t tcpip_if)
} }
#endif #endif
static bool _hostname_is_ours(const char *hostname)
{
if (strcasecmp(hostname, _mdns_server->hostname) == 0) {
return true;
}
mdns_host_item_t *host = _mdns_host_list;
while (host != NULL) {
if (strcasecmp(hostname, host->hostname) == 0) {
return true;
}
host = host->next;
}
return false;
}
static bool _mdns_delegate_hostname_add(const char *hostname, const esp_ip_addr_t *address)
{
if (_hostname_is_ours(hostname)) {
return true;
}
mdns_host_item_t *host = (mdns_host_item_t *)malloc(sizeof(mdns_host_item_t));
if (host == NULL) {
return false;
}
host->address = *address;
host->hostname = hostname;
host->next = _mdns_host_list;
_mdns_host_list = host;
return true;
}
/** /**
* @brief Check if parsed name is discovery * @brief Check if parsed name is discovery
*/ */
@ -2369,7 +2500,7 @@ static bool _mdns_name_is_ours(mdns_name_t * name)
if (_str_null_or_empty(name->service) && _str_null_or_empty(name->proto)) { if (_str_null_or_empty(name->service) && _str_null_or_empty(name->proto)) {
if (!_str_null_or_empty(name->host) if (!_str_null_or_empty(name->host)
&& !_str_null_or_empty(_mdns_server->hostname) && !_str_null_or_empty(_mdns_server->hostname)
&& strcasecmp(name->host, _mdns_server->hostname) == 0) && _hostname_is_ours(name->host) == 0)
{ {
return true; return true;
} }
@ -2382,7 +2513,7 @@ static bool _mdns_name_is_ours(mdns_name_t * name)
} }
//find the service //find the service
mdns_srv_item_t * service = _mdns_get_service_item(name->service, name->proto); mdns_srv_item_t * service = _mdns_get_service_item(name->service, name->proto, name->host);
if (!service) { if (!service) {
return false; return false;
} }
@ -2860,7 +2991,7 @@ void mdns_parse_packet(mdns_rx_packet_t * packet)
} else if (!name->sub && _mdns_name_is_ours(name)) { } else if (!name->sub && _mdns_name_is_ours(name)) {
ours = true; ours = true;
if (name->service && name->service[0] && name->proto && name->proto[0]) { if (name->service && name->service[0] && name->proto && name->proto[0]) {
service = _mdns_get_service_item(name->service, name->proto); service = _mdns_get_service_item(name->service, name->proto, name->host);
} }
} else { } else {
if (!parsed_packet->authoritative || record_type == MDNS_NS) { if (!parsed_packet->authoritative || record_type == MDNS_NS) {
@ -2878,7 +3009,7 @@ void mdns_parse_packet(mdns_rx_packet_t * packet)
_mdns_search_result_add_ptr(search_result, name->host, packet->tcpip_if, packet->ip_protocol); _mdns_search_result_add_ptr(search_result, name->host, packet->tcpip_if, packet->ip_protocol);
} else if ((discovery || ours) && !name->sub && _mdns_name_is_ours(name)) { } else if ((discovery || ours) && !name->sub && _mdns_name_is_ours(name)) {
if (discovery) { if (discovery) {
service = _mdns_get_service_item(name->service, name->proto); service = _mdns_get_service_item(name->service, name->proto, name->host);
_mdns_remove_parsed_question(parsed_packet, MDNS_TYPE_SDPTR, service); _mdns_remove_parsed_question(parsed_packet, MDNS_TYPE_SDPTR, service);
} else if (parsed_packet->questions && !parsed_packet->probe) { } else if (parsed_packet->questions && !parsed_packet->probe) {
_mdns_remove_parsed_question(parsed_packet, type, service); _mdns_remove_parsed_question(parsed_packet, type, service);
@ -3831,7 +3962,7 @@ static void _mdns_free_action(mdns_action_t * action)
{ {
switch(action->type) { switch(action->type) {
case ACTION_HOSTNAME_SET: case ACTION_HOSTNAME_SET:
free(action->data.hostname); free(action->data.hostname_set.hostname);
break; break;
case ACTION_INSTANCE_SET: case ACTION_INSTANCE_SET:
free(action->data.instance); free(action->data.instance);
@ -3892,9 +4023,10 @@ static void _mdns_execute_action(mdns_action_t * action)
case ACTION_HOSTNAME_SET: case ACTION_HOSTNAME_SET:
_mdns_send_bye_all_pcbs_no_instance(true); _mdns_send_bye_all_pcbs_no_instance(true);
free((char*)_mdns_server->hostname); free((char*)_mdns_server->hostname);
_mdns_server->hostname = action->data.hostname; _mdns_server->hostname = action->data.hostname_set.hostname;
_mdns_self_host.hostname = action->data.hostname_set.hostname;
_mdns_restart_all_pcbs(); _mdns_restart_all_pcbs();
xTaskNotifyGive(action->data.hostname_set.calling_task);
break; break;
case ACTION_INSTANCE_SET: case ACTION_INSTANCE_SET:
_mdns_send_bye_all_pcbs_no_instance(false); _mdns_send_bye_all_pcbs_no_instance(false);
@ -3907,7 +4039,6 @@ static void _mdns_execute_action(mdns_action_t * action)
action->data.srv_add.service->next = _mdns_server->services; action->data.srv_add.service->next = _mdns_server->services;
_mdns_server->services = action->data.srv_add.service; _mdns_server->services = action->data.srv_add.service;
_mdns_probe_all_pcbs(&action->data.srv_add.service, 1, false, false); _mdns_probe_all_pcbs(&action->data.srv_add.service, 1, false, false);
break; break;
case ACTION_SERVICE_INSTANCE_SET: case ACTION_SERVICE_INSTANCE_SET:
if (action->data.srv_instance.service->service->instance) { if (action->data.srv_instance.service->service->instance) {
@ -4058,6 +4189,8 @@ static void _mdns_execute_action(mdns_action_t * action)
pbuf_free(action->data.rx_handle.packet->pb); pbuf_free(action->data.rx_handle.packet->pb);
free(action->data.rx_handle.packet); free(action->data.rx_handle.packet);
break; break;
case ACTION_DELEGATE_HOSTNAME_ADD:
_mdns_delegate_hostname_add(action->data.delegate_hostname.hostname, &action->data.delegate_hostname.address);
default: default:
break; break;
} }
@ -4461,7 +4594,40 @@ esp_err_t mdns_hostname_set(const char * hostname)
return ESP_ERR_NO_MEM; return ESP_ERR_NO_MEM;
} }
action->type = ACTION_HOSTNAME_SET; action->type = ACTION_HOSTNAME_SET;
action->data.hostname = new_hostname; action->data.hostname_set.hostname = new_hostname;
action->data.hostname_set.calling_task = xTaskGetCurrentTaskHandle();
if (xQueueSend(_mdns_server->action_queue, &action, (portTickType)0) != pdPASS) {
assert(false);
free(new_hostname);
free(action);
return ESP_ERR_NO_MEM;
}
xTaskNotifyWait(0, 0, NULL, portMAX_DELAY);
return ERR_OK;
}
esp_err_t mdns_delegate_hostname_add(const char * hostname, const esp_ip_addr_t *address)
{
if (!_mdns_server) {
return ESP_ERR_INVALID_ARG;
}
if (_str_null_or_empty(hostname) || strlen(hostname) > (MDNS_NAME_BUF_LEN - 1)) {
return ESP_ERR_INVALID_ARG;
}
char * new_hostname = strndup(hostname, MDNS_NAME_BUF_LEN - 1);
if (!new_hostname) {
return ESP_ERR_NO_MEM;
}
mdns_action_t * action = (mdns_action_t *)malloc(sizeof(mdns_action_t));
if (!action) {
HOOK_MALLOC_FAILED;
free(new_hostname);
return ESP_ERR_NO_MEM;
}
action->type = ACTION_DELEGATE_HOSTNAME_ADD;
action->data.delegate_hostname.hostname = new_hostname;
action->data.delegate_hostname.address = *address;
if (xQueueSend(_mdns_server->action_queue, &action, (portTickType)0) != pdPASS) { if (xQueueSend(_mdns_server->action_queue, &action, (portTickType)0) != pdPASS) {
free(new_hostname); free(new_hostname);
free(action); free(action);
@ -4470,6 +4636,10 @@ esp_err_t mdns_hostname_set(const char * hostname)
return ERR_OK; return ERR_OK;
} }
bool mdns_hostname_exists(const char *hostname) {
return _hostname_is_ours(hostname);
}
esp_err_t mdns_instance_name_set(const char * instance) esp_err_t mdns_instance_name_set(const char * instance)
{ {
if (!_mdns_server) { if (!_mdns_server) {
@ -4503,7 +4673,9 @@ esp_err_t mdns_instance_name_set(const char * instance)
* MDNS SERVICES * MDNS SERVICES
* */ * */
esp_err_t mdns_service_add(const char * instance, const char * service, const char * proto, uint16_t port, mdns_txt_item_t txt[], size_t num_items) esp_err_t mdns_service_add_custom_host(const char *instance, const char *service, const char *proto,
const char *hostname, uint16_t port,
mdns_txt_item_t txt[], size_t num_items)
{ {
if (!_mdns_server || _str_null_or_empty(service) || _str_null_or_empty(proto) || !port) { if (!_mdns_server || _str_null_or_empty(service) || _str_null_or_empty(proto) || !port) {
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
@ -4513,12 +4685,12 @@ esp_err_t mdns_service_add(const char * instance, const char * service, const ch
return ESP_ERR_NO_MEM; return ESP_ERR_NO_MEM;
} }
mdns_srv_item_t * item = _mdns_get_service_item(service, proto); mdns_srv_item_t * item = _mdns_get_service_item(service, proto, hostname);
if (item) { if (item) {
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
mdns_service_t * s = _mdns_create_service(service, proto, port, instance, num_items, txt); mdns_service_t * s = _mdns_create_service(service, proto, hostname, port, instance, num_items, txt);
if (!s) { if (!s) {
return ESP_ERR_NO_MEM; return ESP_ERR_NO_MEM;
} }
@ -4551,7 +4723,7 @@ esp_err_t mdns_service_add(const char * instance, const char * service, const ch
size_t start = xTaskGetTickCount(); size_t start = xTaskGetTickCount();
size_t timeout_ticks = pdMS_TO_TICKS(MDNS_SERVICE_ADD_TIMEOUT_MS); size_t timeout_ticks = pdMS_TO_TICKS(MDNS_SERVICE_ADD_TIMEOUT_MS);
while (_mdns_get_service_item(service, proto) == NULL) while (_mdns_get_service_item(service, proto, hostname) == NULL)
{ {
uint32_t expired = xTaskGetTickCount() - start; uint32_t expired = xTaskGetTickCount() - start;
if (expired >= timeout_ticks) { if (expired >= timeout_ticks) {
@ -4563,12 +4735,24 @@ esp_err_t mdns_service_add(const char * instance, const char * service, const ch
return ESP_OK; return ESP_OK;
} }
esp_err_t mdns_service_port_set(const char * service, const char * proto, uint16_t port) esp_err_t mdns_service_add(const char *instance, const char *service, const char *proto, uint16_t port,
mdns_txt_item_t txt[], size_t num_items)
{
assert(_mdns_server->hostname != NULL);
return mdns_service_add_custom_host(instance, service, proto, _mdns_server->hostname, port, txt, num_items);
}
bool mdns_service_exists(const char *service_type, const char *proto, const char *hostname)
{
return _mdns_get_service_item(service_type, proto, hostname) != NULL;
}
esp_err_t mdns_service_port_set_for_host(const char *service, const char *proto, const char *hostname, uint16_t port)
{ {
if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto) || !port) { if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto) || !port) {
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
mdns_srv_item_t * s = _mdns_get_service_item(service, proto); mdns_srv_item_t * s = _mdns_get_service_item(service, proto, hostname);
if (!s) { if (!s) {
return ESP_ERR_NOT_FOUND; return ESP_ERR_NOT_FOUND;
} }
@ -4588,12 +4772,17 @@ esp_err_t mdns_service_port_set(const char * service, const char * proto, uint16
return ESP_OK; return ESP_OK;
} }
esp_err_t mdns_service_txt_set(const char * service, const char * proto, mdns_txt_item_t txt[], uint8_t num_items) esp_err_t mdns_service_port_set(const char *service, const char *proto, uint16_t port) {
return mdns_service_port_set_for_host(service, proto, _mdns_server->hostname, port);
}
esp_err_t mdns_service_txt_set_for_host(const char *service, const char *proto, const char *hostname,
mdns_txt_item_t txt[], uint8_t num_items)
{ {
if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto) || (num_items && txt == NULL)) { if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto) || (num_items && txt == NULL)) {
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
mdns_srv_item_t * s = _mdns_get_service_item(service, proto); mdns_srv_item_t * s = _mdns_get_service_item(service, proto, hostname);
if (!s) { if (!s) {
return ESP_ERR_NOT_FOUND; return ESP_ERR_NOT_FOUND;
} }
@ -4624,13 +4813,17 @@ esp_err_t mdns_service_txt_set(const char * service, const char * proto, mdns_tx
return ESP_OK; return ESP_OK;
} }
esp_err_t mdns_service_txt_set(const char *service, const char *proto, mdns_txt_item_t txt[], uint8_t num_items)
{
return mdns_service_txt_set_for_host(service, proto, _mdns_server->hostname, txt, num_items);
}
esp_err_t mdns_service_txt_item_set(const char * service, const char * proto, const char * key, const char * value) esp_err_t mdns_service_txt_item_set_for_host(const char * service, const char * proto, const char *hostname, const char * key, const char * value)
{ {
if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto) || _str_null_or_empty(key) || !value) { if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto) || _str_null_or_empty(key) || !value) {
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
mdns_srv_item_t * s = _mdns_get_service_item(service, proto); mdns_srv_item_t * s = _mdns_get_service_item(service, proto, hostname);
if (!s) { if (!s) {
return ESP_ERR_NOT_FOUND; return ESP_ERR_NOT_FOUND;
} }
@ -4662,12 +4855,17 @@ esp_err_t mdns_service_txt_item_set(const char * service, const char * proto, co
return ESP_OK; return ESP_OK;
} }
esp_err_t mdns_service_txt_item_remove(const char * service, const char * proto, const char * key) esp_err_t mdns_service_txt_item_set(const char *service, const char *proto, const char *key, const char *value)
{
return mdns_service_txt_item_set_for_host(service, proto, _mdns_server->hostname, key, value);
}
esp_err_t mdns_service_txt_item_remove_for_host(const char * service, const char * proto, const char *hostname, const char * key)
{ {
if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto) || _str_null_or_empty(key)) { if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto) || _str_null_or_empty(key)) {
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
mdns_srv_item_t * s = _mdns_get_service_item(service, proto); mdns_srv_item_t * s = _mdns_get_service_item(service, proto, hostname);
if (!s) { if (!s) {
return ESP_ERR_NOT_FOUND; return ESP_ERR_NOT_FOUND;
} }
@ -4692,7 +4890,13 @@ esp_err_t mdns_service_txt_item_remove(const char * service, const char * proto,
return ESP_OK; return ESP_OK;
} }
esp_err_t mdns_service_instance_name_set(const char * service, const char * proto, const char * instance) esp_err_t mdns_service_txt_item_remove(const char *service, const char *proto, const char *key)
{
return mdns_service_txt_item_remove_for_host(service, proto, _mdns_server->hostname, key);
}
esp_err_t mdns_service_instance_name_set_for_host(const char *service, const char *proto, const char *hostname,
const char *instance)
{ {
if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto)) { if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto)) {
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
@ -4700,7 +4904,7 @@ esp_err_t mdns_service_instance_name_set(const char * service, const char * prot
if (_str_null_or_empty(instance) || strlen(instance) > (MDNS_NAME_BUF_LEN - 1)) { if (_str_null_or_empty(instance) || strlen(instance) > (MDNS_NAME_BUF_LEN - 1)) {
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
mdns_srv_item_t * s = _mdns_get_service_item(service, proto); mdns_srv_item_t * s = _mdns_get_service_item(service, proto, hostname);
if (!s) { if (!s) {
return ESP_ERR_NOT_FOUND; return ESP_ERR_NOT_FOUND;
} }
@ -4726,12 +4930,17 @@ esp_err_t mdns_service_instance_name_set(const char * service, const char * prot
return ESP_OK; return ESP_OK;
} }
esp_err_t mdns_service_remove(const char * service, const char * proto) esp_err_t mdns_service_instance_name_set(const char *service, const char *proto, const char *instance)
{
return mdns_service_instance_name_set_for_host(service, proto, _mdns_server->hostname, instance);
}
esp_err_t mdns_service_remove_for_host(const char * service, const char * proto, const char *hostname)
{ {
if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto)) { if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto)) {
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
mdns_srv_item_t * s = _mdns_get_service_item(service, proto); mdns_srv_item_t * s = _mdns_get_service_item(service, proto, hostname);
if (!s) { if (!s) {
return ESP_ERR_NOT_FOUND; return ESP_ERR_NOT_FOUND;
} }
@ -4750,6 +4959,11 @@ esp_err_t mdns_service_remove(const char * service, const char * proto)
return ESP_OK; return ESP_OK;
} }
esp_err_t mdns_service_remove(const char *service_type, const char *proto)
{
return mdns_service_remove_for_host(service_type, proto, _mdns_server->hostname);
}
esp_err_t mdns_service_remove_all(void) esp_err_t mdns_service_remove_all(void)
{ {
if (!_mdns_server) { if (!_mdns_server) {

View File

@ -17,8 +17,10 @@
#include "esp_event_base.h" #include "esp_event_base.h"
#include "esp_task.h" #include "esp_task.h"
#include "esp_timer.h" #include "esp_timer.h"
#include "esp_netif_ip_addr.h"
#include "freertos/FreeRTOS.h"
//#define MDNS_ENABLE_DEBUG #define MDNS_ENABLE_DEBUG
#ifdef MDNS_ENABLE_DEBUG #ifdef MDNS_ENABLE_DEBUG
#define _mdns_dbg_printf(...) printf(__VA_ARGS__) #define _mdns_dbg_printf(...) printf(__VA_ARGS__)
@ -182,6 +184,7 @@ typedef enum {
ACTION_TX_HANDLE, ACTION_TX_HANDLE,
ACTION_RX_HANDLE, ACTION_RX_HANDLE,
ACTION_TASK_STOP, ACTION_TASK_STOP,
ACTION_DELEGATE_HOSTNAME_ADD,
ACTION_MAX ACTION_MAX
} mdns_action_type_t; } mdns_action_type_t;
@ -280,6 +283,7 @@ typedef struct {
const char * instance; const char * instance;
const char * service; const char * service;
const char * proto; const char * proto;
const char * hostname;
uint16_t priority; uint16_t priority;
uint16_t weight; uint16_t weight;
uint16_t port; uint16_t port;
@ -302,12 +306,19 @@ typedef struct mdns_out_question_s {
bool own_dynamic_memory; bool own_dynamic_memory;
} mdns_out_question_t; } mdns_out_question_t;
typedef struct mdns_host_item_t {
const char * hostname;
esp_ip_addr_t address;
struct mdns_host_item_t *next;
} mdns_host_item_t;
typedef struct mdns_out_answer_s { typedef struct mdns_out_answer_s {
struct mdns_out_answer_s * next; struct mdns_out_answer_s * next;
uint16_t type; uint16_t type;
uint8_t bye; uint8_t bye;
uint8_t flush; uint8_t flush;
mdns_service_t * service; mdns_service_t * service;
mdns_host_item_t* host;
const char * custom_instance; const char * custom_instance;
const char * custom_service; const char * custom_service;
const char * custom_proto; const char * custom_proto;
@ -381,7 +392,10 @@ typedef struct mdns_server_s {
typedef struct { typedef struct {
mdns_action_type_t type; mdns_action_type_t type;
union { union {
char * hostname; struct {
char * hostname;
xTaskHandle calling_task;
} hostname_set;
char * instance; char * instance;
struct { struct {
esp_event_base_t event_base; esp_event_base_t event_base;
@ -424,6 +438,10 @@ typedef struct {
struct { struct {
mdns_rx_packet_t * packet; mdns_rx_packet_t * packet;
} rx_handle; } rx_handle;
struct {
const char * hostname;
esp_ip_addr_t address;
} delegate_hostname;
} data; } data;
} mdns_action_t; } mdns_action_t;

View File

@ -24,34 +24,47 @@
#define EXAMPLE_BUTTON_GPIO 0 #define EXAMPLE_BUTTON_GPIO 0
static const char *TAG = "mdns-test"; static const char *TAG = "mdns-test";
static char* generate_hostname(void); static char *generate_hostname(void);
#if CONFIG_MDNS_RESOLVE_TEST_SERVICES == 1 #if CONFIG_MDNS_RESOLVE_TEST_SERVICES == 1
static void query_mdns_host_with_gethostbyname(char * host); static void query_mdns_host_with_gethostbyname(char *host);
static void query_mdns_host_with_getaddrinfo(char * host); static void query_mdns_host_with_getaddrinfo(char *host);
#endif #endif
static void initialise_mdns(void) static void initialise_mdns(void)
{ {
char* hostname = generate_hostname(); printf("generate_hostname\n");
char *hostname = generate_hostname();
//initialize mDNS //initialize mDNS
printf("mdns_init\n");
ESP_ERROR_CHECK( mdns_init() ); ESP_ERROR_CHECK( mdns_init() );
printf("mdns_hostname_set\n");
//set mDNS hostname (required if you want to advertise services) //set mDNS hostname (required if you want to advertise services)
ESP_ERROR_CHECK( mdns_hostname_set(hostname) ); ESP_ERROR_CHECK( mdns_hostname_set(hostname) );
ESP_LOGI(TAG, "mdns hostname set to: [%s]", hostname); ESP_LOGI(TAG, "mdns hostname set to: [%s]", hostname);
//set default mDNS instance name //set default mDNS instance name
printf("mdns_instance_name_set\n");
ESP_ERROR_CHECK( mdns_instance_name_set(EXAMPLE_MDNS_INSTANCE) ); ESP_ERROR_CHECK( mdns_instance_name_set(EXAMPLE_MDNS_INSTANCE) );
//structure with TXT records //structure with TXT records
mdns_txt_item_t serviceTxtData[3] = { mdns_txt_item_t serviceTxtData[3] = {
{"board","esp32"}, {"board", "esp32"},
{"u","user"}, {"u", "user"},
{"p","password"} {"p", "password"}
}; };
//initialize service //initialize service
printf("mdns_service_add\n");
ESP_ERROR_CHECK( mdns_service_add("ESP32-WebServer", "_http", "_tcp", 80, serviceTxtData, 3) ); ESP_ERROR_CHECK( mdns_service_add("ESP32-WebServer", "_http", "_tcp", 80, serviceTxtData, 3) );
esp_ip_addr_t addr;
ip6_addr_t ip6_addr;
ip6addr_aton("fe80::849b:bb01:415c:b722", &ip6_addr);
addr.type = ESP_IPADDR_TYPE_V6;
memcpy(addr.u_addr.ip6.addr, ip6_addr.addr, sizeof(ip6_addr.addr));
ESP_ERROR_CHECK(mdns_delegate_hostname_add("test-device", &addr));
ESP_ERROR_CHECK( mdns_service_add_custom_host("test0", "_http", "_tcp", "test-device", 1234, serviceTxtData, 3) );
//add another TXT item //add another TXT item
printf("mdns_service_txt_item_set\n");
ESP_ERROR_CHECK( mdns_service_txt_item_set("_http", "_tcp", "path", "/foobar") ); ESP_ERROR_CHECK( mdns_service_txt_item_set("_http", "_tcp", "path", "/foobar") );
//change TXT item value //change TXT item value
ESP_ERROR_CHECK( mdns_service_txt_item_set("_http", "_tcp", "u", "admin") ); ESP_ERROR_CHECK( mdns_service_txt_item_set("_http", "_tcp", "u", "admin") );
@ -59,33 +72,34 @@ static void initialise_mdns(void)
} }
/* these strings match tcpip_adapter_if_t enumeration */ /* these strings match tcpip_adapter_if_t enumeration */
static const char * if_str[] = {"STA", "AP", "ETH", "MAX"}; static const char *if_str[] = {"STA", "AP", "ETH", "MAX"};
/* these strings match mdns_ip_protocol_t enumeration */ /* these strings match mdns_ip_protocol_t enumeration */
static const char * ip_protocol_str[] = {"V4", "V6", "MAX"}; static const char *ip_protocol_str[] = {"V4", "V6", "MAX"};
static void mdns_print_results(mdns_result_t * results){ static void mdns_print_results(mdns_result_t *results)
mdns_result_t * r = results; {
mdns_ip_addr_t * a = NULL; mdns_result_t *r = results;
mdns_ip_addr_t *a = NULL;
int i = 1, t; int i = 1, t;
while(r){ while (r) {
printf("%d: Interface: %s, Type: %s\n", i++, if_str[r->tcpip_if], ip_protocol_str[r->ip_protocol]); printf("%d: Interface: %s, Type: %s\n", i++, if_str[r->tcpip_if], ip_protocol_str[r->ip_protocol]);
if(r->instance_name){ if (r->instance_name) {
printf(" PTR : %s\n", r->instance_name); printf(" PTR : %s\n", r->instance_name);
} }
if(r->hostname){ if (r->hostname) {
printf(" SRV : %s.local:%u\n", r->hostname, r->port); printf(" SRV : %s.local:%u\n", r->hostname, r->port);
} }
if(r->txt_count){ if (r->txt_count) {
printf(" TXT : [%u] ", r->txt_count); printf(" TXT : [%u] ", r->txt_count);
for(t=0; t<r->txt_count; t++){ for (t = 0; t < r->txt_count; t++) {
printf("%s=%s; ", r->txt[t].key, r->txt[t].value?r->txt[t].value:"NULL"); printf("%s=%s; ", r->txt[t].key, r->txt[t].value ? r->txt[t].value : "NULL");
} }
printf("\n"); printf("\n");
} }
a = r->addr; a = r->addr;
while(a){ while (a) {
if(a->addr.type == ESP_IPADDR_TYPE_V6){ if (a->addr.type == ESP_IPADDR_TYPE_V6) {
printf(" AAAA: " IPV6STR "\n", IPV62STR(a->addr.u_addr.ip6)); printf(" AAAA: " IPV6STR "\n", IPV62STR(a->addr.u_addr.ip6));
} else { } else {
printf(" A : " IPSTR "\n", IP2STR(&(a->addr.u_addr.ip4))); printf(" A : " IPSTR "\n", IP2STR(&(a->addr.u_addr.ip4)));
@ -97,17 +111,17 @@ static void mdns_print_results(mdns_result_t * results){
} }
static void query_mdns_service(const char * service_name, const char * proto) static void query_mdns_service(const char *service_name, const char *proto)
{ {
ESP_LOGI(TAG, "Query PTR: %s.%s.local", service_name, proto); ESP_LOGI(TAG, "Query PTR: %s.%s.local", service_name, proto);
mdns_result_t * results = NULL; mdns_result_t *results = NULL;
esp_err_t err = mdns_query_ptr(service_name, proto, 3000, 20, &results); esp_err_t err = mdns_query_ptr(service_name, proto, 3000, 20, &results);
if(err){ if (err) {
ESP_LOGE(TAG, "Query Failed: %s", esp_err_to_name(err)); ESP_LOGE(TAG, "Query Failed: %s", esp_err_to_name(err));
return; return;
} }
if(!results){ if (!results) {
ESP_LOGW(TAG, "No results found!"); ESP_LOGW(TAG, "No results found!");
return; return;
} }
@ -116,7 +130,7 @@ static void query_mdns_service(const char * service_name, const char * proto)
mdns_query_results_free(results); mdns_query_results_free(results);
} }
static void query_mdns_host(const char * host_name) static void query_mdns_host(const char *host_name)
{ {
ESP_LOGI(TAG, "Query A: %s.local", host_name); ESP_LOGI(TAG, "Query A: %s.local", host_name);
@ -124,8 +138,8 @@ static void query_mdns_host(const char * host_name)
addr.addr = 0; addr.addr = 0;
esp_err_t err = mdns_query_a(host_name, 2000, &addr); esp_err_t err = mdns_query_a(host_name, 2000, &addr);
if(err){ if (err) {
if(err == ESP_ERR_NOT_FOUND){ if (err == ESP_ERR_NOT_FOUND) {
ESP_LOGW(TAG, "%s: Host was not found!", esp_err_to_name(err)); ESP_LOGW(TAG, "%s: Host was not found!", esp_err_to_name(err));
return; return;
} }
@ -174,7 +188,7 @@ static void mdns_example_task(void *pvParameters)
query_mdns_host_with_getaddrinfo("tinytester-lwip.local"); query_mdns_host_with_getaddrinfo("tinytester-lwip.local");
#endif #endif
while(1) { while (1) {
check_button(); check_button();
vTaskDelay(50 / portTICK_PERIOD_MS); vTaskDelay(50 / portTICK_PERIOD_MS);
} }
@ -201,7 +215,7 @@ void app_main(void)
/** Generate host name based on sdkconfig, optionally adding a portion of MAC address to it. /** Generate host name based on sdkconfig, optionally adding a portion of MAC address to it.
* @return host name string allocated from the heap * @return host name string allocated from the heap
*/ */
static char* generate_hostname(void) static char *generate_hostname(void)
{ {
#ifndef CONFIG_MDNS_ADD_MAC_TO_HOSTNAME #ifndef CONFIG_MDNS_ADD_MAC_TO_HOSTNAME
return strdup(CONFIG_MDNS_HOSTNAME); return strdup(CONFIG_MDNS_HOSTNAME);
@ -221,7 +235,7 @@ static char* generate_hostname(void)
* @brief Executes gethostbyname and displays list of resolved addresses. * @brief Executes gethostbyname and displays list of resolved addresses.
* Note: This function is used only to test advertised mdns hostnames resolution * Note: This function is used only to test advertised mdns hostnames resolution
*/ */
static void query_mdns_host_with_gethostbyname(char * host) static void query_mdns_host_with_gethostbyname(char *host)
{ {
struct hostent *res = gethostbyname(host); struct hostent *res = gethostbyname(host);
if (res) { if (res) {
@ -237,10 +251,10 @@ static void query_mdns_host_with_gethostbyname(char * host)
* @brief Executes getaddrinfo and displays list of resolved addresses. * @brief Executes getaddrinfo and displays list of resolved addresses.
* Note: This function is used only to test advertised mdns hostnames resolution * Note: This function is used only to test advertised mdns hostnames resolution
*/ */
static void query_mdns_host_with_getaddrinfo(char * host) static void query_mdns_host_with_getaddrinfo(char *host)
{ {
struct addrinfo hints; struct addrinfo hints;
struct addrinfo * res; struct addrinfo *res;
memset(&hints, 0, sizeof(hints)); memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
@ -249,8 +263,8 @@ static void query_mdns_host_with_getaddrinfo(char * host)
if (!getaddrinfo(host, NULL, &hints, &res)) { if (!getaddrinfo(host, NULL, &hints, &res)) {
while (res) { while (res) {
ESP_LOGI(TAG, "getaddrinfo: %s resolved to: %s", host, ESP_LOGI(TAG, "getaddrinfo: %s resolved to: %s", host,
res->ai_family == AF_INET? res->ai_family == AF_INET ?
inet_ntoa(((struct sockaddr_in *) res->ai_addr)->sin_addr): inet_ntoa(((struct sockaddr_in *) res->ai_addr)->sin_addr) :
inet_ntoa(((struct sockaddr_in6 *) res->ai_addr)->sin6_addr)); inet_ntoa(((struct sockaddr_in6 *) res->ai_addr)->sin6_addr));
res = res->ai_next; res = res->ai_next;
} }