mDNS Service

Overview

mDNS is a multicast UDP service that is used to provide local network service and host discovery.

mDNS is installed by default on most operating systems or is available as separate package. On Mac OS it is installed by default and is called Bonjour. Apple releases an installer for Windows that can be found on Apple’s support page. On Linux, mDNS is provided by avahi and is usually installed by default.

mDNS Properties

  • hostname: the hostname that the device will respond to. If not set, the hostname will be read from the interface. Example: my-esp32 will resolve to my-esp32.local

  • default_instance: friendly name for your device, like Jhon's ESP32 Thing. If not set, hostname will be used.

Example method to start mDNS for the STA interface and set hostname and default_instance:

void start_mdns_service()
{
    //initialize mDNS service
    esp_err_t err = mdns_init();
    if (err) {
        printf("MDNS Init failed: %d\n", err);
        return;
    }

    //set hostname
    mdns_hostname_set("my-esp32");
    //set default instance
    mdns_instance_name_set("Jhon's ESP32 Thing");
}

mDNS Services

mDNS can advertise information about network services that your device offers. Each service is defined by a few properties.

  • instance_name: friendly name for your service, like Jhon's ESP32 Web Server. If not defined, default_instance will be used.

  • service_type: (required) service type, prepended with underscore. Some common types can be found here.

  • proto: (required) protocol that the service runs on, prepended with underscore. Example: _tcp or _udp

  • port: (required) network port that the service runs on

  • txt: {var, val} array of strings, used to define properties for your service

Example method to add a few services and different properties:

void add_mdns_services()
{
    //add our services
    mdns_service_add(NULL, "_http", "_tcp", 80, NULL, 0);
    mdns_service_add(NULL, "_arduino", "_tcp", 3232, NULL, 0);
    mdns_service_add(NULL, "_myservice", "_udp", 1234, NULL, 0);

    //NOTE: services must be added before their properties can be set
    //use custom instance for the web server
    mdns_service_instance_name_set("_http", "_tcp", "Jhon's ESP32 Web Server");

    mdns_txt_item_t serviceTxtData[3] = {
        {"board","esp32"},
        {"u","user"},
        {"p","password"}
    };
    //set txt data for service (will free and replace current data)
    mdns_service_txt_set("_http", "_tcp", serviceTxtData, 3);

    //change service port
    mdns_service_port_set("_myservice", "_udp", 4321);
}

mDNS Query

mDNS provides methods for browsing for services and resolving host’s IP/IPv6 addresses.

Results for services are returned as a linked list of mdns_result_t objects.

Example method to resolve host IPs:

void resolve_mdns_host(const char * host_name)
{
    printf("Query A: %s.local", host_name);

    struct ip4_addr addr;
    addr.addr = 0;

    esp_err_t err = mdns_query_a(host_name, 2000,  &addr);
    if(err){
        if(err == ESP_ERR_NOT_FOUND){
            printf("Host was not found!");
            return;
        }
        printf("Query Failed");
        return;
    }

    printf(IPSTR, IP2STR(&addr));
}

Example method to resolve local services:

static const char * if_str[] = {"STA", "AP", "ETH", "MAX"};
static const char * ip_protocol_str[] = {"V4", "V6", "MAX"};

void mdns_print_results(mdns_result_t * results){
    mdns_result_t * r = results;
    mdns_ip_addr_t * a = NULL;
    int i = 1, t;
    while(r){
        printf("%d: Interface: %s, Type: %s\n", i++, if_str[r->tcpip_if], ip_protocol_str[r->ip_protocol]);
        if(r->instance_name){
            printf("  PTR : %s\n", r->instance_name);
        }
        if(r->hostname){
            printf("  SRV : %s.local:%u\n", r->hostname, r->port);
        }
        if(r->txt_count){
            printf("  TXT : [%u] ", r->txt_count);
            for(t=0; t<r->txt_count; t++){
                printf("%s=%s; ", r->txt[t].key, r->txt[t].value);
            }
            printf("\n");
        }
        a = r->addr;
        while(a){
            if(a->addr.type == IPADDR_TYPE_V6){
                printf("  AAAA: " IPV6STR "\n", IPV62STR(a->addr.u_addr.ip6));
            } else {
                printf("  A   : " IPSTR "\n", IP2STR(&(a->addr.u_addr.ip4)));
            }
            a = a->next;
        }
        r = r->next;
    }

}

