[core] Rework mDNS responder to fix TXT records

This commit is contained in:
Kuba Szczodrzyński
2022-08-26 23:09:35 +02:00
parent 3264807e77
commit 3f588e970a
7 changed files with 127 additions and 113 deletions

View File

@@ -3,6 +3,7 @@
#ifdef LT_HAS_LWIP2 #ifdef LT_HAS_LWIP2
#include "mDNS.h" #include "mDNS.h"
#include <vector>
extern "C" { extern "C" {
#include <lwip/apps/mdns.h> #include <lwip/apps/mdns.h>
@@ -11,59 +12,35 @@ extern "C" {
static u8_t mdns_netif_client_id = 0; // TODO fix this static u8_t mdns_netif_client_id = 0; // TODO fix this
struct mdns_domain { static std::vector<char *> services;
/* Encoded domain name */ static std::vector<uint8_t> protos;
u8_t name[256]; static std::vector<std::vector<char *>> records;
/* Total length of domain name, including zero */
u16_t length;
/* Set if compression of this domain is not allowed */
u8_t skip_compression;
};
/** Description of a service */
struct mdns_service {
/** TXT record to answer with */
struct mdns_domain txtdata;
/** Name of service, like 'myweb' */
char name[MDNS_LABEL_MAXLEN + 1];
/** Type of service, like '_http' */
char service[MDNS_LABEL_MAXLEN + 1];
/** Callback function and userdata
* to update txtdata buffer */
service_get_txt_fn_t txt_fn;
void *txt_userdata;
/** TTL in seconds of SRV/TXT replies */
u32_t dns_ttl;
/** Protocol, TCP or UDP */
u16_t proto;
/** Port of the service */
u16_t port;
};
/** Description of a host/netif */
struct mdns_host {
/** Hostname */
char name[MDNS_LABEL_MAXLEN + 1];
/** Pointer to services */
struct mdns_service *services[MDNS_MAX_SERVICES];
/** TTL in seconds of A/AAAA/PTR replies */
u32_t dns_ttl;
};
static String mdnsInstanceName = "default_instance";
mDNS::mDNS() {} mDNS::mDNS() {}
mDNS::~mDNS() {} mDNS::~mDNS() {}
static void mdnsTxtCallback(struct mdns_service *service, void *userdata) {
size_t index = (size_t)userdata;
if (index >= records.size())
return;
for (const auto record : records[index]) {
err_t err = mdns_resp_add_service_txtitem(service, record, strlen(record));
if (err != ERR_OK)
return;
}
}
static void mdnsStatusCallback(struct netif *netif, uint8_t result) {}
bool mDNS::begin(const char *hostname) { bool mDNS::begin(const char *hostname) {
mdns_resp_register_name_result_cb(mdnsStatusCallback);
mdns_resp_init(); mdns_resp_init();
struct netif *netif = netif_list; struct netif *netif = netif_list;
uint8_t enabled = 0; uint8_t enabled = 0;
while (netif != NULL) { while (netif != NULL) {
netif->flags |= NETIF_FLAG_IGMP; netif->flags |= NETIF_FLAG_IGMP;
// TODO: detect mdns_netif_client_id by checking netif_get_client_data()
// and finding the requested hostname in struct mdns_host
if (netif_is_up(netif) && mdns_resp_add_netif(netif, hostname, 255) == ERR_OK) { if (netif_is_up(netif) && mdns_resp_add_netif(netif, hostname, 255) == ERR_OK) {
enabled++; enabled++;
} }
@@ -81,72 +58,52 @@ void mDNS::end() {
} }
} }
void mDNS::setInstanceName(String name) { bool mDNS::addServiceImpl(const char *name, const char *service, uint8_t proto, uint16_t port) {
mdnsInstanceName = name; bool added = false;
}
bool mDNS::addService(char *service, char *proto, uint16_t port) {
char _service[strlen(service) + 2];
char _proto[strlen(proto) + 2];
_service[0] = '_';
_proto[0] = '_';
// prepend names with _
strcpy(_service + 1, service + (service[0] == '_'));
strcpy(_proto + 1, proto + (proto[0] == '_'));
mdns_sd_proto protocol = DNSSD_PROTO_UDP;
if (strncmp(_proto + 1, "tcp", 3) == 0)
protocol = DNSSD_PROTO_TCP;
struct netif *netif = netif_list; struct netif *netif = netif_list;
while (netif != NULL) { while (netif != NULL) {
if (netif_is_up(netif)) { if (netif_is_up(netif)) {
mdns_resp_add_service(netif, mdnsInstanceName.c_str(), _service, protocol, port, 255, NULL, NULL); // register TXT callback;
// pass service index as userdata parameter
mdns_resp_add_service(
netif,
name,
service,
(mdns_sd_proto)proto,
port,
255,
mdnsTxtCallback,
(void *)services.size() // index of newly added service
);
added = true;
} }
netif = netif->next; netif = netif->next;
} }
if (!added)
return false;
// add the service to TXT record arrays
services.push_back(strdup(service));
protos.push_back(proto);
records.emplace_back();
return true;
} }
bool mDNS::addServiceTxt(char *name, char *proto, char *key, char *value) { bool mDNS::addServiceTxtImpl(const char *service, uint8_t proto, const char *item) {
char _name[strlen(name) + 2]; int8_t index = -1;
char _proto[strlen(proto) + 2]; for (uint8_t i = 0; i < services.size(); i++) {
_name[0] = '_'; // find a matching service
_proto[0] = '_'; if (strcmp(services[i], service) == 0 && protos[i] == proto) {
// prepend names with _ index = i;
strcpy(_name + 1, name + (name[0] == '_')); break;
strcpy(_proto + 1, proto + (proto[0] == '_'));
mdns_sd_proto protocol = DNSSD_PROTO_UDP;
if (strncmp(_proto + 1, "tcp", 3) == 0)
protocol = DNSSD_PROTO_TCP;
struct netif *netif = netif_list;
struct mdns_host *mdns;
struct mdns_service *service;
uint8_t txt_len = strlen(key) + strlen(value) + 1;
char *txt = (char *)malloc(txt_len + 1);
sprintf(txt, "%s=%s", key, value);
while (netif != NULL) {
if (netif_is_up(netif)) {
mdns = (struct mdns_host *)netif_get_client_data(netif, mdns_netif_client_id);
for (uint8_t i = 0; i < MDNS_MAX_SERVICES; i++) {
service = mdns->services[i];
if (service == NULL)
continue;
if (strcmp(service->service, _name) || service->proto != protocol)
continue;
if (mdns_resp_add_service_txtitem(service, txt, txt_len) != ERR_OK) {
free(txt);
return false;
}
}
} }
netif = netif->next;
} }
free(txt); if (index == -1)
return false;
records[index].push_back(strdup(item));
return true; return true;
} }

View File

@@ -0,0 +1,40 @@
/* Copyright (c) Kuba Szczodrzyński 2022-08-26. */
#include "mDNS.h"
static char *ensureUnderscore(const char *value) {
uint8_t len = strlen(value) + 1;
char *result = (char *)malloc(len);
result[0] = '_';
strcpy(result + 1, value + (value[0] == '_'));
return result;
}
void mDNS::setInstanceName(const char *name) {
if (instanceName)
free(instanceName);
instanceName = strdup(name);
}
bool mDNS::addService(char *service, char *proto, uint16_t port) {
char *_service = ensureUnderscore(service);
uint8_t _proto = strncmp(proto + (proto[0] == '_'), "tcp", 3) == 0 ? MDNS_TCP : MDNS_UDP;
bool result = addServiceImpl(instanceName ? instanceName : "LT mDNS", _service, _proto, port);
free(_service);
return result;
}
bool mDNS::addServiceTxt(char *service, char *proto, char *key, char *value) {
char *_service = ensureUnderscore(service);
uint8_t _proto = strncmp(proto + (proto[0] == '_'), "tcp", 3) == 0 ? MDNS_TCP : MDNS_UDP;
uint8_t txt_len = strlen(key) + strlen(value) + 1;
char *txt = (char *)malloc(txt_len + 1);
sprintf(txt, "%s=%s", key, value);
bool result = addServiceTxtImpl(_service, _proto, txt);
free(_service);
free(txt);
return result;
}

View File

@@ -44,7 +44,16 @@ License (MIT license):
#include <Arduino.h> #include <Arduino.h>
#include <api/IPv6Address.h> #include <api/IPv6Address.h>
#define MDNS_UDP 0
#define MDNS_TCP 1
class mDNS { class mDNS {
private:
bool addServiceImpl(const char *name, const char *service, uint8_t proto, uint16_t port);
bool addServiceTxtImpl(const char *service, uint8_t proto, const char *item);
char *instanceName = NULL;
public: public:
mDNS(); mDNS();
~mDNS(); ~mDNS();
@@ -52,9 +61,9 @@ class mDNS {
bool begin(const char *hostname); bool begin(const char *hostname);
void end(); void end();
void setInstanceName(String name); void setInstanceName(const char *name);
bool addService(char *service, char *proto, uint16_t port); bool addService(char *service, char *proto, uint16_t port);
bool addServiceTxt(char *name, char *proto, char *key, char *value); bool addServiceTxt(char *service, char *proto, char *key, char *value);
// void enableArduino(uint16_t port = 3232, bool auth = false); // void enableArduino(uint16_t port = 3232, bool auth = false);
// void disableArduino(); // void disableArduino();
// void enableWorkstation(esp_interface_t interface = ESP_IF_WIFI_STA); // void enableWorkstation(esp_interface_t interface = ESP_IF_WIFI_STA);
@@ -73,12 +82,12 @@ class mDNS {
String txt(int idx, int txtIdx); String txt(int idx, int txtIdx);
String txtKey(int idx, int txtIdx); String txtKey(int idx, int txtIdx);
void setInstanceName(const char *name) { void setInstanceName(String name) {
setInstanceName(String(name)); setInstanceName(name.c_str());
} }
void setInstanceName(char *name) { void setInstanceName(char *name) {
setInstanceName(String(name)); setInstanceName((const char *)name);
} }
bool addService(const char *service, const char *proto, uint16_t port) { bool addService(const char *service, const char *proto, uint16_t port) {
@@ -89,12 +98,12 @@ class mDNS {
return addService(service.c_str(), proto.c_str(), port); return addService(service.c_str(), proto.c_str(), port);
} }
void addServiceTxt(const char *name, const char *proto, const char *key, const char *value) { void addServiceTxt(const char *service, const char *proto, const char *key, const char *value) {
addServiceTxt((char *)name, (char *)proto, (char *)key, (char *)value); addServiceTxt((char *)service, (char *)proto, (char *)key, (char *)value);
} }
void addServiceTxt(String name, String proto, String key, String value) { void addServiceTxt(String service, String proto, String key, String value) {
addServiceTxt(name.c_str(), proto.c_str(), key.c_str(), value.c_str()); addServiceTxt(service.c_str(), proto.c_str(), key.c_str(), value.c_str());
} }
IPAddress queryHost(const char *host, uint32_t timeout = 2000) { IPAddress queryHost(const char *host, uint32_t timeout = 2000) {

View File

@@ -47,6 +47,7 @@ def env_add_defaults(env, platform, board):
# Default build options # Default build options
env.Prepend( env.Prepend(
CPPPATH=[ CPPPATH=[
"$LT_DIR/platform/common/config",
"$LT_DIR/platform/common/fixups", "$LT_DIR/platform/common/fixups",
"$LT_DIR/platform/common/fixups/lib_inc", "$LT_DIR/platform/common/fixups/lib_inc",
"$BOARD_DIR", "$BOARD_DIR",

View File

@@ -6,9 +6,10 @@
#include <sys/time.h> #include <sys/time.h>
#define LWIP_MDNS_RESPONDER 1 // mDNS support
#undef MEMP_NUM_UDP_PCB
#define LWIP_NUM_NETIF_CLIENT_DATA 1 #define LWIP_NUM_NETIF_CLIENT_DATA 1
#define LWIP_SO_RCVBUF 1 // for ioctl(FIONREAD) #define MEMP_NUM_UDP_PCB (MAX_SOCKETS_UDP + 2 + 1)
#define ip_addr ip4_addr #define ip_addr ip4_addr
#define ip_addr_t ip4_addr_t #define ip_addr_t ip4_addr_t

View File

@@ -0,0 +1,10 @@
/* Copyright (c) Kuba Szczodrzyński 2022-08-26. */
#define LWIP_TIMEVAL_PRIVATE 0
#define LWIP_NETIF_HOSTNAME 1 // to support hostname changing
#define LWIP_SO_RCVBUF 1 // for ioctl(FIONREAD)
#define LWIP_MDNS_RESPONDER 1
#define MDNS_MAX_SERVICES 10
#include_next "lwipopts.h"

View File

@@ -2,10 +2,6 @@
#pragma once #pragma once
#define LWIP_TIMEVAL_PRIVATE 0
#define LWIP_NETIF_HOSTNAME 1 // to support hostname changing
#define LWIP_SO_RCVBUF 1 // for ioctl(FIONREAD)
#include_next "lwipopts.h" #include_next "lwipopts.h"
#define ip_addr ip4_addr // LwIP 2.0.x compatibility #define ip_addr ip4_addr // LwIP 2.0.x compatibility