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

mdns: Add asynchronous query API

Closes https://github.com/espressif/esp-idf/issues/7090
David Cermak 4 лет назад
Родитель
Сommit
d81482d699

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

@@ -30,6 +30,11 @@ extern "C" {
 #define MDNS_TYPE_NSEC              0x002F
 #define MDNS_TYPE_ANY               0x00FF
 
+/**
+ * @brief   Asynchronous query handle
+ */
+typedef struct mdns_search_once_s mdns_search_once_t;
+
 /**
  * @brief   mDNS enum to specify the ip_protocol type
  */
@@ -477,6 +482,49 @@ esp_err_t mdns_service_txt_item_remove_for_host(const char * service_type, const
  */
 esp_err_t mdns_service_remove_all(void);
 
+/**
+ * @brief Deletes the finished query. Call this only after the search has ended!
+ *
+ * @param search pointer to search object
+ *
+ * @return
+ *     - ESP_OK success
+ *     - ESP_ERR_INVALID_STATE  search has not finished
+ *     - ESP_ERR_INVALID_ARG    pointer to search object is NULL
+ */
+esp_err_t mdns_query_async_delete(mdns_search_once_t* search);
+
+/**
+ * @brief Get results from search pointer. Results available as a pointer to the output parameter.
+ *        Pointer to search object has to be deleted via `mdns_query_async_delete` once the query has finished.
+ *        The results although have to be freed manually.
+ *
+ * @param search pointer to search object
+ * @param timeout time in milliseconds to wait for answers
+ * @param results pointer to the results of the query
+ *
+ * @return
+ *      True if search has finished before or at timeout
+ *      False if search timeout is over
+ */
+bool mdns_query_async_get_results(mdns_search_once_t* search, uint32_t timeout, mdns_result_t ** results);
+
+/**
+ * @brief  Query mDNS for host or service asynchronousely.
+ *         Search has to be tested for progress and deleted manually!
+ *
+ * @param  name         service instance or host name (NULL for PTR queries)
+ * @param  service_type service type (_http, _arduino, _ftp etc.) (NULL for host queries)
+ * @param  proto        service protocol (_tcp, _udp, etc.) (NULL for host queries)
+ * @param  type         type of query (MDNS_TYPE_*)
+ * @param  timeout      time in milliseconds during which mDNS query is active
+ * @param  max_results  maximum results to be collected
+ *
+ * @return mdns_search_once_s pointer to new search object if query initiated successfully.
+ *         NULL otherwise.
+ */
+mdns_search_once_t* mdns_query_async_new(const char * name, const char * service_type, const char * proto, uint16_t type, uint32_t timeout, size_t max_results);
+
 /**
  * @brief  Query mDNS for host or service
  *         All following query methods are derived from this one

+ 46 - 0
components/mdns/mdns.c

@@ -5292,6 +5292,52 @@ void mdns_query_results_free(mdns_result_t * results)
     }
 }
 
+esp_err_t mdns_query_async_delete(mdns_search_once_t* search)
+{
+    if (!search) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    if (search->state != SEARCH_OFF) {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    MDNS_SERVICE_LOCK();
+    _mdns_search_free(search);
+    MDNS_SERVICE_UNLOCK();
+
+    return ESP_OK;
+}
+
+bool mdns_query_async_get_results(mdns_search_once_t* search, uint32_t timeout, mdns_result_t ** results)
+{
+    if (xSemaphoreTake(search->done_semaphore, pdMS_TO_TICKS(timeout)) == pdTRUE) {
+        *results = search->result;
+        return true;
+    }
+    return false;
+}
+
+mdns_search_once_t* mdns_query_async_new(const char * name, const char * service, const char * proto, uint16_t type, uint32_t timeout, size_t max_results)
+{
+    mdns_search_once_t *search = NULL;
+
+    if (!_mdns_server || !timeout || _str_null_or_empty(service) != _str_null_or_empty(proto)) {
+        return NULL;
+    }
+
+    search = _mdns_search_init(name, service, proto, type, timeout, max_results);
+    if (!search) {
+        return NULL;
+    }
+
+    if (_mdns_send_search_action(ACTION_SEARCH_ADD, search)) {
+        _mdns_search_free(search);
+        return NULL;
+    }
+
+    return search;
+}
+
 esp_err_t mdns_query(const char * name, const char * service, const char * proto, uint16_t type, uint32_t timeout, size_t max_results, mdns_result_t ** results)
 {
     mdns_search_once_t * search = NULL;

+ 2 - 2
components/mdns/test_afl_fuzz_host/esp32_compat.h

@@ -63,10 +63,10 @@
 
 #define pdMS_TO_TICKS(a) a
 #define portTICK_RATE_MS 10
-#define xSemaphoreTake(s,d)
 #define xTaskDelete(a)
-#define vTaskDelete(a)             free(a)
+#define vTaskDelete(a)              free(a)
 #define xSemaphoreGive(s)
+#define xSemaphoreTake(s,d)         true
 #define xQueueCreateMutex(s)
 #define _mdns_pcb_init(a,b)         true
 #define _mdns_pcb_deinit(a,b)       true

+ 49 - 0
examples/protocols/mdns/main/mdns_example_main.c

@@ -138,6 +138,54 @@ static void query_mdns_service(const char * service_name, const char * proto)
     mdns_query_results_free(results);
 }
 
+static bool check_and_print_result(mdns_search_once_t *search)
+{
+    // Check if any result is available
+    mdns_result_t * result = NULL;
+    if (!mdns_query_async_get_results(search, 0, &result)) {
+        return false;
+    }
+
+    if (!result) {   // search timeout, but no result
+        return true;
+    }
+
+    // If yes, print the result
+    mdns_ip_addr_t * a = result->addr;
+    while (a) {
+        if(a->addr.type == ESP_IPADDR_TYPE_V6){
+            printf("  AAAA: " IPV6STR "\n", IPV62STR(a->addr.u_addr.ip6));
+        } else {
+            printf("  A   : " IPSTR "\n", IP2STR(&(a->addr.u_addr.ip4)));
+        }
+        a = a->next;
+    }
+    // and free the result
+    mdns_query_results_free(result);
+    return true;
+}
+
+static void query_mdns_hosts_async(const char * host_name)
+{
+    ESP_LOGI(TAG, "Query both A and AAA: %s.local", host_name);
+
+    mdns_search_once_t *s_a = mdns_query_async_new(host_name, NULL, NULL, MDNS_TYPE_A, 1000, 1);
+    mdns_query_async_delete(s_a);
+    mdns_search_once_t *s_aaaa = mdns_query_async_new(host_name, NULL, NULL, MDNS_TYPE_AAAA, 1000, 1);
+    while (s_a || s_aaaa) {
+        if (s_a && check_and_print_result(s_a)) {
+            ESP_LOGI(TAG, "Query A %s.local finished", host_name);
+            mdns_query_async_delete(s_a);
+            s_a = NULL;
+        }
+        if (s_aaaa && check_and_print_result(s_aaaa)) {
+            ESP_LOGI(TAG, "Query AAAA %s.local finished", host_name);
+            mdns_query_async_delete(s_aaaa);
+            s_aaaa = NULL;
+        }
+    }
+}
+
 static void query_mdns_host(const char * host_name)
 {
     ESP_LOGI(TAG, "Query A: %s.local", host_name);
@@ -174,6 +222,7 @@ static void check_button(void)
     static bool old_level = true;
     bool new_level = gpio_get_level(EXAMPLE_BUTTON_GPIO);
     if (!new_level && old_level) {
+        query_mdns_hosts_async("esp32-mdns");
         query_mdns_host("esp32");
         query_mdns_service("_arduino", "_tcp");
         query_mdns_service("_http", "_tcp");