static void _mdns_search_result_add_txt(mdns_search_once_t * search, mdns_txt_item_t * txt, size_t txt_count, tcpip_adapter_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, tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol);
+static inline bool _str_null_or_empty(const char * str){
+ return (str == NULL || *str == 0);
+}
+
/*
* @brief Appends/increments a number to name/instance in case of collision
* */
return len;
}
+/**
+ * @brief Get the service name of a service
+ */
+static const char * _mdns_get_service_instance_name(mdns_service_t * service)
+{
+ if (service && !_str_null_or_empty(service->instance)) {
+ return service->instance;
+ }
+
+ if (_mdns_server && !_str_null_or_empty(_mdns_server->instance)) {
+ return _mdns_server->instance;
+ }
+
+ if (_mdns_server && !_str_null_or_empty(_mdns_server->hostname)) {
+ return _mdns_server->hostname;
+ }
+
+ return NULL;
+}
+
/**
* @brief reads MDNS FQDN into mdns_name_t structure
* FQDN is in format: [hostname.|[instance.]_service._proto.]local.
uint16_t record_length = 0;
uint8_t part_length;
- str[0] = (service->instance)?service->instance
- :(_mdns_server->instance)?_mdns_server->instance
- :_mdns_server->hostname;
+ str[0] = _mdns_get_service_instance_name(service);
str[1] = service->service;
str[2] = service->proto;
str[3] = MDNS_DEFAULT_DOMAIN;
+ if (!str[0]) {
+ return 0;
+ }
+
part_length = _mdns_append_fqdn(packet, index, str, 4);
if (!part_length) {
return 0;
uint16_t record_length = 0;
uint8_t part_length;
- str[0] = (service->instance)?service->instance
- :(_mdns_server->instance)?_mdns_server->instance
- :_mdns_server->hostname;
+ str[0] = _mdns_get_service_instance_name(service);
str[1] = service->service;
str[2] = service->proto;
str[3] = MDNS_DEFAULT_DOMAIN;
+ if (!str[0]) {
+ return 0;
+ }
+
part_length = _mdns_append_fqdn(packet, index, str, 4);
if (!part_length) {
return 0;
str[0] = _mdns_server->hostname;
str[1] = MDNS_DEFAULT_DOMAIN;
+
+ if (_str_null_or_empty(str[0])) {
+ return 0;
+ }
+
part_length = _mdns_append_fqdn(packet, index, str, 2);
if (!part_length) {
return 0;
str[0] = _mdns_server->hostname;
str[1] = MDNS_DEFAULT_DOMAIN;
+ if (_str_null_or_empty(str[0])) {
+ return 0;
+ }
+
+
part_length = _mdns_append_fqdn(packet, index, str, 2);
if (!part_length) {
return 0;
str[0] = _mdns_server->hostname;
str[1] = MDNS_DEFAULT_DOMAIN;
+ if (_str_null_or_empty(str[0])) {
+ return 0;
+ }
+
+
part_length = _mdns_append_fqdn(packet, index, str, 2);
if (!part_length) {
return 0;
if (answer->service) {
return _mdns_append_ptr_record(packet, index,
- (answer->service->instance)?answer->service->instance
- :(_mdns_server->instance)?_mdns_server->instance
- :_mdns_server->hostname,
+ _mdns_get_service_instance_name(answer->service),
answer->service->service, answer->service->proto,
answer->flush, answer->bye) > 0;
} else {
q->next = NULL;
q->unicast = first;
q->type = MDNS_TYPE_ANY;
- q->host = (services[i]->service->instance)?services[i]->service->instance
- :(_mdns_server->instance)?_mdns_server->instance
- :_mdns_server->hostname;
+ q->host = _mdns_get_service_instance_name(services[i]->service);
q->service = services[i]->service->service;
q->proto = services[i]->service->proto;
q->domain = MDNS_DEFAULT_DOMAIN;
- if (_mdns_question_exists(q, packet->questions)) {
+ if (!q->host || _mdns_question_exists(q, packet->questions)) {
free(q);
} else {
queueToEnd(mdns_out_question_t, packet->questions, q);
}
- if (!_mdns_alloc_answer(&packet->servers, MDNS_TYPE_SRV, services[i]->service, false, false)) {
+ if (!q->host || !_mdns_alloc_answer(&packet->servers, MDNS_TYPE_SRV, services[i]->service, false, false)) {
_mdns_free_tx_packet(packet);
return NULL;
}
}
- if (include_ip) {
+ if (include_ip && !_str_null_or_empty(_mdns_server->hostname)) {
mdns_out_question_t * q = (mdns_out_question_t *)malloc(sizeof(mdns_out_question_t));
if (!q) {
_mdns_free_tx_packet(packet);
_mdns_clear_pcb_tx_queue_head(tcpip_if, ip_protocol);
- if (!_mdns_server->hostname || !_mdns_server->hostname[0]) {
+ if (_str_null_or_empty(_mdns_server->hostname)) {
pcb->state = PCB_RUNNING;
return;
}
static void _mdns_send_bye(mdns_srv_item_t ** services, size_t len, bool include_ip)
{
uint8_t i, j;
- if (!_mdns_server->hostname || !_mdns_server->hostname[0]) {
+ if (_str_null_or_empty(_mdns_server->hostname)) {
return;
}
}
} else if (_pcb->state == PCB_RUNNING) {
- if (!_mdns_server->hostname || !_mdns_server->hostname[0]) {
+ if (_str_null_or_empty(_mdns_server->hostname)) {
return;
}
return s;
}
+/**
+ * @brief Remove and free service answer from answer list (destination)
+ */
+static void _mdns_dealloc_scheduled_service_answers(mdns_out_answer_t ** destination, mdns_service_t * service)
+{
+ mdns_out_answer_t * d = *destination;
+ if (!d) {
+ return;
+ }
+ while (d && d->service == service) {
+ *destination = d->next;
+ free(d);
+ d = *destination;
+ }
+ while (d && d->next) {
+ mdns_out_answer_t * a = d->next;
+ if (a->service == service) {
+ d->next = a->next;
+ free(a);
+ } else {
+ d = d->next;
+ }
+ }
+}
+
+/**
+ * @brief Find, remove and free answers and scheduled packets for service
+ */
+static void _mdns_remove_scheduled_service_packets(mdns_service_t * service)
+{
+ mdns_tx_packet_t * p = NULL;
+ mdns_tx_packet_t * q = _mdns_server->tx_queue_head;
+ while (q) {
+ bool had_answers = (q->answers != NULL);
+
+ _mdns_dealloc_scheduled_service_answers(&(q->answers), service);
+ _mdns_dealloc_scheduled_service_answers(&(q->additional), service);
+ _mdns_dealloc_scheduled_service_answers(&(q->servers), service);
+
+
+ mdns_pcb_t * _pcb = &_mdns_server->interfaces[q->tcpip_if].pcbs[q->ip_protocol];
+ if(_pcb->pcb) {
+ if (PCB_STATE_IS_PROBING(_pcb)) {
+ uint8_t i;
+ //check if we are probing this service
+ for (i=0; i<_pcb->probe_services_len; i++) {
+ mdns_srv_item_t * s = _pcb->probe_services[i];
+ if (s->service == service){
+ break;
+ }
+ }
+ if (i < _pcb->probe_services_len) {
+ if (_pcb->probe_services_len > 1) {
+ uint8_t n;
+ for (n=(i+1); n<_pcb->probe_services_len; n++) {
+ _pcb->probe_services[n-1] = _pcb->probe_services[n];
+ }
+ _pcb->probe_services_len--;
+ } else {
+ _pcb->probe_services_len = 0;
+ free(_pcb->probe_services);
+ _pcb->probe_services = NULL;
+ if (!_pcb->probe_ip) {
+ _pcb->probe_running = false;
+ _pcb->state = PCB_RUNNING;
+ }
+ }
+
+ if (q->questions) {
+ mdns_out_question_t * qsn = NULL;
+ mdns_out_question_t * qs = q->questions;
+ if (qs->type == MDNS_TYPE_ANY
+ && qs->service && strcmp(qs->service, service->service) == 0
+ && qs->proto && strcmp(qs->proto, service->proto) == 0)
+ {
+ q->questions = q->questions->next;
+ free(qs);
+ } else while (qs->next) {
+ qsn = qs->next;
+ if (qsn->type == MDNS_TYPE_ANY
+ && qsn->service && strcmp(qsn->service, service->service) == 0
+ && qsn->proto && strcmp(qsn->proto, service->proto) == 0)
+ {
+ qs->next = qsn->next;
+ free(qsn);
+ break;
+ }
+ qs = qs->next;
+ }
+ }
+ }
+ } else if (PCB_STATE_IS_ANNOUNCING(_pcb)) {
+ //if answers were cleared, set to running
+ if (had_answers && q->answers == NULL) {
+ _pcb->state = PCB_RUNNING;
+ }
+ }
+ }
+
+ p = q;
+ q = q->next;
+ if(!p->questions && !p->answers && !p->additional && !p->servers){
+ queueDetach(mdns_tx_packet_t, _mdns_server->tx_queue_head, p);
+ _mdns_free_tx_packet(p);
+ }
+ }
+}
+
/**
* @brief free service memory
*
if (!service) {
return;
}
+ _mdns_remove_scheduled_service_packets(service);
free((char *)service->instance);
free((char *)service->service);
free((char *)service->proto);
*/
static int _mdns_check_srv_collision(mdns_service_t * service, uint16_t priority, uint16_t weight, uint16_t port, const char * host, const char * domain)
{
+ if (_str_null_or_empty(_mdns_server->hostname)) {
+ return 0;
+ }
+
size_t our_host_len = strlen(_mdns_server->hostname);
size_t our_len = 14 + our_host_len;
static bool _mdns_name_is_ours(mdns_name_t * name)
{
//domain have to be "local"
- if (!name->domain || !name->domain[0] || strcasecmp(name->domain, MDNS_DEFAULT_DOMAIN)) {
+ if (_str_null_or_empty(name->domain) || strcasecmp(name->domain, MDNS_DEFAULT_DOMAIN)) {
return false;
}
//if service and proto are empty, host must match out hostname
- if ((!name->service || !name->service[0]) && (!name->proto || !name->proto[0])) {
- if (name->host && name->host[0] && strcasecmp(name->host, _mdns_server->hostname) == 0) {
+ if (_str_null_or_empty(name->service) && _str_null_or_empty(name->proto)) {
+ if (!_str_null_or_empty(name->host)
+ && !_str_null_or_empty(_mdns_server->hostname)
+ && strcasecmp(name->host, _mdns_server->hostname) == 0)
+ {
return true;
}
return false;
}
//if service or proto is empty, name is invalid
- if ((!name->service || !name->service[0]) || (!name->proto || !name->proto[0])) {
+ if (_str_null_or_empty(name->service) || _str_null_or_empty(name->proto)) {
return false;
}
}
//if host is empty and we have service, we have success
- if (!name->host || !name->host[0]) {
+ if (_str_null_or_empty(name->host)) {
return true;
}
//OK we have host in the name. find what is the instance of the service
- const char * instance = service->service->instance;
+ const char * instance = _mdns_get_service_instance_name(service->service);
if (instance == NULL) {
- if (_mdns_server->instance && _mdns_server->instance[0]) {
- instance = _mdns_server->instance;
- } else if (_mdns_server->hostname && _mdns_server->hostname[0]) {
- instance = _mdns_server->hostname;
- } else {
- return false;
- }
+ return false;
}
//compare the instance against the name
return true;
}
} else if (type == MDNS_TYPE_SRV || type == MDNS_TYPE_TXT) {
- const char * name = service->service->instance;
- if (!name) {
- name = _mdns_server->instance;
- }
- if (!name) {
- name = _mdns_server->hostname;
- }
- if (!strcasecmp(name, question->host)
+ const char * name = _mdns_get_service_instance_name(service->service);
+ if (name && !strcasecmp(name, question->host)
&& !strcasecmp(service->service->service, question->service)
&& !strcasecmp(service->service->proto, question->proto)
&& !strcasecmp(MDNS_DEFAULT_DOMAIN, question->domain)) {
return;
}
+ //if we have not set the hostname, we can not answer questions
+ if (header.questions && _str_null_or_empty(_mdns_server->hostname)) {
+ free(parsed_packet);
+ return;
+ }
+
parsed_packet->tcpip_if = packet->tcpip_if;
parsed_packet->ip_protocol = packet->ip_protocol;
parsed_packet->multicast = packet->multicast;
do_not_reply = true;
if (_mdns_server->interfaces[packet->tcpip_if].pcbs[packet->ip_protocol].probe_running) {
_mdns_server->interfaces[packet->tcpip_if].pcbs[packet->ip_protocol].failed_probes++;
- if (service->service->instance) {
+ if (!_str_null_or_empty(service->service->instance)) {
char * new_instance = _mdns_mangle_name((char *)service->service->instance);
if (new_instance) {
free((char *)service->service->instance);
service->service->instance = new_instance;
}
_mdns_probe_all_pcbs(&service, 1, false, false);
- } else if (_mdns_server->instance) {
+ } else if (!_str_null_or_empty(_mdns_server->instance)) {
char * new_instance = _mdns_mangle_name((char *)_mdns_server->instance);
if (new_instance) {
free((char *)_mdns_server->instance);
return NULL;
}
- if (name) {
+ if (!_str_null_or_empty(name)) {
search->instance = strndup(name, MDNS_NAME_BUF_LEN-1);
if (!search->instance) {
_mdns_search_free(search);
}
}
- if (service) {
+ if (!_str_null_or_empty(service)) {
search->service = strndup(service, MDNS_NAME_BUF_LEN-1);
if (!search->service) {
_mdns_search_free(search);
}
}
- if (proto) {
+ if (!_str_null_or_empty(proto)) {
search->proto = strndup(proto, MDNS_NAME_BUF_LEN-1);
if (!search->proto) {
_mdns_search_free(search);
} else if (search->type == MDNS_TYPE_PTR) {
r = search->result;
while (r) {
- if (r->tcpip_if == tcpip_if && r->ip_protocol == ip_protocol && r->hostname && !strcasecmp(hostname, r->hostname)) {
+ if (r->tcpip_if == tcpip_if && r->ip_protocol == ip_protocol && !_str_null_or_empty(r->hostname) && !strcasecmp(hostname, r->hostname)) {
_mdns_result_add_ip(r, ip);
break;
}
{
mdns_result_t * r = search->result;
while (r) {
- if (r->tcpip_if == tcpip_if && r->ip_protocol == ip_protocol && r->instance_name && !strcasecmp(instance, r->instance_name)) {
+ if (r->tcpip_if == tcpip_if && r->ip_protocol == ip_protocol && !_str_null_or_empty(r->instance_name) && !strcasecmp(instance, r->instance_name)) {
return r;
}
r = r->next;
{
mdns_result_t * r = search->result;
while (r) {
- if (r->tcpip_if == tcpip_if && r->ip_protocol == ip_protocol && r->hostname && !strcasecmp(hostname, r->hostname)) {
+ if (r->tcpip_if == tcpip_if && r->ip_protocol == ip_protocol && !_str_null_or_empty(r->hostname) && !strcasecmp(hostname, r->hostname)) {
return;
}
r = r->next;
}
r = s->result;
while (r) {
- if (r->tcpip_if == tcpip_if && r->ip_protocol == ip_protocol && r->hostname && !strcasecmp(name->host, r->hostname)) {
+ if (r->tcpip_if == tcpip_if && r->ip_protocol == ip_protocol && !_str_null_or_empty(r->hostname) && !strcasecmp(name->host, r->hostname)) {
return s;
}
r = r->next;
break;
case ACTION_SERVICE_INSTANCE_SET:
- if (action->data.srv_port.service->service->instance) {
+ if (action->data.srv_instance.service->service->instance) {
_mdns_send_bye(&action->data.srv_instance.service, 1, false);
free((char*)action->data.srv_instance.service->service->instance);
}
if (!_mdns_server) {
return ESP_ERR_INVALID_ARG;
}
- if (strlen(hostname) > (MDNS_NAME_BUF_LEN - 1)) {
+ if (_str_null_or_empty(hostname) || strlen(hostname) > (MDNS_NAME_BUF_LEN - 1)) {
return ESP_ERR_INVALID_ARG;
}
char * new_hostname = strndup(hostname, MDNS_NAME_BUF_LEN - 1);
if (!_mdns_server) {
return ESP_ERR_INVALID_ARG;
}
- if (strlen(instance) > (MDNS_NAME_BUF_LEN - 1)) {
+ if (_str_null_or_empty(instance) || strlen(instance) > (MDNS_NAME_BUF_LEN - 1)) {
return ESP_ERR_INVALID_ARG;
}
char * new_instance = strndup(instance, MDNS_NAME_BUF_LEN - 1);
esp_err_t mdns_service_add(const char * instance, const char * service, const char * proto, uint16_t port, mdns_txt_item_t txt[], size_t num_items)
{
- if (!_mdns_server || !service || !proto || !port) {
+ if (!_mdns_server || _str_null_or_empty(service) || _str_null_or_empty(proto) || !port) {
return ESP_ERR_INVALID_ARG;
}
mdns_srv_item_t * item = _mdns_get_service_item(service, proto);
esp_err_t mdns_service_port_set(const char * service, const char * proto, uint16_t port)
{
- if (!_mdns_server || !_mdns_server->services || !service || !proto || !port) {
+ if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto) || !port) {
return ESP_ERR_INVALID_ARG;
}
mdns_srv_item_t * s = _mdns_get_service_item(service, proto);
esp_err_t mdns_service_txt_set(const char * service, const char * proto, mdns_txt_item_t txt[], uint8_t num_items)
{
- if (!_mdns_server || !_mdns_server->services || !service || !proto || (num_items && txt == NULL)) {
+ if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto) || (num_items && txt == NULL)) {
return ESP_ERR_INVALID_ARG;
}
mdns_srv_item_t * s = _mdns_get_service_item(service, proto);
esp_err_t mdns_service_txt_item_set(const char * service, const char * proto, const char * key, const char * value)
{
- if (!_mdns_server || !_mdns_server->services || !service || !proto) {
+ 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);
esp_err_t mdns_service_txt_item_remove(const char * service, const char * proto, const char * key)
{
- if (!_mdns_server || !_mdns_server->services || !service || !proto) {
+ if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto) || _str_null_or_empty(key)) {
return ESP_ERR_INVALID_ARG;
}
mdns_srv_item_t * s = _mdns_get_service_item(service, proto);
esp_err_t mdns_service_instance_name_set(const char * service, const char * proto, const char * instance)
{
- if (!_mdns_server || !_mdns_server->services || !service || !proto) {
+ if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto)) {
return ESP_ERR_INVALID_ARG;
}
- if (strlen(instance) > (MDNS_NAME_BUF_LEN - 1)) {
+ if (_str_null_or_empty(instance) || strlen(instance) > (MDNS_NAME_BUF_LEN - 1)) {
return ESP_ERR_INVALID_ARG;
}
mdns_srv_item_t * s = _mdns_get_service_item(service, proto);
esp_err_t mdns_service_remove(const char * service, const char * proto)
{
- if (!_mdns_server || !_mdns_server->services || !service || !proto) {
+ if (!_mdns_server || !_mdns_server->services || _str_null_or_empty(service) || _str_null_or_empty(proto)) {
return ESP_ERR_INVALID_ARG;
}
mdns_srv_item_t * s = _mdns_get_service_item(service, proto);
return ESP_ERR_INVALID_STATE;
}
- if (!timeout) {
+ if (!timeout || _str_null_or_empty(service) != _str_null_or_empty(proto)) {
return ESP_ERR_INVALID_ARG;
}
esp_err_t mdns_query_ptr(const char * service, const char * proto, uint32_t timeout, size_t max_results, mdns_result_t ** results)
{
- if (!service || !proto) {
+ if (_str_null_or_empty(service) || _str_null_or_empty(proto)) {
return ESP_ERR_INVALID_ARG;
}
esp_err_t mdns_query_srv(const char * instance, const char * service, const char * proto, uint32_t timeout, mdns_result_t ** result)
{
- if (!instance || !service || !proto) {
+ if (_str_null_or_empty(instance) || _str_null_or_empty(service) || _str_null_or_empty(proto)) {
return ESP_ERR_INVALID_ARG;
}
esp_err_t mdns_query_txt(const char * instance, const char * service, const char * proto, uint32_t timeout, mdns_result_t ** result)
{
- if (!instance || !service || !proto) {
+ if (_str_null_or_empty(instance) || _str_null_or_empty(service) || _str_null_or_empty(proto)) {
return ESP_ERR_INVALID_ARG;
}
mdns_result_t * result = NULL;
esp_err_t err;
- if (!name) {
+ if (_str_null_or_empty(name)) {
return ESP_ERR_INVALID_ARG;
}
mdns_result_t * result = NULL;
esp_err_t err;
- if (!name) {
+ if (_str_null_or_empty(name)) {
return ESP_ERR_INVALID_ARG;
}