Explorar o código

Merge pull request #988 from pjsg/mdns

Simple mdns implementation using the Espressif code
Arnim Läuger %!s(int64=8) %!d(string=hai) anos
pai
achega
78e9873d33
Modificáronse 4 ficheiros con 200 adicións e 0 borrados
  1. 1 0
      app/include/user_modules.h
  2. 160 0
      app/modules/mdns.c
  3. 38 0
      docs/en/modules/mdns.md
  4. 1 0
      mkdocs.yml

+ 1 - 0
app/include/user_modules.h

@@ -29,6 +29,7 @@
 #define LUA_USE_MODULES_HTTP
 //#define LUA_USE_MODULES_HX711
 #define LUA_USE_MODULES_I2C
+//#define LUA_USE_MODULES_MDNS
 #define LUA_USE_MODULES_MQTT
 #define LUA_USE_MODULES_NET
 #define LUA_USE_MODULES_NODE

+ 160 - 0
app/modules/mdns.c

@@ -0,0 +1,160 @@
+// 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);

+ 38 - 0
docs/en/modules/mdns.md

@@ -0,0 +1,38 @@
+# mdns Module
+
+Multicast DNS is used as part of Bonjour / Zeroconf. This allows system to identify themselves and the services that they provide on a local area network. Clients are then
+able to discover these systems and connect to them. 
+
+## mdns.register()
+Register a hostname and start the mDns service. If the service is already running, then it 
+will be restarted with the new parameters.
+
+#### Syntax
+`mdns.register(hostname, servicename, port [, attributes])`
+
+#### Parameters
+- `hostname` The hostname for this device. Alphanumeric characters are best.
+- `servicename` The servicename for this device. Alphanumeric characters are best. This will get prefixed with '_' and suffixed with ._tcp
+- `port` The port number for the primary service.
+- `attributes` A optional table of up to 10 attributes to be exposed. The keys must all be strings.
+
+#### Returns
+Nothing.
+
+#### Errors
+Various errors can be generated during argument validation. The nodemcu must have an IP address at the time of the call, otherwise an error is thrown.
+
+#### Example
+
+    mdns.register("fishtank", "http", 80, { hardware='NodeMCU'})
+
+Using dns-sd on OSX, you can see fishtank.local as providing the _http._tcp service. You can also browse directly to fishtank.local. In safari you can get all the mdns web pages as part of your bookmarks menu.
+
+## mdns.close()
+Shut down the mDns service. This is not normally needed.
+
+#### Syntax
+`mdns.close()`
+
+#### Returns
+Nothing.

+ 1 - 0
mkdocs.yml

@@ -49,6 +49,7 @@ pages:
         - 'http': 'en/modules/http.md'
         - 'hx711' : 'en/modules/hx711.md'
         - 'i2c' : 'en/modules/i2c.md'
+        - 'mdns': 'en/modules/mdns.md'
         - 'mqtt': 'en/modules/mqtt.md'
         - 'net': 'en/modules/net.md'
         - 'node': 'en/modules/node.md'