Просмотр исходного кода

Merge branch 'feature/add-mdns-delegation' into 'master'

mdns: add host and service delegation

See merge request espressif/esp-idf!13063
David Čermák 4 лет назад
Родитель
Сommit
a09e413fb6

+ 183 - 0
components/mdns/include/mdns.h

@@ -114,6 +114,50 @@ void mdns_free(void);
  */
  */
 esp_err_t mdns_hostname_set(const char * hostname);
 esp_err_t mdns_hostname_set(const char * hostname);
 
 
+/**
+ * @brief  Adds a hostname and address to be delegated
+ *         A/AAAA queries will be replied for the hostname and
+ *         services can be added to this host.
+ *
+ * @param  hostname     Hostname to add
+ * @param  address_list The IP address list of the host
+ *
+ * @return
+ *     - ESP_OK success
+ *     - ESP_ERR_INVALID_STATE mDNS is not running
+ *     - ESP_ERR_INVALID_ARG Parameter error
+ *     - ESP_ERR_NO_MEM memory error
+ *
+ */
+esp_err_t mdns_delegate_hostname_add(const char * hostname, const mdns_ip_addr_t *address_list);
+
+/**
+ * @brief  Remove a delegated hostname
+ *         All the services added to this host will also be removed.
+ *
+ * @param  hostname     Hostname to remove
+ *
+ * @return
+ *     - ESP_OK success
+ *     - ESP_ERR_INVALID_STATE mDNS is not running
+ *     - ESP_ERR_INVALID_ARG Parameter error
+ *     - ESP_ERR_NO_MEM memory error
+ *
+ */
+esp_err_t mdns_delegate_hostname_remove(const char * hostname);
+
+/**
+ * @brief  Query whether a hostname has been added
+ *
+ * @param  hostname     Hostname to query
+ *
+ * @return
+ *     - true   The hostname has been added.
+ *     - false  The hostname has not been added.
+ *
+ */
+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 +189,41 @@ 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);
 
 
+
+/**
+ * @brief  Add service to mDNS server with a delegated hostname
+ *
+ * @param  instance_name    instance name to set. If NULL,
+ *                          global instance name or hostname will be used
+ * @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  port             service port
+ * @param  txt              string array of TXT data (eg. {{"var","val"},{"other","2"}})
+ * @param  num_items        number of items in TXT data
+ *
+ * @return
+ *     - ESP_OK success
+ *     - ESP_ERR_INVALID_ARG Parameter error
+ *     - ESP_ERR_NO_MEM memory error
+ *     - ESP_FAIL failed to add service
+ */
+esp_err_t mdns_service_add_for_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);
+
+/**
+ * @brief  Check whether a service has been added.
+ *
+ * @param  service_type     service type (_http, _ftp, etc)
+ * @param  proto            service protocol (_tcp, _udp)
+ * @param  hostname         service hostname. If NULL, checks for the local hostname.
+ *
+ * @return
+ *     - true   Correspondding service has been added.
+ *     - false  Service not found.
+ */
+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 +238,21 @@ 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);
 
 
+/**
+ * @brief  Remove service from mDNS server with hostname
+ *
+ * @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.
+ *
+ * @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_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 +268,23 @@ 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);
 
 
+/**
+ * @brief  Set instance name for service with hostname
+ *
+ * @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  instance_name    instance name to set
+ *
+ * @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_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 +300,24 @@ 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);
 
 
+
+/**
+ * @brief  Set service port with hostname
+ *
+ * @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  port         service port
+ *
+ * @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_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 +334,24 @@ 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);
 
 
+/**
+ * @brief  Replace all TXT items for service with hostname
+ *
+ * @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  txt          array of TXT data (eg. {{"var","val"},{"other","2"}})
+ * @param  num_items    number of items in TXT data
+ *
+ * @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_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 +368,25 @@ 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);
 
 
+
+/**
+ * @brief  Set/Add TXT item for service TXT record with hostname
+ *
+ * @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  key          the key that you want to add/update
+ * @param  value        the new value of the key
+ *
+ * @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_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 +402,23 @@ 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);
 
 
+/**
+ * @brief  Remove TXT item for service TXT record with hostname
+ *
+ * @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  key          the key that you want to remove
+ *
+ * @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_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
  *
  *

Разница между файлами не показана из-за своего большого размера
+ 495 - 173
components/mdns/mdns.c


+ 23 - 2
components/mdns/private_include/mdns_private.h

@@ -17,6 +17,9 @@
 #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"
+#include "mdns.h"
 
 
 //#define MDNS_ENABLE_DEBUG
 //#define MDNS_ENABLE_DEBUG
 
 
@@ -182,6 +185,8 @@ 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_DELEGATE_HOSTNAME_REMOVE,
     ACTION_MAX
     ACTION_MAX
 } mdns_action_type_t;
 } mdns_action_type_t;
 
 
@@ -210,7 +215,7 @@ typedef struct {
 } mdns_header_t;
 } mdns_header_t;
 
 
 typedef struct {
 typedef struct {
-    char host[MDNS_NAME_BUF_LEN];
+    char host[MDNS_NAME_BUF_LEN]; // hostname for A/AAAA records, instance name for SRV records
     char service[MDNS_NAME_BUF_LEN];
     char service[MDNS_NAME_BUF_LEN];
     char proto[MDNS_NAME_BUF_LEN];
     char proto[MDNS_NAME_BUF_LEN];
     char domain[MDNS_NAME_BUF_LEN];
     char domain[MDNS_NAME_BUF_LEN];
@@ -280,6 +285,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;
@@ -299,14 +305,22 @@ typedef struct mdns_out_question_s {
     const char * service;
     const char * service;
     const char * proto;
     const char * proto;
     const char * domain;
     const char * domain;
+    bool own_dynamic_memory;
 } mdns_out_question_t;
 } mdns_out_question_t;
 
 
+typedef struct mdns_host_item_t {
+    const char * hostname;
+    mdns_ip_addr_t *address_list;
+    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;
@@ -380,7 +394,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;
@@ -423,6 +440,10 @@ typedef struct {
         struct {
         struct {
             mdns_rx_packet_t * packet;
             mdns_rx_packet_t * packet;
         } rx_handle;
         } rx_handle;
+        struct {
+            const char * hostname;
+            mdns_ip_addr_t *address_list;
+        } delegate_hostname;
     } data;
     } data;
 } mdns_action_t;
 } mdns_action_t;
 
 

+ 15 - 0
components/mdns/test/test_mdns.c

@@ -4,6 +4,7 @@
 
 
 
 
 #define MDNS_HOSTNAME "test-hostname"
 #define MDNS_HOSTNAME "test-hostname"
+#define MDNS_DELEGATE_HOSTNAME "delegate-hostname"
 #define MDNS_INSTANCE "test-instance"
 #define MDNS_INSTANCE "test-instance"
 #define MDNS_SERVICE_NAME  "_http"
 #define MDNS_SERVICE_NAME  "_http"
 #define MDNS_SERVICE_PROTO "_tcp"
 #define MDNS_SERVICE_PROTO "_tcp"
@@ -42,6 +43,10 @@ TEST_CASE("mdns api return expected err-code and do not leak memory", "[mdns][le
 {
 {
     mdns_txt_item_t serviceTxtData[CONFIG_MDNS_MAX_SERVICES] = { {NULL, NULL},
     mdns_txt_item_t serviceTxtData[CONFIG_MDNS_MAX_SERVICES] = { {NULL, NULL},
     };
     };
+    mdns_ip_addr_t addr;
+    addr.addr.type = ESP_IPADDR_TYPE_V4;
+    addr.addr.u_addr.ip4.addr = esp_ip4addr_aton("127.0.0.1");
+    addr.next = NULL;
     for (int i=0; i<CONFIG_MDNS_MAX_SERVICES; ++i) {
     for (int i=0; i<CONFIG_MDNS_MAX_SERVICES; ++i) {
         serviceTxtData[i].key = "Key";
         serviceTxtData[i].key = "Key";
         serviceTxtData[i].value = "Value";
         serviceTxtData[i].value = "Value";
@@ -51,8 +56,15 @@ TEST_CASE("mdns api return expected err-code and do not leak memory", "[mdns][le
 
 
     TEST_ASSERT_EQUAL(ESP_OK, mdns_init() );
     TEST_ASSERT_EQUAL(ESP_OK, mdns_init() );
     TEST_ASSERT_EQUAL(ESP_OK, mdns_hostname_set(MDNS_HOSTNAME) );
     TEST_ASSERT_EQUAL(ESP_OK, mdns_hostname_set(MDNS_HOSTNAME) );
+    TEST_ASSERT_EQUAL(ESP_OK, mdns_delegate_hostname_add(MDNS_DELEGATE_HOSTNAME, &addr) );
+    yield_to_all_priorities();  // Make sure that mdns task has executed to add the hostname
+    TEST_ASSERT_TRUE(mdns_hostname_exists(MDNS_DELEGATE_HOSTNAME) );
     TEST_ASSERT_EQUAL(ESP_OK, mdns_instance_name_set(MDNS_INSTANCE) );
     TEST_ASSERT_EQUAL(ESP_OK, mdns_instance_name_set(MDNS_INSTANCE) );
     TEST_ASSERT_EQUAL(ESP_OK, mdns_service_add(MDNS_INSTANCE, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_SERVICE_PORT, serviceTxtData, CONFIG_MDNS_MAX_SERVICES) );
     TEST_ASSERT_EQUAL(ESP_OK, mdns_service_add(MDNS_INSTANCE, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_SERVICE_PORT, serviceTxtData, CONFIG_MDNS_MAX_SERVICES) );
+    TEST_ASSERT_FALSE(mdns_service_exists(MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_DELEGATE_HOSTNAME) );
+    TEST_ASSERT_EQUAL(ESP_OK, mdns_service_add_for_host(MDNS_INSTANCE, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_DELEGATE_HOSTNAME,
+                                                        MDNS_SERVICE_PORT, serviceTxtData, CONFIG_MDNS_MAX_SERVICES) );
+    TEST_ASSERT_TRUE(mdns_service_exists(MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_DELEGATE_HOSTNAME) );
     TEST_ASSERT_EQUAL(ESP_OK, mdns_service_txt_set(MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, serviceTxtData, CONFIG_MDNS_MAX_SERVICES) );
     TEST_ASSERT_EQUAL(ESP_OK, mdns_service_txt_set(MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, serviceTxtData, CONFIG_MDNS_MAX_SERVICES) );
     TEST_ASSERT_EQUAL(ESP_OK, mdns_service_txt_item_set(MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, "key1", "value1") );
     TEST_ASSERT_EQUAL(ESP_OK, mdns_service_txt_item_set(MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, "key1", "value1") );
     TEST_ASSERT_EQUAL(ESP_OK, mdns_service_txt_item_remove(MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, "key1") );
     TEST_ASSERT_EQUAL(ESP_OK, mdns_service_txt_item_remove(MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, "key1") );
@@ -61,6 +73,9 @@ TEST_CASE("mdns api return expected err-code and do not leak memory", "[mdns][le
     yield_to_all_priorities();  // Make sure that mdns task has executed to remove the service
     yield_to_all_priorities();  // Make sure that mdns task has executed to remove the service
 
 
     TEST_ASSERT_EQUAL(ESP_OK, mdns_service_add(MDNS_INSTANCE, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_SERVICE_PORT, NULL, 0) );
     TEST_ASSERT_EQUAL(ESP_OK, mdns_service_add(MDNS_INSTANCE, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_SERVICE_PORT, NULL, 0) );
+    TEST_ASSERT_EQUAL(ESP_OK, mdns_delegate_hostname_remove(MDNS_DELEGATE_HOSTNAME) );
+    yield_to_all_priorities();  // Make sure that mdns task has executed to remove the hostname
+    TEST_ASSERT_FALSE(mdns_service_exists(MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_DELEGATE_HOSTNAME) );
     TEST_ASSERT_EQUAL(ESP_OK, mdns_service_remove_all() );
     TEST_ASSERT_EQUAL(ESP_OK, mdns_service_remove_all() );
     yield_to_all_priorities();  // Make sure that mdns task has executed to remove all services
     yield_to_all_priorities();  // Make sure that mdns task has executed to remove all services
 
 

+ 1 - 0
components/mdns/test_afl_fuzz_host/esp32_compat.h

@@ -106,6 +106,7 @@ typedef void * SemaphoreHandle_t;
 typedef void * xQueueHandle;
 typedef void * xQueueHandle;
 typedef void * QueueHandle_t;
 typedef void * QueueHandle_t;
 typedef void * TaskHandle_t;
 typedef void * TaskHandle_t;
+typedef int    BaseType_t;
 typedef uint32_t TickType_t;
 typedef uint32_t TickType_t;
 typedef uint32_t portTickType;
 typedef uint32_t portTickType;
 
 

+ 15 - 0
components/mdns/test_afl_fuzz_host/esp32_mock.c

@@ -98,3 +98,18 @@ void ForceTaskDelete(void)
 {
 {
     g_queue_send_shall_fail = 1;
     g_queue_send_shall_fail = 1;
 }
 }
+
+TaskHandle_t xTaskGetCurrentTaskHandle(void)
+{
+    return NULL;
+}
+
+void xTaskNotifyGive(TaskHandle_t task)
+{
+    return;
+}
+
+BaseType_t xTaskNotifyWait(uint32_t bits_entry_clear, uint32_t bits_exit_clear, uint32_t * value, TickType_t wait_time)
+{
+    return pdTRUE;
+}

+ 5 - 0
components/mdns/test_afl_fuzz_host/esp32_mock.h

@@ -24,4 +24,9 @@ esp_err_t esp_event_handler_unregister(const char * event_base, int32_t event_id
 
 
 #define _mdns_udp_pcb_write(tcpip_if, ip_protocol, ip, port, data, len) len
 #define _mdns_udp_pcb_write(tcpip_if, ip_protocol, ip, port, data, len) len
 
 
+// Task signify mock
+TaskHandle_t xTaskGetCurrentTaskHandle(void);
+void xTaskNotifyGive(TaskHandle_t task);
+BaseType_t xTaskNotifyWait(uint32_t bits_entry_clear, uint32_t bits_exit_clear, uint32_t *value, TickType_t wait_time );
+
 #endif /* ESP32_MOCK_H_ */
 #endif /* ESP32_MOCK_H_ */

