diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index 0d75836e88..8d336dabd3 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -2383,6 +2383,53 @@ static void _mdns_send_bye(mdns_srv_item_t **services, size_t len, bool include_ } } +/** + * @brief Send bye for particular subtype + */ +static void _mdns_send_bye_subtype(mdns_srv_item_t *service, const char *instance_name, mdns_subtype_t *remove_subtypes) +{ + uint8_t i, j; + for (i = 0; i < MDNS_MAX_INTERFACES; i++) { + for (j = 0; j < MDNS_IP_PROTOCOL_MAX; j++) { + if (mdns_is_netif_ready(i, j)) { + mdns_tx_packet_t *packet = _mdns_alloc_packet_default((mdns_if_t)i, (mdns_ip_protocol_t)j); + packet->flags = MDNS_FLAGS_QR_AUTHORITATIVE; + if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, service->service, NULL, true, true)) { + _mdns_free_tx_packet(packet); + return; + } + + static uint8_t pkt[MDNS_MAX_PACKET_SIZE]; + uint16_t index = MDNS_HEAD_LEN; + memset(pkt, 0, MDNS_HEAD_LEN); + mdns_out_answer_t *a; + uint8_t count; + + _mdns_set_u16(pkt, MDNS_HEAD_FLAGS_OFFSET, packet->flags); + _mdns_set_u16(pkt, MDNS_HEAD_ID_OFFSET, packet->id); + + count = 0; + a = packet->answers; + while (a) { + if (a->type == MDNS_TYPE_PTR && a->service) { + const mdns_subtype_t *current_subtype = remove_subtypes; + while (current_subtype) { + count += (_mdns_append_subtype_ptr_record(pkt, &index, instance_name, current_subtype->subtype, a->service->service, a->service->proto, a->flush, a->bye) > 0); + current_subtype = current_subtype->next; + } + } + a = a->next; + } + _mdns_set_u16(pkt, MDNS_HEAD_ANSWERS_OFFSET, count); + + _mdns_udp_pcb_write(packet->tcpip_if, packet->ip_protocol, &packet->dst, packet->port, pkt, index); + + _mdns_free_tx_packet(packet); + } + } + } +} + /** * @brief Send announcement on particular PCB */ @@ -2794,16 +2841,22 @@ static void _mdns_remove_scheduled_service_packets(mdns_service_t *service) } } -static void _mdns_free_service_subtype(mdns_service_t *service) +static void _mdns_free_subtype(mdns_subtype_t *subtype) { - while (service->subtype) { - mdns_subtype_t *next = service->subtype->next; - free((char *)service->subtype->subtype); - free(service->subtype); - service->subtype = next; + while (subtype) { + mdns_subtype_t *next = subtype->next; + free((char *)subtype->subtype); + free(subtype); + subtype = next; } } +static void _mdns_free_service_subtype(mdns_service_t *service) +{ + _mdns_free_subtype(service->subtype); + service->subtype = NULL; +} + /** * @brief free service memory * @@ -6347,11 +6400,23 @@ esp_err_t mdns_service_subtype_remove_for_host(const char *instance_name, const 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. + // Transmit a sendbye message for the removed subtype. + mdns_subtype_t *remove_subtypes = (mdns_subtype_t *)malloc(sizeof(mdns_subtype_t)); + ESP_GOTO_ON_FALSE(remove_subtypes, ESP_ERR_NO_MEM, out_of_mem, TAG, "Out of memory"); + remove_subtypes->subtype = strdup(subtype); + ESP_GOTO_ON_FALSE(remove_subtypes->subtype, ESP_ERR_NO_MEM, out_of_mem, TAG, "Out of memory"); + remove_subtypes->next = NULL; + + _mdns_send_bye_subtype(s, instance_name, remove_subtypes); + _mdns_free_subtype(remove_subtypes); err: MDNS_SERVICE_UNLOCK(); return ret; +out_of_mem: + HOOK_MALLOC_FAILED; + free(remove_subtypes); + MDNS_SERVICE_UNLOCK(); + return ret; } static esp_err_t _mdns_service_subtype_add_for_host(mdns_srv_item_t *service, const char *subtype) @@ -6423,6 +6488,55 @@ esp_err_t mdns_service_subtype_add_for_host(const char *instance_name, const cha return mdns_service_subtype_add_multiple_items_for_host(instance_name, service_type, proto, hostname, _subtype, 1); } +static void _mdns_service_drop_sendbye_subtype(mdns_subtype_t **srv_subtype, mdns_subtype_t **goodbye_subtype, + mdns_subtype_item_t subtype[], uint8_t num_items) +{ + if (!srv_subtype || !*srv_subtype || !goodbye_subtype) { + return; + } + + mdns_subtype_t *current = *srv_subtype; + mdns_subtype_t *prev = NULL; + mdns_subtype_t *prev_goodbye = NULL; + + *goodbye_subtype = NULL; + + while (current) { + bool subtype_in_update = false; + + for (int i = 0; i < num_items; i++) { + if (strcmp(subtype[i].subtype, current->subtype) == 0) { + subtype_in_update = true; + break; + } + } + + if (!subtype_in_update) { + // Remove from original list + if (prev) { + prev->next = current->next; + } else { + *srv_subtype = current->next; + } + + mdns_subtype_t *to_move = current; + current = current->next; + + // Add to goodbye list + to_move->next = NULL; + if (prev_goodbye) { + prev_goodbye->next = to_move; + } else { + *goodbye_subtype = to_move; + } + prev_goodbye = to_move; + } else { + prev = current; + current = current->next; + } + } +} + 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) { @@ -6435,7 +6549,14 @@ esp_err_t mdns_service_subtype_update_multiple_items_for_host(const char *instan 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_subtype_t *goodbye_subtype = NULL; + _mdns_service_drop_sendbye_subtype(&(s->service->subtype), &goodbye_subtype, subtype, num_items); + + if (goodbye_subtype){ + _mdns_send_bye_subtype(s, instance_name, goodbye_subtype); + } + + _mdns_free_subtype(goodbye_subtype); _mdns_free_service_subtype(s->service); for (; cur_index < num_items; cur_index++) {