Jelajahi Sumber

mdns: allow mutiple instances with same service type

Jiacheng Guo 4 tahun lalu
induk
melakukan
b7a99f4658

+ 6 - 0
components/mdns/Kconfig

@@ -84,4 +84,10 @@ menu "mDNS"
             This option creates a new thread to serve receiving packets (TODO).
             This option uses additional N sockets, where N is number of interfaces.
 
+    config MDNS_MULTIPLE_INSTANCE
+        bool "Multiple instances under the same service type"
+        default y
+        help
+            Enables adding multiple service instances under the same service type.
+
 endmenu

+ 23 - 1
components/mdns/include/mdns.h

@@ -187,7 +187,10 @@ esp_err_t mdns_instance_name_set(const char * instance_name);
  * @note The value length of txt items will be automatically decided by strlen
  *
  * @param  instance_name    instance name to set. If NULL,
- *                          global instance name or hostname will be used
+ *                          global instance name or hostname will be used.
+ *                          Note that MDNS_MULTIPLE_INSTANCE config option
+ *                          needs to be enabled for adding multiple instances
+ *                          with the same instance type.
  * @param  service_type     service type (_http, _ftp, etc)
  * @param  proto            service protocol (_tcp, _udp)
  * @param  port             service port
@@ -209,6 +212,9 @@ esp_err_t mdns_service_add(const char * instance_name, const char * service_type
  *
  * @param  instance_name    instance name to set. If NULL,
  *                          global instance name or hostname will be used
+ *                          Note that MDNS_MULTIPLE_INSTANCE config option
+ *                          needs to be enabled for adding multiple instances
+ *                          with the same instance type.
  * @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.
@@ -238,6 +244,22 @@ esp_err_t mdns_service_add_for_host(const char * instance_name, const char * ser
  */
 bool mdns_service_exists(const char * service_type, const char * proto, const char * hostname);
 
+
+/**
+ * @brief  Check whether a service has been added.
+ *
+ * @param  instance         instance name
+ * @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_with_instance(const char *instance, const char *service_type, const char *proto,
+                                       const char *hostname);
+
 /**
  * @brief  Remove service from mDNS server
  *

+ 65 - 8
components/mdns/mdns.c

@@ -231,23 +231,59 @@ esp_err_t _mdns_send_rx_action(mdns_rx_packet_t * packet)
     return ESP_OK;
 }
 
+static const char *_mdns_get_default_instance_name(void)
+{
+    if (_mdns_server && !_str_null_or_empty(_mdns_server->instance)) {
+        return _mdns_server->instance;
+    }
+
+    if (_mdns_server && !_str_null_or_empty(_mdns_server->hostname)) {
+        return _mdns_server->hostname;
+    }
+
+    return NULL;
+}
+
 /**
  * @brief  Get the service name of a service
  */
-static const char * _mdns_get_service_instance_name(mdns_service_t * service)
+static const char * _mdns_get_service_instance_name(const mdns_service_t * service)
 {
     if (service && !_str_null_or_empty(service->instance)) {
         return service->instance;
     }
 
-    if (_mdns_server && !_str_null_or_empty(_mdns_server->instance)) {
-        return _mdns_server->instance;
-    }
+    return _mdns_get_default_instance_name();
+}
 
-    if (_mdns_server && !_str_null_or_empty(_mdns_server->hostname)) {
-        return _mdns_server->hostname;
+static bool _mdns_instance_name_match(const char *lhs, const char *rhs)
+{
+    if (lhs == NULL) {
+        lhs = _mdns_get_default_instance_name();
+    }
+    if (rhs == NULL) {
+        rhs = _mdns_get_default_instance_name();
     }
+    return !strcasecmp(lhs, rhs);
+}
 
+static bool _mdns_service_match_instance(const mdns_service_t *srv, const char *instance, const char *service,
+                                         const char *proto, const char *hostname)
+{
+    return !strcasecmp(srv->service, service) && _mdns_instance_name_match(srv->instance, instance) &&
+        !strcasecmp(srv->proto, proto) && (_str_null_or_empty(hostname) || !strcasecmp(srv->hostname, hostname));
+}
+
+static mdns_srv_item_t *_mdns_get_service_item_instance(const char *instance, const char *service, const char *proto,
+                                                        const char *hostname)
+{
+    mdns_srv_item_t *s = _mdns_server->services;
+    while (s) {
+        if (_mdns_service_match_instance(s->service, instance, service, proto, hostname)) {
+            return s;
+        }
+        s = s->next;
+    }
     return NULL;
 }
 
@@ -1428,7 +1464,13 @@ static void _mdns_create_answer_from_parsed_packet(mdns_parsed_packet_t *parsed_
     mdns_parsed_question_t *q = parsed_packet->questions;
     while (q) {
         shared = q->type == MDNS_TYPE_PTR || q->type == MDNS_TYPE_SDPTR || !parsed_packet->probe;
-        if (q->service && q->proto) {
+        if (q->type == MDNS_TYPE_SRV || q->type == MDNS_TYPE_TXT) {
+            mdns_srv_item_t *service = _mdns_get_service_item_instance(q->host, q->service, q->proto, NULL);
+            if (!_mdns_create_answer_from_service(packet, service->service, q, shared, send_flush)) {
+                _mdns_free_tx_packet(packet);
+                return;
+            }
+        } else if (q->service && q->proto) {
             mdns_srv_item_t *service = _mdns_server->services;
             while (service) {
                 if (_mdns_service_match(service->service, q->service, q->proto, NULL)) {
@@ -2667,7 +2709,12 @@ static bool _mdns_name_is_ours(mdns_name_t * name)
     }
 
     //find the service
-    mdns_srv_item_t * service = _mdns_get_service_item(name->service, name->proto, NULL);
+    mdns_srv_item_t * service;
+    if (_str_null_or_empty(name->host)) {
+        service = _mdns_get_service_item(name->service, name->proto, NULL);
+    } else {
+        service = _mdns_get_service_item_instance(name->host, name->service, name->proto, NULL);
+    }
     if (!service) {
         return false;
     }
@@ -4948,7 +4995,11 @@ esp_err_t mdns_service_add_for_host(const char * instance, const char * service,
         return ESP_ERR_NO_MEM;
     }
 
+#if CONFIG_MDNS_MULTIPLE_INSTANCE
+    mdns_srv_item_t * item = _mdns_get_service_item_instance(instance, service, proto, hostname);
+#else
     mdns_srv_item_t * item = _mdns_get_service_item(service, proto, hostname);
+#endif // CONFIG_MDNS_MULTIPLE_INSTANCE
     if (item) {
         return ESP_ERR_INVALID_ARG;
     }
@@ -5011,6 +5062,12 @@ bool mdns_service_exists(const char * service_type, const char * proto, const ch
     return _mdns_get_service_item(service_type, proto, hostname) != NULL;
 }
 
+bool mdns_service_exists_with_instance(const char *instance, const char *service_type, const char *proto,
+                                       const char *hostname)
+{
+    return _mdns_get_service_item_instance(instance, service_type, proto, hostname) != NULL;
+}
+
 esp_err_t mdns_service_port_set_for_host(const char * service, const char * proto, const char * hostname, uint16_t port)
 {
     if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto) || !port) {

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

@@ -53,6 +53,9 @@ static void initialise_mdns(void)
 
     //initialize service
     ESP_ERROR_CHECK( mdns_service_add("ESP32-WebServer", "_http", "_tcp", 80, serviceTxtData, 3) );
+#if CONFIG_MDNS_MULTIPLE_INSTANCE
+    ESP_ERROR_CHECK( mdns_service_add("ESP32-WebServer1", "_http", "_tcp", 80, NULL, 0) );
+#endif
 
 #if CONFIG_MDNS_PUBLISH_DELEGATE_HOST
     char *delegated_hostname;