void find_mdns_service(const char * service_name, const char * proto)
{
    ESP_LOGI(TAG, "Query PTR: %s.%s.local", service_name, proto);

    mdns_result_t * results = NULL;
    esp_err_t err = mdns_query_ptr(service_name, proto, 3000, 20,  &results);
    if(err){
        ESP_LOGE(TAG, "Query Failed");
        return;
    }
    if(!results){
        ESP_LOGW(TAG, "No results found!");
        return;
    }

    mdns_print_results(results);
    mdns_query_results_free(results);
}

Example of using the methods above:

void my_app_some_method(){
    //search for esp32-mdns.local
    resolve_mdns_host("esp32-mdns");

    //search for HTTP servers
    find_mdns_service("_http", "_tcp");
    //or file servers
    find_mdns_service("_smb", "_tcp"); //windows sharing
    find_mdns_service("_afpovertcp", "_tcp"); //apple sharing
    find_mdns_service("_nfs", "_tcp"); //NFS server
    find_mdns_service("_ftp", "_tcp"); //FTP server
    //or networked printer
    find_mdns_service("_printer", "_tcp");
    find_mdns_service("_ipp", "_tcp");
}

Application Example

mDNS server/scanner example: protocols/mdns.

API Reference

Header File

Functions

esp_err_t mdns_init()

Initialize mDNS on given interface.

Return

  • ESP_OK on success

  • ESP_ERR_INVALID_STATE when failed to register event handler

  • ESP_ERR_NO_MEM on memory error

  • ESP_FAIL when failed to start mdns task

void mdns_free()

Stop and free mDNS server.

esp_err_t mdns_hostname_set(const char *hostname)

Set the hostname for mDNS server required if you want to advertise services.

Return

  • ESP_OK success

  • ESP_ERR_INVALID_ARG Parameter error

  • ESP_ERR_NO_MEM memory error

Parameters
  • hostname: Hostname to set

esp_err_t mdns_instance_name_set(const char *instance_name)

Set the default instance name for mDNS server.

Return

  • ESP_OK success

  • ESP_ERR_INVALID_ARG Parameter error

  • ESP_ERR_NO_MEM memory error

Parameters
  • instance_name: Instance name to set

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)

Add service to mDNS server.

Return

  • ESP_OK success

  • ESP_ERR_INVALID_ARG Parameter error

  • ESP_ERR_NO_MEM memory error

  • ESP_FAIL failed to add serivce

Parameters
  • instance_name: instance name to set. If NULL, global instance name or hostname will be used

  • service_type: service type (_http, _ftp, etc)

  • proto: service protocol (_tcp, _udp)

  • port: service port

  • txt: string array of TXT data (eg. {{“var”,”val”},{“other”,”2”}})

  • num_items: number of items in TXT data

esp_err_t mdns_service_remove(const char *service_type, const char *proto)

Remove service from mDNS server.

Return

  • ESP_OK success

  • ESP_ERR_INVALID_ARG Parameter error

  • ESP_ERR_NOT_FOUND Service not found

  • ESP_ERR_NO_MEM memory error

Parameters
  • service_type: service type (_http, _ftp, etc)

  • proto: service protocol (_tcp, _udp)

esp_err_t mdns_service_instance_name_set(const char *service_type, const char *proto, const char *instance_name)

Set instance name for service.

Return

  • ESP_OK success

  • ESP_ERR_INVALID_ARG Parameter error

  • ESP_ERR_NOT_FOUND Service not found

  • ESP_ERR_NO_MEM memory error

Parameters
  • service_type: service type (_http, _ftp, etc)

  • proto: service protocol (_tcp, _udp)

  • instance_name: instance name to set

