From de4c772f54d4560de5c21f50c8e9e9406292318a Mon Sep 17 00:00:00 2001
From: Our Air Quality <info@ourairquality.org>
Date: Sun, 31 Dec 2017 18:13:36 +1100
Subject: [PATCH] mdns: move the announcements to a timer callback

The guts of the mdns code uses a significant amount of stack for a small
system. This makes it problematic calling into this code from the various
paths that trigger announcements. This patch has these code paths queue an
announcement that will be performed via a timer callback.

This also addes 'api' entry functions that use core locking to protect the
mdns code state.
---
 src/apps/mdns/mdns.c         | 89 +++++++++++++++++++++++++++++++++++++++++---
 src/include/lwip/apps/mdns.h |  7 +++-
 2 files changed, 90 insertions(+), 6 deletions(-)

diff --git a/src/apps/mdns/mdns.c b/src/apps/mdns/mdns.c
index 92cd3980..e1ffe9b6 100644
--- a/src/apps/mdns/mdns.c
+++ b/src/apps/mdns/mdns.c
@@ -99,6 +99,15 @@ static const ip_addr_t v6group = DNS_MQUERY_IPV6_GROUP_INIT;
 #define DOMAIN_JUMP_SIZE 2
 #define DOMAIN_JUMP 0xc000
 
+#if LWIP_TCPIP_CORE_LOCKING
+#include "lwip/tcpip.h"
+#define LWIP_MDNS_PROTECT()   LOCK_TCPIP_CORE()
+#define LWIP_MDNS_UNPROTECT() UNLOCK_TCPIP_CORE()
+#else /* LWIP_TCPIP_CORE_LOCKING */
+#define LWIP_MDNS_PROTECT()
+#define LWIP_MDNS_UNPROTECT()
+#endif /* LWIP_TCPIP_CORE_LOCKING */
+
 static u8_t mdns_netif_client_id;
 static struct udp_pcb *mdns_pcb;
 NETIF_DECLARE_EXT_CALLBACK(netif_callback)
@@ -1925,6 +1934,16 @@ cleanup:
   return res;
 }
 
+err_t
+mdnsapi_mdns_resp_add_netif(struct netif *netif, const char *hostname, u32_t dns_ttl)
+{
+  err_t res;
+  LWIP_MDNS_PROTECT();
+  res = mdns_resp_add_netif(netif, hostname, dns_ttl);
+  LWIP_MDNS_UNPROTECT();
+  return res;
+}
+
 /**
  * @ingroup mdns
  * Stop responding to MDNS queries on this interface, leave multicast groups,
@@ -1962,6 +1981,16 @@ mdns_resp_remove_netif(struct netif *netif)
   return ERR_OK;
 }
 
+err_t
+mdnsapi_mdns_resp_remove_netif(struct netif *netif)
+{
+  err_t res;
+  LWIP_MDNS_PROTECT();
+  res = mdns_resp_remove_netif(netif);
+  LWIP_MDNS_UNPROTECT();
+  return res;
+}
+
 /**
  * @ingroup mdns
  * Add a service to the selected network interface.
@@ -2018,6 +2047,16 @@ mdns_resp_add_service(struct netif *netif, const char *name, const char *service
   return slot;
 }
 
+s8_t
+mdnsapi_mdns_resp_add_service(struct netif *netif, const char *name, const char *service, enum mdns_sd_proto proto, u16_t port, u32_t dns_ttl, service_get_txt_fn_t txt_fn, void *txt_data)
+{
+  s8_t res;
+  LWIP_MDNS_PROTECT();
+  res = mdns_resp_add_service(netif, name, service, proto, port, dns_ttl, txt_fn, txt_data);
+  LWIP_MDNS_UNPROTECT();
+  return res;
+}
+
 /**
  * @ingroup mdns
  * Delete a service on the selected network interface.
@@ -2042,6 +2081,16 @@ mdns_resp_del_service(struct netif *netif, s8_t slot)
   return ERR_OK;
 }
 
+err_t
+mdnsapi_mdns_resp_del_service(struct netif *netif, s8_t slot)
+{
+  err_t res;
+  LWIP_MDNS_PROTECT();
+  res = mdns_resp_del_service(netif, slot);
+  LWIP_MDNS_UNPROTECT();
+  return res;
+}
+
 /**
  * @ingroup mdns
  * Call this function from inside the service_get_txt_fn_t callback to add text data.
@@ -2060,15 +2109,16 @@ mdns_resp_add_service_txtitem(struct mdns_service *service, const char *txt, u8_
   return mdns_domain_add_label(&service->txtdata, txt, txt_len);
 }
 
+static volatile u8_t mdns_announce_pending;
+
 /**
- * @ingroup mdns
- * Send unsolicited answer containing all our known data
+ * Timer callback to send unsolicited answer containing all known data
  * @param netif The network interface to send on
  */
