mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/mdns-subtype' into 'master'
mdns: support service subtype Closes IDFGH-3560 See merge request espressif/esp-idf!15467
This commit is contained in:
commit
a928411ab3
@ -1,16 +1,8 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef ESP_MDNS_H_
|
||||
#define ESP_MDNS_H_
|
||||
|
||||
@ -500,6 +492,24 @@ esp_err_t mdns_service_txt_item_remove(const char * service_type, const char * p
|
||||
esp_err_t mdns_service_txt_item_remove_for_host(const char * service_type, const char * proto, const char * hostname,
|
||||
const char * key);
|
||||
|
||||
/**
|
||||
* @brief Add subtype for service.
|
||||
*
|
||||
* @param instance_name instance name. If NULL, will find the first service with the same service type and protocol.
|
||||
* @param service_type service type (_http, _ftp, etc)
|
||||
* @param proto service protocol (_tcp, _udp)
|
||||
* @param hostname service hostname. If NULL, local hostname will be used.
|
||||
* @param subtype The subtype to add.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_ERR_NOT_FOUND Service not found
|
||||
* - ESP_ERR_NO_MEM memory error
|
||||
*/
|
||||
esp_err_t mdns_service_subtype_add_for_host(const char *instance_name, const char *service_type, const char *proto,
|
||||
const char *hostname, const char *subtype);
|
||||
|
||||
/**
|
||||
* @brief Remove and free all services from mDNS server
|
||||
*
|
||||
|
@ -15,6 +15,10 @@
|
||||
void mdns_debug_packet(const uint8_t * data, size_t len);
|
||||
#endif
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
|
||||
#endif
|
||||
|
||||
// Internal size of IPv6 address is defined here as size of AAAA record in mdns packet
|
||||
// since the ip6_addr_t is defined in lwip and depends on using IPv6 zones
|
||||
#define _MDNS_SIZEOF_IP6_ADDR (MDNS_ANSWER_AAAA_SIZE)
|
||||
@ -174,6 +178,24 @@ static mdns_srv_item_t * _mdns_get_service_item(const char * service, const char
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static mdns_srv_item_t * _mdns_get_service_item_subtype(const char *subtype, const char * service, const char * proto)
|
||||
{
|
||||
mdns_srv_item_t * s = _mdns_server->services;
|
||||
while (s) {
|
||||
if (_mdns_service_match(s->service, service, proto, NULL)) {
|
||||
mdns_subtype_t *subtype_item = s->service->subtype;
|
||||
while(subtype_item) {
|
||||
if (!strcasecmp(subtype_item->subtype, subtype)) {
|
||||
return s;
|
||||
}
|
||||
subtype_item = subtype_item->next;
|
||||
}
|
||||
}
|
||||
s = s->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static mdns_host_item_t * mdns_get_host_item(const char * hostname)
|
||||
{
|
||||
if (hostname == NULL || strcasecmp(hostname, _mdns_server->hostname) == 0) {
|
||||
@ -605,6 +627,54 @@ static uint16_t _mdns_append_ptr_record(uint8_t * packet, uint16_t * index, cons
|
||||
return record_length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief appends PTR record for a subtype to a packet, incrementing the index
|
||||
*
|
||||
* @param packet MDNS packet
|
||||
* @param index offset in the packet
|
||||
* @param instance the service instance name
|
||||
* @param subtype the service subtype
|
||||
* @param proto the service protocol
|
||||
* @param flush whether to set the flush flag
|
||||
* @param bye whether to set the bye flag
|
||||
*
|
||||
* @return length of added data: 0 on error or length on success
|
||||
*/
|
||||
static uint16_t _mdns_append_subtype_ptr_record(uint8_t *packet, uint16_t *index, const char *instance,
|
||||
const char *subtype, const char *service, const char *proto, bool flush,
|
||||
bool bye)
|
||||
{
|
||||
const char *subtype_str[5] = {subtype, MDNS_SUB_STR, service, proto, MDNS_DEFAULT_DOMAIN};
|
||||
const char *instance_str[4] = {instance, service, proto, MDNS_DEFAULT_DOMAIN};
|
||||
uint16_t record_length = 0;
|
||||
uint8_t part_length;
|
||||
|
||||
if (service == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
part_length = _mdns_append_fqdn(packet, index, subtype_str, ARRAY_SIZE(subtype_str));
|
||||
if (!part_length) {
|
||||
return 0;
|
||||
}
|
||||
record_length += part_length;
|
||||
|
||||
part_length = _mdns_append_type(packet, index, MDNS_ANSWER_PTR, false, bye ? 0 : MDNS_ANSWER_PTR_TTL);
|
||||
if (!part_length) {
|
||||
return 0;
|
||||
}
|
||||
record_length += part_length;
|
||||
|
||||
uint16_t data_len_location = *index - 2;
|
||||
part_length = _mdns_append_fqdn(packet, index, instance_str, ARRAY_SIZE(instance_str));
|
||||
if (!part_length) {
|
||||
return 0;
|
||||
}
|
||||
_mdns_set_u16(packet, data_len_location, part_length);
|
||||
record_length += part_length;
|
||||
return record_length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief appends DNS-SD PTR record for service to a packet, incrementing the index
|
||||
*
|
||||
@ -1010,6 +1080,33 @@ static uint8_t _mdns_append_host_answer(uint8_t * packet, uint16_t * index, mdns
|
||||
return num_records;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Append PTR answers to packet
|
||||
*
|
||||
* @return number of answers added to the packet
|
||||
*/
|
||||
static uint8_t _mdns_append_service_ptr_answers(uint8_t *packet, uint16_t *index, mdns_service_t *service, bool flush,
|
||||
bool bye)
|
||||
{
|
||||
uint8_t appended_answers = 0;
|
||||
|
||||
if (_mdns_append_ptr_record(packet, index, _mdns_get_service_instance_name(service), service->service,
|
||||
service->proto, flush, bye) <= 0) {
|
||||
return appended_answers;
|
||||
}
|
||||
|
||||
mdns_subtype_t *subtype = service->subtype;
|
||||
while (subtype) {
|
||||
appended_answers +=
|
||||
(_mdns_append_subtype_ptr_record(packet, index, _mdns_get_service_instance_name(service), subtype->subtype,
|
||||
service->service, service->proto, flush, bye) > 0);
|
||||
subtype = subtype->next;
|
||||
}
|
||||
|
||||
return appended_answers;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Append answer to packet
|
||||
*
|
||||
@ -1018,12 +1115,8 @@ static uint8_t _mdns_append_host_answer(uint8_t * packet, uint16_t * index, mdns
|
||||
static uint8_t _mdns_append_answer(uint8_t * packet, uint16_t * index, mdns_out_answer_t * answer, mdns_if_t tcpip_if)
|
||||
{
|
||||
if (answer->type == MDNS_TYPE_PTR) {
|
||||
|
||||
if (answer->service) {
|
||||
return _mdns_append_ptr_record(packet, index,
|
||||
_mdns_get_service_instance_name(answer->service),
|
||||
answer->service->service, answer->service->proto,
|
||||
answer->flush, answer->bye) > 0;
|
||||
return _mdns_append_service_ptr_answers(packet, index, answer->service, answer->flush, answer->bye);
|
||||
} else {
|
||||
return _mdns_append_ptr_record(packet, index,
|
||||
answer->custom_instance, answer->custom_service, answer->custom_proto,
|
||||
@ -1435,6 +1528,24 @@ static bool _mdns_create_answer_from_hostname(mdns_tx_packet_t * packet, const c
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _mdns_service_match_ptr_question(const mdns_service_t *service, const mdns_parsed_question_t *question)
|
||||
{
|
||||
if (!_mdns_service_match(service, question->service, question->proto, NULL)) {
|
||||
return false;
|
||||
}
|
||||
if (question->sub) {
|
||||
mdns_subtype_t *subtype = service->subtype;
|
||||
while (subtype) {
|
||||
if (!strcasecmp(subtype->subtype, question->host)) {
|
||||
return true;
|
||||
}
|
||||
subtype = subtype->next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create answer packet to questions from parsed packet
|
||||
*/
|
||||
@ -1466,7 +1577,7 @@ static void _mdns_create_answer_from_parsed_packet(mdns_parsed_packet_t *parsed_
|
||||
} else if (q->service && q->proto) {
|
||||
mdns_srv_item_t *service = _mdns_server->services;
|
||||
while (service) {
|
||||
if (_mdns_service_match(service->service, q->service, q->proto, NULL)) {
|
||||
if (_mdns_service_match_ptr_question(service->service, q)) {
|
||||
if (!_mdns_create_answer_from_service(packet, service->service, q, shared, send_flush)) {
|
||||
_mdns_free_tx_packet(packet);
|
||||
return;
|
||||
@ -2179,6 +2290,7 @@ static mdns_service_t * _mdns_create_service(const char * service, const char *
|
||||
s->instance = instance?strndup(instance, MDNS_NAME_BUF_LEN - 1):NULL;
|
||||
s->txt = new_txt;
|
||||
s->port = port;
|
||||
s->subtype = NULL;
|
||||
|
||||
if (hostname) {
|
||||
s->hostname = strndup(hostname, MDNS_NAME_BUF_LEN - 1);
|
||||
@ -2338,7 +2450,12 @@ static void _mdns_free_service(mdns_service_t * service)
|
||||
free((char *)s->value);
|
||||
free(s);
|
||||
}
|
||||
free(service->txt);
|
||||
while (service->subtype) {
|
||||
mdns_subtype_t * next = service->subtype->next;
|
||||
free((char *)service->subtype->subtype);
|
||||
free(service->subtype);
|
||||
service->subtype = next;
|
||||
}
|
||||
free(service);
|
||||
}
|
||||
|
||||
@ -2701,9 +2818,12 @@ static bool _mdns_name_is_ours(mdns_name_t * name)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//find the service
|
||||
mdns_srv_item_t * service;
|
||||
if (_str_null_or_empty(name->host)) {
|
||||
if (name->sub) {
|
||||
service = _mdns_get_service_item_subtype(name->host, name->service, name->proto);
|
||||
} else if (_str_null_or_empty(name->host)) {
|
||||
service = _mdns_get_service_item(name->service, name->proto, NULL);
|
||||
} else {
|
||||
service = _mdns_get_service_item_instance(name->host, name->service, name->proto, NULL);
|
||||
@ -2712,8 +2832,8 @@ static bool _mdns_name_is_ours(mdns_name_t * name)
|
||||
return false;
|
||||
}
|
||||
|
||||
//if host is empty and we have service, we have success
|
||||
if (_str_null_or_empty(name->host)) {
|
||||
//if query is PTR query and we have service, we have success
|
||||
if (name->sub || _str_null_or_empty(name->host)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -3122,7 +3242,8 @@ void mdns_parse_packet(mdns_rx_packet_t * packet)
|
||||
a = a->next;
|
||||
}
|
||||
continue;
|
||||
} else if (name->sub || !_mdns_name_is_ours(name)) {
|
||||
}
|
||||
if (!_mdns_name_is_ours(name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -3140,6 +3261,7 @@ void mdns_parse_packet(mdns_rx_packet_t * packet)
|
||||
|
||||
question->unicast = unicast;
|
||||
question->type = type;
|
||||
question->sub = name->sub;
|
||||
if (_mdns_strdup_check(&(question->host), name->host)
|
||||
|| _mdns_strdup_check(&(question->service), name->service)
|
||||
|| _mdns_strdup_check(&(question->proto), name->proto)
|
||||
@ -4247,6 +4369,9 @@ static void _mdns_free_action(mdns_action_t * action)
|
||||
case ACTION_SERVICE_TXT_DEL:
|
||||
free(action->data.srv_txt_del.key);
|
||||
break;
|
||||
case ACTION_SERVICE_SUBTYPE_ADD:
|
||||
free(action->data.srv_subtype_add.subtype);
|
||||
break;
|
||||
case ACTION_SEARCH_ADD:
|
||||
//fallthrough
|
||||
case ACTION_SEARCH_SEND:
|
||||
@ -4282,6 +4407,8 @@ static void _mdns_execute_action(mdns_action_t * action)
|
||||
mdns_service_t * service;
|
||||
char * key;
|
||||
char * value;
|
||||
char *subtype;
|
||||
mdns_subtype_t *subtype_item;
|
||||
mdns_txt_linked_item_t * txt, * t;
|
||||
|
||||
switch(action->type) {
|
||||
@ -4395,6 +4522,19 @@ static void _mdns_execute_action(mdns_action_t * action)
|
||||
|
||||
_mdns_announce_all_pcbs(&action->data.srv_txt_set.service, 1, false);
|
||||
|
||||
break;
|
||||
case ACTION_SERVICE_SUBTYPE_ADD:
|
||||
service = action->data.srv_subtype_add.service->service;
|
||||
subtype = action->data.srv_subtype_add.subtype;
|
||||
subtype_item = (mdns_subtype_t *)malloc(sizeof(mdns_subtype_t));
|
||||
if (!subtype_item) {
|
||||
HOOK_MALLOC_FAILED;
|
||||
_mdns_free_action(action);
|
||||
return;
|
||||
}
|
||||
subtype_item->subtype = subtype;
|
||||
subtype_item->next = service->subtype;
|
||||
service->subtype = subtype_item;
|
||||
break;
|
||||
case ACTION_SERVICE_DEL:
|
||||
a = _mdns_server->services;
|
||||
@ -5249,6 +5389,40 @@ esp_err_t mdns_service_txt_item_remove(const char * service, const char * proto,
|
||||
return mdns_service_txt_item_remove_for_host(service, proto, _mdns_server->hostname, key);
|
||||
}
|
||||
|
||||
esp_err_t mdns_service_subtype_add_for_host(const char *instance_name, const char *service, const char *proto,
|
||||
const char *hostname, const char *subtype)
|
||||
{
|
||||
if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto) ||
|
||||
_str_null_or_empty(subtype)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
mdns_srv_item_t * s = _mdns_get_service_item_instance(instance_name, service, proto, hostname);
|
||||
|
||||
if (!s) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
mdns_action_t * action = (mdns_action_t *)malloc(sizeof(mdns_action_t));
|
||||
if (!action) {
|
||||
HOOK_MALLOC_FAILED;
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
action->type = ACTION_SERVICE_SUBTYPE_ADD;
|
||||
action->data.srv_subtype_add.service = s;
|
||||
action->data.srv_subtype_add.subtype = strdup(subtype);
|
||||
|
||||
if (!action->data.srv_subtype_add.subtype) {
|
||||
free(action);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
if (xQueueSend(_mdns_server->action_queue, &action, (portTickType)0) != pdPASS) {
|
||||
free(action->data.srv_subtype_add.subtype);
|
||||
free(action);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t mdns_service_instance_name_set_for_host(const char * service, const char * proto, const char * hostname,
|
||||
const char * instance)
|
||||
{
|
||||
|
@ -1,16 +1,8 @@
|
||||
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef MDNS_PRIVATE_H_
|
||||
#define MDNS_PRIVATE_H_
|
||||
|
||||
@ -176,6 +168,7 @@ typedef enum {
|
||||
ACTION_SERVICE_TXT_REPLACE,
|
||||
ACTION_SERVICE_TXT_SET,
|
||||
ACTION_SERVICE_TXT_DEL,
|
||||
ACTION_SERVICE_SUBTYPE_ADD,
|
||||
ACTION_SERVICES_CLEAR,
|
||||
ACTION_SEARCH_ADD,
|
||||
ACTION_SEARCH_SEND,
|
||||
@ -225,6 +218,7 @@ typedef struct {
|
||||
typedef struct mdns_parsed_question_s {
|
||||
struct mdns_parsed_question_s * next;
|
||||
uint16_t type;
|
||||
bool sub;
|
||||
bool unicast;
|
||||
char * host;
|
||||
char * service;
|
||||
@ -279,6 +273,11 @@ typedef struct mdns_txt_linked_item_s {
|
||||
struct mdns_txt_linked_item_s * next; /*!< next result, or NULL for the last result in the list */
|
||||
} mdns_txt_linked_item_t;
|
||||
|
||||
typedef struct mdns_subtype_s {
|
||||
const char *subtype; /*!< subtype */
|
||||
struct mdns_subtype_s * next; /*!< next result, or NULL for the last result in the list */
|
||||
} mdns_subtype_t;
|
||||
|
||||
typedef struct {
|
||||
const char * instance;
|
||||
const char * service;
|
||||
@ -288,6 +287,7 @@ typedef struct {
|
||||
uint16_t weight;
|
||||
uint16_t port;
|
||||
mdns_txt_linked_item_t * txt;
|
||||
mdns_subtype_t *subtype;
|
||||
} mdns_service_t;
|
||||
|
||||
typedef struct mdns_srv_item_s {
|
||||
@ -431,6 +431,10 @@ typedef struct {
|
||||
mdns_srv_item_t * service;
|
||||
char * key;
|
||||
} srv_txt_del;
|
||||
struct {
|
||||
mdns_srv_item_t * service;
|
||||
char * subtype;
|
||||
} srv_subtype_add;
|
||||
struct {
|
||||
mdns_search_once_t * search;
|
||||
} search_add;
|
||||
|
@ -53,6 +53,7 @@ static void initialise_mdns(void)
|
||||
|
||||
//initialize service
|
||||
ESP_ERROR_CHECK( mdns_service_add("ESP32-WebServer", "_http", "_tcp", 80, serviceTxtData, 3) );
|
||||
ESP_ERROR_CHECK( mdns_service_subtype_add_for_host("ESP32-WebServer", "_http", "_tcp", NULL, "_server") );
|
||||
#if CONFIG_MDNS_MULTIPLE_INSTANCE
|
||||
ESP_ERROR_CHECK( mdns_service_add("ESP32-WebServer1", "_http", "_tcp", 80, NULL, 0) );
|
||||
#endif
|
||||
|
@ -1833,13 +1833,11 @@ components/mdns/host_test/components/freertos_linux/include/freertos/task.h
|
||||
components/mdns/host_test/components/freertos_linux/queue_unique_ptr.cpp
|
||||
components/mdns/host_test/components/freertos_linux/queue_unique_ptr.hpp
|
||||
components/mdns/host_test/main/main.c
|
||||
components/mdns/include/mdns.h
|
||||
components/mdns/include/mdns_console.h
|
||||
components/mdns/mdns_console.c
|
||||
components/mdns/mdns_networking_lwip.c
|
||||
components/mdns/mdns_networking_socket.c
|
||||
components/mdns/private_include/mdns_networking.h
|
||||
components/mdns/private_include/mdns_private.h
|
||||
components/mdns/test/test_mdns.c
|
||||
components/mdns/test_afl_fuzz_host/esp32_mock.c
|
||||
components/mdns/test_afl_fuzz_host/esp32_mock.h
|
||||
|
Loading…
Reference in New Issue
Block a user