diff --git a/components/mdns/include/mdns.h b/components/mdns/include/mdns.h index 416740d137..29c22b022a 100644 --- a/components/mdns/include/mdns.h +++ b/components/mdns/include/mdns.h @@ -79,6 +79,7 @@ typedef struct mdns_result_s { uint16_t port; /*!< service port */ // TXT mdns_txt_item_t * txt; /*!< txt record */ + uint8_t *txt_value_len; /*!< array of txt value len of each record */ size_t txt_count; /*!< number of txt items */ // A and AAAA mdns_ip_addr_t * addr; /*!< linked list of IP addresses found */ @@ -173,6 +174,8 @@ esp_err_t mdns_instance_name_set(const char * instance_name); /** * @brief Add service to mDNS server * + * @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 * @param service_type service type (_http, _ftp, etc) @@ -189,10 +192,11 @@ esp_err_t mdns_instance_name_set(const char * instance_name); */ 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 Add service to mDNS server with a delegated hostname * + * @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 * @param service_type service type (_http, _ftp, etc) @@ -321,6 +325,8 @@ esp_err_t mdns_service_port_set_for_host(const char * service_type, const char * /** * @brief Replace all TXT items for service * + * @note The value length of txt items will be automatically decided by strlen + * * @param service_type service type (_http, _ftp, etc) * @param proto service protocol (_tcp, _udp) * @param txt array of TXT data (eg. {{"var","val"},{"other","2"}}) @@ -337,6 +343,8 @@ esp_err_t mdns_service_txt_set(const char * service_type, const char * proto, md /** * @brief Replace all TXT items for service with hostname * + * @note The value length of txt items will be automatically decided by strlen + * * @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. @@ -355,6 +363,8 @@ esp_err_t mdns_service_txt_set_for_host(const char * service_type, const char * /** * @brief Set/Add TXT item for service TXT record * + * @note The value length will be automatically decided by strlen + * * @param service_type service type (_http, _ftp, etc) * @param proto service protocol (_tcp, _udp) * @param key the key that you want to add/update @@ -368,10 +378,29 @@ esp_err_t mdns_service_txt_set_for_host(const char * service_type, const char * */ esp_err_t mdns_service_txt_item_set(const char * service_type, const char * proto, const char * key, const char * value); +/** + * @brief Set/Add TXT item for service TXT record + * + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param key the key that you want to add/update + * @param value the new value of the key + * @param value_len the length of the value + * + * @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_set_with_explicit_value_len(const char *service_type, const char *proto, + const char *key, const char *value, uint8_t value_len); /** * @brief Set/Add TXT item for service TXT record with hostname * + * @note The value length will be automatically decided by strlen + * * @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. @@ -387,6 +416,26 @@ esp_err_t mdns_service_txt_item_set(const char * service_type, const char * prot esp_err_t mdns_service_txt_item_set_for_host(const char * service_type, const char * proto, const char * hostname, const char * key, const char * value); +/** + * @brief Set/Add TXT item for service TXT record with hostname and txt value length + * + * @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 key the key that you want to add/update + * @param value the new value of the key + * @param value_len the length of the value + * + * @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_set_for_host_with_explicit_value_len(const char *service_type, const char *proto, + const char *hostname, const char *key, + const char *value, uint8_t value_len); + /** * @brief Remove TXT item for service TXT record * diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index 1858859ba4..04396f2578 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -43,7 +43,7 @@ static void _mdns_search_finish_done(void); static mdns_search_once_t * _mdns_search_find_from(mdns_search_once_t * search, mdns_name_t * name, uint16_t type, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol); static void _mdns_search_result_add_ip(mdns_search_once_t * search, const char * hostname, esp_ip_addr_t * ip, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol); static void _mdns_search_result_add_srv(mdns_search_once_t * search, const char * hostname, uint16_t port, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol); -static void _mdns_search_result_add_txt(mdns_search_once_t * search, mdns_txt_item_t * txt, size_t txt_count, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol); +static void _mdns_search_result_add_txt(mdns_search_once_t * search, mdns_txt_item_t * txt, uint8_t *txt_value_len, size_t txt_count, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol); static mdns_result_t * _mdns_search_result_add_ptr(mdns_search_once_t * search, const char * instance, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol); static bool _mdns_append_host_list_in_services(mdns_out_answer_t ** destination, mdns_srv_item_t * services[], size_t services_len, bool flush, bool bye); static bool _mdns_append_host_list(mdns_out_answer_t ** destination, bool flush, bool bye); @@ -418,6 +418,17 @@ static inline uint8_t _mdns_append_type(uint8_t * packet, uint16_t * index, uint return 10; } +static inline uint8_t _mdns_append_string_with_len(uint8_t * packet, uint16_t * index, const char * string, uint8_t len) +{ + if ((*index + len + 1) >= MDNS_MAX_PACKET_SIZE) { + return 0; + } + _mdns_append_u8(packet, index, len); + memcpy(packet + *index, string, len); + *index += len; + return len + 1; +} + /** * @brief appends single string to a packet, incrementing the index * @@ -656,10 +667,12 @@ static uint16_t _mdns_append_txt_record(uint8_t * packet, uint16_t * index, mdns char * tmp; mdns_txt_linked_item_t * txt = service->txt; while (txt) { - tmp = (char *)malloc(2 + strlen(txt->key) + strlen(txt->value)); + uint8_t txt_data_len = strlen(txt->key) + txt->value_len + 1; + tmp = (char *)malloc(txt_data_len); if (tmp) { - sprintf(tmp, "%s=%s", txt->key, txt->value); - uint8_t l = _mdns_append_string(packet, index, tmp); + int offset = sprintf(tmp, "%s=", txt->key); + memcpy(tmp + offset, txt->value, txt->value_len); + uint8_t l = _mdns_append_string_with_len(packet, index, tmp, txt_data_len); free(tmp); if (!l) { return 0; @@ -2072,6 +2085,7 @@ static mdns_txt_linked_item_t * _mdns_allocate_txt(size_t num_items, mdns_txt_it free(new_item); break; } + new_item->value_len = strlen(new_item->value); new_item->next = new_txt; new_txt = new_item; } @@ -2842,7 +2856,8 @@ static int _mdns_txt_item_name_get_len(const uint8_t * data, size_t len) /** * @brief Create TXT result array from parsed TXT data */ -static void _mdns_result_txt_create(const uint8_t * data, size_t len, mdns_txt_item_t ** out_txt, size_t * out_count) +static void _mdns_result_txt_create(const uint8_t *data, size_t len, mdns_txt_item_t **out_txt, uint8_t **out_value_len, + size_t *out_count) { *out_txt = NULL; *out_count = 0; @@ -2862,7 +2877,14 @@ static void _mdns_result_txt_create(const uint8_t * data, size_t len, mdns_txt_i HOOK_MALLOC_FAILED; return; } + uint8_t * txt_value_len = (uint8_t *)malloc(num_items); + if (!txt_value_len) { + free(txt); + HOOK_MALLOC_FAILED; + return; + } memset(txt, 0, sizeof(mdns_txt_item_t) * num_items); + memset(txt_value_len, 0, num_items); size_t txt_num = 0; while (i < len) { @@ -2886,29 +2908,33 @@ static void _mdns_result_txt_create(const uint8_t * data, size_t len, mdns_txt_i goto handle_error;//error } - mdns_txt_item_t * t = &txt[txt_num++]; + mdns_txt_item_t * t = &txt[txt_num]; + uint8_t * value_len = &txt_value_len[txt_num]; + txt_num++; memcpy(key, data + i, name_len); key[name_len] = 0; i += name_len + 1; t->key = key; - int value_len = partLen - name_len - 1; - if (value_len > 0) { - char * value = (char *)malloc(value_len + 1); + int new_value_len = partLen - name_len - 1; + if (new_value_len > 0) { + char * value = (char *)malloc(new_value_len + 1); if (!value) { HOOK_MALLOC_FAILED; goto handle_error;//error } - memcpy(value, data + i, value_len); - value[value_len] = 0; - i += value_len; + memcpy(value, data + i, new_value_len); + value[new_value_len] = 0; + *value_len = new_value_len; + i += new_value_len; t->value = value; } } *out_txt = txt; *out_count = txt_num; + *out_value_len = txt_value_len; return; handle_error : @@ -2917,6 +2943,7 @@ handle_error : free((char *)t->key); free((char *)t->value); } + free(txt_value_len); free(txt); } @@ -3246,6 +3273,7 @@ void mdns_parse_packet(mdns_rx_packet_t * packet) } else if (type == MDNS_TYPE_TXT) { if (search_result) { mdns_txt_item_t * txt = NULL; + uint8_t *txt_value_len = NULL; size_t txt_count = 0; mdns_result_t * result = NULL; @@ -3266,16 +3294,17 @@ void mdns_parse_packet(mdns_rx_packet_t * packet) } } if (!result->txt) { - _mdns_result_txt_create(data_ptr, data_len, &txt, &txt_count); + _mdns_result_txt_create(data_ptr, data_len, &txt, &txt_value_len, &txt_count); if (txt_count) { result->txt = txt; result->txt_count = txt_count; + result->txt_value_len = txt_value_len; } } } else { - _mdns_result_txt_create(data_ptr, data_len, &txt, &txt_count); + _mdns_result_txt_create(data_ptr, data_len, &txt, &txt_value_len, &txt_count); if (txt_count) { - _mdns_search_result_add_txt(search_result, txt, txt_count, packet->tcpip_if, packet->ip_protocol); + _mdns_search_result_add_txt(search_result, txt, txt_value_len, txt_count, packet->tcpip_if, packet->ip_protocol); } } } else if (ours) { @@ -3824,7 +3853,7 @@ static void _mdns_search_result_add_srv(mdns_search_once_t * search, const char /** * @brief Called from parser to add TXT data to search result */ -static void _mdns_search_result_add_txt(mdns_search_once_t * search, mdns_txt_item_t * txt, size_t txt_count, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) +static void _mdns_search_result_add_txt(mdns_search_once_t * search, mdns_txt_item_t * txt, uint8_t *txt_value_len, size_t txt_count, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) { mdns_result_t * r = search->result; while (r) { @@ -3833,6 +3862,7 @@ static void _mdns_search_result_add_txt(mdns_search_once_t * search, mdns_txt_it goto free_txt; } r->txt = txt; + r->txt_value_len = txt_value_len; r->txt_count = txt_count; return; } @@ -3847,6 +3877,7 @@ static void _mdns_search_result_add_txt(mdns_search_once_t * search, mdns_txt_it memset(r, 0 , sizeof(mdns_result_t)); r->txt = txt; + r->txt_value_len = txt_value_len; r->txt_count = txt_count; r->tcpip_if = tcpip_if; r->ip_protocol = ip_protocol; @@ -4225,6 +4256,7 @@ static void _mdns_execute_action(mdns_action_t * action) free((char *)txt->value); free(key); txt->value = value; + txt->value_len = action->data.srv_txt_set.value_len; break; } txt = txt->next; @@ -4238,6 +4270,7 @@ static void _mdns_execute_action(mdns_action_t * action) } txt->key = key; txt->value = value; + txt->value_len = action->data.srv_txt_set.value_len; txt->next = service->txt; service->txt = txt; } @@ -4860,8 +4893,8 @@ esp_err_t mdns_instance_name_set(const char * instance) * MDNS SERVICES * */ -esp_err_t mdns_service_add_for_host(const char * instance, const char * service, const char * proto, - const char * hostname, uint16_t port, mdns_txt_item_t txt[], size_t num_items) +esp_err_t mdns_service_add_for_host(const char * instance, const char * service, const char * proto, const char * hostname, + uint16_t port, mdns_txt_item_t txt[], size_t num_items) { if (!_mdns_server || _str_null_or_empty(service) || _str_null_or_empty(proto) || _str_null_or_empty(hostname) || !port) { @@ -5013,17 +5046,19 @@ esp_err_t mdns_service_txt_set(const char * service, const char * proto, mdns_tx return mdns_service_txt_set_for_host(service, proto, _mdns_server->hostname, txt, num_items); } -esp_err_t mdns_service_txt_item_set_for_host(const char * service, const char * proto, const char * hostname, - const char * key, const char * value) +esp_err_t mdns_service_txt_item_set_for_host_with_explicit_value_len(const char *service, const char *proto, + const char *hostname, const char *key, + const char *value, uint8_t value_len) { - if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto) || _str_null_or_empty(key) || !value) { + if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto) || + _str_null_or_empty(key) || !value) { return ESP_ERR_INVALID_ARG; } - mdns_srv_item_t * s = _mdns_get_service_item(service, proto, hostname); + mdns_srv_item_t *s = _mdns_get_service_item(service, proto, hostname); if (!s) { return ESP_ERR_NOT_FOUND; } - mdns_action_t * action = (mdns_action_t *)malloc(sizeof(mdns_action_t)); + mdns_action_t *action = (mdns_action_t *)malloc(sizeof(mdns_action_t)); if (!action) { HOOK_MALLOC_FAILED; return ESP_ERR_NO_MEM; @@ -5036,12 +5071,14 @@ esp_err_t mdns_service_txt_item_set_for_host(const char * service, const char * free(action); return ESP_ERR_NO_MEM; } - action->data.srv_txt_set.value = strdup(value); + action->data.srv_txt_set.value = (char *)malloc(value_len); if (!action->data.srv_txt_set.value) { free(action->data.srv_txt_set.key); free(action); return ESP_ERR_NO_MEM; } + memcpy(action->data.srv_txt_set.value, value, value_len); + action->data.srv_txt_set.value_len = value_len; if (xQueueSend(_mdns_server->action_queue, &action, (portTickType)0) != pdPASS) { free(action->data.srv_txt_set.key); free(action->data.srv_txt_set.value); @@ -5051,12 +5088,31 @@ esp_err_t mdns_service_txt_item_set_for_host(const char * service, const char * return ESP_OK; } -esp_err_t mdns_service_txt_item_set(const char * service, const char * proto, const char * key, const char * value) +esp_err_t mdns_service_txt_item_set_for_host(const char *service, const char *proto, const char *hostname, + const char *key, const char *value) +{ + return mdns_service_txt_item_set_for_host_with_explicit_value_len(service, proto, hostname, key, value, + strlen(value)); +} + + +esp_err_t mdns_service_txt_item_set(const char *service, const char *proto, const char *key, const char *value) { if (!_mdns_server) { return ESP_ERR_INVALID_STATE; } - return mdns_service_txt_item_set_for_host(service, proto, _mdns_server->hostname, key, value); + return mdns_service_txt_item_set_for_host_with_explicit_value_len(service, proto, _mdns_server->hostname, key, + value, strlen(value)); +} + +esp_err_t mdns_service_txt_item_set_with_explicit_value_len(const char *service, const char *proto, const char *key, + const char *value, uint8_t value_len) +{ + if (!_mdns_server) { + return ESP_ERR_INVALID_STATE; + } + return mdns_service_txt_item_set_for_host_with_explicit_value_len(service, proto, _mdns_server->hostname, key, + value, value_len); } esp_err_t mdns_service_txt_item_remove_for_host(const char * service, const char * proto, const char * hostname, @@ -5215,6 +5271,7 @@ void mdns_query_results_free(mdns_result_t * results) free((char *)(r->txt[i].value)); } free(r->txt); + free(r->txt_value_len); while (r->addr) { a = r->addr; diff --git a/components/mdns/private_include/mdns_private.h b/components/mdns/private_include/mdns_private.h index 3851c4694c..e1a091b453 100644 --- a/components/mdns/private_include/mdns_private.h +++ b/components/mdns/private_include/mdns_private.h @@ -277,7 +277,8 @@ typedef struct { typedef struct mdns_txt_linked_item_s { const char * key; /*!< item key name */ - const char * value; /*!< item value string */ + char * value; /*!< item value string */ + uint8_t value_len; /*!< item value length */ struct mdns_txt_linked_item_s * next; /*!< next result, or NULL for the last result in the list */ } mdns_txt_linked_item_t; @@ -426,6 +427,7 @@ typedef struct { mdns_srv_item_t * service; char * key; char * value; + uint8_t value_len; } srv_txt_set; struct { mdns_srv_item_t * service; diff --git a/examples/protocols/mdns/main/mdns_example_main.c b/examples/protocols/mdns/main/mdns_example_main.c index f8641197b6..ff026fd625 100644 --- a/examples/protocols/mdns/main/mdns_example_main.c +++ b/examples/protocols/mdns/main/mdns_example_main.c @@ -75,7 +75,7 @@ static void initialise_mdns(void) //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") ); + ESP_ERROR_CHECK( mdns_service_txt_item_set_with_explicit_value_len("_http", "_tcp", "u", "admin", strlen("admin")) ); free(hostname); } @@ -98,9 +98,10 @@ static void mdns_print_results(mdns_result_t * results){ printf(" SRV : %s.local:%u\n", r->hostname, r->port); } if(r->txt_count){ - printf(" TXT : [%u] ", r->txt_count); + printf(" TXT : [%zu] ", r->txt_count); for(t=0; ttxt_count; t++){ - printf("%s=%s; ", r->txt[t].key, r->txt[t].value?r->txt[t].value:"NULL"); + printf("%s=%s(%d); ", r->txt[t].key, r->txt[t].value?r->txt[t].value:"NULL", + r->txt_value_len[t]); } printf("\n"); }