Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(mdns): support update subtype (IDFGH-14068) #693

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 63 additions & 1 deletion components/mdns/include/mdns.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down Expand Up @@ -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)
Expand All @@ -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)
david-cermak marked this conversation as resolved.
Show resolved Hide resolved
* @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)
zwx1995esp marked this conversation as resolved.
Show resolved Hide resolved
* @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)
zwx1995esp marked this conversation as resolved.
Show resolved Hide resolved
* @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
*
Expand Down
157 changes: 143 additions & 14 deletions components/mdns/mdns.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand All @@ -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);
}

Expand Down Expand Up @@ -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;
Fixed Show fixed Hide fixed
zwx1995esp marked this conversation as resolved.
Show resolved Hide resolved
}
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();
Expand All @@ -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)
{
Expand Down
Loading