me-no-dev преди 8 години
родител
ревизия
4bddbc031c

+ 2 - 0
components/mdns/component.mk

@@ -0,0 +1,2 @@
+COMPONENT_ADD_INCLUDEDIRS := include
+COMPONENT_PRIV_INCLUDEDIRS := private_include

+ 201 - 74
components/mdns/include/mdns.h

@@ -20,35 +20,69 @@ extern "C" {
 
 #ifndef MDNS_TEST_MODE
 #include <tcpip_adapter.h>
+#include "esp_event.h"
 #else
 #include "esp32_compat.h"
 #endif
 
-struct mdns_server_s;
-typedef struct mdns_server_s mdns_server_t;
+#define MDNS_TYPE_A                 0x0001
+#define MDNS_TYPE_PTR               0x000C
+#define MDNS_TYPE_TXT               0x0010
+#define MDNS_TYPE_AAAA              0x001C
+#define MDNS_TYPE_SRV               0x0021
+#define MDNS_TYPE_OPT               0x0029
+#define MDNS_TYPE_NSEC              0x002F
+#define MDNS_TYPE_ANY               0x00FF
 
 /**
- * @brief mDNS query result structure
- *
+ * @brief   mDNS enum to specify the ip_protocol type
+ */
+typedef enum {
+    MDNS_IP_PROTOCOL_V4,
+    MDNS_IP_PROTOCOL_V6,
+    MDNS_IP_PROTOCOL_MAX
+} mdns_ip_protocol_t;
+
+/**
+ * @brief   mDNS basic text item structure
+ *          Used in mdns_service_add()
+ */
+typedef struct {
+    char * key;                             /*!< item key name */
+    char * value;                           /*!< item value string */
+} mdns_txt_item_t;
+
+/**
+ * @brief   mDNS query linked list IP item
+ */
+typedef struct mdns_ip_addr_s {
+    ip_addr_t addr;                         /*!< IP address */
+    struct mdns_ip_addr_s * next;           /*!< next IP, or NULL for the last IP in the list */
+} mdns_ip_addr_t;
+
+/**
+ * @brief   mDNS query result structure
  */
 typedef struct mdns_result_s {
-    const char * host;                  /*!< hostname */
-    const char * instance;              /*!< instance */
-    const char * txt;                   /*!< txt data */
-    uint16_t priority;                  /*!< service priority */
-    uint16_t weight;                    /*!< service weight */
-    uint16_t port;                      /*!< service port */
-    struct ip4_addr addr;               /*!< ip4 address */
-    struct ip6_addr addrv6;             /*!< ip6 address */
-    const struct mdns_result_s * next;  /*!< next result, or NULL for the last result in the list */
+    struct mdns_result_s * next;            /*!< next result, or NULL for the last result in the list */
+
+    tcpip_adapter_if_t tcpip_if;            /*!< interface on which the result came (AP/STA/ETH) */
+    mdns_ip_protocol_t ip_protocol;         /*!< ip_protocol type of the interface (v4/v6) */
+    // PTR
+    char * instance_name;                   /*!< instance name */
+    // SRV
+    char * hostname;                        /*!< hostname */
+    uint16_t port;                          /*!< service port */
+    // TXT
+    mdns_txt_item_t * txt;                  /*!< txt record */
+    size_t txt_count;                       /*!< number of txt items */
+    // A and AAAA
+    mdns_ip_addr_t * addr;                  /*!< linked list of IP addreses found */
 } mdns_result_t;
 
 /**
  * @brief  Initialize mDNS on given interface
  *
- * @param  tcpip_if     Interface that the server will listen on
- * @param  server       Server pointer to populate on success
- *
  * @return
  *     - ESP_OK on success
  *     - ESP_ERR_INVALID_ARG when bad tcpip_if is given
@@ -56,20 +90,18 @@ typedef struct mdns_result_s {
  *     - ESP_ERR_NO_MEM on memory error
  *     - ESP_ERR_WIFI_NOT_INIT when WiFi is not initialized by eps_wifi_init
  */
-esp_err_t mdns_init(tcpip_adapter_if_t tcpip_if, mdns_server_t ** server);
+esp_err_t mdns_init();
 
 /**
  * @brief  Stop and free mDNS server
  *
- * @param  server       mDNS Server to free
- *
  */
-void mdns_free(mdns_server_t * server);
+void mdns_free();
 
 /**
  * @brief  Set the hostname for mDNS server
+ *         required if you want to advertise services
  *
- * @param  server       mDNS Server
  * @param  hostname     Hostname to set
  *
  * @return
@@ -77,41 +109,42 @@ void mdns_free(mdns_server_t * server);
  *     - ESP_ERR_INVALID_ARG Parameter error
  *     - ESP_ERR_NO_MEM memory error
  */
-esp_err_t mdns_set_hostname(mdns_server_t * server, const char * hostname);
+esp_err_t mdns_hostname_set(const char * hostname);
 
 /**
  * @brief  Set the default instance name for mDNS server
  *
- * @param  server       mDNS Server
- * @param  instance     Instance name to set
+ * @param  instance_name     Instance name to set
  *
  * @return
  *     - ESP_OK success
  *     - ESP_ERR_INVALID_ARG Parameter error
  *     - ESP_ERR_NO_MEM memory error
  */
-esp_err_t mdns_set_instance(mdns_server_t * server, const char * instance);
+esp_err_t mdns_instance_name_set(const char * instance_name);
 
 /**
  * @brief  Add service to mDNS server
  *
- * @param  server       mDNS Server
- * @param  service      service type (_http, _ftp, etc)
- * @param  proto        service protocol (_tcp, _udp)
- * @param  port         service port
+ * @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  port             service port
+ * @param  num_items        number of items in TXT data
+ * @param  txt              string array of TXT data (eg. {{"var","val"},{"other","2"}})
  *
  * @return
  *     - ESP_OK success
  *     - ESP_ERR_INVALID_ARG Parameter error
  *     - ESP_ERR_NO_MEM memory error
  */
-esp_err_t mdns_service_add(mdns_server_t * server, const char * service, const char * proto, uint16_t port);
+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  Remove service from mDNS server
  *
- * @param  server       mDNS Server
- * @param  service      service type (_http, _ftp, etc)
+ * @param  service_type service type (_http, _ftp, etc)
  * @param  proto        service protocol (_tcp, _udp)
  *
  * @return
@@ -120,15 +153,14 @@ esp_err_t mdns_service_add(mdns_server_t * server, const char * service, const c
  *     - ESP_ERR_NOT_FOUND Service not found
  *     - ESP_FAIL unknown error
  */
-esp_err_t mdns_service_remove(mdns_server_t * server, const char * service, const char * proto);
+esp_err_t mdns_service_remove(const char * service_type, const char * proto);
 
 /**
  * @brief  Set instance name for service
  *
- * @param  server       mDNS Server
- * @param  service      service type (_http, _ftp, etc)
- * @param  proto        service protocol (_tcp, _udp)
- * @param  instance     instance name to set
+ * @param  service_type     service type (_http, _ftp, etc)
+ * @param  proto            service protocol (_tcp, _udp)
+ * @param  instance_name    instance name to set
  *
  * @return
  *     - ESP_OK success
@@ -136,16 +168,29 @@ esp_err_t mdns_service_remove(mdns_server_t * server, const char * service, cons
  *     - ESP_ERR_NOT_FOUND Service not found
  *     - ESP_ERR_NO_MEM memory error
  */
-esp_err_t mdns_service_instance_set(mdns_server_t * server, const char * service, const char * proto, const char * instance);
+esp_err_t mdns_service_instance_name_set(const char * service_type, const char * proto, const char * instance_name);
+
+/**
+ * @brief  Set service port
+ *
+ * @param  service_type service type (_http, _ftp, etc)
+ * @param  proto        service protocol (_tcp, _udp)
+ * @param  port         service port
+ *
+ * @return
+ *     - ESP_OK success
+ *     - ESP_ERR_INVALID_ARG Parameter error
+ *     - ESP_ERR_NOT_FOUND Service not found
+ */
+esp_err_t mdns_service_port_set(const char * service_type, const char * proto, uint16_t port);
 
 /**
- * @brief  Set TXT data for service
+ * @brief  Replace all TXT items for service
  *
- * @param  server       mDNS Server
- * @param  service      service type (_http, _ftp, etc)
+ * @param  service_type service type (_http, _ftp, etc)
  * @param  proto        service protocol (_tcp, _udp)
  * @param  num_items    number of items in TXT data
- * @param  txt          string array of TXT data (eg. {"var=val","other=2"})
+ * @param  txt          array of TXT data (eg. {{"var","val"},{"other","2"}})
  *
  * @return
  *     - ESP_OK success
@@ -153,84 +198,166 @@ esp_err_t mdns_service_instance_set(mdns_server_t * server, const char * service
  *     - ESP_ERR_NOT_FOUND Service not found
  *     - ESP_ERR_NO_MEM memory error
  */
-esp_err_t mdns_service_txt_set(mdns_server_t * server, const char * service, const char * proto, uint8_t num_items, const char ** txt);
+esp_err_t mdns_service_txt_set(const char * service_type, const char * proto, mdns_txt_item_t txt[], uint8_t num_items);
 
 /**
- * @brief  Set service port
+ * @brief  Set/Add TXT item for service TXT record
  *
- * @param  server       mDNS Server
- * @param  service      service type (_http, _ftp, etc)
+ * @param  service_type service type (_http, _ftp, etc)
  * @param  proto        service protocol (_tcp, _udp)
- * @param  port         service port
+ * @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_port_set(mdns_server_t * server, const char * service, const char * proto, uint16_t port);
+esp_err_t mdns_service_txt_item_set(const char * service_type, const char * proto, const char * key, const char * value);
 
 /**
- * @brief  Remove and free all services from mDNS server
+ * @brief  Remove TXT item for service TXT record
  *
- * @param  server       mDNS Server
+ * @param  service_type service type (_http, _ftp, etc)
+ * @param  proto        service protocol (_tcp, _udp)
+ * @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(const char * service_type, const char * proto, const char * key);
+
+/**
+ * @brief  Remove and free all services from mDNS server
  *
  * @return
  *     - ESP_OK success
  *     - ESP_ERR_INVALID_ARG Parameter error
  */
-esp_err_t mdns_service_remove_all(mdns_server_t * server);
+esp_err_t mdns_service_remove_all();
 
 /**
  * @brief  Query mDNS for host or service
+ *         All following query methods are derived from this one
  *
- * @param  server       mDNS Server
- * @param  service      service type or host name
- * @param  proto        service protocol or NULL if searching for host
- * @param  timeout      time to wait for answers. If 0, mdns_query_end MUST be called to end the search
+ * @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 to wait for answers.
+ * @param  max_results  maximum results to be collected
+ * @param  results      pointer to the results of the query
+ *                      results must be freed using mdns_query_results_free below
  *
- * @return the number of results found
+ * @return
+ *     - ESP_OK success
+ *     - ESP_ERR_INVALID_STATE  mDNS is not running
+ *     - ESP_ERR_NO_MEM         memory error
+ *     - ESP_ERR_INVALID_ARG    timeout was not given
+ */
+esp_err_t mdns_query(const char * name, const char * service_type, const char * proto, uint16_t type, uint32_t timeout, size_t max_results, mdns_result_t ** results);
+
+/**
+ * @brief  Free query results
+ *
+ * @param  results      linked list of results to be freed
  */
-size_t mdns_query(mdns_server_t * server, const char * service, const char * proto, uint32_t timeout);
+void mdns_query_results_free(mdns_result_t * results);
 
 /**
- * @brief  Stop mDNS Query started with timeout = 0
+ * @brief  Query mDNS for service
  *
- * @param  server       mDNS Server
+ * @param  service_type service type (_http, _arduino, _ftp etc.)
+ * @param  proto        service protocol (_tcp, _udp, etc.)
+ * @param  timeout      time in milliseconds to wait for answer.
+ * @param  max_results  maximum results to be collected
+ * @param  results      pointer to the results of the query
  *
- * @return the number of results found
+ * @return
+ *     - ESP_OK success
+ *     - ESP_ERR_INVALID_STATE  mDNS is not running
+ *     - ESP_ERR_NO_MEM         memory error
+ *     - ESP_ERR_INVALID_ARG    parameter error
  */
-size_t mdns_query_end(mdns_server_t * server);
+esp_err_t mdns_query_ptr(const char * service_type, const char * proto, uint32_t timeout, size_t max_results, mdns_result_t ** results);
 
 /**
- * @brief  get the number of results currently in memoty
+ * @brief  Query mDNS for SRV record
  *
- * @param  server       mDNS Server
+ * @param  instance_name    service instance name
+ * @param  service_type     service type (_http, _arduino, _ftp etc.)
+ * @param  proto            service protocol (_tcp, _udp, etc.)
+ * @param  timeout          time in milliseconds to wait for answer.
+ * @param  result           pointer to the result of the query
  *
- * @return the number of results
+ * @return
+ *     - ESP_OK success
+ *     - ESP_ERR_INVALID_STATE  mDNS is not running
+ *     - ESP_ERR_NO_MEM         memory error
+ *     - ESP_ERR_INVALID_ARG    parameter error
  */
-size_t mdns_result_get_count(mdns_server_t * server);
+esp_err_t mdns_query_srv(const char * instance_name, const char * service_type, const char * proto, uint32_t timeout, mdns_result_t ** result);
 
 /**
- * @brief  Get mDNS Search result with given index
+ * @brief  Query mDNS for TXT record
  *
- * @param  server       mDNS Server
- * @param  num          the index of the result
+ * @param  instance_name    service instance name
+ * @param  service_type     service type (_http, _arduino, _ftp etc.)
+ * @param  proto            service protocol (_tcp, _udp, etc.)
+ * @param  timeout          time in milliseconds to wait for answer.
+ * @param  result           pointer to the result of the query
  *
- * @return the result or NULL if error
+ * @return
+ *     - ESP_OK success
+ *     - ESP_ERR_INVALID_STATE  mDNS is not running
+ *     - ESP_ERR_NO_MEM         memory error
+ *     - ESP_ERR_INVALID_ARG    parameter error
  */
-const mdns_result_t * mdns_result_get(mdns_server_t * server, size_t num);
+esp_err_t mdns_query_txt(const char * instance_name, const char * service_type, const char * proto, uint32_t timeout, mdns_result_t ** result);
 
 /**
- * @brief  Remove and free all search results from mDNS server
+ * @brief  Query mDNS for A record
  *
- * @param  server       mDNS Server
+ * @param  host_name    host name to look for
+ * @param  timeout      time in milliseconds to wait for answer.
+ * @param  addr         pointer to the resulting IP4 address
  *
  * @return
  *     - ESP_OK success
- *     - ESP_ERR_INVALID_ARG Parameter error
+ *     - ESP_ERR_INVALID_STATE  mDNS is not running
+ *     - ESP_ERR_NO_MEM         memory error
+ *     - ESP_ERR_INVALID_ARG    parameter error
+ */
+esp_err_t mdns_query_a(const char * host_name, uint32_t timeout, ip4_addr_t * addr);
+
+/**
+ * @brief  Query mDNS for A record
+ *
+ * @param  host_name    host name to look for
+ * @param  timeout      time in milliseconds to wait for answer. If 0, max_results needs to be defined
+ * @param  addr         pointer to the resulting IP6 address
+ *
+ * @return
+ *     - ESP_OK success
+ *     - ESP_ERR_INVALID_STATE  mDNS is not running
+ *     - ESP_ERR_NO_MEM         memory error
+ *     - ESP_ERR_INVALID_ARG    parameter error
+ */
+esp_err_t mdns_query_aaaa(const char * host_name, uint32_t timeout, ip6_addr_t * addr);
+
+/**
+ * @brief   System event handler
+ *          This method controls the service state on all active interfaces and applications are required
+ *          to call it from the system event handler for normal operation of mDNS service.
+ *
+ * @param  ctx          The system event context
+ * @param  event        The system event
  */
-esp_err_t mdns_result_free(mdns_server_t * server);
+esp_err_t mdns_handle_system_event(void *ctx, system_event_t *event);
 
 #ifdef __cplusplus
 }

+ 22 - 0
components/mdns/include/mdns_console.h

@@ -0,0 +1,22 @@
+// 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.
+#ifndef _MDNS_CONSOLE_H_
+#define _MDNS_CONSOLE_H_
+
+/**
+ * @brief  Register MDNS functions with the console component
+ */
+void mdns_console_register();
+
+#endif /* _MDNS_CONSOLE_H_ */

Файловите разлики са ограничени, защото са твърде много
+ 363 - 529
components/mdns/mdns.c


+ 1060 - 0
components/mdns/mdns_console.c

@@ -0,0 +1,1060 @@
+// 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.
+#include <stdio.h>
+#include <string.h>
+#include "esp_console.h"
+#include "argtable3/argtable3.h"
+#include "mdns.h"
+
+static const char * if_str[] = {"STA", "AP", "ETH", "MAX"};
+static const char * ip_protocol_str[] = {"V4", "V6", "MAX"};
+
+static void mdns_print_results(mdns_result_t * results)
+{
+    mdns_result_t * r = results;
+    mdns_ip_addr_t * a = NULL;
+    int i = 1, t;
+    while (r) {
+        printf("%d: Interface: %s, Type: %s\n", i++, if_str[r->tcpip_if], ip_protocol_str[r->ip_protocol]);
+        if (r->instance_name) {
+            printf("  PTR : %s\n", r->instance_name);
+        }
+        if (r->hostname) {
+            printf("  SRV : %s.local:%u\n", r->hostname, r->port);
+        }
+        if (r->txt_count) {
+            printf("  TXT : [%u] ", r->txt_count);
+            for (t=0; t<r->txt_count; t++) {
+                printf("%s=%s; ", r->txt[t].key, r->txt[t].value);
+            }
+            printf("\n");
+        }
+        a = r->addr;
+        while (a) {
+            if (a->addr.type == 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;
+        }
+        r = r->next;
+    }
+}
+
+static struct {
+    struct arg_str *hostname;
+    struct arg_int *timeout;
+    struct arg_end *end;
+} mdns_query_a_args;
+
+static int cmd_mdns_query_a(int argc, char** argv)
+{
+    int nerrors = arg_parse(argc, argv, (void**) &mdns_query_a_args);
+    if (nerrors != 0) {
+        arg_print_errors(stderr, mdns_query_a_args.end, argv[0]);
+        return 1;
+    }
+
+    const char * hostname = mdns_query_a_args.hostname->sval[0];
+    int timeout = mdns_query_a_args.timeout->ival[0];
+
+    if (!hostname || !hostname[0]) {
+        printf("ERROR: Hostname not supplied\n");
+        return 1;
+    }
+
+    if (timeout <= 0) {
+        timeout = 1000;
+    }
+
+    printf("Query A: %s.local, Timeout: %d\n", hostname, timeout);
+
+    struct ip4_addr addr;
+    addr.addr = 0;
+
+    esp_err_t err = mdns_query_a(hostname, timeout,  &addr);
+    if (err) {
+        if (err == ESP_ERR_NOT_FOUND) {
+            printf("ERROR: Host was not found!\n");
+            return 0;
+        }
+        printf("ERROR: Query Failed\n");
+        return 1;
+    }
+
+    printf(IPSTR "\n", IP2STR(&addr));
+
+    return 0;
+}
+
+static void register_mdns_query_a()
+{
+    mdns_query_a_args.hostname = arg_str1(NULL, NULL, "<hostname>", "Hostname that is searched for");
+    mdns_query_a_args.timeout = arg_int0("t", "timeout", "<timeout>", "Timeout for this query");
+    mdns_query_a_args.end = arg_end(2);
+
+    const esp_console_cmd_t cmd_init = {
+        .command = "mdns_query_a",
+        .help = "Query MDNS for IPv4",
+        .hint = NULL,
+        .func = &cmd_mdns_query_a,
+        .argtable = &mdns_query_a_args
+    };
+
+    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_init) );
+}
+
+static int cmd_mdns_query_aaaa(int argc, char** argv)
+{
+    int nerrors = arg_parse(argc, argv, (void**) &mdns_query_a_args);
+    if (nerrors != 0) {
+        arg_print_errors(stderr, mdns_query_a_args.end, argv[0]);
+        return 1;
+    }
+
+    const char * hostname = mdns_query_a_args.hostname->sval[0];
+    int timeout = mdns_query_a_args.timeout->ival[0];
+
+    if (!hostname || !hostname[0]) {
+        printf("ERROR: Hostname not supplied\n");
+        return 1;
+    }
+
+    if (timeout <= 0) {
+        timeout = 1000;
+    }
+
+    printf("Query AAAA: %s.local, Timeout: %d\n", hostname, timeout);
+
+    struct ip6_addr addr;
+    memset(addr.addr, 0, 16);
+
+    esp_err_t err = mdns_query_aaaa(hostname, timeout,  &addr);
+    if (err) {
+        if (err == ESP_ERR_NOT_FOUND) {
+            printf("Host was not found!\n");
+            return 0;
+        }
+        printf("ERROR: Query Failed\n");
+        return 1;
+    }
+
+    printf(IPV6STR "\n", IPV62STR(addr));
+
+    return 0;
+}
+
+static void register_mdns_query_aaaa()
+{
+    mdns_query_a_args.hostname = arg_str1(NULL, NULL, "<hostname>", "Hostname that is searched for");
+    mdns_query_a_args.timeout = arg_int0("t", "timeout", "<timeout>", "Timeout for this query");
+    mdns_query_a_args.end = arg_end(2);
+
+    const esp_console_cmd_t cmd_init = {
+        .command = "mdns_query_aaaa",
+        .help = "Query MDNS for IPv6",
+        .hint = NULL,
+        .func = &cmd_mdns_query_aaaa,
+        .argtable = &mdns_query_a_args
+    };
+
+    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_init) );
+}
+
+static struct {
+    struct arg_str *instance;
+    struct arg_str *service;
+    struct arg_str *proto;
+    struct arg_int *timeout;
+    struct arg_end *end;
+} mdns_query_srv_args;
+
+static int cmd_mdns_query_srv(int argc, char** argv)
+{
+    int nerrors = arg_parse(argc, argv, (void**) &mdns_query_srv_args);
+    if (nerrors != 0) {
+        arg_print_errors(stderr, mdns_query_srv_args.end, argv[0]);
+        return 1;
+    }
+
+    const char * instance = mdns_query_srv_args.instance->sval[0];
+    const char * service = mdns_query_srv_args.service->sval[0];
+    const char * proto = mdns_query_srv_args.proto->sval[0];
+    int timeout = mdns_query_srv_args.timeout->ival[0];
+
+    if (timeout <= 0) {
+        timeout = 1000;
+    }
+
+    printf("Query SRV: %s.%s.%s.local, Timeout: %d\n", instance, service, proto, timeout);
+
+    mdns_result_t * results = NULL;
+    esp_err_t err = mdns_query_srv(instance, service, proto, timeout,  &results);
+    if (err) {
+        printf("ERROR: Query Failed\n");
+        return 1;
+    }
+    if (!results) {
+        printf("No results found!\n");
+        return 0;
+    }
+    mdns_print_results(results);
+    mdns_query_results_free(results);
+    return 0;
+}
+
+static void register_mdns_query_srv()
+{
+    mdns_query_srv_args.instance = arg_str1(NULL, NULL, "<instance>", "Instance to search for");
+    mdns_query_srv_args.service = arg_str1(NULL, NULL, "<service>", "Service to search for (ex. _http, _smb, etc.)");
+    mdns_query_srv_args.proto = arg_str1(NULL, NULL, "<proto>", "Protocol to search for (_tcp, _udp, etc.)");
+    mdns_query_srv_args.timeout = arg_int0("t", "timeout", "<timeout>", "Timeout for this query");
+    mdns_query_srv_args.end = arg_end(2);
+
+    const esp_console_cmd_t cmd_init = {
+        .command = "mdns_query_srv",
+        .help = "Query MDNS for Service SRV",
+        .hint = NULL,
+        .func = &cmd_mdns_query_srv,
+        .argtable = &mdns_query_srv_args
+    };
+
+    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_init) );
+}
+
+static struct {
+    struct arg_str *instance;
+    struct arg_str *service;
+    struct arg_str *proto;
+    struct arg_int *timeout;
+    struct arg_end *end;
+} mdns_query_txt_args;
+
+static int cmd_mdns_query_txt(int argc, char** argv)
+{
+    int nerrors = arg_parse(argc, argv, (void**) &mdns_query_txt_args);
+    if (nerrors != 0) {
+        arg_print_errors(stderr, mdns_query_txt_args.end, argv[0]);
+        return 1;
+    }
+
+    const char * instance = mdns_query_txt_args.instance->sval[0];
+    const char * service = mdns_query_txt_args.service->sval[0];
+    const char * proto = mdns_query_txt_args.proto->sval[0];
+    int timeout = mdns_query_txt_args.timeout->ival[0];
+
+    printf("Query TXT: %s.%s.%s.local, Timeout: %d\n", instance, service, proto, timeout);
+
+    if (timeout <= 0) {
+        timeout = 5000;
+    }
+
+    mdns_result_t * results = NULL;
+    esp_err_t err = mdns_query_txt(instance, service, proto, timeout,  &results);
+    if (err) {
+        printf("ERROR: Query Failed\n");
+        return 1;
+    }
+    if (!results) {
+        printf("No results found!\n");
+        return 0;
+    }
+
+    mdns_print_results(results);
+    mdns_query_results_free(results);
+    return 0;
+}
+
+static void register_mdns_query_txt()
+{
+    mdns_query_txt_args.instance = arg_str1(NULL, NULL, "<instance>", "Instance to search for");
+    mdns_query_txt_args.service = arg_str1(NULL, NULL, "<service>", "Service to search for (ex. _http, _smb, etc.)");
+    mdns_query_txt_args.proto = arg_str1(NULL, NULL, "<proto>", "Protocol to search for (_tcp, _udp, etc.)");
+    mdns_query_txt_args.timeout = arg_int0("t", "timeout", "<timeout>", "Timeout for this query");
+    mdns_query_txt_args.end = arg_end(2);
+
+    const esp_console_cmd_t cmd_init = {
+        .command = "mdns_query_txt",
+        .help = "Query MDNS for Service TXT",
+        .hint = NULL,
+        .func = &cmd_mdns_query_txt,
+        .argtable = &mdns_query_txt_args
+    };
+
+    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_init) );
+}
+
+static struct {
+    struct arg_str *service;
+    struct arg_str *proto;
+    struct arg_int *timeout;
+    struct arg_int *max_results;
+    struct arg_end *end;
+} mdns_query_ptr_args;
+
+static int cmd_mdns_query_ptr(int argc, char** argv)
+{
+    int nerrors = arg_parse(argc, argv, (void**) &mdns_query_ptr_args);
+    if (nerrors != 0) {
+        arg_print_errors(stderr, mdns_query_ptr_args.end, argv[0]);
+        return 1;
+    }
+
+    const char * service = mdns_query_ptr_args.service->sval[0];
+    const char * proto = mdns_query_ptr_args.proto->sval[0];
+    int timeout = mdns_query_ptr_args.timeout->ival[0];
+    int max_results = mdns_query_ptr_args.max_results->ival[0];
+
+    if (timeout <= 0) {
+        timeout = 5000;
+    }
+
+    if (max_results <= 0 || max_results > 255) {
+        max_results = 255;
+    }
+
+    printf("Query PTR: %s.%s.local, Timeout: %d, Max Results: %d\n", service, proto, timeout, max_results);
+
+    mdns_result_t * results = NULL;
+    esp_err_t err = mdns_query_ptr(service, proto, timeout, max_results,  &results);
+    if (err) {
+        printf("ERROR: Query Failed\n");
+        return 1;
+    }
+    if (!results) {
+        printf("No results found!\n");
+        return 0;
+    }
+
+    mdns_print_results(results);
+    mdns_query_results_free(results);
+    return 0;
+}
+
+static void register_mdns_query_ptr()
+{
+    mdns_query_ptr_args.service = arg_str1(NULL, NULL, "<service>", "Service to search for (ex. _http, _smb, etc.)");
+    mdns_query_ptr_args.proto = arg_str1(NULL, NULL, "<proto>", "Protocol to search for (_tcp, _udp, etc.)");
+    mdns_query_ptr_args.timeout = arg_int0("t", "timeout", "<timeout>", "Timeout for this query");
+    mdns_query_ptr_args.max_results = arg_int0("m", "max_results", "<max_results>", "Maximum results returned");
+    mdns_query_ptr_args.end = arg_end(2);
+
+    const esp_console_cmd_t cmd_init = {
+        .command = "mdns_query_ptr",
+        .help = "Query MDNS for Service",
+        .hint = NULL,
+        .func = &cmd_mdns_query_ptr,
+        .argtable = &mdns_query_ptr_args
+    };
+
+    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_init) );
+}
+
+static struct {
+    struct arg_str *hostname;
+    struct arg_int *timeout;
+    struct arg_int *max_results;
+    struct arg_end *end;
+} mdns_query_ip_args;
+
+static int cmd_mdns_query_ip(int argc, char** argv)
+{
+    int nerrors = arg_parse(argc, argv, (void**) &mdns_query_ip_args);
+    if (nerrors != 0) {
+        arg_print_errors(stderr, mdns_query_ip_args.end, argv[0]);
+        return 1;
+    }
+
+    const char * hostname = mdns_query_ip_args.hostname->sval[0];
+    int timeout = mdns_query_ip_args.timeout->ival[0];
+    int max_results = mdns_query_ip_args.max_results->ival[0];
+
+    if (!hostname || !hostname[0]) {
+        printf("ERROR: Hostname not supplied\n");
+        return 1;
+    }
+
+    if (timeout <= 0) {
+        timeout = 1000;
+    }
+
+    if (max_results < 0 || max_results > 255) {
+        max_results = 255;
+    }
+
+    printf("Query IP: %s.local, Timeout: %d, Max Results: %d\n", hostname, timeout, max_results);
+
+    mdns_result_t * results = NULL;
+    esp_err_t err = mdns_query(hostname, NULL, NULL, MDNS_TYPE_ANY, timeout, max_results, &results);
+    if (err) {
+        printf("ERROR: Query Failed\n");
+        return 1;
+    }
+    if (!results) {
+        printf("No results found!\n");
+        return 0;
+    }
+    mdns_print_results(results);
+    mdns_query_results_free(results);
+
+    return 0;
+}
+
+static void register_mdns_query_ip()
+{
+    mdns_query_ip_args.hostname = arg_str1(NULL, NULL, "<hostname>", "Hostname that is searched for");
+    mdns_query_ip_args.timeout = arg_int0("t", "timeout", "<timeout>", "Timeout for this query");
+    mdns_query_ip_args.max_results = arg_int0("m", "max_results", "<max_results>", "Maximum results returned");
+    mdns_query_ip_args.end = arg_end(2);
+
+    const esp_console_cmd_t cmd_init = {
+        .command = "mdns_query_ip",
+        .help = "Query MDNS for IP",
+        .hint = NULL,
+        .func = &cmd_mdns_query_ip,
+        .argtable = &mdns_query_ip_args
+    };
+
+    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_init) );
+}
+
+static struct {
+    struct arg_str *instance;
+    struct arg_str *service;
+    struct arg_str *proto;
+    struct arg_int *timeout;
+    struct arg_int *max_results;
+    struct arg_end *end;
+} mdns_query_svc_args;
+
+static int cmd_mdns_query_svc(int argc, char** argv)
+{
+    int nerrors = arg_parse(argc, argv, (void**) &mdns_query_svc_args);
+    if (nerrors != 0) {
+        arg_print_errors(stderr, mdns_query_svc_args.end, argv[0]);
+        return 1;
+    }
+
+    const char * instance = mdns_query_svc_args.instance->sval[0];
+    const char * service = mdns_query_svc_args.service->sval[0];
+    const char * proto = mdns_query_svc_args.proto->sval[0];
+    int timeout = mdns_query_svc_args.timeout->ival[0];
+    int max_results = mdns_query_svc_args.max_results->ival[0];
+
+    if (timeout <= 0) {
+        timeout = 5000;
+    }
+
+    if (max_results < 0 || max_results > 255) {
+        max_results = 255;
+    }
+
+    printf("Query SVC: %s.%s.%s.local, Timeout: %d, Max Results: %d\n", instance, service, proto, timeout, max_results);
+
+    mdns_result_t * results = NULL;
+    esp_err_t err = mdns_query(instance, service, proto, MDNS_TYPE_ANY, timeout, max_results,  &results);
+    if (err) {
+        printf("ERROR: Query Failed\n");
+        return 1;
+    }
+    if (!results) {
+        printf("No results found!\n");
+        return 0;
+    }
+
+    mdns_print_results(results);
+    mdns_query_results_free(results);
+    return 0;
+}
+
+static void register_mdns_query_svc()
+{
+    mdns_query_svc_args.instance = arg_str1(NULL, NULL, "<instance>", "Instance to search for");
+    mdns_query_svc_args.service = arg_str1(NULL, NULL, "<service>", "Service to search for (ex. _http, _smb, etc.)");
+    mdns_query_svc_args.proto = arg_str1(NULL, NULL, "<proto>", "Protocol to search for (_tcp, _udp, etc.)");
+    mdns_query_svc_args.timeout = arg_int0("t", "timeout", "<timeout>", "Timeout for this query");
+    mdns_query_svc_args.max_results = arg_int0("m", "max_results", "<max_results>", "Maximum results returned");
+    mdns_query_svc_args.end = arg_end(2);
+
+    const esp_console_cmd_t cmd_init = {
+        .command = "mdns_query_svc",
+        .help = "Query MDNS for Service TXT & SRV",
+        .hint = NULL,
+        .func = &cmd_mdns_query_svc,
+        .argtable = &mdns_query_svc_args
+    };
+
+    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_init) );
+}
+
+static struct {
+    struct arg_str *hostname;
+    struct arg_str *instance;
+    struct arg_end *end;
+} mdns_init_args;
+
+static int cmd_mdns_init(int argc, char** argv)
+{
+    int nerrors = arg_parse(argc, argv, (void**) &mdns_init_args);
+    if (nerrors != 0) {
+        arg_print_errors(stderr, mdns_init_args.end, argv[0]);
+        return 1;
+    }
+
+    ESP_ERROR_CHECK( mdns_init() );
+
+    if (mdns_init_args.hostname->sval[0]) {
+        ESP_ERROR_CHECK( mdns_hostname_set(mdns_init_args.hostname->sval[0]) );
+        printf("MDNS: Hostname: %s\n", mdns_init_args.hostname->sval[0]);
+    }
+
+    if (mdns_init_args.instance->sval[0]) {
+        ESP_ERROR_CHECK( mdns_instance_name_set(mdns_init_args.instance->sval[0]) );
+        printf("MDNS: Instance: %s\n", mdns_init_args.instance->sval[0]);
+    }
+
+    return 0;
+}
+
+static void register_mdns_init()
+{
+    mdns_init_args.hostname = arg_str0("h", "hostname", "<hostname>", "Hostname that the server will advertise");
+    mdns_init_args.instance = arg_str0("i", "instance", "<instance>", "Default instance name for services");
+    mdns_init_args.end = arg_end(2);
+
+    const esp_console_cmd_t cmd_init = {
+        .command = "mdns_init",
+        .help = "Start MDNS Server",
+        .hint = NULL,
+        .func = &cmd_mdns_init,
+        .argtable = &mdns_init_args
+    };
+
+    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_init) );
+}
+
+static int cmd_mdns_free(int argc, char** argv)
+{
+    mdns_free();
+    return 0;
+}
+
+static void register_mdns_free()
+{
+    const esp_console_cmd_t cmd_free = {
+        .command = "mdns_free",
+        .help = "Stop MDNS Server",
+        .hint = NULL,
+        .func = &cmd_mdns_free,
+        .argtable = NULL
+    };
+
+    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_free) );
+}
+
+static struct {
+    struct arg_str *hostname;
+    struct arg_end *end;
+} mdns_set_hostname_args;
+
+static int cmd_mdns_set_hostname(int argc, char** argv)
+{
+    int nerrors = arg_parse(argc, argv, (void**) &mdns_set_hostname_args);
+    if (nerrors != 0) {
+        arg_print_errors(stderr, mdns_set_hostname_args.end, argv[0]);
+        return 1;
+    }
+
+    if (mdns_set_hostname_args.hostname->sval[0] == NULL) {
+        printf("ERROR: Bad arguments!\n");
+        return 1;
+    }
+
+    ESP_ERROR_CHECK( mdns_hostname_set(mdns_set_hostname_args.hostname->sval[0]) );
+    return 0;
+}
+
+static void register_mdns_set_hostname()
+{
+    mdns_set_hostname_args.hostname = arg_str1(NULL, NULL, "<hostname>", "Hostname that the server will advertise");
+    mdns_set_hostname_args.end = arg_end(2);
+
+    const esp_console_cmd_t cmd_set_hostname = {
+        .command = "mdns_set_hostname",
+        .help = "Set MDNS Server hostname",
+        .hint = NULL,
+        .func = &cmd_mdns_set_hostname,
+        .argtable = &mdns_set_hostname_args
+    };
+
+    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_set_hostname) );
+}
+
+static struct {
+    struct arg_str *instance;
+    struct arg_end *end;
+} mdns_set_instance_args;
+
+static int cmd_mdns_set_instance(int argc, char** argv)
+{
+    int nerrors = arg_parse(argc, argv, (void**) &mdns_set_instance_args);
+    if (nerrors != 0) {
+        arg_print_errors(stderr, mdns_set_instance_args.end, argv[0]);
+        return 1;
+    }
+
+    if (mdns_set_instance_args.instance->sval[0] == NULL) {
+        printf("ERROR: Bad arguments!\n");
+        return 1;
+    }
+
+    ESP_ERROR_CHECK( mdns_instance_name_set(mdns_set_instance_args.instance->sval[0]) );
+    return 0;
+}
+
+static void register_mdns_set_instance()
+{
+    mdns_set_instance_args.instance = arg_str1(NULL, NULL, "<instance>", "Default instance name for services");
+    mdns_set_instance_args.end = arg_end(2);
+
+    const esp_console_cmd_t cmd_set_instance = {
+        .command = "mdns_set_instance",
+        .help = "Set MDNS Server Istance Name",
+        .hint = NULL,
+        .func = &cmd_mdns_set_instance,
+        .argtable = &mdns_set_instance_args
+    };
+
+    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_set_instance) );
+}
+
+static mdns_txt_item_t * _convert_items(const char **values, int count)
+{
+    int i=0,e;
+    const char * value = NULL;
+    mdns_txt_item_t * items = (mdns_txt_item_t*) malloc(sizeof(mdns_txt_item_t) * count);
+    if (!items) {
+        printf("ERROR: No Memory!\n");
+        goto fail;
+
+    }
+    memset(items, 0, sizeof(mdns_txt_item_t) * count);
+
+    for (i=0; i<count; i++) {
+        value = values[i];
+        char * esign = strchr(value, '=');
+        if (!esign) {
+            printf("ERROR: Equal sign not found in '%s'!\n", value);
+            goto fail;
+        }
+        int var_len = esign - value;
+        int val_len = strlen(value) - var_len - 1;
+        char * var = (char*)malloc(var_len+1);
+        if (var == NULL) {
+            printf("ERROR: No Memory!\n");
+            goto fail;
+        }
+        char * val = (char*)malloc(val_len+1);
+        if (val == NULL) {
+            printf("ERROR: No Memory!\n");
+            free(var);
+            goto fail;
+        }
+        memcpy(var, value, var_len);
+        var[var_len] = 0;
+        memcpy(val, esign+1, val_len);
+        val[val_len] = 0;
+
+        items[i].key = var;
+        items[i].value = val;
+    }
+
+    return items;
+
+fail:
+    for (e=0;e<i;e++) {
+        free((char *)items[e].key);
+        free((char *)items[e].value);
+    }
+    free(items);
+    return NULL;
+}
+
+static struct {
+    struct arg_str *service;
+    struct arg_str *proto;
+    struct arg_int *port;
+    struct arg_str *instance;
+    struct arg_str *txt;
+    struct arg_end *end;
+} mdns_add_args;
+
+static int cmd_mdns_service_add(int argc, char** argv)
+{
+    int nerrors = arg_parse(argc, argv, (void**) &mdns_add_args);
+    if (nerrors != 0) {
+        arg_print_errors(stderr, mdns_add_args.end, argv[0]);
+        return 1;
+    }
+
+    if (!mdns_add_args.service->sval[0] || !mdns_add_args.proto->sval[0] || !mdns_add_args.port->ival[0]) {
+        printf("ERROR: Bad arguments!\n");
+        return 1;
+    }
+    const char * instance = NULL;
+    if (mdns_add_args.instance->sval[0] && mdns_add_args.instance->sval[0][0]) {
+        instance = mdns_add_args.instance->sval[0];
+        printf("MDNS: Service Instance: %s\n", instance);
+    }
+    mdns_txt_item_t * items = NULL;
+    if (mdns_add_args.txt->count) {
+        items = _convert_items(mdns_add_args.txt->sval, mdns_add_args.txt->count);
+        if (!items) {
+            printf("ERROR: No Memory!\n");
+            return 1;
+
+        }
+    }
+
+    ESP_ERROR_CHECK( mdns_service_add(instance, mdns_add_args.service->sval[0], mdns_add_args.proto->sval[0], mdns_add_args.port->ival[0], items, mdns_add_args.txt->count) );
+    free(items);
+    return 0;
+}
+
+static void register_mdns_service_add()
+{
+    mdns_add_args.service = arg_str1(NULL, NULL, "<service>", "MDNS Service");
+    mdns_add_args.proto = arg_str1(NULL, NULL, "<proto>", "IP Protocol");
+    mdns_add_args.port = arg_int1(NULL, NULL, "<port>", "Service Port");
+    mdns_add_args.instance = arg_str0("i", "instance", "<instance>", "Instance name");
+    mdns_add_args.txt = arg_strn(NULL, NULL, "item", 0, 30, "TXT Items (name=value)");
+    mdns_add_args.end = arg_end(2);
+
+    const esp_console_cmd_t cmd_add = {
+        .command = "mdns_service_add",
+        .help = "Add service to MDNS",
+        .hint = NULL,
+        .func = &cmd_mdns_service_add,
+        .argtable = &mdns_add_args
+    };
+
+    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_add) );
+}
+
+static struct {
+    struct arg_str *service;
+    struct arg_str *proto;
+    struct arg_end *end;
+} mdns_remove_args;
+
+static int cmd_mdns_service_remove(int argc, char** argv)
+{
+    int nerrors = arg_parse(argc, argv, (void**) &mdns_remove_args);
+    if (nerrors != 0) {
+        arg_print_errors(stderr, mdns_remove_args.end, argv[0]);
+        return 1;
+    }
+
+    if (!mdns_remove_args.service->sval[0] || !mdns_remove_args.proto->sval[0]) {
+        printf("ERROR: Bad arguments!\n");
+        return 1;
+    }
+
+    ESP_ERROR_CHECK( mdns_service_remove(mdns_remove_args.service->sval[0], mdns_remove_args.proto->sval[0]) );
+    return 0;
+}
+
+static void register_mdns_service_remove()
+{
+    mdns_remove_args.service = arg_str1(NULL, NULL, "<service>", "MDNS Service");
+    mdns_remove_args.proto = arg_str1(NULL, NULL, "<proto>", "IP Protocol");
+    mdns_remove_args.end = arg_end(2);
+
+    const esp_console_cmd_t cmd_remove = {
+        .command = "mdns_service_remove",
+        .help = "Remove service from MDNS",
+        .hint = NULL,
+        .func = &cmd_mdns_service_remove,
+        .argtable = &mdns_remove_args
+    };
+
+    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_remove) );
+}
+
+static struct {
+    struct arg_str *service;
+    struct arg_str *proto;
+    struct arg_str *instance;
+    struct arg_end *end;
+} mdns_service_instance_set_args;
+
+static int cmd_mdns_service_instance_set(int argc, char** argv)
+{
+    int nerrors = arg_parse(argc, argv, (void**) &mdns_service_instance_set_args);
+    if (nerrors != 0) {
+        arg_print_errors(stderr, mdns_service_instance_set_args.end, argv[0]);
+        return 1;
+    }
+
+    if (!mdns_service_instance_set_args.service->sval[0] || !mdns_service_instance_set_args.proto->sval[0] || !mdns_service_instance_set_args.instance->sval[0]) {
+        printf("ERROR: Bad arguments!\n");
+        return 1;
+    }
+
+    ESP_ERROR_CHECK( mdns_service_instance_name_set(mdns_service_instance_set_args.service->sval[0], mdns_service_instance_set_args.proto->sval[0], mdns_service_instance_set_args.instance->sval[0]) );
+    return 0;
+}
+
+static void register_mdns_service_instance_set()
+{
+    mdns_service_instance_set_args.service = arg_str1(NULL, NULL, "<service>", "MDNS Service");
+    mdns_service_instance_set_args.proto = arg_str1(NULL, NULL, "<proto>", "IP Protocol");
+    mdns_service_instance_set_args.instance = arg_str1(NULL, NULL, "<instance>", "Instance name");
+    mdns_service_instance_set_args.end = arg_end(2);
+
+    const esp_console_cmd_t cmd_add = {
+        .command = "mdns_service_instance_set",
+        .help = "Set MDNS Service Instance Name",
+        .hint = NULL,
+        .func = &cmd_mdns_service_instance_set,
+        .argtable = &mdns_service_instance_set_args
+    };
+
+    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_add) );
+}
+
+static struct {
+    struct arg_str *service;
+    struct arg_str *proto;
+    struct arg_int *port;
+    struct arg_end *end;
+} mdns_service_port_set_args;
+
+static int cmd_mdns_service_port_set(int argc, char** argv) {
+    int nerrors = arg_parse(argc, argv, (void**) &mdns_service_port_set_args);
+    if (nerrors != 0) {
+        arg_print_errors(stderr, mdns_service_port_set_args.end, argv[0]);
+        return 1;
+    }
+
+    if (!mdns_service_port_set_args.service->sval[0] || !mdns_service_port_set_args.proto->sval[0] || !mdns_service_port_set_args.port->ival[0]) {
+        printf("ERROR: Bad arguments!\n");
+        return 1;
+    }
+
+    ESP_ERROR_CHECK( mdns_service_port_set(mdns_service_port_set_args.service->sval[0], mdns_service_port_set_args.proto->sval[0], mdns_service_port_set_args.port->ival[0]) );
+    return 0;
+}
+
+static void register_mdns_service_port_set()
+{
+    mdns_service_port_set_args.service = arg_str1(NULL, NULL, "<service>", "MDNS Service");
+    mdns_service_port_set_args.proto = arg_str1(NULL, NULL, "<proto>", "IP Protocol");
+    mdns_service_port_set_args.port = arg_int1(NULL, NULL, "<port>", "Service Port");
+    mdns_service_port_set_args.end = arg_end(2);
+
+    const esp_console_cmd_t cmd_add = {
+        .command = "mdns_service_port_set",
+        .help = "Set MDNS Service port",
+        .hint = NULL,
+        .func = &cmd_mdns_service_port_set,
+        .argtable = &mdns_service_port_set_args
+    };
+
+    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_add) );
+}
+
+static struct {
+    struct arg_str *service;
+    struct arg_str *proto;
+    struct arg_str *txt;
+    struct arg_end *end;
+} mdns_txt_replace_args;
+
+static int cmd_mdns_service_txt_replace(int argc, char** argv)
+{
+    mdns_txt_item_t * items = NULL;
+    int nerrors = arg_parse(argc, argv, (void**) &mdns_txt_replace_args);
+    if (nerrors != 0) {
+        arg_print_errors(stderr, mdns_txt_replace_args.end, argv[0]);
+        return 1;
+    }
+
+    if (!mdns_txt_replace_args.service->sval[0] || !mdns_txt_replace_args.proto->sval[0]) {
+        printf("ERROR: Bad arguments!\n");
+        return 1;
+    }
+
+    if (mdns_txt_replace_args.txt->count) {
+        items = _convert_items(mdns_txt_replace_args.txt->sval, mdns_txt_replace_args.txt->count);
+        if (!items) {
+            printf("ERROR: No Memory!\n");
+            return 1;
+
+        }
+    }
+    ESP_ERROR_CHECK( mdns_service_txt_set(mdns_txt_replace_args.service->sval[0], mdns_txt_replace_args.proto->sval[0], items, mdns_txt_replace_args.txt->count) );
+    free(items);
+    return 0;
+}
+
+static void register_mdns_service_txt_replace()
+{
+    mdns_txt_replace_args.service = arg_str1(NULL, NULL, "<service>", "MDNS Service");
+    mdns_txt_replace_args.proto = arg_str1(NULL, NULL, "<proto>", "IP Protocol");
+    mdns_txt_replace_args.txt = arg_strn(NULL, NULL, "item", 0, 30, "TXT Items (name=value)");
+    mdns_txt_replace_args.end = arg_end(2);
+
+    const esp_console_cmd_t cmd_txt_set = {
+        .command = "mdns_service_txt_replace",
+        .help = "Replace MDNS service TXT items",
+        .hint = NULL,
+        .func = &cmd_mdns_service_txt_replace,
+        .argtable = &mdns_txt_replace_args
+    };
+
+    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_txt_set) );
+}
+
+static struct {
+    struct arg_str *service;
+    struct arg_str *proto;
+    struct arg_str *var;
+    struct arg_str *value;
+    struct arg_end *end;
+} mdns_txt_set_args;
+
+static int cmd_mdns_service_txt_set(int argc, char** argv)
+{
+    int nerrors = arg_parse(argc, argv, (void**) &mdns_txt_set_args);
+    if (nerrors != 0) {
+        arg_print_errors(stderr, mdns_txt_set_args.end, argv[0]);
+        return 1;
+    }
+
+    if (!mdns_txt_set_args.service->sval[0] || !mdns_txt_set_args.proto->sval[0] || !mdns_txt_set_args.var->sval[0]) {
+        printf("ERROR: Bad arguments!\n");
+        return 1;
+    }
+
+    ESP_ERROR_CHECK( mdns_service_txt_item_set(mdns_txt_set_args.service->sval[0], mdns_txt_set_args.proto->sval[0], mdns_txt_set_args.var->sval[0], mdns_txt_set_args.value->sval[0]) );
+    return 0;
+}
+
+static void register_mdns_service_txt_set()
+{
+    mdns_txt_set_args.service = arg_str1(NULL, NULL, "<service>", "MDNS Service");
+    mdns_txt_set_args.proto = arg_str1(NULL, NULL, "<proto>", "IP Protocol");
+    mdns_txt_set_args.var = arg_str1(NULL, NULL, "<var>", "Item Name");
+    mdns_txt_set_args.value = arg_str1(NULL, NULL, "<value>", "Item Value");
+    mdns_txt_set_args.end = arg_end(2);
+
+    const esp_console_cmd_t cmd_txt_set = {
+        .command = "mdns_service_txt_set",
+        .help = "Add/Set MDNS service TXT item",
+        .hint = NULL,
+        .func = &cmd_mdns_service_txt_set,
+        .argtable = &mdns_txt_set_args
+    };
+
+    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_txt_set) );
+}
+
+static struct {
+    struct arg_str *service;
+    struct arg_str *proto;
+    struct arg_str *var;
+    struct arg_end *end;
+} mdns_txt_remove_args;
+
+static int cmd_mdns_service_txt_remove(int argc, char** argv)
+{
+    int nerrors = arg_parse(argc, argv, (void**) &mdns_txt_remove_args);
+    if (nerrors != 0) {
+        arg_print_errors(stderr, mdns_txt_remove_args.end, argv[0]);
+        return 1;
+    }
+
+    if (!mdns_txt_remove_args.service->sval[0] || !mdns_txt_remove_args.proto->sval[0] || !mdns_txt_remove_args.var->sval[0]) {
+        printf("ERROR: Bad arguments!\n");
+        return 1;
+    }
+
+    ESP_ERROR_CHECK( mdns_service_txt_item_remove(mdns_txt_remove_args.service->sval[0], mdns_txt_remove_args.proto->sval[0], mdns_txt_remove_args.var->sval[0]) );
+    return 0;
+}
+
+static void register_mdns_service_txt_remove()
+{
+    mdns_txt_remove_args.service = arg_str1(NULL, NULL, "<service>", "MDNS Service");
+    mdns_txt_remove_args.proto = arg_str1(NULL, NULL, "<proto>", "IP Protocol");
+    mdns_txt_remove_args.var = arg_str1(NULL, NULL, "<var>", "Item Name");
+    mdns_txt_remove_args.end = arg_end(2);
+
+    const esp_console_cmd_t cmd_txt_remove = {
+        .command = "mdns_service_txt_remove",
+        .help = "Remove MDNS service TXT item",
+        .hint = NULL,
+        .func = &cmd_mdns_service_txt_remove,
+        .argtable = &mdns_txt_remove_args
+    };
+
+    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_txt_remove) );
+}
+
+static int cmd_mdns_service_remove_all(int argc, char** argv)
+{
+    mdns_service_remove_all();
+    return 0;
+}
+
+static void register_mdns_service_remove_all()
+{
+    const esp_console_cmd_t cmd_free = {
+        .command = "mdns_service_remove_all",
+        .help = "Remove all MDNS services",
+        .hint = NULL,
+        .func = &cmd_mdns_service_remove_all,
+        .argtable = NULL
+    };
+
+    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_free) );
+}
+
+void mdns_console_register()
+{
+    register_mdns_init();
+    register_mdns_free();
+    register_mdns_set_hostname();
+    register_mdns_set_instance();
+    register_mdns_service_add();
+    register_mdns_service_remove();
+    register_mdns_service_instance_set();
+    register_mdns_service_port_set();
+    register_mdns_service_txt_replace();
+    register_mdns_service_txt_set();
+    register_mdns_service_txt_remove();
+    register_mdns_service_remove_all();
+
+    register_mdns_query_a();
+    register_mdns_query_aaaa();
+    register_mdns_query_txt();
+    register_mdns_query_srv();
+    register_mdns_query_ptr();
+
+    register_mdns_query_ip();
+    register_mdns_query_svc();
+}
+

