fix(mdns): Fix API races removing txt item for services

Fixes **API race issue** (described in 8a690503) for API
mdns_service_txt_item_remove_for_host()
This commit is contained in:
David Cermak
2024-07-23 10:02:26 +02:00
parent c62b920bb9
commit 3f97a8228b
2 changed files with 48 additions and 74 deletions

View File

@ -5111,9 +5111,6 @@ static void _mdns_free_action(mdns_action_t *action)
case ACTION_SERVICE_INSTANCE_SET: case ACTION_SERVICE_INSTANCE_SET:
free(action->data.srv_instance.instance); free(action->data.srv_instance.instance);
break; break;
case ACTION_SERVICE_TXT_DEL:
free(action->data.srv_txt_del.key);
break;
case ACTION_SERVICE_SUBTYPE_ADD: case ACTION_SERVICE_SUBTYPE_ADD:
free(action->data.srv_subtype_add.subtype); free(action->data.srv_subtype_add.subtype);
break; break;
@ -5159,10 +5156,8 @@ static void _mdns_execute_action(mdns_action_t *action)
{ {
mdns_srv_item_t *a = NULL; mdns_srv_item_t *a = NULL;
mdns_service_t *service; mdns_service_t *service;
char *key;
char *subtype; char *subtype;
mdns_subtype_t *subtype_item; mdns_subtype_t *subtype_item;
mdns_txt_linked_item_t *txt, * t;
switch (action->type) { switch (action->type) {
case ACTION_SYSTEM_EVENT: case ACTION_SYSTEM_EVENT:
@ -5192,37 +5187,6 @@ static void _mdns_execute_action(mdns_action_t *action)
action->data.srv_instance.service->service->instance = action->data.srv_instance.instance; action->data.srv_instance.service->service->instance = action->data.srv_instance.instance;
_mdns_probe_all_pcbs(&action->data.srv_instance.service, 1, false, false); _mdns_probe_all_pcbs(&action->data.srv_instance.service, 1, false, false);
break;
case ACTION_SERVICE_TXT_DEL:
service = action->data.srv_txt_del.service->service;
key = action->data.srv_txt_del.key;
txt = service->txt;
if (!txt) {
break;
}
if (strcmp(txt->key, key) == 0) {
service->txt = txt->next;
free((char *)txt->key);
free((char *)txt->value);
free(txt);
} else {
while (txt->next) {
if (strcmp(txt->next->key, key) == 0) {
t = txt->next;
txt->next = t->next;
free((char *)t->key);
free((char *)t->value);
free(t);
break;
} else {
txt = txt->next;
}
}
}
free(key);
_mdns_announce_all_pcbs(&action->data.srv_txt_del.service, 1, false);
break; break;
case ACTION_SERVICE_SUBTYPE_ADD: case ACTION_SERVICE_SUBTYPE_ADD:
service = action->data.srv_subtype_add.service->service; service = action->data.srv_subtype_add.service->service;
@ -6248,6 +6212,7 @@ esp_err_t mdns_service_txt_item_set_for_host_with_explicit_value_len(const char
{ {
MDNS_SERVICE_LOCK(); MDNS_SERVICE_LOCK();
esp_err_t ret = ESP_OK; esp_err_t ret = ESP_OK;
char *value = NULL;
const char *hostname = host ? host : _mdns_server->hostname; const char *hostname = host ? host : _mdns_server->hostname;
ESP_GOTO_ON_FALSE(_mdns_server && _mdns_server->services && !_str_null_or_empty(service) && !_str_null_or_empty(proto) && !_str_null_or_empty(key) && ESP_GOTO_ON_FALSE(_mdns_server && _mdns_server->services && !_str_null_or_empty(service) && !_str_null_or_empty(proto) && !_str_null_or_empty(key) &&
!((!value_arg && value_len)), ESP_ERR_INVALID_ARG, err, TAG, "Invalid state or arguments"); !((!value_arg && value_len)), ESP_ERR_INVALID_ARG, err, TAG, "Invalid state or arguments");
@ -6256,10 +6221,9 @@ esp_err_t mdns_service_txt_item_set_for_host_with_explicit_value_len(const char
ESP_GOTO_ON_FALSE(s, ESP_ERR_NOT_FOUND, err, TAG, "Service doesn't exist"); ESP_GOTO_ON_FALSE(s, ESP_ERR_NOT_FOUND, err, TAG, "Service doesn't exist");
mdns_service_t *srv = s->service; mdns_service_t *srv = s->service;
char *value = NULL;
if (value_len > 0) { if (value_len > 0) {
value = (char *) malloc(value_len); value = (char *) malloc(value_len);
ESP_GOTO_ON_FALSE(s, ESP_ERR_NO_MEM, err, TAG, "Out of memory"); ESP_GOTO_ON_FALSE(s, ESP_ERR_NO_MEM, out_of_mem, TAG, "Out of memory");
memcpy(value, value_arg, value_len); memcpy(value, value_arg, value_len);
} else { } else {
value_len = 0; value_len = 0;
@ -6276,9 +6240,9 @@ esp_err_t mdns_service_txt_item_set_for_host_with_explicit_value_len(const char
} }
if (!txt) { if (!txt) {
txt = (mdns_txt_linked_item_t *)malloc(sizeof(mdns_txt_linked_item_t)); txt = (mdns_txt_linked_item_t *)malloc(sizeof(mdns_txt_linked_item_t));
ESP_GOTO_ON_FALSE(s, ESP_ERR_NO_MEM, err, TAG, "Out of memory"); ESP_GOTO_ON_FALSE(s, ESP_ERR_NO_MEM, out_of_mem, TAG, "Out of memory");
txt->key = strdup(key); txt->key = strdup(key);
ESP_GOTO_ON_FALSE(txt->key, ESP_ERR_NO_MEM, err, TAG, "Out of memory"); ESP_GOTO_ON_FALSE(txt->key, ESP_ERR_NO_MEM, out_of_mem, TAG, "Out of memory");
txt->value = value; txt->value = value;
txt->value_len = value_len; txt->value_len = value_len;
txt->next = srv->txt; txt->next = srv->txt;
@ -6289,10 +6253,12 @@ esp_err_t mdns_service_txt_item_set_for_host_with_explicit_value_len(const char
err: err:
MDNS_SERVICE_UNLOCK(); MDNS_SERVICE_UNLOCK();
if (ret == ESP_ERR_NO_MEM) { return ret;
HOOK_MALLOC_FAILED; out_of_mem:
} MDNS_SERVICE_UNLOCK();
return ESP_OK; HOOK_MALLOC_FAILED;
free(value);
return ret;
} }
esp_err_t mdns_service_txt_item_set_for_host(const char *instance, const char *service, const char *proto, const char *hostname, esp_err_t mdns_service_txt_item_set_for_host(const char *instance, const char *service, const char *proto, const char *hostname,
@ -6321,38 +6287,51 @@ esp_err_t mdns_service_txt_item_set_with_explicit_value_len(const char *service,
return mdns_service_txt_item_set_for_host_with_explicit_value_len(NULL, service, proto, NULL, key, value, value_len); return mdns_service_txt_item_set_for_host_with_explicit_value_len(NULL, service, proto, NULL, key, value, value_len);
} }
esp_err_t mdns_service_txt_item_remove_for_host(const char *instance, const char *service, const char *proto, const char *hostname, esp_err_t mdns_service_txt_item_remove_for_host(const char *instance, const char *service, const char *proto, const char *host,
const char *key) const char *key)
{ {
MDNS_SERVICE_LOCK(); MDNS_SERVICE_LOCK();
if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto) || _str_null_or_empty(key)) { esp_err_t ret = ESP_OK;
MDNS_SERVICE_UNLOCK(); const char *hostname = host ? host : _mdns_server->hostname;
return ESP_ERR_INVALID_ARG; ESP_GOTO_ON_FALSE(_mdns_server && _mdns_server->services && !_str_null_or_empty(service) && !_str_null_or_empty(proto) && !_str_null_or_empty(key),
} ESP_ERR_INVALID_ARG, err, TAG, "Invalid state or arguments");
mdns_srv_item_t *s = _mdns_get_service_item_instance(instance, service, proto, hostname); mdns_srv_item_t *s = _mdns_get_service_item_instance(instance, service, proto, hostname);
MDNS_SERVICE_UNLOCK(); ESP_GOTO_ON_FALSE(s, ESP_ERR_NOT_FOUND, err, TAG, "Service doesn't exist");
if (!s) {
return ESP_ERR_NOT_FOUND; mdns_service_t *srv = s->service;
mdns_txt_linked_item_t *txt = srv->txt;
if (!txt) {
goto err;
} }
mdns_action_t *action = (mdns_action_t *)malloc(sizeof(mdns_action_t)); if (strcmp(txt->key, key) == 0) {
if (!action) { srv->txt = txt->next;
HOOK_MALLOC_FAILED; free((char *)txt->key);
return ESP_ERR_NO_MEM; free((char *)txt->value);
free(txt);
} else {
while (txt->next) {
if (strcmp(txt->next->key, key) == 0) {
mdns_txt_linked_item_t *t = txt->next;
txt->next = t->next;
free((char *)t->key);
free((char *)t->value);
free(t);
break;
} else {
txt = txt->next;
}
}
} }
action->type = ACTION_SERVICE_TXT_DEL; _mdns_announce_all_pcbs(&s, 1, false);
action->data.srv_txt_del.service = s;
action->data.srv_txt_del.key = strdup(key); err:
if (!action->data.srv_txt_del.key) { MDNS_SERVICE_UNLOCK();
free(action); if (ret == ESP_ERR_NO_MEM) {
return ESP_ERR_NO_MEM; HOOK_MALLOC_FAILED;
} }
if (xQueueSend(_mdns_server->action_queue, &action, (TickType_t)0) != pdPASS) { return ret;
free(action->data.srv_txt_del.key);
free(action);
return ESP_ERR_NO_MEM;
}
return ESP_OK;
} }
esp_err_t mdns_service_txt_item_remove(const char *service, const char *proto, const char *key) esp_err_t mdns_service_txt_item_remove(const char *service, const char *proto, const char *key)
@ -6360,7 +6339,7 @@ esp_err_t mdns_service_txt_item_remove(const char *service, const char *proto, c
if (!_mdns_server) { if (!_mdns_server) {
return ESP_ERR_INVALID_STATE; return ESP_ERR_INVALID_STATE;
} }
return mdns_service_txt_item_remove_for_host(NULL, service, proto, _mdns_server->hostname, key); 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, esp_err_t mdns_service_subtype_add_for_host(const char *instance_name, const char *service, const char *proto,

View File

@ -188,7 +188,6 @@ typedef enum {
ACTION_HOSTNAME_SET, ACTION_HOSTNAME_SET,
ACTION_INSTANCE_SET, ACTION_INSTANCE_SET,
ACTION_SERVICE_INSTANCE_SET, ACTION_SERVICE_INSTANCE_SET,
ACTION_SERVICE_TXT_DEL,
ACTION_SERVICE_SUBTYPE_ADD, ACTION_SERVICE_SUBTYPE_ADD,
ACTION_SERVICES_CLEAR, ACTION_SERVICES_CLEAR,
ACTION_SEARCH_ADD, ACTION_SEARCH_ADD,
@ -445,10 +444,6 @@ typedef struct {
mdns_srv_item_t *service; mdns_srv_item_t *service;
char *instance; char *instance;
} srv_instance; } srv_instance;
struct {
mdns_srv_item_t *service;
char *key;
} srv_txt_del;
struct { struct {
mdns_srv_item_t *service; mdns_srv_item_t *service;
char *subtype; char *subtype;