Skip to content

Commit 86623e8

Browse files
committed
Add mDNS module.
1 parent 7b21778 commit 86623e8

File tree

6 files changed

+510
-1
lines changed

6 files changed

+510
-1
lines changed

components/modules/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ set(module_srcs
2525
"i2c_hw_master.c"
2626
"i2c_hw_slave.c"
2727
"ledc.c"
28+
"mdns.c"
2829
"mqtt.c"
2930
"net.c"
3031
"node.c"

components/modules/Kconfig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,12 @@ menu "NodeMCU modules"
177177
help
178178
Includes the LEDC module.
179179

180+
config NODEMCU_CMODULE_MDNS
181+
bool "mDNS module"
182+
default "n"
183+
help
184+
Includes the mDNS module.
185+
180186
config NODEMCU_CMODULE_MQTT
181187
bool "MQTT module"
182188
default "n"

components/modules/idf_component.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ dependencies:
44
idf:
55
version: ">=5.0.0"
66
# Component dependencies
7-
libsodium: "~1.0.20"
7+
espressif/libsodium: "~1.0.20"
8+
espressif/mdns: "^1.4.2"

components/modules/mdns.c

Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
#include "module.h"
2+
#include "lauxlib.h"
3+
#include "ip_fmt.h"
4+
5+
#include "esp_err.h"
6+
#include "mdns.h"
7+
8+
// Table key names
9+
static const char *HOSTNAME = "hostname";
10+
static const char *INSTANCE_NAME = "instance_name";
11+
static const char *SERVICES = "services";
12+
static const char *SERVICE_TYPE = "service_type";
13+
static const char *PROTO = "protocol";
14+
static const char *PORT = "port";
15+
static const char *TXT = "txt";
16+
static const char *SUBTYPE = "subtype";
17+
static const char *QUERY_TYPE = "query_type";
18+
static const char *NAME = "name";
19+
static const char *TIMEOUT = "timeout";
20+
static const char *MAX_RESULTS = "max_results";
21+
static const char *ADDRESSES = "addresses";
22+
23+
#define DEFAULT_TIMEOUT_MS 2000
24+
#define DEFAULT_MAX_RESULTS 10
25+
26+
static bool started;
27+
28+
static bool valid_query_type(int t)
29+
{
30+
switch(t)
31+
{
32+
case MDNS_TYPE_A:
33+
case MDNS_TYPE_PTR:
34+
case MDNS_TYPE_TXT:
35+
case MDNS_TYPE_AAAA:
36+
case MDNS_TYPE_SRV:
37+
//case MDNS_TYPE_OPT:
38+
//case MDNS_TYPE_NSEC:
39+
case MDNS_TYPE_ANY: return true;
40+
default: return false;
41+
}
42+
}
43+
44+
45+
static int lmdns_start(lua_State *L)
46+
{
47+
luaL_checktable(L, 1);
48+
lua_settop(L, 1);
49+
50+
if (started)
51+
return luaL_error(L, "already started");
52+
53+
bool inited = false;
54+
esp_err_t err = mdns_init();
55+
if (err != ESP_OK)
56+
goto mdns_err;
57+
inited = true;
58+
59+
// Hostname
60+
lua_getfield(L, 1, HOSTNAME);
61+
const char *hostname = luaL_optstring(L, -1, NULL);
62+
if (hostname)
63+
{
64+
err = mdns_hostname_set(hostname);
65+
if (err != ESP_OK)
66+
goto mdns_err;
67+
}
68+
lua_pop(L, 1);
69+
70+
// Instance name
71+
lua_getfield(L, 1, INSTANCE_NAME);
72+
const char *instname = luaL_optstring(L, -1, NULL);
73+
if (instname)
74+
{
75+
err = mdns_instance_name_set(instname);
76+
if (err != ESP_OK)
77+
goto mdns_err;
78+
}
79+
lua_pop(L, 1);
80+
81+
// Services
82+
lua_getfield(L, 1, SERVICES);
83+
unsigned i = 1;
84+
if (!lua_isnoneornil(L, 2)) // array of service entries
85+
{
86+
luaL_checktable(L, 2);
87+
for (i = 1; true; ++i)
88+
{
89+
lua_rawgeti(L, 2, i);
90+
if (!lua_istable(L, 3))
91+
break;
92+
93+
lua_getfield(L, 3, SERVICE_TYPE);
94+
const char *svctype = luaL_checkstring(L, -1);
95+
96+
lua_getfield(L, 3, PROTO);
97+
const char *proto = luaL_checkstring(L, -1);
98+
99+
lua_getfield(L, 3, PORT);
100+
int port = luaL_checkint(L, -1);
101+
102+
lua_getfield(L, 3, INSTANCE_NAME);
103+
const char *instname2 = luaL_optstring(L, -1, NULL);
104+
105+
// Note: we add txt entries iteratively to avoid having to size and
106+
// allocate a buffer to hold them all.
107+
err = mdns_service_add(instname2, svctype, proto, port, NULL, 0);
108+
if (err != ESP_OK)
109+
goto mdns_err;
110+
111+
lua_pop(L, 4); // svctype, proto, port, instname2
112+
113+
lua_getfield(L, 3, TXT);
114+
if (lua_istable(L, 4))
115+
{
116+
lua_pushnil(L); // 5 is now table key
117+
while(lua_next(L, 4)) // replaces 5 with actual key
118+
{
119+
// copy key, value so we can safely tostring() them
120+
lua_pushvalue(L, 5);
121+
lua_pushvalue(L, 6);
122+
123+
const char *key = luaL_checkstring(L, -2);
124+
const char *val = luaL_checkstring(L, -1);
125+
126+
err = mdns_service_txt_item_set_for_host(
127+
instname2, svctype, proto, hostname, key, val);
128+
if (err != ESP_OK)
129+
goto mdns_err;
130+
131+
lua_pop(L, 3); // value, key, value
132+
}
133+
}
134+
lua_pop(L, 1); // txt table
135+
136+
// Subtype
137+
lua_getfield(L, 1, SUBTYPE);
138+
const char *subtype = luaL_optstring(L, -1, NULL);
139+
if (subtype)
140+
{
141+
err = mdns_service_subtype_add_for_host(
142+
instname2, svctype, proto, hostname, subtype);
143+
if (err != ESP_OK)
144+
goto mdns_err;
145+
}
146+
lua_pop(L, 1); // subtype
147+
148+
lua_pop(L, 1); // services[i] table
149+
}
150+
}
151+
lua_pop(L, 1); // services array
152+
153+
started = true;
154+
155+
// Return number of services we added
156+
lua_pushinteger(L, i - 1);
157+
return 1;
158+
159+
mdns_err:
160+
if (inited)
161+
{
162+
mdns_service_remove_all();
163+
mdns_free();
164+
}
165+
return luaL_error(L, "mdns error: %s", esp_err_to_name(err));
166+
}
167+
168+
169+
static int lmdns_stop(lua_State *L)
170+
{
171+
if (started)
172+
{
173+
mdns_service_remove_all();
174+
started = false;
175+
}
176+
mdns_free();
177+
return 0;
178+
}
179+
180+
181+
static int lmdns_query(lua_State *L)
182+
{
183+
luaL_checktable(L, 1);
184+
lua_settop(L, 1);
185+
186+
lua_getfield(L, 1, NAME);
187+
const char *name = luaL_optstring(L, -1, NULL);
188+
189+
lua_getfield(L, 1, SERVICE_TYPE);
190+
const char *svctype = luaL_optstring(L, -1, NULL);
191+
192+
lua_getfield(L, 1, PROTO);
193+
const char *proto = luaL_optstring(L, -1, NULL);
194+
195+
lua_getfield(L, 1, QUERY_TYPE);
196+
int qtype = luaL_checkint(L, -1);
197+
if (!valid_query_type(qtype))
198+
return luaL_error(L, "unknown mDNS query type");
199+
200+
lua_getfield(L, 1, TIMEOUT);
201+
int timeout = luaL_optinteger(L, -1, DEFAULT_TIMEOUT_MS);
202+
203+
lua_getfield(L, 1, MAX_RESULTS);
204+
int max_results = luaL_optinteger(L, -1, DEFAULT_MAX_RESULTS);
205+
206+
mdns_result_t *res = NULL;
207+
esp_err_t err =
208+
mdns_query(name, svctype, proto, qtype, timeout, max_results, &res);
209+
if (err != ESP_OK)
210+
return luaL_error(L, "mdns error: %s", esp_err_to_name(err));
211+
212+
lua_settop(L, 0);
213+
lua_createtable(L, max_results, 0); // results array at idx 1
214+
215+
for (int n = 1; res; ++n, res = res->next)
216+
{
217+
// Reserve 5 slots, for SRV result host/port/instance/service_type/proto
218+
lua_createtable(L, 0, 5); // result entry table at idx 2
219+
220+
if (res->instance_name)
221+
{
222+
lua_pushstring(L, res->instance_name);
223+
lua_setfield(L, 2, INSTANCE_NAME);
224+
}
225+
if (res->service_type)
226+
{
227+
lua_pushstring(L, res->service_type);
228+
lua_setfield(L, 2, SERVICE_TYPE);
229+
}
230+
if (res->proto)
231+
{
232+
lua_pushstring(L, res->proto);
233+
lua_setfield(L, 2, PROTO);
234+
}
235+
if (res->hostname)
236+
{
237+
lua_pushstring(L, res->hostname);
238+
lua_setfield(L, 2, HOSTNAME);
239+
}
240+
if (res->port)
241+
{
242+
lua_pushinteger(L, res->port);
243+
lua_setfield(L, 2, PORT);
244+
}
245+
if (res->txt)
246+
{
247+
lua_createtable(L, 0, res->txt_count); // txt table at idx 3
248+
for (int i = 0; i < res->txt_count; ++i)
249+
{
250+
lua_pushstring(L, res->txt[i].key);
251+
if (res->txt[i].value)
252+
lua_pushlstring(L, res->txt[i].value, res->txt_value_len[i]);
253+
else
254+
lua_pushliteral(L, "");
255+
lua_settable(L, 3);
256+
}
257+
lua_setfield(L, 2, TXT);
258+
}
259+
if (res->addr)
260+
{
261+
lua_createtable(L, 1, 0); // address array table at idx 3
262+
int i = 1;
263+
for (mdns_ip_addr_t *a = res->addr; a; ++i, a = a->next)
264+
{
265+
char buf[IP_STR_SZ];
266+
ipstr_esp(buf, &a->addr);
267+
lua_pushstring(L, buf);
268+
lua_rawseti(L, 3, i);
269+
}
270+
lua_setfield(L, 2, ADDRESSES);
271+
}
272+
273+
lua_rawseti(L, 1, n); // insert into array of results
274+
}
275+
276+
mdns_query_results_free(res);
277+
return 1;
278+
}
279+
280+
281+
LROT_BEGIN(mdns, NULL, 0)
282+
LROT_FUNCENTRY( start, lmdns_start )
283+
LROT_FUNCENTRY( query, lmdns_query )
284+
LROT_FUNCENTRY( stop, lmdns_stop )
285+
286+
LROT_NUMENTRY( TYPE_A, MDNS_TYPE_A )
287+
LROT_NUMENTRY( TYPE_PTR, MDNS_TYPE_PTR )
288+
LROT_NUMENTRY( TYPE_TXT, MDNS_TYPE_TXT )
289+
LROT_NUMENTRY( TYPE_AAAA, MDNS_TYPE_AAAA )
290+
LROT_NUMENTRY( TYPE_SRV, MDNS_TYPE_SRV )
291+
//LROT_NUMENTRY( TYPE_OPT, MDNS_TYPE_OPT )
292+
//LROT_NUMENTRY( TYPE_NSEC, MDNS_TYPE_NSEC )
293+
LROT_NUMENTRY( TYPE_ANY, MDNS_TYPE_ANY )
294+
LROT_END(mdns, NULL, 0)
295+
296+
NODEMCU_MODULE(MDNS, "mdns", mdns, NULL);

0 commit comments

Comments
 (0)