+ 388 - 0
components/mdns/private_include/mdns_private.h

@@ -0,0 +1,388 @@
+// 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.
+#ifndef MDNS_PRIVATE_H_
+#define MDNS_PRIVATE_H_
+
+//#define MDNS_ENABLE_DEBUG
+
+#ifdef MDNS_ENABLE_DEBUG
+#define _mdns_dbg_printf(...) printf(__VA_ARGS__)
+#endif
+
+#define MDNS_ANSWER_PTR_TTL         4500
+#define MDNS_ANSWER_TXT_TTL         4500
+#define MDNS_ANSWER_SRV_TTL         120
+#define MDNS_ANSWER_A_TTL           120
+#define MDNS_ANSWER_AAAA_TTL        120
+
+#define MDNS_FLAGS_AUTHORITATIVE    0x8400
+#define MDNS_FLAGS_DISTRIBUTED      0x0200
+
+#define MDNS_NAME_REF               0xC000
+
+//custom type! only used by this implementation
+//to help manage service discovery handling
+#define MDNS_TYPE_SDPTR             0x0032
+
+#define MDNS_CLASS_IN               0x0001
+#define MDNS_CLASS_ANY              0x00FF
+#define MDNS_CLASS_IN_FLUSH_CACHE   0x8001
+
+#define MDNS_ANSWER_ALL             0x3F
+#define MDNS_ANSWER_PTR             0x08
+#define MDNS_ANSWER_TXT             0x04
+#define MDNS_ANSWER_SRV             0x02
+#define MDNS_ANSWER_A               0x01
+#define MDNS_ANSWER_AAAA            0x10
+#define MDNS_ANSWER_NSEC            0x20
+#define MDNS_ANSWER_SDPTR           0x80
+
+#define MDNS_SERVICE_PORT           5353                    // UDP port that the server runs on
+#define MDNS_SERVICE_STACK_DEPTH    4096                    // Stack size for the service thread
+#define MDNS_PACKET_QUEUE_LEN       16                      // Maximum packets that can be queued for parsing
+#define MDNS_ACTION_QUEUE_LEN       16                      // Maximum actions pending to the server
+#define MDNS_TXT_MAX_LEN            1024                    // Maximum string length of text data in TXT record
+#define MDNS_NAME_MAX_LEN           64                      // Maximum string length of hostname, instance, service and proto
+#define MDNS_NAME_BUF_LEN           (MDNS_NAME_MAX_LEN+1)   // Maximum char buffer size to hold hostname, instance, service or proto
+#define MDNS_MAX_PACKET_SIZE        1460                    // Maximum size of mDNS  outgoing packet
+
+#define MDNS_HEAD_LEN               12
+#define MDNS_HEAD_ID_OFFSET         0
+#define MDNS_HEAD_FLAGS_OFFSET      2
+#define MDNS_HEAD_QUESTIONS_OFFSET  4
+#define MDNS_HEAD_ANSWERS_OFFSET    6
+#define MDNS_HEAD_SERVERS_OFFSET    8
+#define MDNS_HEAD_ADDITIONAL_OFFSET 10
+
+#define MDNS_TYPE_OFFSET            0
+#define MDNS_CLASS_OFFSET           2
+#define MDNS_TTL_OFFSET             4
+#define MDNS_LEN_OFFSET             8
+#define MDNS_DATA_OFFSET            10
+
+#define MDNS_SRV_PRIORITY_OFFSET    0
+#define MDNS_SRV_WEIGHT_OFFSET      2
+#define MDNS_SRV_PORT_OFFSET        4
+#define MDNS_SRV_FQDN_OFFSET        6
+
+#define MDNS_TIMER_PERIOD_US        100000
+
+#define MDNS_SERVICE_LOCK()     xSemaphoreTake(_mdns_service_semaphore, portMAX_DELAY)
+#define MDNS_SERVICE_UNLOCK()   xSemaphoreGive(_mdns_service_semaphore)
+
+#define queueToEnd(type, queue, item)       \
+    if (!queue) {                           \
+        queue = item;                       \
+    } else {                                \
+        type * _q = queue;                  \
+        while (_q->next) { _q = _q->next; } \
+        _q->next = item;                    \
+    }
+
+#define queueDetach(type, queue, item)              \
+    if (queue) {                                    \
+        if (queue == item) {                        \
+            queue = queue->next;                    \
+        } else {                                    \
+            type * _q = queue;                      \
+            while (_q->next && _q->next != item) {  \
+                _q = _q->next;                      \
+            }                                       \
+            if (_q->next == item) {                 \
+                _q->next = item->next;              \
+                item->next = NULL;                  \
+            }                                       \
+        }                                           \
+    }
+
+#define queueFree(type, queue)  while (queue) { type * _q = queue; queue = queue->next; free(_q); }
+
+#define PCB_STATE_IS_PROBING(s) (s->state > PCB_OFF && s->state < PCB_ANNOUNCE_1)
+#define PCB_STATE_IS_ANNOUNCING(s) (s->state > PCB_PROBE_3 && s->state < PCB_RUNNING)
+#define PCB_STATE_IS_RUNNING(s) (s->state == PCB_RUNNING)
+
+#define MDNS_SEARCH_LOCK()      xSemaphoreTake(_mdns_server->search.lock, portMAX_DELAY)
+#define MDNS_SEARCH_UNLOCK()    xSemaphoreGive(_mdns_server->search.lock)
+
+
+typedef enum {
+    PCB_OFF, PCB_DUP, PCB_INIT,
+    PCB_PROBE_1, PCB_PROBE_2, PCB_PROBE_3,
+    PCB_ANNOUNCE_1, PCB_ANNOUNCE_2, PCB_ANNOUNCE_3,
+    PCB_RUNNING
+} mdns_pcb_state_t;
+
+typedef enum {
+    MDNS_ANSWER, MDNS_NS, MDNS_EXTRA
+} mdns_parsed_recort_type_t;
+
+typedef enum {
+    ACTION_SYSTEM_EVENT,
+    ACTION_HOSTNAME_SET,
+    ACTION_INSTANCE_SET,
+    ACTION_SERVICE_ADD,
+    ACTION_SERVICE_DEL,
+    ACTION_SERVICE_INSTANCE_SET,
+    ACTION_SERVICE_PORT_SET,
+    ACTION_SERVICE_TXT_REPLACE,
+    ACTION_SERVICE_TXT_SET,
+    ACTION_SERVICE_TXT_DEL,
+    ACTION_SERVICES_CLEAR,
+    ACTION_SEARCH_ADD,
+    ACTION_SEARCH_SEND,
+    ACTION_SEARCH_END,
+    ACTION_TX_HANDLE,
+    ACTION_RX_HANDLE,
+    ACTION_TASK_STOP,
+    ACTION_MAX
+} mdns_action_type_t;
+
+
+typedef struct {
+    uint16_t id;
+    union {
+        struct {
+            uint16_t qr :1;
+            uint16_t opCode :4;
+            uint16_t aa :1;
+            uint16_t tc :1;
+            uint16_t rd :1;
+            uint16_t ra :1;
+            uint16_t z :1;
+            uint16_t ad :1;
+            uint16_t cd :1;
+            uint16_t rCode :4;//response/error code
+        };
+        uint16_t value;
+    } flags;
+    uint16_t questions; //QDCOUNT
+    uint16_t answers;   //ANCOUNT
+    uint16_t servers;   //NSCOUNT
+    uint16_t additional;//ARCOUNT
+} mdns_header_t;
+
+typedef struct {
+    char host[MDNS_NAME_BUF_LEN];
+    char service[MDNS_NAME_BUF_LEN];
+    char proto[MDNS_NAME_BUF_LEN];
+    char domain[MDNS_NAME_BUF_LEN];
+    uint8_t parts;
+    uint8_t sub;
+} mdns_name_t;
+
+typedef struct mdns_parsed_question_s {
+    struct mdns_parsed_question_s * next;
+    uint16_t type;
+    bool unicast;
+    char * host;
+    char * service;
+    char * proto;
+    char * domain;
+} mdns_parsed_question_t;
+
+typedef struct mdns_parsed_record_s {
+    struct mdns_parsed_record_s * next;
+    mdns_parsed_recort_type_t record_type;
+    uint16_t type;
+    uint16_t clas;
+    uint8_t flush;
+    uint32_t ttl;
+    char * host;
+    char * service;
+    char * proto;
+    char * domain;
+    uint16_t data_len;
+    uint8_t *data;
+} mdns_parsed_record_t;
+
+typedef struct {
+    tcpip_adapter_if_t tcpip_if;
+    mdns_ip_protocol_t ip_protocol;
+    //struct udp_pcb *pcb;
+    ip_addr_t src;
+    uint16_t src_port;
+    uint8_t multicast;
+    uint8_t authoritative;
+    uint8_t probe;
+    uint8_t discovery;
+    uint8_t distributed;
+    mdns_parsed_question_t * questions;
+    mdns_parsed_record_t * records;
+} mdns_parsed_packet_t;
+
+typedef struct {
+    tcpip_adapter_if_t tcpip_if;
+    mdns_ip_protocol_t ip_protocol;
+    struct pbuf *pb;
+    ip_addr_t src;
+    ip_addr_t dest;
+    uint16_t src_port;
+    uint8_t multicast;
+} mdns_rx_packet_t;
+
+typedef struct mdns_txt_linked_item_s {
+    const char * key;                       /*!< item key name */
+    const char * value;                     /*!< item value string */
+    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 {
+    const char * instance;
+    const char * service;
+    const char * proto;
+    uint16_t priority;
+    uint16_t weight;
+    uint16_t port;
+    mdns_txt_linked_item_t * txt;
+} mdns_service_t;
+
+typedef struct mdns_srv_item_s {
+    struct mdns_srv_item_s * next;
+    mdns_service_t * service;
+} mdns_srv_item_t;
+
+typedef struct mdns_out_question_s {
+    struct mdns_out_question_s * next;
+    uint16_t type;
+    uint8_t unicast;
+    const char * host;
+    const char * service;
+    const char * proto;
+    const char * domain;
+} mdns_out_question_t;
+
+typedef struct mdns_out_answer_s {
+    struct mdns_out_answer_s * next;
+    uint16_t type;
+    uint8_t bye;
+    uint8_t flush;
+    mdns_service_t * service;
+    const char * custom_instance;
+    const char * custom_service;
+    const char * custom_proto;
+} mdns_out_answer_t;
+
+typedef struct mdns_tx_packet_s {
+    struct mdns_tx_packet_s * next;
+    uint32_t send_at;
+    tcpip_adapter_if_t tcpip_if;
+    mdns_ip_protocol_t ip_protocol;
+    ip_addr_t dst;
+    uint16_t port;
+    uint16_t flags;
+    uint8_t distributed;
+    mdns_out_question_t * questions;
+    mdns_out_answer_t * answers;
+    mdns_out_answer_t * servers;
+    mdns_out_answer_t * additional;
+} mdns_tx_packet_t;
+
+typedef struct {
+    mdns_pcb_state_t state;
+    struct udp_pcb * pcb;
+    mdns_srv_item_t ** probe_services;
+    uint8_t probe_services_len;
+    uint8_t probe_ip;
+    uint8_t probe_running;
+    uint16_t failed_probes;
+} mdns_pcb_t;
+
+typedef enum {
+    SEARCH_OFF,
+    SEARCH_INIT,
+    SEARCH_RUNNING,
+    SEARCH_MAX
+} mdns_search_once_state_t;
+
+typedef struct mdns_search_once_s {
+    struct mdns_search_once_s * next;
+
+    mdns_search_once_state_t state;
+    uint32_t started_at;
+    uint32_t sent_at;
+    uint32_t timeout;
+    SemaphoreHandle_t lock;
+    uint16_t type;
+    uint8_t max_results;
+    uint8_t num_results;
+    char * instance;
+    char * service;
+    char * proto;
+    mdns_result_t * result;
+} mdns_search_once_t;
+
+typedef struct mdns_server_s {
+    struct {
+        mdns_pcb_t pcbs[MDNS_IP_PROTOCOL_MAX];
+    } interfaces[TCPIP_ADAPTER_IF_MAX];
+    const char * hostname;
+    const char * instance;
+    mdns_srv_item_t * services;
+    SemaphoreHandle_t lock;
+    QueueHandle_t action_queue;
+    mdns_tx_packet_t * tx_queue_head;
+    mdns_search_once_t * search_once;
+    esp_timer_handle_t timer_handle;
+} mdns_server_t;
+
+typedef struct {
+    mdns_action_type_t type;
+    union {
+        char * hostname;
+        char * instance;
+        struct {
+            system_event_id_t event_id;
+            tcpip_adapter_if_t interface;
+        } sys_event;
+        struct {
+            mdns_srv_item_t * service;
+        } srv_add;
+        struct {
+            mdns_srv_item_t * service;
+        } srv_del;
+        struct {
+            mdns_srv_item_t * service;
+            char * instance;
+        } srv_instance;
+        struct {
+            mdns_srv_item_t * service;
+            uint16_t port;
+        } srv_port;
+        struct {
+            mdns_srv_item_t * service;
+            uint8_t num_items;
+            mdns_txt_item_t * txt;
+        } srv_txt_replace;
+        struct {
+            mdns_srv_item_t * service;
+            char * key;
+            char * value;
+        } srv_txt_set;
+        struct {
+            mdns_srv_item_t * service;
+            char * key;
+        } srv_txt_del;
+        struct {
+            mdns_search_once_t * search;
+        } search_add;
+        struct {
+            mdns_tx_packet_t * packet;
+        } tx_handle;
+        struct {
+            mdns_rx_packet_t * packet;
+        } rx_handle;
+    } data;
+} mdns_action_t;
+
+#endif /* MDNS_PRIVATE_H_ */

+ 12 - 0
components/tcpip_adapter/include/tcpip_adapter.h

@@ -603,6 +603,18 @@ esp_err_t tcpip_adapter_set_hostname(tcpip_adapter_if_t tcpip_if, const char *ho
  */
 esp_err_t tcpip_adapter_get_hostname(tcpip_adapter_if_t tcpip_if, const char **hostname);
 
+/**
+ * @brief  Get the LwIP netif* that is assigned to the interface
+ *
+ * @param[in]   tcpip_if: the interface which we will get the hostname
+ * @param[out]  void ** netif: pointer to fill the resulting interface
+ *
+ * @return ESP_OK:success
+ *         ESP_ERR_TCPIP_ADAPTER_IF_NOT_READY:interface status error
+ *         ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS:parameter error
+ */
+esp_err_t tcpip_adapter_get_netif(tcpip_adapter_if_t tcpip_if, void ** netif);
+
 #ifdef __cplusplus
 }
 #endif

+ 14 - 0
components/tcpip_adapter/tcpip_adapter_lwip.c

@@ -1181,4 +1181,18 @@ static esp_err_t tcpip_adapter_reset_ip_info(tcpip_adapter_if_t tcpip_if)
     return ESP_OK;
 }
 