+ 3 - 3
components/mdns/test_afl_fuzz_host/mdns_di.h

@@ -7,13 +7,13 @@
 #include "mdns_private.h"
 #include "mdns_private.h"
 
 
 void              (*mdns_test_static_execute_action)(mdns_action_t *) = NULL;
 void              (*mdns_test_static_execute_action)(mdns_action_t *) = NULL;
-mdns_srv_item_t * (*mdns_test_static_mdns_get_service_item)(const char * service, const char * proto) = NULL;
+mdns_srv_item_t * (*mdns_test_static_mdns_get_service_item)(const char * service, const char * proto, const char *hostname) = NULL;
 mdns_search_once_t * (*mdns_test_static_search_init)(const char * name, const char * service, const char * proto, uint16_t type, uint32_t timeout, uint8_t max_results) = NULL;
 mdns_search_once_t * (*mdns_test_static_search_init)(const char * name, const char * service, const char * proto, uint16_t type, uint32_t timeout, uint8_t max_results) = NULL;
 esp_err_t         (*mdns_test_static_send_search_action)(mdns_action_type_t type, mdns_search_once_t * search) = NULL;
 esp_err_t         (*mdns_test_static_send_search_action)(mdns_action_type_t type, mdns_search_once_t * search) = NULL;
 void              (*mdns_test_static_search_free)(mdns_search_once_t * search) = NULL;
 void              (*mdns_test_static_search_free)(mdns_search_once_t * search) = NULL;
 
 
 static void _mdns_execute_action(mdns_action_t * action);
 static void _mdns_execute_action(mdns_action_t * action);