esp_err_t mdns_service_port_set(const char *service_type, const char *proto, uint16_t port)

Set service port.

Return

  • ESP_OK success

  • ESP_ERR_INVALID_ARG Parameter error

  • ESP_ERR_NOT_FOUND Service not found

  • ESP_ERR_NO_MEM memory error

Parameters
  • service_type: service type (_http, _ftp, etc)

  • proto: service protocol (_tcp, _udp)

  • port: service port

esp_err_t mdns_service_txt_set(const char *service_type, const char *proto, mdns_txt_item_t txt[], uint8_t num_items)

Replace all TXT items for service.

Return

  • ESP_OK success

  • ESP_ERR_INVALID_ARG Parameter error

  • ESP_ERR_NOT_FOUND Service not found

  • ESP_ERR_NO_MEM memory error

Parameters
  • service_type: service type (_http, _ftp, etc)

  • proto: service protocol (_tcp, _udp)

  • txt: array of TXT data (eg. {{“var”,”val”},{“other”,”2”}})

  • num_items: number of items in TXT data

esp_err_t mdns_service_txt_item_set(const char *service_type, const char *proto, const char *key, const char *value)

Set/Add TXT item for service TXT record.

Return

  • ESP_OK success

  • ESP_ERR_INVALID_ARG Parameter error

  • ESP_ERR_NOT_FOUND Service not found

  • ESP_ERR_NO_MEM memory error

Parameters
  • service_type: service type (_http, _ftp, etc)

  • proto: service protocol (_tcp, _udp)

  • key: the key that you want to add/update

  • value: the new value of the key

esp_err_t mdns_service_txt_item_remove(const char *service_type, const char *proto, const char *key)

Remove TXT item for service TXT record.

Return

  • ESP_OK success

  • ESP_ERR_INVALID_ARG Parameter error

  • ESP_ERR_NOT_FOUND Service not found

  • ESP_ERR_NO_MEM memory error

Parameters
  • service_type: service type (_http, _ftp, etc)

  • proto: service protocol (_tcp, _udp)

  • key: the key that you want to remove

esp_err_t mdns_service_remove_all()

Remove and free all services from mDNS server.

Return

  • ESP_OK success

  • ESP_ERR_INVALID_ARG Parameter error

esp_err_t mdns_query(const char *name, const char *service_type, const char *proto, uint16_t type, uint32_t timeout, size_t max_results, mdns_result_t **results)

Query mDNS for host or service All following query methods are derived from this one.

Return

  • ESP_OK success

  • ESP_ERR_INVALID_STATE mDNS is not running

  • ESP_ERR_NO_MEM memory error

  • ESP_ERR_INVALID_ARG timeout was not given

Parameters
  • name: service instance or host name (NULL for PTR queries)

  • service_type: service type (_http, _arduino, _ftp etc.) (NULL for host queries)

  • proto: service protocol (_tcp, _udp, etc.) (NULL for host queries)

  • type: type of query (MDNS_TYPE_*)

  • timeout: time in milliseconds to wait for answers.

  • max_results: maximum results to be collected

  • results: pointer to the results of the query results must be freed using mdns_query_results_free below

void mdns_query_results_free(mdns_result_t *results)

Free query results.

Parameters
  • results: linked list of results to be freed

esp_err_t mdns_query_ptr(const char *service_type, const char *proto, uint32_t timeout, size_t max_results, mdns_result_t **results)

Query mDNS for service.

Return

  • ESP_OK success

  • ESP_ERR_INVALID_STATE mDNS is not running

  • ESP_ERR_NO_MEM memory error

  • ESP_ERR_INVALID_ARG parameter error

Parameters
  • service_type: service type (_http, _arduino, _ftp etc.)

  • proto: service protocol (_tcp, _udp, etc.)

  • timeout: time in milliseconds to wait for answer.

  • max_results: maximum results to be collected

  • results: pointer to the results of the query

esp_err_t mdns_query_srv(const char *instance_name, const char *service_type, const char *proto, uint32_t timeout, mdns_result_t **result)

