mirror of
https://github.com/espressif/ESP8266_RTOS_SDK.git
synced 2025-05-24 02:28:21 +08:00

Commit ID: 2f8508c7 1. Fix possible crash when probing on particular interface with duplicated service instances due to naming conflicts on network. Issue: MDNS server initially sends probing packets to resolve naming confilicts with already registered service instances. In case of a conflict, instance name is altered and probing restarts. Original instance however wasnnot removed from the structure and upon service removal only one entry was removed and a dangling service might have been kept in the structure to bring about a crash. Resolution: Keep only one instance of a service in the probing structure 2. Enable pcbs before starting service thread to avoid updating pcb's internal variables from concurent tasks. Possible race condition: user task runs mdns_init, which enables pcbs while mdns-task already created could execute enable/disable of the same pcbs if an appropriate system event received 3. Fix possible deadlock on mdns deinit calling mdns_free(). Mnds_free() initiates stop and delete timer tasks, which after locking the mutex could lead to a dead lock in case timer task executed before deleting the task, as it would wait indefinitelly for unlocking the mutex. This condition is fixed by calling _mdns_stop_timer without locking the mutex, because there's no need to protect any data when stopping and deleting the timer task 4. Fix race condition in updating packet data from user task when failed to allocate or queue a new service. Issue: mdns_service_add API allocates and queues an action to be processed in mdns task context; when allocation or queueing fails, allocated structure needs to be freed. Function _mdns_free_service did not only fee all the structures, but also updates packet data. Resolution: Moved removal of packet data outside of _mdns_free_service function 5. Fix possible crash when packet scheduled to transmit contained service which might have been already removed. Packets scheduled to transmit are pushed to action queue and removed from tx_queue_head structure, which is searched for all remaining services and while service is removed, then service questions/asnwers are also removed from this structure. This update fixes possible crash when packet is pushed to action queue, and when service is removed, its answers are removed from tx_queue_head, but not from action queue. This could lead to a crash when the packet is poped from action queue containing questions/answers to already removed (freed) service 6. Use binary semaphore instead of mutex when searching. Mdns_search_once_t::lock is used to synchronize tasks (taken by one task and given by the other) so it should not be a mutex. Convert to semaphore, and rename to indicate its purpose 7. Fix memory leak in pbuf if tcpipadapter failed to get netif 8. Fix malfuctional query_txt. When running a query for a single txt, result entries were not created and attached to result structure. This issue was introduced when fixing memory leak in txt structure, which worked correctly for PTR queries, but caused trouble for TXT query 9. Fix possible crash when mdns_free called while action queue not empty 10. Fix memory leak when query for service receives multiple ptr entries for one instance 11. Fix crash after init if no memory for task. Mdns init first starts timer task, then starts service task. If service task failed to be created, timer task needs to be stopped too 12. Fixed crash on free undefined ptr after skipped strdup. Shortcircuit evaluation may cause skip of _mdns_strdup_check of any further question field, which after clear_rx_packet freed undefined memory 13. Fix networking running udp_sendif from lwip thread 14. Check all mallocs for failure and add default hook to log error with free heap. Solves crash about _mdns_result_txt_create when stress test 15. Fixed static memory leak 16. Resolve memory leak when txt record received multiple times 17. Skip sending search when finished, not properly locked timer task 18. Sending search packets also in probing and announcing state. Mdns queries did not work properly when send imeadiately after set_hostname, which cuased reinit of pcb and therefore restarted probing, so search packets were blocked until probing finished
398 lines
12 KiB
C
398 lines
12 KiB
C
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
#ifndef MDNS_PRIVATE_H_
|
|
#define MDNS_PRIVATE_H_
|
|
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include "tcpip_adapter.h"
|
|
#include "esp_timer.h"
|
|
#include "mdns.h"
|
|
|
|
//#define MDNS_ENABLE_DEBUG
|
|
|
|
#ifdef MDNS_ENABLE_DEBUG
|
|
#define _mdns_dbg_printf(...) printf(__VA_ARGS__)
|
|
#endif
|
|
|
|
/** The maximum number of services */
|
|
#define MDNS_MAX_SERVICES CONFIG_MDNS_MAX_SERVICES
|
|
|
|
#define MDNS_ANSWER_PTR_TTL 4500
|
|
#define MDNS_ANSWER_TXT_TTL 4500
|
|
#define MDNS_ANSWER_SRV_TTL 120
|
|
#define MDNS_ANSWER_A_TTL 120
|
|
#define MDNS_ANSWER_AAAA_TTL 120
|
|
|
|
#define MDNS_FLAGS_AUTHORITATIVE 0x8400
|
|
#define MDNS_FLAGS_DISTRIBUTED 0x0200
|
|
|
|
#define MDNS_NAME_REF 0xC000
|
|
|
|
//custom type! only used by this implementation
|
|
//to help manage service discovery handling
|
|
#define MDNS_TYPE_SDPTR 0x0032
|
|
|
|
#define MDNS_CLASS_IN 0x0001
|
|
#define MDNS_CLASS_ANY 0x00FF
|
|
#define MDNS_CLASS_IN_FLUSH_CACHE 0x8001
|
|
|
|
#define MDNS_ANSWER_ALL 0x3F
|
|
#define MDNS_ANSWER_PTR 0x08
|
|
#define MDNS_ANSWER_TXT 0x04
|
|
#define MDNS_ANSWER_SRV 0x02
|
|
#define MDNS_ANSWER_A 0x01
|
|
#define MDNS_ANSWER_AAAA 0x10
|
|
#define MDNS_ANSWER_NSEC 0x20
|
|
#define MDNS_ANSWER_SDPTR 0x80
|
|
|
|
#define MDNS_SERVICE_PORT 5353 // UDP port that the server runs on
|
|
#define MDNS_SERVICE_STACK_DEPTH 4096 // Stack size for the service thread
|
|
#define MDNS_PACKET_QUEUE_LEN 16 // Maximum packets that can be queued for parsing
|
|
#define MDNS_ACTION_QUEUE_LEN 16 // Maximum actions pending to the server
|
|
#define MDNS_TXT_MAX_LEN 1024 // Maximum string length of text data in TXT record
|
|
#define MDNS_NAME_MAX_LEN 64 // Maximum string length of hostname, instance, service and proto
|
|
#define MDNS_NAME_BUF_LEN (MDNS_NAME_MAX_LEN+1) // Maximum char buffer size to hold hostname, instance, service or proto
|
|
#define MDNS_MAX_PACKET_SIZE 1460 // Maximum size of mDNS outgoing packet
|
|
|
|
#define MDNS_HEAD_LEN 12
|
|
#define MDNS_HEAD_ID_OFFSET 0
|
|
#define MDNS_HEAD_FLAGS_OFFSET 2
|
|
#define MDNS_HEAD_QUESTIONS_OFFSET 4
|
|
#define MDNS_HEAD_ANSWERS_OFFSET 6
|
|
#define MDNS_HEAD_SERVERS_OFFSET 8
|
|
#define MDNS_HEAD_ADDITIONAL_OFFSET 10
|
|
|
|
#define MDNS_TYPE_OFFSET 0
|
|
#define MDNS_CLASS_OFFSET 2
|
|
#define MDNS_TTL_OFFSET 4
|
|
#define MDNS_LEN_OFFSET 8
|
|
#define MDNS_DATA_OFFSET 10
|
|
|
|
#define MDNS_SRV_PRIORITY_OFFSET 0
|
|
#define MDNS_SRV_WEIGHT_OFFSET 2
|
|
#define MDNS_SRV_PORT_OFFSET 4
|
|
#define MDNS_SRV_FQDN_OFFSET 6
|
|
|
|
#define MDNS_TIMER_PERIOD_US 100000
|
|
|
|
#define MDNS_SERVICE_LOCK() xSemaphoreTake(_mdns_service_semaphore, portMAX_DELAY)
|
|
#define MDNS_SERVICE_UNLOCK() xSemaphoreGive(_mdns_service_semaphore)
|
|
|
|
#define queueToEnd(type, queue, item) \
|
|
if (!queue) { \
|
|
queue = item; \
|
|
} else { \
|
|
type * _q = queue; \
|
|
while (_q->next) { _q = _q->next; } \
|
|
_q->next = item; \
|
|
}
|
|
|
|
#define queueDetach(type, queue, item) \
|
|
if (queue) { \
|
|
if (queue == item) { \
|
|
queue = queue->next; \
|
|
} else { \
|
|
type * _q = queue; \
|
|
while (_q->next && _q->next != item) { \
|
|
_q = _q->next; \
|
|
} \
|
|
if (_q->next == item) { \
|
|
_q->next = item->next; \
|
|
item->next = NULL; \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
#define queueFree(type, queue) while (queue) { type * _q = queue; queue = queue->next; free(_q); }
|
|
|
|
#define PCB_STATE_IS_PROBING(s) (s->state > PCB_OFF && s->state < PCB_ANNOUNCE_1)
|
|
#define PCB_STATE_IS_ANNOUNCING(s) (s->state > PCB_PROBE_3 && s->state < PCB_RUNNING)
|
|
#define PCB_STATE_IS_RUNNING(s) (s->state == PCB_RUNNING)
|
|
|
|
#ifndef HOOK_MALLOC_FAILED
|
|
#define HOOK_MALLOC_FAILED ESP_LOGE(TAG, "Cannot allocate memory (line: %d, free heap: %d bytes)", __LINE__, esp_get_free_heap_size());
|
|
#endif
|
|
|
|
typedef enum {
|
|
PCB_OFF, PCB_DUP, PCB_INIT,
|
|
PCB_PROBE_1, PCB_PROBE_2, PCB_PROBE_3,
|
|
PCB_ANNOUNCE_1, PCB_ANNOUNCE_2, PCB_ANNOUNCE_3,
|
|
PCB_RUNNING
|
|
} mdns_pcb_state_t;
|
|
|
|
typedef enum {
|
|
MDNS_ANSWER, MDNS_NS, MDNS_EXTRA
|
|
} mdns_parsed_recort_type_t;
|
|
|
|
typedef enum {
|
|
ACTION_SYSTEM_EVENT,
|
|
ACTION_HOSTNAME_SET,
|
|
ACTION_INSTANCE_SET,
|
|
ACTION_SERVICE_ADD,
|
|
ACTION_SERVICE_DEL,
|
|
ACTION_SERVICE_INSTANCE_SET,
|
|
ACTION_SERVICE_PORT_SET,
|
|
ACTION_SERVICE_TXT_REPLACE,
|
|
ACTION_SERVICE_TXT_SET,
|
|
ACTION_SERVICE_TXT_DEL,
|
|
ACTION_SERVICES_CLEAR,
|
|
ACTION_SEARCH_ADD,
|
|
ACTION_SEARCH_SEND,
|
|
ACTION_SEARCH_END,
|
|
ACTION_TX_HANDLE,
|
|
ACTION_RX_HANDLE,
|
|
ACTION_TASK_STOP,
|
|
ACTION_MAX
|
|
} mdns_action_type_t;
|
|
|
|
|
|
typedef struct {
|
|
uint16_t id;
|
|
union {
|
|
struct {
|
|
uint16_t qr :1;
|
|
uint16_t opCode :4;
|
|
uint16_t aa :1;
|
|
uint16_t tc :1;
|
|
uint16_t rd :1;
|
|
uint16_t ra :1;
|
|
uint16_t z :1;
|
|
uint16_t ad :1;
|
|
uint16_t cd :1;
|
|
uint16_t rCode :4;//response/error code
|
|
};
|
|
uint16_t value;
|
|
} flags;
|
|
uint16_t questions; //QDCOUNT
|
|
uint16_t answers; //ANCOUNT
|
|
uint16_t servers; //NSCOUNT
|
|
uint16_t additional;//ARCOUNT
|
|
} mdns_header_t;
|
|
|
|
typedef struct {
|
|
char host[MDNS_NAME_BUF_LEN];
|
|
char service[MDNS_NAME_BUF_LEN];
|
|
char proto[MDNS_NAME_BUF_LEN];
|
|
char domain[MDNS_NAME_BUF_LEN];
|
|
uint8_t parts;
|
|
uint8_t sub;
|
|
} mdns_name_t;
|
|
|
|
typedef struct mdns_parsed_question_s {
|
|
struct mdns_parsed_question_s * next;
|
|
uint16_t type;
|
|
bool unicast;
|
|
char * host;
|
|
char * service;
|
|
char * proto;
|
|
char * domain;
|
|
} mdns_parsed_question_t;
|
|
|
|
typedef struct mdns_parsed_record_s {
|
|
struct mdns_parsed_record_s * next;
|
|
mdns_parsed_recort_type_t record_type;
|
|
uint16_t type;
|
|
uint16_t clas;
|
|
uint8_t flush;
|
|
uint32_t ttl;
|
|
char * host;
|
|
char * service;
|
|
char * proto;
|
|
char * domain;
|
|
uint16_t data_len;
|
|
uint8_t *data;
|
|
} mdns_parsed_record_t;
|
|
|
|
typedef struct {
|
|
tcpip_adapter_if_t tcpip_if;
|
|
mdns_ip_protocol_t ip_protocol;
|
|
//struct udp_pcb *pcb;
|
|
ip_addr_t src;
|
|
uint16_t src_port;
|
|
uint8_t multicast;
|
|
uint8_t authoritative;
|
|
uint8_t probe;
|
|
uint8_t discovery;
|
|
uint8_t distributed;
|
|
mdns_parsed_question_t * questions;
|
|
mdns_parsed_record_t * records;
|
|
} mdns_parsed_packet_t;
|
|
|
|
typedef struct {
|
|
tcpip_adapter_if_t tcpip_if;
|
|
mdns_ip_protocol_t ip_protocol;
|
|
struct pbuf *pb;
|
|
ip_addr_t src;
|
|
ip_addr_t dest;
|
|
uint16_t src_port;
|
|
uint8_t multicast;
|
|
} mdns_rx_packet_t;
|
|
|
|
typedef struct mdns_txt_linked_item_s {
|
|
const char * key; /*!< item key name */
|
|
const char * value; /*!< item value string */
|
|
struct mdns_txt_linked_item_s * next; /*!< next result, or NULL for the last result in the list */
|
|
} mdns_txt_linked_item_t;
|
|
|
|
typedef struct {
|
|
const char * instance;
|
|
const char * service;
|
|
const char * proto;
|
|
uint16_t priority;
|
|
uint16_t weight;
|
|
uint16_t port;
|
|
mdns_txt_linked_item_t * txt;
|
|
} mdns_service_t;
|
|
|
|
typedef struct mdns_srv_item_s {
|
|
struct mdns_srv_item_s * next;
|
|
mdns_service_t * service;
|
|
} mdns_srv_item_t;
|
|
|
|
typedef struct mdns_out_question_s {
|
|
struct mdns_out_question_s * next;
|
|
uint16_t type;
|
|
uint8_t unicast;
|
|
const char * host;
|
|
const char * service;
|
|
const char * proto;
|
|
const char * domain;
|
|
} mdns_out_question_t;
|
|
|
|
typedef struct mdns_out_answer_s {
|
|
struct mdns_out_answer_s * next;
|
|
uint16_t type;
|
|
uint8_t bye;
|
|
uint8_t flush;
|
|
mdns_service_t * service;
|
|
const char * custom_instance;
|
|
const char * custom_service;
|
|
const char * custom_proto;
|
|
} mdns_out_answer_t;
|
|
|
|
typedef struct mdns_tx_packet_s {
|
|
struct mdns_tx_packet_s * next;
|
|
uint32_t send_at;
|
|
tcpip_adapter_if_t tcpip_if;
|
|
mdns_ip_protocol_t ip_protocol;
|
|
ip_addr_t dst;
|
|
uint16_t port;
|
|
uint16_t flags;
|
|
uint8_t distributed;
|
|
mdns_out_question_t * questions;
|
|
mdns_out_answer_t * answers;
|
|
mdns_out_answer_t * servers;
|
|
mdns_out_answer_t * additional;
|
|
bool queued;
|
|
} mdns_tx_packet_t;
|
|
|
|
typedef struct {
|
|
mdns_pcb_state_t state;
|
|
struct udp_pcb * pcb;
|
|
mdns_srv_item_t ** probe_services;
|
|
uint8_t probe_services_len;
|
|
uint8_t probe_ip;
|
|
uint8_t probe_running;
|
|
uint16_t failed_probes;
|
|
} mdns_pcb_t;
|
|
|
|
typedef enum {
|
|
SEARCH_OFF,
|
|
SEARCH_INIT,
|
|
SEARCH_RUNNING,
|
|
SEARCH_MAX
|
|
} mdns_search_once_state_t;
|
|
|
|
typedef struct mdns_search_once_s {
|
|
struct mdns_search_once_s * next;
|
|
|
|
mdns_search_once_state_t state;
|
|
uint32_t started_at;
|
|
uint32_t sent_at;
|
|
uint32_t timeout;
|
|
SemaphoreHandle_t done_semaphore;
|
|
uint16_t type;
|
|
uint8_t max_results;
|
|
uint8_t num_results;
|
|
char * instance;
|
|
char * service;
|
|
char * proto;
|
|
mdns_result_t * result;
|
|
} mdns_search_once_t;
|
|
|
|
typedef struct mdns_server_s {
|
|
struct {
|
|
mdns_pcb_t pcbs[MDNS_IP_PROTOCOL_MAX];
|
|
} interfaces[TCPIP_ADAPTER_IF_MAX];
|
|
const char * hostname;
|
|
const char * instance;
|
|
mdns_srv_item_t * services;
|
|
SemaphoreHandle_t lock;
|
|
QueueHandle_t action_queue;
|
|
mdns_tx_packet_t * tx_queue_head;
|
|
mdns_search_once_t * search_once;
|
|
esp_timer_handle_t timer_handle;
|
|
} mdns_server_t;
|
|
|
|
typedef struct {
|
|
mdns_action_type_t type;
|
|
union {
|
|
char * hostname;
|
|
char * instance;
|
|
struct {
|
|
system_event_id_t event_id;
|
|
tcpip_adapter_if_t interface;
|
|
} sys_event;
|
|
struct {
|
|
mdns_srv_item_t * service;
|
|
} srv_add;
|
|
struct {
|
|
mdns_srv_item_t * service;
|
|
} srv_del;
|
|
struct {
|
|
mdns_srv_item_t * service;
|
|
char * instance;
|
|
} srv_instance;
|
|
struct {
|
|
mdns_srv_item_t * service;
|
|
uint16_t port;
|
|
} srv_port;
|
|
struct {
|
|
mdns_srv_item_t * service;
|
|
mdns_txt_linked_item_t * txt;
|
|
} srv_txt_replace;
|
|
struct {
|
|
mdns_srv_item_t * service;
|
|
char * key;
|
|
char * value;
|
|
} srv_txt_set;
|
|
struct {
|
|
mdns_srv_item_t * service;
|
|
char * key;
|
|
} srv_txt_del;
|
|
struct {
|
|
mdns_search_once_t * search;
|
|
} search_add;
|
|
struct {
|
|
mdns_tx_packet_t * packet;
|
|
} tx_handle;
|
|
struct {
|
|
mdns_rx_packet_t * packet;
|
|
} rx_handle;
|
|
} data;
|
|
} mdns_action_t;
|
|
|
|
#endif /* MDNS_PRIVATE_H_ */
|