+esp_err_t tcpip_adapter_get_netif(tcpip_adapter_if_t tcpip_if, void ** netif)
+{
+    if (tcpip_if >= TCPIP_ADAPTER_IF_MAX) {
+        return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS;
+    }
+
+    *netif = esp_netif[tcpip_if];
+
+    if (*netif == NULL) {
+        return ESP_ERR_TCPIP_ADAPTER_IF_NOT_READY;
+    }
+    return ESP_OK;
+}
+
 #endif /* CONFIG_TCPIP_LWIP */

+ 84 - 62
docs/api-reference/protocols/mdns.rst

@@ -20,21 +20,19 @@ Example method to start mDNS for the STA interface and set ``hostname`` and ``de
 
 ::
 
-    mdns_server_t * mdns = NULL;
-    
     void start_mdns_service()
     {
-        //initialize mDNS service on STA interface
-        esp_err_t err = mdns_init(TCPIP_ADAPTER_IF_STA, &mdns);
+        //initialize mDNS service
+        esp_err_t err = mdns_init();
         if (err) {
             printf("MDNS Init failed: %d\n", err);
             return;
         }
     
         //set hostname
-        mdns_set_hostname(mdns, "my-esp32");
+        mdns_hostname_set("my-esp32");
         //set default instance
-        mdns_set_instance(mdns, "Jhon's ESP32 Thing");
+        mdns_instance_name_set("Jhon's ESP32 Thing");
     }
 
 mDNS Services
