File LwIPmDNS.cpp
File List > arduino > libraries > common > mDNS > LwIPmDNS.cpp
Go to the documentation of this file.
/* Copyright (c) Kuba Szczodrzyński 2022-05-23. */
#if LT_HAS_LWIP2
#include "mDNS.h"
#include <vector>
extern "C" {
#include <errno.h>
#include <lwip/apps/mdns.h>
#include <lwip/igmp.h>
#include <lwip/init.h>
#include <lwip/netif.h>
}
#if LWIP_VERSION_SIMPLE < 20100 && defined(LWIP_NETIF_EXT_STATUS_CALLBACK)
#warning "LWIP_NETIF_EXT_STATUS_CALLBACK not available before lwIP 2.1.0"
#undef LWIP_NETIF_EXT_STATUS_CALLBACK
#endif
#if LWIP_MDNS_RESPONDER
struct CachedService {
CachedService(const char *_name, const char *_service, mdns_sd_proto _proto, uint16_t _port)
: name(strdup(_name)), service(strdup(_service)), proto(_proto), port(_port) {}
CachedService(const CachedService &) = delete;
CachedService &operator=(const CachedService &) = delete;
CachedService(CachedService &&other)
: name(other.name), service(other.service), proto(other.proto), port(other.port),
records(std::move(other.records)) {
other.name = nullptr;
other.service = nullptr;
other.records.clear();
}
~CachedService() {
if (name) {
free(name);
}
if (service) {
free(service);
}
for (auto &str : records) {
if (str) {
free(str);
}
}
}
char *name;
char *service;
mdns_sd_proto proto;
uint16_t port;
std::vector<char *> records;
};
static std::vector<CachedService> sCachedServices;
static const char *hostName;
#ifdef LWIP_NETIF_EXT_STATUS_CALLBACK
NETIF_DECLARE_EXT_CALLBACK(netif_callback)
#endif
mDNS::mDNS() {}
mDNS::~mDNS() {
cleanup();
}
void mDNS::cleanup() {
sCachedServices.clear();
free((void *)hostName);
hostName = NULL;
free((void *)instanceName);
instanceName = NULL;
}
static void mdnsTxtCallback(struct mdns_service *service, void *userdata) {
size_t index = (size_t)userdata;
if (index >= sCachedServices.size())
return;
for (const auto &record : sCachedServices[index].records) {
err_t err = mdns_resp_add_service_txtitem(service, record, strlen(record));
if (err != ERR_OK) {
LT_DM(MDNS, "Error %d while adding txt record: %s", err, record);
}
}
}
#if LWIP_VERSION_SIMPLE < 20200 // TTL removed in LwIP commit 62fb2fd749b (2.2.0 release)
static void mdnsStatusCallback(struct netif *netif, uint8_t result) {
LT_DM(MDNS, "Status: netif %u, status %u", netif->num, result);
}
#else
static void mdnsStatusCallback(struct netif *netif, uint8_t result, int8_t slot) {
LT_DM(MDNS, "Status: netif %u, status %u slot %d", netif->num, result, slot);
}
#endif
#ifdef LWIP_NETIF_EXT_STATUS_CALLBACK
static void addServices(struct netif *netif) {
for (uint8_t i = 0; i < sCachedServices.size(); i++) {
const auto &cachedService = sCachedServices[i];
LT_DM(
MDNS,
"Add service: netif %u / %s / %s / %u / %u",
netif->num,
cachedService.name,
cachedService.service,
cachedService.proto,
cachedService.port
);
s8_t slot = mdns_resp_add_service(
netif,
cachedService.name,
cachedService.service,
cachedService.proto,
cachedService.port,
#if LWIP_VERSION_SIMPLE < 20200 // TTL removed in LwIP commit 62fb2fd749b (2.2.0 release)
255,
#endif
mdnsTxtCallback,
reinterpret_cast<void *>(i) // index of newly added service
);
if (slot < 0) {
LT_DM(MDNS, "mdns_resp_add_service returned error %d", slot);
}
}
}
#endif
static bool enableMDNS(struct netif *netif) {
if (netif_is_up(netif)) {
LT_DM(MDNS, "Starting mDNS on netif %u", netif->num);
if ((netif->flags & NETIF_FLAG_IGMP) == 0) {
netif->flags |= NETIF_FLAG_IGMP;
igmp_start(netif);
LT_DM(MDNS, "Added IGMP to netif %u", netif->num);
}
#if LWIP_VERSION_SIMPLE < 20200 // TTL removed in LwIP commit 62fb2fd749b (2.2.0 release)
err_t ret = mdns_resp_add_netif(netif, hostName, 255);
#else
err_t ret = mdns_resp_add_netif(netif, hostName);
#endif
if (ret == ERR_OK) {
LT_DM(MDNS, "mDNS started on netif %u, announcing it to network", netif->num);
#if LWIP_VERSION_SIMPLE >= 20100
mdns_resp_announce(netif);
#else
#warning "lwIP version older than 2.1.0, mdns_resp_announce() unavailable"
#endif
return true;
} else {
LT_DM(MDNS, "Cannot start mDNS on netif %u; ret=%d, errno=%d", netif->num, ret, errno);
}
}
return false;
}
#ifdef LWIP_NETIF_EXT_STATUS_CALLBACK
static void mdns_netif_ext_status_callback(
struct netif *netif,
netif_nsc_reason_t reason,
const netif_ext_callback_args_t *args
) {
if (reason & LWIP_NSC_NETIF_REMOVED) {
LT_DM(MDNS, "Netif removed, stopping mDNS on netif %u", netif->num);
mdns_resp_remove_netif(netif);
} else if ((reason & LWIP_NSC_STATUS_CHANGED) || (reason & LWIP_NSC_NETIF_ADDED)) {
LT_DM(MDNS, "Netif changed/added, starting mDNS on netif %u", netif->num);
if (enableMDNS(netif) && sCachedServices.size() > 0) {
LT_DM(MDNS, "Adding services to netif %u", netif->num);
addServices(netif);
}
}
}
#endif
bool mDNS::begin(const char *hostname) {
hostName = strdup(hostname);
setInstanceName(hostname);
#ifdef LWIP_NETIF_EXT_STATUS_CALLBACK
netif_add_ext_callback(&netif_callback, mdns_netif_ext_status_callback);
#endif
LT_DM(MDNS, "Starting (%s)", hostname);
#if LWIP_VERSION_MAJOR >= 2 && LWIP_VERSION_MINOR >= 1
mdns_resp_register_name_result_cb(mdnsStatusCallback);
#endif
mdns_resp_init();
struct netif *netif;
for (netif = netif_list; netif != NULL; netif = netif->next) {
enableMDNS(netif);
}
return true;
}
void mDNS::end() {
#ifdef LWIP_NETIF_EXT_STATUS_CALLBACK
netif_remove_ext_callback(&netif_callback);
#endif
struct netif *netif = netif_list;
while (netif != NULL) {
if (netif_is_up(netif))
mdns_resp_remove_netif(netif);
netif = netif->next;
}
cleanup();
}
bool mDNS::addServiceImpl(const char *name, const char *service, uint8_t proto, uint16_t port) {
bool added = false;
struct netif *netif = netif_list;
std::size_t serviceIndex = sCachedServices.size();
// add the service to TXT record arrays
sCachedServices.emplace_back(name, service, (mdns_sd_proto)proto, port);
while (netif != NULL) {
if (netif_is_up(netif)) {
// register TXT callback;
// pass service index as userdata parameter
LT_DM(MDNS, "Add service: netif %u / %s / %s / %u / %u", netif->num, name, service, proto, port);
s8_t slot = mdns_resp_add_service(
netif,
name,
service,
(mdns_sd_proto)proto,
port,
#if LWIP_VERSION_SIMPLE < 20200 // TTL removed in LwIP commit 62fb2fd749b (2.2.0 release)
255,
#endif
mdnsTxtCallback,
(void *)serviceIndex // index of newly added service
);
if (slot < 0) {
LT_DM(MDNS, "mdns_resp_add_service returned error %d", slot);
}
added = true;
}
netif = netif->next;
}
return added;
}
bool mDNS::addServiceTxtImpl(const char *service, uint8_t proto, const char *item) {
uint8_t i;
for (i = 0; i < sCachedServices.size(); i++) {
const auto &cachedService = sCachedServices[i];
// find a matching service
if (strcmp(cachedService.service, service) == 0 && cachedService.proto == proto) {
break;
}
}
if (i == sCachedServices.size())
return false;
sCachedServices[i].records.push_back(strdup(item));
return true;
}
MDNSResponder MDNS;
#endif
#endif