[core] Rework mDNS responder to fix TXT records
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
#ifdef LT_HAS_LWIP2
|
||||
|
||||
#include "mDNS.h"
|
||||
#include <vector>
|
||||
|
||||
extern "C" {
|
||||
#include <lwip/apps/mdns.h>
|
||||
@@ -11,59 +12,35 @@ extern "C" {
|
||||
|
||||
static u8_t mdns_netif_client_id = 0; // TODO fix this
|
||||
|
||||
struct mdns_domain {
|
||||
/* Encoded domain name */
|
||||
u8_t name[256];
|
||||
/* 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";
|
||||
static std::vector<char *> services;
|
||||
static std::vector<uint8_t> protos;
|
||||
static std::vector<std::vector<char *>> records;
|
||||
|
||||
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) {
|
||||
mdns_resp_register_name_result_cb(mdnsStatusCallback);
|
||||
mdns_resp_init();
|
||||
struct netif *netif = netif_list;
|
||||
uint8_t enabled = 0;
|
||||
while (netif != NULL) {
|
||||
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) {
|
||||
enabled++;
|
||||
}
|
||||
@@ -81,72 +58,52 @@ void mDNS::end() {
|
||||
}
|
||||
}
|
||||
|
||||
void mDNS::setInstanceName(String name) {
|
||||
mdnsInstanceName = name;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
bool mDNS::addServiceImpl(const char *name, const char *service, uint8_t proto, uint16_t port) {
|
||||
bool added = false;
|
||||
struct netif *netif = netif_list;
|
||||
while (netif != NULL) {
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
char _name[strlen(name) + 2];
|
||||
char _proto[strlen(proto) + 2];
|
||||
_name[0] = '_';
|
||||
_proto[0] = '_';
|
||||
// prepend names with _
|
||||
strcpy(_name + 1, name + (name[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 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;
|
||||
}
|
||||
}
|
||||
bool mDNS::addServiceTxtImpl(const char *service, uint8_t proto, const char *item) {
|
||||
int8_t index = -1;
|
||||
for (uint8_t i = 0; i < services.size(); i++) {
|
||||
// find a matching service
|
||||
if (strcmp(services[i], service) == 0 && protos[i] == proto) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
netif = netif->next;
|
||||
}
|
||||
free(txt);
|
||||
if (index == -1)
|
||||
return false;
|
||||
|
||||
records[index].push_back(strdup(item));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
40
arduino/libretuya/libraries/mDNS/mDNS.cpp
Normal file
40
arduino/libretuya/libraries/mDNS/mDNS.cpp
Normal 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;
|
||||
}
|
||||
@@ -44,7 +44,16 @@ License (MIT license):
|
||||
#include <Arduino.h>
|
||||
#include <api/IPv6Address.h>
|
||||
|
||||
#define MDNS_UDP 0
|
||||
#define MDNS_TCP 1
|
||||
|
||||
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:
|
||||
mDNS();
|
||||
~mDNS();
|
||||
@@ -52,9 +61,9 @@ class mDNS {
|
||||
bool begin(const char *hostname);
|
||||
void end();
|
||||
|
||||
void setInstanceName(String name);
|
||||
void setInstanceName(const char *name);
|
||||
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 disableArduino();
|
||||
// void enableWorkstation(esp_interface_t interface = ESP_IF_WIFI_STA);
|
||||
@@ -73,12 +82,12 @@ class mDNS {
|
||||
String txt(int idx, int txtIdx);
|
||||
String txtKey(int idx, int txtIdx);
|
||||
|
||||
void setInstanceName(const char *name) {
|
||||
setInstanceName(String(name));
|
||||
void setInstanceName(String name) {
|
||||
setInstanceName(name.c_str());
|
||||
}
|
||||
|
||||
void setInstanceName(char *name) {
|
||||
setInstanceName(String(name));
|
||||
setInstanceName((const char *)name);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void addServiceTxt(const char *name, const char *proto, const char *key, const char *value) {
|
||||
addServiceTxt((char *)name, (char *)proto, (char *)key, (char *)value);
|
||||
void addServiceTxt(const char *service, const char *proto, const char *key, const char *value) {
|
||||
addServiceTxt((char *)service, (char *)proto, (char *)key, (char *)value);
|
||||
}
|
||||
|
||||
void addServiceTxt(String name, String proto, String key, String value) {
|
||||
addServiceTxt(name.c_str(), proto.c_str(), key.c_str(), value.c_str());
|
||||
void addServiceTxt(String service, String proto, String key, String value) {
|
||||
addServiceTxt(service.c_str(), proto.c_str(), key.c_str(), value.c_str());
|
||||
}
|
||||
|
||||
IPAddress queryHost(const char *host, uint32_t timeout = 2000) {
|
||||
|
||||
@@ -47,6 +47,7 @@ def env_add_defaults(env, platform, board):
|
||||
# Default build options
|
||||
env.Prepend(
|
||||
CPPPATH=[
|
||||
"$LT_DIR/platform/common/config",
|
||||
"$LT_DIR/platform/common/fixups",
|
||||
"$LT_DIR/platform/common/fixups/lib_inc",
|
||||
"$BOARD_DIR",
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
|
||||
#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_SO_RCVBUF 1 // for ioctl(FIONREAD)
|
||||
#define MEMP_NUM_UDP_PCB (MAX_SOCKETS_UDP + 2 + 1)
|
||||
|
||||
#define ip_addr ip4_addr
|
||||
#define ip_addr_t ip4_addr_t
|
||||
|
||||
10
platform/common/config/lwipopts.h
Normal file
10
platform/common/config/lwipopts.h
Normal 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"
|
||||
@@ -2,10 +2,6 @@
|
||||
|
||||
#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"
|
||||
|
||||
#define ip_addr ip4_addr // LwIP 2.0.x compatibility
|
||||
|
||||
Reference in New Issue
Block a user