From b7a99f46587a69a2cd07e7616c3bb30b7b1a6edf Mon Sep 17 00:00:00 2001 From: Jiacheng Guo Date: Mon, 13 Sep 2021 19:33:02 +0800 Subject: [PATCH] mdns: allow mutiple instances with same service type --- components/mdns/Kconfig | 6 ++ components/mdns/include/mdns.h | 24 +++++- components/mdns/mdns.c | 77 ++++++++++++++++--- .../protocols/mdns/main/mdns_example_main.c | 3 + 4 files changed, 99 insertions(+), 11 deletions(-) diff --git a/components/mdns/Kconfig b/components/mdns/Kconfig index b49ae703c7..5607afac84 100644 --- a/components/mdns/Kconfig +++ b/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 diff --git a/components/mdns/include/mdns.h b/components/mdns/include/mdns.h index 4bb288d417..35c8d538ab 100644 --- a/components/mdns/include/mdns.h +++ b/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 * diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index 417b01fe0f..048e0e51fa 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -231,15 +231,8 @@ esp_err_t _mdns_send_rx_action(mdns_rx_packet_t * packet) return ESP_OK; } -/** - * @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_default_instance_name(void) { - 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; } @@ -251,6 +244,49 @@ static const char * _mdns_get_service_instance_name(mdns_service_t * service) return NULL; } +/** + * @brief Get the service name of a 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; + } + + return _mdns_get_default_instance_name(); +} + +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; +} + /** * @brief reads MDNS FQDN into mdns_name_t structure * FQDN is in format: [hostname.|[instance.]_service._proto.]local. @@ -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) { diff --git a/examples/protocols/mdns/main/mdns_example_main.c b/examples/protocols/mdns/main/mdns_example_main.c index d442ece4e6..ad347ddb25 100644 --- a/examples/protocols/mdns/main/mdns_example_main.c +++ b/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;