-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);
 static mdns_search_once_t * _mdns_search_init(const char * name, const char * service, const char * proto, uint16_t type, uint32_t timeout, uint8_t max_results);
 static mdns_search_once_t * _mdns_search_init(const char * name, const char * service, const char * proto, uint16_t type, uint32_t timeout, uint8_t max_results);
 static esp_err_t _mdns_send_search_action(mdns_action_type_t type, mdns_search_once_t * search);
 static esp_err_t _mdns_send_search_action(mdns_action_type_t type, mdns_search_once_t * search);
 static void _mdns_search_free(mdns_search_once_t * search);
 static void _mdns_search_free(mdns_search_once_t * search);
@@ -49,5 +49,5 @@ mdns_search_once_t * mdns_test_search_init(const char * name, const char * servi
 
 
 mdns_srv_item_t * mdns_test_mdns_get_service_item(const char * service, const char * proto)
 mdns_srv_item_t * mdns_test_mdns_get_service_item(const char * service, const char * proto)
 {
 {
-    return mdns_test_static_mdns_get_service_item(service, proto);
+    return mdns_test_static_mdns_get_service_item(service, proto, NULL);
 }
 }

+ 1 - 0
examples/protocols/mdns/README.md

@@ -5,6 +5,7 @@ Shows how to use mDNS to advertise lookup services and hosts
 ## Example workflow
 ## Example workflow
 
 
 - mDNS is initialized with host name and instance name defined through the project configuration and `_http._tcp` service is added to be advertised
 - mDNS is initialized with host name and instance name defined through the project configuration and `_http._tcp` service is added to be advertised
+- A delegated host `esp32-delegated._local` is added and another `_http._tcp` service is added for this host.
 - WiFi STA is started and trying to connect to the access point defined through the project configuration
 - WiFi STA is started and trying to connect to the access point defined through the project configuration
 - The system event handler is used to pass the network events to mDNS so the service is aware when the interface comes up or down
 - The system event handler is used to pass the network events to mDNS so the service is aware when the interface comes up or down
 - GPIO0 (BOOT Button) is initialized as pulled-up input that can be monitored for button press
 - GPIO0 (BOOT Button) is initialized as pulled-up input that can be monitored for button press

+ 6 - 0
examples/protocols/mdns/main/Kconfig.projbuild

@@ -12,6 +12,12 @@ menu "Example Configuration"
         help
         help
             mDNS Instance Name for example to use
             mDNS Instance Name for example to use
 
 
+    config MDNS_PUBLISH_DELEGATE_HOST
+        bool "Publish a delegated host"
+        help
+            Enable publishing a delegated host other than ESP32.
+            The example will also add a mock service for this host.
+
     config MDNS_RESOLVE_TEST_SERVICES
     config MDNS_RESOLVE_TEST_SERVICES
         bool "Resolve test services"
         bool "Resolve test services"
         default n
         default n

+ 28 - 7
examples/protocols/mdns/main/mdns_example_main.c

@@ -9,6 +9,7 @@
 #include <string.h>
 #include <string.h>
 #include "freertos/FreeRTOS.h"
 #include "freertos/FreeRTOS.h"
 #include "freertos/task.h"
 #include "freertos/task.h"
+#include "esp_netif_ip_addr.h"
 #include "esp_system.h"
 #include "esp_system.h"
 #include "esp_event.h"
 #include "esp_event.h"
 #include "esp_log.h"
 #include "esp_log.h"
@@ -23,8 +24,8 @@
 #define EXAMPLE_MDNS_INSTANCE CONFIG_MDNS_INSTANCE
 #define EXAMPLE_MDNS_INSTANCE CONFIG_MDNS_INSTANCE
 #define EXAMPLE_BUTTON_GPIO     0
 #define EXAMPLE_BUTTON_GPIO     0
 
 
-static const char *TAG = "mdns-test";
-static char* generate_hostname(void);
+static const char * TAG = "mdns-test";
+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);
@@ -33,7 +34,8 @@ static void  query_mdns_host_with_getaddrinfo(char * host);
 
 
 static void initialise_mdns(void)
 static void initialise_mdns(void)
 {
 {
-    char* hostname = generate_hostname();
+    char * hostname = generate_hostname();
+
     //initialize mDNS
     //initialize mDNS
     ESP_ERROR_CHECK( mdns_init() );
     ESP_ERROR_CHECK( mdns_init() );
     //set mDNS hostname (required if you want to advertise services)
     //set mDNS hostname (required if you want to advertise services)
@@ -44,13 +46,32 @@ static void initialise_mdns(void)
 
 
     //structure with TXT records
     //structure with TXT records
     mdns_txt_item_t serviceTxtData[3] = {
     mdns_txt_item_t serviceTxtData[3] = {
-        {"board","esp32"},
-        {"u","user"},
-        {"p","password"}
+        {"board", "esp32"},
+        {"u", "user"},
+        {"p", "password"}
     };
     };
 
 
     //initialize service
     //initialize service
     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) );