-void
-mdns_resp_announce(struct netif *netif)
+static void
+mdns_announce_callback(struct netif *netif)
 {
-  LWIP_ERROR("mdns_resp_netif_ip_changed: netif != NULL", (netif != NULL), return);
+  mdns_announce_pending = 0;
 
   if (NETIF_TO_HOST(netif) == NULL) {
     return;
@@ -2085,6 +2135,27 @@ mdns_resp_announce(struct netif *netif)
 #endif
 }
 
+/**
+ * @ingroup mdns
+ * Queue unsolicited answer containing all our known data.
+ * For calling within the tcpip thread, core lock held.
+ * @param netif The network interface to send on
+ */
+void
+mdns_resp_announce(struct netif *netif)
+{
+  u8_t queued;
+
+  LWIP_ERROR("mdns_resp_announce: netif != NULL", (netif != NULL), return);
+
+  queued = mdns_announce_pending;
+  mdns_announce_pending = 1;
+
+  if (!queued) {
+    sys_timeout(50, (sys_timeout_handler)mdns_announce_callback, netif);
+  }
+}
+
 /**
  * @ingroup mdns
  * Initiate MDNS responder. Will open UDP sockets on port 5353
@@ -2112,4 +2183,12 @@ mdns_resp_init(void)
   netif_add_ext_callback(&netif_callback, mdns_netif_ext_status_callback);
 }
 
+void
+mdnsapi_mdns_resp_init(void)
+{
+  LWIP_MDNS_PROTECT();
+  mdns_resp_init();
+  LWIP_MDNS_UNPROTECT();
+}
+
 #endif /* LWIP_MDNS_RESPONDER */
diff --git a/src/include/lwip/apps/mdns.h b/src/include/lwip/apps/mdns.h
index 54c56264..2f74ffa1 100644
--- a/src/include/lwip/apps/mdns.h
+++ b/src/include/lwip/apps/mdns.h
@@ -57,12 +57,17 @@ struct mdns_service;
 typedef void (*service_get_txt_fn_t)(struct mdns_service *service, void *txt_userdata);
 
 void mdns_resp_init(void);
+void mdnsapi_mdns_resp_init(void);
 
 err_t mdns_resp_add_netif(struct netif *netif, const char *hostname, u32_t dns_ttl);
+err_t mdnsapi_mdns_resp_add_netif(struct netif *netif, const char *hostname, u32_t dns_ttl);
 err_t mdns_resp_remove_netif(struct netif *netif);
+err_t mdnsapi_mdns_resp_remove_netif(struct netif *netif);
 
 s8_t  mdns_resp_add_service(struct netif *netif, const char *name, const char *service, enum mdns_sd_proto proto, u16_t port, u32_t dns_ttl, service_get_txt_fn_t txt_fn, void *txt_userdata);
+s8_t  mdnsapi_mdns_resp_add_service(struct netif *netif, const char *name, const char *service, enum mdns_sd_proto proto, u16_t port, u32_t dns_ttl, service_get_txt_fn_t txt_fn, void *txt_userdata);
 err_t mdns_resp_del_service(struct netif *netif, s8_t slot);
+err_t mdnsapi_mdns_resp_del_service(struct netif *netif, s8_t slot);
 
 err_t mdns_resp_add_service_txtitem(struct mdns_service *service, const char *txt, u8_t txt_len);
 
@@ -77,7 +82,7 @@ void mdns_resp_announce(struct netif *netif);
  * @param netif The network interface where settings have changed.
  */
 #define mdns_resp_netif_settings_changed(netif) mdns_resp_announce(netif)
- 
+
 /** @ingroup mdns
  * To trigger announces from non-TCPIP threads
  * Be sure to \#include lwip/netifapi.h when using this macro
-- 
2.14.3