@@ -42,36 +40,35 @@ mDNS Services
 
 mDNS can advertise information about network services that your device offers. Each service is defined by a few properties.
 
-    * ``service``: (required) service type, prepended with underscore. Some common types can be found `here <http://www.dns-sd.org/serviceTypes.html>`_.
+    * ``instance_name``: friendly name for your service, like ``Jhon's ESP32 Web Server``. If not defined, ``default_instance`` will be used.
+    * ``service_type``: (required) service type, prepended with underscore. Some common types can be found `here <http://www.dns-sd.org/serviceTypes.html>`_.
     * ``proto``: (required) protocol that the service runs on, prepended with underscore. Example: ``_tcp`` or ``_udp`` 
     * ``port``: (required) network port that the service runs on
-    * ``instance``: friendly name for your service, like ``Jhon's ESP32 Web Server``. If not defined, ``default_instance`` will be used.
-    * ``txt``: ``var=val`` array of strings, used to define properties for your service
+    * ``txt``: ``{var, val}`` array of strings, used to define properties for your service
 
 Example method to add a few services and different properties::
 
     void add_mdns_services()
     {
         //add our services
-        mdns_service_add(mdns, "_http", "_tcp", 80);
-        mdns_service_add(mdns, "_arduino", "_tcp", 3232);
-        mdns_service_add(mdns, "_myservice", "_udp", 1234);
+        mdns_service_add(NULL, "_http", "_tcp", 80, NULL, 0);
+        mdns_service_add(NULL, "_arduino", "_tcp", 3232, NULL, 0);
+        mdns_service_add(NULL, "_myservice", "_udp", 1234, NULL, 0);
         
         //NOTE: services must be added before their properties can be set
         //use custom instance for the web server
-        mdns_service_instance_set(mdns, "_http", "_tcp", "Jhon's ESP32 Web Server");
+        mdns_service_instance_name_set("_http", "_tcp", "Jhon's ESP32 Web Server");
 
-        const char * arduTxtData[4] = {
-                "board=esp32",
-                "tcp_check=no",
-                "ssh_upload=no",
-                "auth_upload=no"
+        mdns_txt_item_t serviceTxtData[3] = {
+            {"board","esp32"},
+            {"u","user"},
+            {"p","password"}
         };
         //set txt data for service (will free and replace current data)
-        mdns_service_txt_set(mdns, "_arduino", "_tcp", 4, arduTxtData);
+        mdns_service_txt_set("_http", "_tcp", serviceTxtData, 3);
         
         //change service port
-        mdns_service_port_set(mdns, "_myservice", "_udp", 4321);
+        mdns_service_port_set("_myservice", "_udp", 4321);
     }
 
 mDNS Query
@@ -79,60 +76,85 @@ mDNS Query
 
 mDNS provides methods for browsing for services and resolving host's IP/IPv6 addresses.
 
-Results are returned as a linked list of ``mdns_result_t`` objects. If the result is from host query, it will contain only ``addr`` and ``addrv6`` if found. Service queries will populate all fields in a result that were found.
+Results for services are returned as a linked list of ``mdns_result_t`` objects.
 
 Example method to resolve host IPs::
 
-    void resolve_mdns_host(const char * hostname)
+    void resolve_mdns_host(const char * host_name)
     {
-        printf("mDNS Host Lookup: %s.local\n", hostname);
-        //run search for 1000 ms
-        if (mdns_query(mdns, hostname, NULL, 1000)) {
-            //results were found
-            const mdns_result_t * results = mdns_result_get(mdns, 0);
-            //itterate through all results
-            size_t i = 1;
-            while(results) {
-                //print result information
-                printf("  %u: IP:" IPSTR ", IPv6:" IPV6STR "\n", i++
-                    IP2STR(&results->addr), IPV62STR(results->addrv6));
-                //load next result. Will be NULL if this was the last one
-                results = results->next;
+        printf("Query A: %s.local", host_name);
+
+        struct ip4_addr addr;
+        addr.addr = 0;
+
+        esp_err_t err = mdns_query_a(host_name, 2000,  &addr);
+        if(err){
+            if(err == ESP_ERR_NOT_FOUND){
+                printf("Host was not found!");
+                return;
             }
-            //free the results from memory
-            mdns_result_free(mdns);
-        } else {
-            //host was not found
-            printf("  Host Not Found\n");
+            printf("Query Failed");
+            return;
         }
+
+        printf(IPSTR, IP2STR(&addr));
     }
 
 Example method to resolve local services::
 
-    void find_mdns_service(const char * service, const char * proto)
-    {
-        printf("mDNS Service Lookup: %s.%s\n", service, proto);
-        //run search for 1000 ms
-        if (mdns_query(mdns, service, proto, 1000)) {
-            //results were found
-            const mdns_result_t * results = mdns_result_get(mdns, 0);
-            //itterate through all results
-            size_t i = 1;
-            while(results) {
-                //print result information
-                printf("  %u: hostname:%s, instance:\"%s\", IP:" IPSTR ", IPv6:" IPV6STR ", port:%u, txt:%s\n", i++,
-                    (results->host)?results->host:"NULL", (results->instance)?results->instance:"NULL",
-                    IP2STR(&results->addr), IPV62STR(results->addrv6),
-                    results->port, (results->txt)?results->txt:"\r");
-                //load next result. Will be NULL if this was the last one
-                results = results->next;
+    static const char * if_str[] = {"STA", "AP", "ETH", "MAX"};
+    static const char * ip_protocol_str[] = {"V4", "V6", "MAX"};
+
+    void mdns_print_results(mdns_result_t * results){
+        mdns_result_t * r = results;
+        mdns_ip_addr_t * a = NULL;
+        int i = 1, t;
+        while(r){
+            printf("%d: Interface: %s, Type: %s\n", i++, if_str[r->tcpip_if], ip_protocol_str[r->ip_protocol]);
+            if(r->instance_name){
+                printf("  PTR : %s\n", r->instance_name);
+            }
+            if(r->hostname){
+                printf("  SRV : %s.local:%u\n", r->hostname, r->port);
+            }
+            if(r->txt_count){
+                printf("  TXT : [%u] ", r->txt_count);
+                for(t=0; t<r->txt_count; t++){
+                    printf("%s=%s; ", r->txt[t].key, r->txt[t].value);
+                }
+                printf("\n");
             }
-            //free the results from memory
-            mdns_result_free(mdns);
-        } else {
-            //service was not found
-            printf("  Service Not Found\n");
+            a = r->addr;
+            while(a){
+                if(a->addr.type == MDNS_IP_PROTOCOL_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;
+            }
+            r = r->next;
         }
+
+    }
+
+    void find_mdns_service(const char * service_name, const char * proto)
+    {
+        ESP_LOGI(TAG, "Query PTR: %s.%s.local", service_name, proto);
+
+        mdns_result_t * results = NULL;
+        esp_err_t err = mdns_query_ptr(service_name, proto, 3000, 20,  &results);
+        if(err){
+            ESP_LOGE(TAG, "Query Failed");
+            return;
+        }
+        if(!results){
+            ESP_LOGW(TAG, "No results found!");
+            return;
+        }
+
+        mdns_print_results(results);
+        mdns_query_results_free(results);
     }
 
 Example of using the methods above::

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

@@ -2,4 +2,20 @@
 
 Shows how to use mDNS to advertise lookup services and hosts
 
+## Example workflow
+
+- mDNS is initialized with host name and instance name defined through `make menuconfig` and `_http._tcp` service is added to be advertised
+- WiFi STA is started and trying to connect to the access point defined through `make menuconfig`
+- 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
+- Example task is started to check if the button is pressed so it can execute the mDNS queries defined
+
+## Running the example
+
+- Run `make menuconfig` to configure the access point's SSID and Password and the default device mDNS host name and instance name
+- Run `make flash monitor` to build and upload the example to your board and connect to it's serial terminal
+- Wait for WiFi to connec to your access point
+- You can now ping the device at `[hostname].local` and browse for `_http._tcp` on the same network to find the advertised service
+- Pressing the BOOT button will start quring the local network for the predefined in `check_button` hosts and services
+
 See the README.md file in the upper level 'examples' directory for more information about examples.

+ 141 - 81
examples/protocols/mdns/main/mdns_example_main.c

@@ -16,6 +16,9 @@
 #include "esp_log.h"
 #include "nvs_flash.h"
 #include "mdns.h"
+#include "driver/gpio.h"
+#include <sys/socket.h>
+#include <netdb.h>
 
 /* The examples use simple WiFi configuration that you can set via
    'make menuconfig'.
@@ -35,9 +38,11 @@ static EventGroupHandle_t wifi_event_group;
 /* The event group allows multiple bits for each event,
    but we only care about one event - are we connected
    to the AP with an IP? */
-const int CONNECTED_BIT = BIT0;
+const int IP4_CONNECTED_BIT = BIT0;
+const int IP6_CONNECTED_BIT = BIT1;
 
 static const char *TAG = "mdns-test";
+static bool auto_reconnect = true;
 
 static esp_err_t event_handler(void *ctx, system_event_t *event)
 {
@@ -50,17 +55,23 @@ static esp_err_t event_handler(void *ctx, system_event_t *event)
         tcpip_adapter_create_ip6_linklocal(TCPIP_ADAPTER_IF_STA);
         break;
     case SYSTEM_EVENT_STA_GOT_IP:
-        xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
+        xEventGroupSetBits(wifi_event_group, IP4_CONNECTED_BIT);
+        break;
+    case SYSTEM_EVENT_AP_STA_GOT_IP6:
+        xEventGroupSetBits(wifi_event_group, IP6_CONNECTED_BIT);
         break;
     case SYSTEM_EVENT_STA_DISCONNECTED:
         /* This is a workaround as ESP32 WiFi libs don't currently
            auto-reassociate. */
-        esp_wifi_connect();
-        xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
+        if (auto_reconnect) {
+            esp_wifi_connect();
+        }
+        xEventGroupClearBits(wifi_event_group, IP4_CONNECTED_BIT | IP6_CONNECTED_BIT);
         break;
     default:
         break;
     }
+    mdns_handle_system_event(ctx, event);
     return ESP_OK;
 }
 
@@ -84,101 +95,150 @@ static void initialise_wifi(void)
     ESP_ERROR_CHECK( esp_wifi_start() );
 }
 
-static void query_mdns_service(mdns_server_t * mdns, const char * service, const char * proto)
+static void initialise_mdns(void)
 {
-    if(!mdns) {
-        return;
-    }
-    uint32_t res;
-    if (!proto) {
-        ESP_LOGI(TAG, "Host Lookup: %s", service);
-        res = mdns_query(mdns, service, 0, 1000);
-        if (res) {
-            size_t i;
-            for(i=0; i<res; i++) {
-                const mdns_result_t * r = mdns_result_get(mdns, i);
-                if (r) {
-                    ESP_LOGI(TAG, "  %u: " IPSTR " " IPV6STR, i+1, 
-                        IP2STR(&r->addr), IPV62STR(r->addrv6));
-                }
+    //initialize mDNS
+    ESP_ERROR_CHECK( mdns_init() );
+    //set mDNS hostname (required if you want to advertise services)
+    ESP_ERROR_CHECK( mdns_hostname_set(EXAMPLE_MDNS_HOSTNAME) );
+    //set default mDNS instance name
+    ESP_ERROR_CHECK( mdns_instance_name_set(EXAMPLE_MDNS_INSTANCE) );
+
+    //structure with TXT records
+    mdns_txt_item_t serviceTxtData[3] = {
+        {"board","esp32"},
+        {"u","user"},
+        {"p","password"}
+    };
+
+    //initialize service
+    ESP_ERROR_CHECK( mdns_service_add("ESP32-WebServer", "_http", "_tcp", 80, serviceTxtData, 3) );
+    //add another TXT item
+    ESP_ERROR_CHECK( mdns_service_txt_item_set("_http", "_tcp", "path", "/foobar") );
+    //change TXT item value
+    ESP_ERROR_CHECK( mdns_service_txt_item_set("_http", "_tcp", "u", "admin") );
+}
+
+static const char * if_str[] = {"STA", "AP", "ETH", "MAX"};
+static const char * ip_protocol_str[] = {"V4", "V6", "MAX"};
+
+static void mdns_print_results(mdns_result_t * results){
+    mdns_result_t * r = results;
+    mdns_ip_addr_t * a = NULL;
+    int i = 1, t;
+    while(r){
+        printf("%d: Interface: %s, Type: %s\n", i++, if_str[r->tcpip_if], ip_protocol_str[r->ip_protocol]);
+        if(r->instance_name){
+            printf("  PTR : %s\n", r->instance_name);
+        }
+        if(r->hostname){
+            printf("  SRV : %s.local:%u\n", r->hostname, r->port);
+        }
+        if(r->txt_count){
+            printf("  TXT : [%u] ", r->txt_count);
+            for(t=0; t<r->txt_count; t++){
+                printf("%s=%s; ", r->txt[t].key, r->txt[t].value);
             }
-            mdns_result_free(mdns);
-        } else {
-            ESP_LOGI(TAG, "  Not Found");
+            printf("\n");
         }
-    } else {
-        ESP_LOGI(TAG, "Service Lookup: %s.%s ", service, proto);
-        res = mdns_query(mdns, service, proto, 1000);
-        if (res) {
-            size_t i;
-            for(i=0; i<res; i++) {
-                const mdns_result_t * r = mdns_result_get(mdns, i);
-                if (r) {
-                    ESP_LOGI(TAG, "  %u: %s \"%s\" " IPSTR " " IPV6STR " %u %s", i+1, 
-                        (r->host)?r->host:"", (r->instance)?r->instance:"", 
-                        IP2STR(&r->addr), IPV62STR(r->addrv6),
-                        r->port, (r->txt)?r->txt:"");
-                }
+        a = r->addr;
+        while(a){
+            if(a->addr.type == MDNS_IP_PROTOCOL_V6){
+                printf("  AAAA: " IPV6STR "\n", IPV62STR(a->addr.u_addr.ip6));
+            } else {
+                printf("  A   : " IPSTR "\n", IP2STR(&(a->addr.u_addr.ip4)));
             }
-            mdns_result_free(mdns);
+            a = a->next;
         }
+        r = r->next;
     }
+
 }
 
-static void mdns_example_task(void *pvParameters)
+static void query_mdns_service(const char * service_name, const char * proto)
 {
-    mdns_server_t * mdns = NULL;
-    while(1) {
-        /* Wait for the callback to set the CONNECTED_BIT in the
-           event group.
-        */
-        xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT,
-                            false, true, portMAX_DELAY);
-        ESP_LOGI(TAG, "Connected to AP");
-
-        if (!mdns) {
-            esp_err_t err = mdns_init(TCPIP_ADAPTER_IF_STA, &mdns);
-            if (err) {
-                ESP_LOGE(TAG, "Failed starting MDNS: %u", err);
-                continue;
-            }
+    ESP_LOGI(TAG, "Query PTR: %s.%s.local", service_name, proto);
+
+    mdns_result_t * results = NULL;
+    esp_err_t err = mdns_query_ptr(service_name, proto, 3000, 20,  &results);
+    if(err){
+        ESP_LOGE(TAG, "Query Failed");
+        return;
+    }
+    if(!results){
+        ESP_LOGW(TAG, "No results found!");
+        return;
+    }
 
-            ESP_ERROR_CHECK( mdns_set_hostname(mdns, EXAMPLE_MDNS_HOSTNAME) );
-            ESP_ERROR_CHECK( mdns_set_instance(mdns, EXAMPLE_MDNS_INSTANCE) );
-
-            const char * arduTxtData[4] = {
-                "board=esp32",
-                "tcp_check=no",
-                "ssh_upload=no",
-                "auth_upload=no"
-            };
-
-            ESP_ERROR_CHECK( mdns_service_add(mdns, "_arduino", "_tcp", 3232) );
-            ESP_ERROR_CHECK( mdns_service_txt_set(mdns, "_arduino", "_tcp", 4, arduTxtData) );
-            ESP_ERROR_CHECK( mdns_service_add(mdns, "_http", "_tcp", 80) );
-            ESP_ERROR_CHECK( mdns_service_instance_set(mdns, "_http", "_tcp", "ESP32 WebServer") );
-            ESP_ERROR_CHECK( mdns_service_add(mdns, "_smb", "_tcp", 445) );
-        } else {
-            query_mdns_service(mdns, "esp32", NULL);
-            query_mdns_service(mdns, "_arduino", "_tcp");
-            query_mdns_service(mdns, "_http", "_tcp");
-            query_mdns_service(mdns, "_printer", "_tcp");
-            query_mdns_service(mdns, "_ipp", "_tcp");
-            query_mdns_service(mdns, "_afpovertcp", "_tcp");
-            query_mdns_service(mdns, "_smb", "_tcp");
-            query_mdns_service(mdns, "_ftp", "_tcp");
-            query_mdns_service(mdns, "_nfs", "_tcp");
+    mdns_print_results(results);
+    mdns_query_results_free(results);
+}
+
+static void query_mdns_host(const char * host_name)
+{
+    ESP_LOGI(TAG, "Query A: %s.local", host_name);
+
+    struct ip4_addr addr;
+    addr.addr = 0;
+
+    esp_err_t err = mdns_query_a(host_name, 2000,  &addr);
+    if(err){
+        if(err == ESP_ERR_NOT_FOUND){
+            ESP_LOGW(TAG, "Host was not found!");
+            return;
         }
+        ESP_LOGE(TAG, "Query Failed");
+        return;
+    }
 
-        ESP_LOGI(TAG, "Restarting in 10 seconds!");
-        vTaskDelay(10000 / portTICK_PERIOD_MS);
-        ESP_LOGI(TAG, "Starting again!");
+    ESP_LOGI(TAG, IPSTR, IP2STR(&addr));
+}
+
+static void initialise_button(void)
+{
+    gpio_config_t io_conf;
+    io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
+    io_conf.pin_bit_mask = 1;
+    io_conf.mode = GPIO_MODE_INPUT;
+    io_conf.pull_up_en = 1;
+    io_conf.pull_down_en = 0;
+    gpio_config(&io_conf);
+}
+
+static void check_button(void)
+{
+    static bool old_level = true;
+    bool new_level = gpio_get_level(GPIO_NUM_0);
+    if (!new_level && old_level) {
+        query_mdns_host("esp32");
+        query_mdns_service("_arduino", "_tcp");
+        query_mdns_service("_http", "_tcp");
+        query_mdns_service("_printer", "_tcp");
+        query_mdns_service("_ipp", "_tcp");
+        query_mdns_service("_afpovertcp", "_tcp");
+        query_mdns_service("_smb", "_tcp");
+        query_mdns_service("_ftp", "_tcp");
+        query_mdns_service("_nfs", "_tcp");
+    }
+    old_level = new_level;
+}
+
+static void mdns_example_task(void *pvParameters)
+{
+    /* Wait for the callback to set the CONNECTED_BIT in the event group. */
+    xEventGroupWaitBits(wifi_event_group, IP4_CONNECTED_BIT | IP6_CONNECTED_BIT,
+                     false, true, portMAX_DELAY);
+    while(1) {
+        check_button();
+        vTaskDelay(50 / portTICK_PERIOD_MS);
     }
 }
 
 void app_main()
 {
     ESP_ERROR_CHECK( nvs_flash_init() );
+    initialise_mdns();
     initialise_wifi();
+    initialise_button();
     xTaskCreate(&mdns_example_task, "mdns_example_task", 2048, NULL, 5, NULL);
 }

Някои файлове не бяха показани, защото твърде много файлове са промени