+
+#if CONFIG_MDNS_PUBLISH_DELEGATE_HOST
+    char *delegated_hostname;
+    if (-1 == asprintf(&delegated_hostname, "%s-delegated", hostname)) {
+        abort();
+    }
+
+    mdns_ip_addr_t addr4, addr6;
+    esp_netif_str_to_ip4("10.0.0.1", &addr4.addr.u_addr.ip4);
+    addr4.addr.type = ESP_IPADDR_TYPE_V4;
+    esp_netif_str_to_ip6("fd11:22::1", &addr6.addr.u_addr.ip6);
+    addr6.addr.type = ESP_IPADDR_TYPE_V6;
+    addr4.next = &addr6;
+    addr6.next = NULL;
+    ESP_ERROR_CHECK( mdns_delegate_hostname_add(delegated_hostname, &addr4) );
+    ESP_ERROR_CHECK( mdns_service_add_for_host("test0", "_http", "_tcp", delegated_hostname, 1234, serviceTxtData, 3) );
+    free(delegated_hostname);
+#endif // CONFIG_MDNS_PUBLISH_DELEGATE_HOST
+
     //add another TXT item
     //add another TXT item
     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
@@ -174,7 +195,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);
     }
     }

+ 26 - 10
examples/protocols/mdns/mdns_example_test.py

