diff --git a/components/mdns/include/mdns.h b/components/mdns/include/mdns.h index ddb31feac5..c15ecb6221 100644 --- a/components/mdns/include/mdns.h +++ b/components/mdns/include/mdns.h @@ -60,6 +60,14 @@ typedef struct { const char *value; /*!< item value string */ } mdns_txt_item_t; +/** + * @brief mDNS basic subtype item structure + * Used in mdns_service_subtype_xxx() APIs + */ +typedef struct { + const char *subtype; /*!< subtype name */ +} mdns_subtype_item_t; + /** * @brief mDNS query linked list IP item */ @@ -544,7 +552,7 @@ esp_err_t mdns_service_txt_item_remove_for_host(const char *instance, const char const char *key); /** - * @brief Add subtype for service. + * @brief Add a subtype for service. * * @param instance_name instance name. If NULL, will find the first service with the same service type and protocol. * @param service_type service type (_http, _ftp, etc) @@ -561,6 +569,60 @@ esp_err_t mdns_service_txt_item_remove_for_host(const char *instance, const char esp_err_t mdns_service_subtype_add_for_host(const char *instance_name, const char *service_type, const char *proto, const char *hostname, const char *subtype); +/** + * @brief Remove a subtype for service. + * + * @param instance_name instance name. If NULL, will find the first service with the same service type and protocol. + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param hostname service hostname. If NULL, local hostname will be used. + * @param subtype The subtype to remove. + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NOT_FOUND Service not found + */ +esp_err_t mdns_service_subtype_remove_for_host(const char *instance_name, const char *service_type, const char *proto, + const char *hostname, const char *subtype); + +/** + * @brief Add multiple subtypes for service at once. + * + * @param instance_name instance name. If NULL, will find the first service with the same service type and protocol. + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param hostname service hostname. If NULL, local hostname will be used. + * @param subtype the pointer of subtype array to add. + * @param num_items number of items in subtype array + * + * @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_subtype_add_multiple_items_for_host(const char *instance_name, const char *service_type, const char *proto, + const char *hostname, mdns_subtype_item_t subtype[], uint8_t num_items); + +/** + * @brief Update subtype for service. + * + * @param instance_name instance name. If NULL, will find the first service with the same service type and protocol. + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param hostname service hostname. If NULL, local hostname will be used. + * @param subtype the pointer of subtype array to add. + * @param num_items number of items in subtype array + * + * @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_subtype_update_multiple_items_for_host(const char *instance_name, const char *service_type, const char *proto, + const char *hostname, mdns_subtype_item_t subtype[], uint8_t num_items); /** * @brief Remove and free all services from mDNS server * diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index 6efff05b1d..113a1e999b 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -2794,6 +2794,16 @@ static void _mdns_remove_scheduled_service_packets(mdns_service_t *service) } } +static void _mdns_free_service_subtype(mdns_service_t *service) +{ + while (service->subtype) { + mdns_subtype_t *next = service->subtype->next; + free((char *)service->subtype->subtype); + free(service->subtype); + service->subtype = next; + } +} + /** * @brief free service memory * @@ -2815,12 +2825,7 @@ static void _mdns_free_service(mdns_service_t *service) free((char *)s->value); free(s); } - while (service->subtype) { - mdns_subtype_t *next = service->subtype->next; - free((char *)service->subtype->subtype); - free(service->subtype); - service->subtype = next; - } + _mdns_free_service_subtype(service); free(service); } @@ -6299,7 +6304,36 @@ esp_err_t mdns_service_txt_item_remove(const char *service, const char *proto, c return mdns_service_txt_item_remove_for_host(NULL, service, proto, NULL, key); } -esp_err_t mdns_service_subtype_add_for_host(const char *instance_name, const char *service, const char *proto, +static esp_err_t _mdns_service_subtype_remove_for_host(mdns_srv_item_t *service, const char *subtype) +{ + esp_err_t ret = ESP_ERR_NOT_FOUND; + mdns_subtype_t *srv_subtype = service->service->subtype; + mdns_subtype_t *pre = service->service->subtype; + while (srv_subtype) { + if (strcmp(srv_subtype->subtype, subtype) == 0) { + // Target subtype is found. + if (srv_subtype == service->service->subtype) { + // The first node needs to be removed + service->service->subtype = service->service->subtype->next; + } else { + pre->next = srv_subtype->next; + } + free((char *)srv_subtype->subtype); + free(srv_subtype); + ret = ESP_OK; + break; + } + pre = srv_subtype; + srv_subtype = srv_subtype->next; + } + if (ret == ESP_ERR_NOT_FOUND) { + ESP_LOGE(TAG, "Subtype : %s doesn't exist", subtype); + } + + return ret; +} + +esp_err_t mdns_service_subtype_remove_for_host(const char *instance_name, const char *service, const char *proto, const char *hostname, const char *subtype) { MDNS_SERVICE_LOCK(); @@ -6310,30 +6344,125 @@ esp_err_t mdns_service_subtype_add_for_host(const char *instance_name, const cha mdns_srv_item_t *s = _mdns_get_service_item_instance(instance_name, service, proto, hostname); ESP_GOTO_ON_FALSE(s, ESP_ERR_NOT_FOUND, err, TAG, "Service doesn't exist"); - mdns_subtype_t *srv_subtype = s->service->subtype; + ret = _mdns_service_subtype_remove_for_host(s, subtype); + ESP_GOTO_ON_ERROR(ret, err, TAG, "Failed to remove the subtype: %s", subtype); + + // TODO: Need to transmit a sendbye message for the removed subtype. + // TODO: Need to remove this subtype answer from the scheduled answer list. +err: + MDNS_SERVICE_UNLOCK(); + return ret; +} + +static esp_err_t _mdns_service_subtype_add_for_host(mdns_srv_item_t *service, const char *subtype) +{ + esp_err_t ret = ESP_OK; + mdns_subtype_t *srv_subtype = service->service->subtype; while (srv_subtype) { - ESP_GOTO_ON_FALSE(strcmp(srv_subtype->subtype, subtype) != 0, ESP_ERR_INVALID_ARG, err, TAG, "The same subtype has already been added"); + ESP_GOTO_ON_FALSE(strcmp(srv_subtype->subtype, subtype) != 0, ESP_ERR_INVALID_ARG, err, TAG, "Subtype: %s has already been added", subtype); srv_subtype = srv_subtype->next; } - mdns_service_t *srv = s->service; mdns_subtype_t *subtype_item = (mdns_subtype_t *)malloc(sizeof(mdns_subtype_t)); ESP_GOTO_ON_FALSE(subtype_item, ESP_ERR_NO_MEM, out_of_mem, TAG, "Out of memory"); subtype_item->subtype = strdup(subtype); ESP_GOTO_ON_FALSE(subtype_item->subtype, ESP_ERR_NO_MEM, out_of_mem, TAG, "Out of memory"); - subtype_item->next = srv->subtype; - srv->subtype = subtype_item; + subtype_item->next = service->service->subtype; + service->service->subtype = subtype_item; err: - MDNS_SERVICE_UNLOCK(); return ret; out_of_mem: - MDNS_SERVICE_UNLOCK(); HOOK_MALLOC_FAILED; free(subtype_item); return ret; } +esp_err_t mdns_service_subtype_add_multiple_items_for_host(const char *instance_name, const char *service, const char *proto, + const char *hostname, mdns_subtype_item_t subtype[], uint8_t num_items) +{ + MDNS_SERVICE_LOCK(); + esp_err_t ret = ESP_OK; + int cur_index = 0; + ESP_GOTO_ON_FALSE(_mdns_server && _mdns_server->services && !_str_null_or_empty(service) && !_str_null_or_empty(proto) && + (num_items > 0), ESP_ERR_INVALID_ARG, err, TAG, "Invalid state or arguments"); + + mdns_srv_item_t *s = _mdns_get_service_item_instance(instance_name, service, proto, hostname); + ESP_GOTO_ON_FALSE(s, ESP_ERR_NOT_FOUND, err, TAG, "Service doesn't exist"); + + for (; cur_index < num_items; cur_index++) { + ret = _mdns_service_subtype_add_for_host(s, subtype[cur_index].subtype); + if (ret == ESP_OK) { + continue; + } else if (ret == ESP_ERR_NO_MEM) { + ESP_LOGE(TAG, "Out of memory"); + goto err; + } else { + ESP_LOGE(TAG, "Failed to add subtype: %s", subtype[cur_index].subtype); + goto exit; + } + } + + _mdns_announce_all_pcbs(&s, 1, false); +err: + if (ret == ESP_ERR_NO_MEM) { + for (int idx = 0; idx < cur_index; idx++) { + _mdns_service_subtype_remove_for_host(s, subtype[idx].subtype); + } + } +exit: + MDNS_SERVICE_UNLOCK(); + return ret; +} + +esp_err_t mdns_service_subtype_add_for_host(const char *instance_name, const char *service_type, const char *proto, + const char *hostname, const char *subtype) +{ + mdns_subtype_item_t _subtype[1]; + _subtype[0].subtype = subtype; + return mdns_service_subtype_add_multiple_items_for_host(instance_name, service_type, proto, hostname, _subtype, 1); +} + +esp_err_t mdns_service_subtype_update_multiple_items_for_host(const char *instance_name, const char *service_type, const char *proto, + const char *hostname, mdns_subtype_item_t subtype[], uint8_t num_items) +{ + MDNS_SERVICE_LOCK(); + esp_err_t ret = ESP_OK; + int cur_index = 0; + ESP_GOTO_ON_FALSE(_mdns_server && _mdns_server->services && !_str_null_or_empty(service_type) && !_str_null_or_empty(proto) && + (num_items > 0), ESP_ERR_INVALID_ARG, err, TAG, "Invalid state or arguments"); + + mdns_srv_item_t *s = _mdns_get_service_item_instance(instance_name, service_type, proto, hostname); + ESP_GOTO_ON_FALSE(s, ESP_ERR_NOT_FOUND, err, TAG, "Service doesn't exist"); + + // TODO: find subtype needs to say sendbye + _mdns_free_service_subtype(s->service); + + for (; cur_index < num_items; cur_index++) { + ret = _mdns_service_subtype_add_for_host(s, subtype[cur_index].subtype); + if (ret == ESP_OK) { + continue; + } else if (ret == ESP_ERR_NO_MEM) { + ESP_LOGE(TAG, "Out of memory"); + goto err; + } else { + ESP_LOGE(TAG, "Failed to add subtype: %s", subtype[cur_index].subtype); + goto exit; + } + } + + _mdns_announce_all_pcbs(&s, 1, false); +err: + if (ret == ESP_ERR_NO_MEM) { + for (int idx = 0; idx < cur_index; idx++) { + _mdns_service_subtype_remove_for_host(s, subtype[idx].subtype); + } + } +exit: + MDNS_SERVICE_UNLOCK(); + return ret; +} + esp_err_t mdns_service_instance_name_set_for_host(const char *instance_old, const char *service, const char *proto, const char *host, const char *instance) {