Query mDNS for SRV record.

Return

  • ESP_OK success

  • ESP_ERR_INVALID_STATE mDNS is not running

  • ESP_ERR_NO_MEM memory error

  • ESP_ERR_INVALID_ARG parameter error

Parameters
  • instance_name: service instance name

  • service_type: service type (_http, _arduino, _ftp etc.)

  • proto: service protocol (_tcp, _udp, etc.)

  • timeout: time in milliseconds to wait for answer.

  • result: pointer to the result of the query

esp_err_t mdns_query_txt(const char *instance_name, const char *service_type, const char *proto, uint32_t timeout, mdns_result_t **result)

Query mDNS for TXT record.

Return

  • ESP_OK success

  • ESP_ERR_INVALID_STATE mDNS is not running

  • ESP_ERR_NO_MEM memory error

  • ESP_ERR_INVALID_ARG parameter error

Parameters
  • instance_name: service instance name

  • service_type: service type (_http, _arduino, _ftp etc.)

  • proto: service protocol (_tcp, _udp, etc.)

  • timeout: time in milliseconds to wait for answer.

  • result: pointer to the result of the query

esp_err_t mdns_query_a(const char *host_name, uint32_t timeout, ip4_addr_t *addr)

Query mDNS for A record.

Return

  • ESP_OK success

  • ESP_ERR_INVALID_STATE mDNS is not running

  • ESP_ERR_NO_MEM memory error

  • ESP_ERR_INVALID_ARG parameter error

Parameters
  • host_name: host name to look for

  • timeout: time in milliseconds to wait for answer.

  • addr: pointer to the resulting IP4 address

esp_err_t mdns_query_aaaa(const char *host_name, uint32_t timeout, ip6_addr_t *addr)

Query mDNS for A record.

Return

  • ESP_OK success

  • ESP_ERR_INVALID_STATE mDNS is not running

  • ESP_ERR_NO_MEM memory error

  • ESP_ERR_INVALID_ARG parameter error

Parameters
  • host_name: host name to look for

  • timeout: time in milliseconds to wait for answer. If 0, max_results needs to be defined

  • addr: pointer to the resulting IP6 address

esp_err_t mdns_handle_system_event(void *ctx, system_event_t *event)

System event handler This method controls the service state on all active interfaces and applications are required to call it from the system event handler for normal operation of mDNS service.

Parameters
  • ctx: The system event context

  • event: The system event

Structures

struct mdns_txt_item_t

mDNS basic text item structure Used in mdns_service_add()

Public Members

const char *key

item key name

const char *value

item value string

struct mdns_ip_addr_s

mDNS query linked list IP item

Public Members

ip_addr_t addr

IP address

struct mdns_ip_addr_s *next

next IP, or NULL for the last IP in the list

struct mdns_result_s

mDNS query result structure

Public Members

struct mdns_result_s *next

next result, or NULL for the last result in the list

tcpip_adapter_if_t tcpip_if

interface on which the result came (AP/STA/ETH)

mdns_ip_protocol_t ip_protocol

ip_protocol type of the interface (v4/v6)

char *instance_name

instance name

char *hostname

hostname

uint16_t port

service port

mdns_txt_item_t *txt

txt record

size_t txt_count

number of txt items

mdns_ip_addr_t *addr

linked list of IP addreses found

Macros

MDNS_TYPE_A
MDNS_TYPE_PTR
MDNS_TYPE_TXT
MDNS_TYPE_AAAA
MDNS_TYPE_SRV
MDNS_TYPE_OPT
MDNS_TYPE_NSEC
MDNS_TYPE_ANY

Type Definitions

typedef struct mdns_ip_addr_s mdns_ip_addr_t

mDNS query linked list IP item

typedef struct mdns_result_s mdns_result_t

mDNS query result structure

Enumerations

enum mdns_ip_protocol_t

mDNS enum to specify the ip_protocol type

Values:

MDNS_IP_PROTOCOL_V4
MDNS_IP_PROTOCOL_V6
MDNS_IP_PROTOCOL_MAX