@@ -1,5 +1,6 @@
 import os
 import os
 import re
 import re
+import select
 import socket
 import socket
 import struct
 import struct
 import subprocess
 import subprocess
@@ -10,15 +11,17 @@ import dpkt
 import dpkt.dns
 import dpkt.dns
 import ttfw_idf
 import ttfw_idf
 from tiny_test_fw import DUT
 from tiny_test_fw import DUT
+from tiny_test_fw.Utility import console_log
 
 
 stop_mdns_server = Event()
 stop_mdns_server = Event()
 esp_answered = Event()
 esp_answered = Event()
+esp_delegated_answered = Event()
 
 
 
 
 def get_dns_query_for_esp(esp_host):
 def get_dns_query_for_esp(esp_host):
     dns = dpkt.dns.DNS(b'\x00\x00\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x01')
     dns = dpkt.dns.DNS(b'\x00\x00\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x01')
     dns.qd[0].name = esp_host + u'.local'
     dns.qd[0].name = esp_host + u'.local'
-    print('Created query for esp host: {} '.format(dns.__repr__()))
+    console_log('Created query for esp host: {} '.format(dns.__repr__()))
     return dns.pack()
     return dns.pack()
 
 
 
 
@@ -32,7 +35,7 @@ def get_dns_answer_to_mdns(tester_host):
     arr.name = tester_host
     arr.name = tester_host
     arr.ip = socket.inet_aton('127.0.0.1')
     arr.ip = socket.inet_aton('127.0.0.1')
     dns. an.append(arr)
     dns. an.append(arr)
