nodemcu-firmware/app/modules/mdns.c

161 lines
3.6 KiB
C

// Module for access to the espconn_mdns functions
#include "module.h"
#include "lauxlib.h"
#include "c_string.h"
#include "c_stdlib.h"
#include "c_types.h"
#include "mem.h"
#include "lwip/ip_addr.h"
#include "espconn.h"
#include "user_interface.h"
typedef struct wrapper {
struct mdns_info mdns_info;
char data;
} wrapper_t;
static wrapper_t *info;
typedef enum phase {
PHASE_CALCULATE_LENGTH,
PHASE_COPY_DATA
} phase_t;
static char *advance_over_string(char *s)
{
while (*s++) {
}
// s now points after the null
return s;
}
//
// mdns.close()
//
static int mdns_close(lua_State *L)
{
if (info) {
espconn_mdns_close();
c_free(info);
info = NULL;
}
return 0;
}
//
// this handles all the arguments. Two passes are necessary --
// one to calculate the size of the block, and the other to
// copy the data. It is vitally important that these two
// passes are kept in step.
//
static wrapper_t *process_args(lua_State *L, phase_t phase, size_t *sizep)
{
wrapper_t *result = NULL;
char *p = NULL;
if (phase == PHASE_COPY_DATA) {
result = (wrapper_t *) c_zalloc(sizeof(wrapper_t) + *sizep);
if (!result) {
return NULL;
}
p = &result->data;
}
if (phase == PHASE_CALCULATE_LENGTH) {
luaL_checktype(L, 1, LUA_TSTRING);
luaL_checktype(L, 2, LUA_TSTRING);
(void) luaL_checkinteger(L, 3);
*sizep += c_strlen(luaL_checkstring(L, 1)) + 1;
*sizep += c_strlen(luaL_checkstring(L, 2)) + 1;
} else {
c_strcpy(p, luaL_checkstring(L, 1));
result->mdns_info.host_name = p;
p = advance_over_string(p);
c_strcpy(p, luaL_checkstring(L, 2));
result->mdns_info.server_name = p;
p = advance_over_string(p);
result->mdns_info.server_port = luaL_checkinteger(L, 3);
}
if (lua_gettop(L) >= 4) {
luaL_checktype(L, 4, LUA_TTABLE);
lua_pushnil(L); // first key
int slot = 0;
while (lua_next(L, 4) != 0 && slot < sizeof(result->mdns_info.txt_data) / sizeof(result->mdns_info.txt_data[0])) {
if (phase == PHASE_CALCULATE_LENGTH) {
luaL_checktype(L, -2, LUA_TSTRING);
*sizep += c_strlen(luaL_checkstring(L, -2)) + 1;
*sizep += c_strlen(luaL_checkstring(L, -1)) + 1;
} else {
// put in the key
c_strcpy(p, luaL_checkstring(L, -2));
result->mdns_info.txt_data[slot] = p;
p = advance_over_string(p);
// now smash in the value
const char *value = luaL_checkstring(L, -1);
p[-1] = '=';
c_strcpy(p, value);
p = advance_over_string(p);
}
lua_pop(L, 1);
}
}
return result;
}
//
// mdns.register(hostname, servicename, port [, attributes])
//
static int mdns_register(lua_State *L)
{
size_t len = 0;
(void) process_args(L, PHASE_CALCULATE_LENGTH, &len);
struct ip_info ipconfig;
uint8_t mode = wifi_get_opmode();
if (!wifi_get_ip_info((mode == 2) ? SOFTAP_IF : STATION_IF, &ipconfig) || !ipconfig.ip.addr) {
return luaL_error(L, "No network connection");
}
wrapper_t *result = process_args(L, PHASE_COPY_DATA, &len);
if (!result) {
return luaL_error( L, "failed to allocate info block" );
}
result->mdns_info.ipAddr = ipconfig.ip.addr;
// Close up the old session (if any). This cannot fail
// so no chance of losing the memory in 'result'
mdns_close(L);
// Save the result as it appears that espconn_mdns_init needs
// to have the data valid while it is running.
info = result;
espconn_mdns_init(&(info->mdns_info));
return 0;
}
// Module function map
static const LUA_REG_TYPE mdns_map[] = {
{ LSTRKEY("register"), LFUNCVAL(mdns_register) },
{ LSTRKEY("close"), LFUNCVAL(mdns_close) },
{ LNILKEY, LNILVAL }
};
NODEMCU_MODULE(MDNS, "mdns", mdns_map, NULL);