-    print('Created answer to mdns query: {} '.format(dns.__repr__()))
+    console_log('Created answer to mdns query: {} '.format(dns.__repr__()))
     return dns.pack()
     return dns.pack()
 
 
 
 
@@ -56,31 +59,42 @@ def mdns_server(esp_host):
     MCAST_GRP = '224.0.0.251'
     MCAST_GRP = '224.0.0.251'
     TESTER_NAME = u'tinytester.local'
     TESTER_NAME = u'tinytester.local'
     TESTER_NAME_LWIP = u'tinytester-lwip.local'
     TESTER_NAME_LWIP = u'tinytester-lwip.local'
+    QUERY_TIMEOUT = 0.2
     sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
     sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
     sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
     sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
     sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
     sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
+    sock.setblocking(False)
     sock.bind((UDP_IP,UDP_PORT))
     sock.bind((UDP_IP,UDP_PORT))
     mreq = struct.pack('4sl', socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
     mreq = struct.pack('4sl', socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
     sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
     sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
-    sock.settimeout(30)
+    last_query_timepoint = time.time()
     while not stop_mdns_server.is_set():
     while not stop_mdns_server.is_set():
         try:
         try:
-            if not esp_answered.is_set():
+            current_time = time.time()
+            if not esp_answered.is_set() and current_time - last_query_timepoint > QUERY_TIMEOUT:
                 sock.sendto(get_dns_query_for_esp(esp_host), (MCAST_GRP,UDP_PORT))
                 sock.sendto(get_dns_query_for_esp(esp_host), (MCAST_GRP,UDP_PORT))
-                time.sleep(0.2)
+                sock.sendto(get_dns_query_for_esp(esp_host + '-delegated'), (MCAST_GRP,UDP_PORT))
+                last_query_timepoint = current_time
+            timeout = max(0, QUERY_TIMEOUT - (current_time - last_query_timepoint))
+            read_socks, _, _ = select.select([sock], [], [], timeout)
+            if not read_socks:
+                continue
             data, addr = sock.recvfrom(1024)
             data, addr = sock.recvfrom(1024)
             dns = dpkt.dns.DNS(data)
             dns = dpkt.dns.DNS(data)
             if len(dns.qd) > 0 and dns.qd[0].type == dpkt.dns.DNS_A:
             if len(dns.qd) > 0 and dns.qd[0].type == dpkt.dns.DNS_A:
                 if dns.qd[0].name == TESTER_NAME:
                 if dns.qd[0].name == TESTER_NAME:
-                    print('Received query: {} '.format(dns.__repr__()))
+                    console_log('Received query: {} '.format(dns.__repr__()))
                     sock.sendto(get_dns_answer_to_mdns(TESTER_NAME), (MCAST_GRP,UDP_PORT))
                     sock.sendto(get_dns_answer_to_mdns(TESTER_NAME), (MCAST_GRP,UDP_PORT))
                 elif dns.qd[0].name == TESTER_NAME_LWIP:
                 elif dns.qd[0].name == TESTER_NAME_LWIP:
-                    print('Received query: {} '.format(dns.__repr__()))
+                    console_log('Received query: {} '.format(dns.__repr__()))
                     sock.sendto(get_dns_answer_to_mdns_lwip(TESTER_NAME_LWIP, dns.id), addr)
                     sock.sendto(get_dns_answer_to_mdns_lwip(TESTER_NAME_LWIP, dns.id), addr)
             if len(dns.an) > 0 and dns.an[0].type == dpkt.dns.DNS_A:
             if len(dns.an) > 0 and dns.an[0].type == dpkt.dns.DNS_A:
                 if dns.an[0].name == esp_host + u'.local':
                 if dns.an[0].name == esp_host + u'.local':
-                    print('Received answer to esp32-mdns query: {}'.format(dns.__repr__()))
+                    console_log('Received answer to esp32-mdns query: {}'.format(dns.__repr__()))
                     esp_answered.set()
                     esp_answered.set()
+                if dns.an[0].name == esp_host + u'-delegated.local':
+                    console_log('Received answer to esp32-mdns-delegate query: {}'.format(dns.__repr__()))
+                    esp_delegated_answered.set()
         except socket.timeout:
         except socket.timeout:
             break
             break
         except dpkt.UnpackError:
         except dpkt.UnpackError:
@@ -111,7 +125,7 @@ def test_examples_protocol_mdns(env, extra_data):
     thread1.start()
     thread1.start()
     try:
     try:
         ip_address = dut1.expect(re.compile(r' sta ip: ([^,]+),'), timeout=30)[0]
         ip_address = dut1.expect(re.compile(r' sta ip: ([^,]+),'), timeout=30)[0]
-        print('Connected to AP with IP: {}'.format(ip_address))
+        console_log('Connected to AP with IP: {}'.format(ip_address))
     except DUT.ExpectTimeout:
     except DUT.ExpectTimeout:
         stop_mdns_server.set()
         stop_mdns_server.set()
         thread1.join()
         thread1.join()
@@ -120,6 +134,8 @@ def test_examples_protocol_mdns(env, extra_data):
         # 3. check the mdns name is accessible
         # 3. check the mdns name is accessible
         if not esp_answered.wait(timeout=30):
         if not esp_answered.wait(timeout=30):
             raise ValueError('Test has failed: did not receive mdns answer within timeout')
             raise ValueError('Test has failed: did not receive mdns answer within timeout')
+        if not esp_delegated_answered.wait(timeout=30):
+            raise ValueError('Test has failed: did not receive mdns answer for delegated host within timeout')
         # 4. check DUT output if mdns advertized host is resolved
         # 4. check DUT output if mdns advertized host is resolved
         dut1.expect(re.compile(r'mdns-test: Query A: tinytester.local resolved to: 127.0.0.1'), timeout=30)
         dut1.expect(re.compile(r'mdns-test: Query A: tinytester.local resolved to: 127.0.0.1'), timeout=30)
         dut1.expect(re.compile(r'mdns-test: gethostbyname: tinytester-lwip.local resolved to: 127.0.0.1'), timeout=30)
         dut1.expect(re.compile(r'mdns-test: gethostbyname: tinytester-lwip.local resolved to: 127.0.0.1'), timeout=30)
@@ -127,7 +143,7 @@ def test_examples_protocol_mdns(env, extra_data):
         # 5. check the DUT answers to `dig` command
         # 5. check the DUT answers to `dig` command
         dig_output = subprocess.check_output(['dig', '+short', '-p', '5353', '@224.0.0.251',
         dig_output = subprocess.check_output(['dig', '+short', '-p', '5353', '@224.0.0.251',
                                               '{}.local'.format(specific_host)])
                                               '{}.local'.format(specific_host)])
-        print('Resolving {} using "dig" succeeded with:\n{}'.format(specific_host, dig_output))
+        console_log('Resolving {} using "dig" succeeded with:\n{}'.format(specific_host, dig_output))
         if not ip_address.encode('utf-8') in dig_output:
         if not ip_address.encode('utf-8') in dig_output:
             raise ValueError('Test has failed: Incorrectly resolved DUT hostname using dig'
             raise ValueError('Test has failed: Incorrectly resolved DUT hostname using dig'
                              "Output should've contained DUT's IP address:{}".format(ip_address))
                              "Output should've contained DUT's IP address:{}".format(ip_address))

+ 1 - 0
examples/protocols/mdns/sdkconfig.ci

@@ -1,3 +1,4 @@
 CONFIG_MDNS_RESOLVE_TEST_SERVICES=y
 CONFIG_MDNS_RESOLVE_TEST_SERVICES=y
 CONFIG_MDNS_ADD_MAC_TO_HOSTNAME=y
 CONFIG_MDNS_ADD_MAC_TO_HOSTNAME=y
+CONFIG_MDNS_PUBLISH_DELEGATE_HOST=y
 CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y
 CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y

Некоторые файлы не были показаны из-за большого количества измененных файлов