net.c 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036
  1. // Module for network
  2. #include "module.h"
  3. #include "lauxlib.h"
  4. #include "platform.h"
  5. #include "lmem.h"
  6. #include "c_string.h"
  7. #include "c_stdlib.h"
  8. #include "c_types.h"
  9. #include "mem.h"
  10. #include "osapi.h"
  11. #include "lwip/err.h"
  12. #include "lwip/ip_addr.h"
  13. #include "lwip/dns.h"
  14. #include "lwip/igmp.h"
  15. #include "lwip/tcp.h"
  16. #include "lwip/udp.h"
  17. #if defined(CLIENT_SSL_ENABLE) && defined(LUA_USE_MODULES_NET) && defined(LUA_USE_MODULES_TLS)
  18. #define TLS_MODULE_PRESENT
  19. #endif
  20. typedef enum net_type {
  21. TYPE_TCP_SERVER = 0,
  22. TYPE_TCP_CLIENT,
  23. TYPE_UDP_SOCKET
  24. } net_type;
  25. typedef const char net_table_name[14];
  26. static const net_table_name NET_TABLES[] = {
  27. "net.tcpserver",
  28. "net.tcpsocket",
  29. "net.udpsocket"
  30. };
  31. #define NET_TABLE_TCP_SERVER NET_TABLES[0]
  32. #define NET_TABLE_TCP_CLIENT NET_TABLES[1]
  33. #define NET_TABLE_UDP_SOCKET NET_TABLES[2]
  34. #define TYPE_TCP TYPE_TCP_CLIENT
  35. #define TYPE_UDP TYPE_UDP_SOCKET
  36. typedef struct lnet_userdata {
  37. enum net_type type;
  38. int self_ref;
  39. union {
  40. struct tcp_pcb *tcp_pcb;
  41. struct udp_pcb *udp_pcb;
  42. void *pcb;
  43. };
  44. union {
  45. struct {
  46. int cb_accept_ref;
  47. int timeout;
  48. } server;
  49. struct {
  50. int wait_dns;
  51. int cb_dns_ref;
  52. int cb_receive_ref;
  53. int cb_sent_ref;
  54. // Only for TCP:
  55. int hold;
  56. int cb_connect_ref;
  57. int cb_disconnect_ref;
  58. int cb_reconnect_ref;
  59. } client;
  60. };
  61. } lnet_userdata;
  62. #pragma mark - LWIP errors
  63. int lwip_lua_checkerr (lua_State *L, err_t err) {
  64. switch (err) {
  65. case ERR_OK: return 0;
  66. case ERR_MEM: return luaL_error(L, "out of memory");
  67. case ERR_BUF: return luaL_error(L, "buffer error");
  68. case ERR_TIMEOUT: return luaL_error(L, "timeout");
  69. case ERR_RTE: return luaL_error(L, "routing problem");
  70. case ERR_INPROGRESS: return luaL_error(L, "in progress");
  71. case ERR_VAL: return luaL_error(L, "illegal value");
  72. case ERR_WOULDBLOCK: return luaL_error(L, "would block");
  73. case ERR_ABRT: return luaL_error(L, "connection aborted");
  74. case ERR_RST: return luaL_error(L, "connection reset");
  75. case ERR_CLSD: return luaL_error(L, "connection closed");
  76. case ERR_CONN: return luaL_error(L, "not connected");
  77. case ERR_ARG: return luaL_error(L, "illegal argument");
  78. case ERR_USE: return luaL_error(L, "address in use");
  79. case ERR_IF: return luaL_error(L, "netif error");
  80. case ERR_ISCONN: return luaL_error(L, "already connected");
  81. default: return luaL_error(L, "unknown error");
  82. }
  83. }
  84. #pragma mark - Create
  85. lnet_userdata *net_create( lua_State *L, enum net_type type ) {
  86. const char *mt = NET_TABLES[type];
  87. lnet_userdata *ud = (lnet_userdata *)lua_newuserdata(L, sizeof(lnet_userdata));
  88. if (!ud) return NULL;
  89. luaL_getmetatable(L, mt);
  90. lua_setmetatable(L, -2);
  91. ud->type = type;
  92. ud->self_ref = LUA_NOREF;
  93. ud->pcb = NULL;
  94. switch (type) {
  95. case TYPE_TCP_CLIENT:
  96. ud->client.cb_connect_ref = LUA_NOREF;
  97. ud->client.cb_reconnect_ref = LUA_NOREF;
  98. ud->client.cb_disconnect_ref = LUA_NOREF;
  99. ud->client.hold = 0;
  100. case TYPE_UDP_SOCKET:
  101. ud->client.wait_dns = 0;
  102. ud->client.cb_dns_ref = LUA_NOREF;
  103. ud->client.cb_receive_ref = LUA_NOREF;
  104. ud->client.cb_sent_ref = LUA_NOREF;
  105. break;
  106. case TYPE_TCP_SERVER:
  107. ud->server.cb_accept_ref = LUA_NOREF;
  108. break;
  109. }
  110. return ud;
  111. }
  112. #pragma mark - LWIP callbacks
  113. static void net_err_cb(void *arg, err_t err) {
  114. lnet_userdata *ud = (lnet_userdata*)arg;
  115. if (!ud || ud->type != TYPE_TCP_CLIENT || ud->self_ref == LUA_NOREF) return;
  116. ud->pcb = NULL; // Will be freed at LWIP level
  117. lua_State *L = lua_getstate();
  118. int ref;
  119. if (err != ERR_OK && ud->client.cb_reconnect_ref != LUA_NOREF)
  120. ref = ud->client.cb_reconnect_ref;
  121. else ref = ud->client.cb_disconnect_ref;
  122. if (ref != LUA_NOREF) {
  123. lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
  124. lua_rawgeti(L, LUA_REGISTRYINDEX, ud->self_ref);
  125. lua_pushinteger(L, err);
  126. lua_call(L, 2, 0);
  127. }
  128. if (ud->client.wait_dns == 0) {
  129. lua_gc(L, LUA_GCSTOP, 0);
  130. luaL_unref(L, LUA_REGISTRYINDEX, ud->self_ref);
  131. ud->self_ref = LUA_NOREF;
  132. lua_gc(L, LUA_GCRESTART, 0);
  133. }
  134. }
  135. static err_t net_connected_cb(void *arg, struct tcp_pcb *tpcb, err_t err) {
  136. lnet_userdata *ud = (lnet_userdata*)arg;
  137. if (!ud || ud->pcb != tpcb) return ERR_ABRT;
  138. if (err != ERR_OK) {
  139. net_err_cb(arg, err);
  140. return ERR_ABRT;
  141. }
  142. lua_State *L = lua_getstate();
  143. if (ud->self_ref != LUA_NOREF && ud->client.cb_connect_ref != LUA_NOREF) {
  144. lua_rawgeti(L, LUA_REGISTRYINDEX, ud->client.cb_connect_ref);
  145. lua_rawgeti(L, LUA_REGISTRYINDEX, ud->self_ref);
  146. lua_call(L, 1, 0);
  147. }
  148. return ERR_OK;
  149. }
  150. static void net_dns_cb(const char *name, ip_addr_t *ipaddr, void *arg) {
  151. ip_addr_t addr;
  152. if (ipaddr != NULL) addr = *ipaddr;
  153. else addr.addr = 0xFFFFFFFF;
  154. lnet_userdata *ud = (lnet_userdata*)arg;
  155. if (!ud) return;
  156. lua_State *L = lua_getstate();
  157. if (ud->self_ref != LUA_NOREF && ud->client.cb_dns_ref != LUA_NOREF) {
  158. lua_rawgeti(L, LUA_REGISTRYINDEX, ud->client.cb_dns_ref);
  159. lua_rawgeti(L, LUA_REGISTRYINDEX, ud->self_ref);
  160. if (addr.addr != 0xFFFFFFFF) {
  161. char iptmp[16];
  162. bzero(iptmp, 16);
  163. ets_sprintf(iptmp, IPSTR, IP2STR(&addr.addr));
  164. lua_pushstring(L, iptmp);
  165. } else {
  166. lua_pushnil(L);
  167. }
  168. lua_call(L, 2, 0);
  169. }
  170. ud->client.wait_dns --;
  171. if (ud->pcb && ud->type == TYPE_TCP_CLIENT && ud->tcp_pcb->state == CLOSED) {
  172. tcp_connect(ud->tcp_pcb, &addr, ud->tcp_pcb->remote_port, net_connected_cb);
  173. } else if (!ud->pcb && ud->client.wait_dns == 0) {
  174. lua_gc(L, LUA_GCSTOP, 0);
  175. luaL_unref(L, LUA_REGISTRYINDEX, ud->self_ref);
  176. ud->self_ref = LUA_NOREF;
  177. lua_gc(L, LUA_GCRESTART, 0);
  178. }
  179. }
  180. static void net_recv_cb(lnet_userdata *ud, struct pbuf *p, ip_addr_t *addr, u16_t port) {
  181. if (ud->client.cb_receive_ref == LUA_NOREF) {
  182. pbuf_free(p);
  183. return;
  184. }
  185. lua_State *L = lua_getstate();
  186. int num_args = 2;
  187. lua_rawgeti(L, LUA_REGISTRYINDEX, ud->client.cb_receive_ref);
  188. lua_rawgeti(L, LUA_REGISTRYINDEX, ud->self_ref);
  189. lua_pushlstring(L, p->payload, p->len);
  190. if (ud->type == TYPE_UDP_SOCKET) {
  191. num_args += 2;
  192. char iptmp[16];
  193. bzero(iptmp, 16);
  194. ets_sprintf(iptmp, IPSTR, IP2STR(&addr->addr));
  195. lua_pushinteger(L, port);
  196. lua_pushstring(L, iptmp);
  197. }
  198. lua_call(L, num_args, 0);
  199. pbuf_free(p);
  200. }
  201. static void net_udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port) {
  202. lnet_userdata *ud = (lnet_userdata*)arg;
  203. if (!ud || !ud->pcb || ud->type != TYPE_UDP_SOCKET || ud->self_ref == LUA_NOREF) {
  204. if (p) pbuf_free(p);
  205. return;
  206. }
  207. net_recv_cb(ud, p, addr, port);
  208. }
  209. static err_t net_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) {
  210. lnet_userdata *ud = (lnet_userdata*)arg;
  211. if (!ud || !ud->pcb || ud->type != TYPE_TCP_CLIENT || ud->self_ref == LUA_NOREF)
  212. return ERR_ABRT;
  213. if (!p) {
  214. net_err_cb(arg, err);
  215. return tcp_close(tpcb);
  216. }
  217. net_recv_cb(ud, p, 0, 0);
  218. tcp_recved(tpcb, ud->client.hold ? 0 : TCP_WND);
  219. return ERR_OK;
  220. }
  221. static err_t net_sent_cb(void *arg, struct tcp_pcb *tpcb, u16_t len) {
  222. lnet_userdata *ud = (lnet_userdata*)arg;
  223. if (!ud || !ud->pcb || ud->type != TYPE_TCP_CLIENT || ud->self_ref == LUA_NOREF) return ERR_ABRT;
  224. if (ud->client.cb_sent_ref == LUA_NOREF) return ERR_OK;
  225. lua_State *L = lua_getstate();
  226. lua_rawgeti(L, LUA_REGISTRYINDEX, ud->client.cb_sent_ref);
  227. lua_rawgeti(L, LUA_REGISTRYINDEX, ud->self_ref);
  228. lua_call(L, 1, 0);
  229. return ERR_OK;
  230. }
  231. static err_t net_accept_cb(void *arg, struct tcp_pcb *newpcb, err_t err) {
  232. lnet_userdata *ud = (lnet_userdata*)arg;
  233. if (!ud || ud->type != TYPE_TCP_SERVER || !ud->pcb) return ERR_ABRT;
  234. if (ud->self_ref == LUA_NOREF || ud->server.cb_accept_ref == LUA_NOREF) return ERR_ABRT;
  235. lua_State *L = lua_getstate();
  236. lua_rawgeti(L, LUA_REGISTRYINDEX, ud->server.cb_accept_ref);
  237. lnet_userdata *nud = net_create(L, TYPE_TCP_CLIENT);
  238. lua_pushvalue(L, 2);
  239. nud->self_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  240. nud->tcp_pcb = newpcb;
  241. tcp_arg(nud->tcp_pcb, nud);
  242. tcp_err(nud->tcp_pcb, net_err_cb);
  243. tcp_recv(nud->tcp_pcb, net_tcp_recv_cb);
  244. tcp_sent(nud->tcp_pcb, net_sent_cb);
  245. nud->tcp_pcb->so_options |= SOF_KEEPALIVE;
  246. nud->tcp_pcb->keep_idle = ud->server.timeout * 1000;
  247. nud->tcp_pcb->keep_cnt = 1;
  248. tcp_accepted(ud->tcp_pcb);
  249. lua_call(L, 1, 0);
  250. return net_connected_cb(nud, nud->tcp_pcb, ERR_OK);
  251. }
  252. #pragma mark - Lua API - create
  253. #ifdef TLS_MODULE_PRESENT
  254. extern int tls_socket_create( lua_State *L );
  255. #endif
  256. // Lua: net.createUDPSocket()
  257. int net_createUDPSocket( lua_State *L ) {
  258. net_create(L, TYPE_UDP_SOCKET);
  259. return 1;
  260. }
  261. // Lua: net.createServer(type, timeout)
  262. int net_createServer( lua_State *L ) {
  263. int type, timeout;
  264. type = luaL_optlong(L, 1, TYPE_TCP);
  265. timeout = luaL_optlong(L, 2, 30);
  266. if (type == TYPE_UDP) {
  267. platform_print_deprecation_note("net.createServer with net.UDP type", "in next version");
  268. return net_createUDPSocket( L );
  269. }
  270. if (type != TYPE_TCP) return luaL_error(L, "invalid type");
  271. lnet_userdata *u = net_create(L, TYPE_TCP_SERVER);
  272. u->server.timeout = timeout;
  273. return 1;
  274. }
  275. // Lua: net.createConnection(type, secure)
  276. int net_createConnection( lua_State *L ) {
  277. int type, secure;
  278. type = luaL_optlong(L, 1, TYPE_TCP);
  279. secure = luaL_optlong(L, 2, 0);
  280. if (type == TYPE_UDP) {
  281. platform_print_deprecation_note("net.createConnection with net.UDP type", "in next version");
  282. return net_createUDPSocket( L );
  283. }
  284. if (type != TYPE_TCP) return luaL_error(L, "invalid type");
  285. if (secure) {
  286. platform_print_deprecation_note("net.createConnection with secure flag", "in next version");
  287. #ifdef TLS_MODULE_PRESENT
  288. return tls_socket_create( L );
  289. #else
  290. return luaL_error(L, "secure connections not enabled");
  291. #endif
  292. }
  293. net_create(L, TYPE_TCP_CLIENT);
  294. return 1;
  295. }
  296. #pragma mark - Get & check userdata
  297. lnet_userdata *net_get_udata_s( lua_State *L, int stack ) {
  298. if (!lua_isuserdata(L, stack)) return NULL;
  299. lnet_userdata *ud = (lnet_userdata *)lua_touserdata(L, stack);
  300. switch (ud->type) {
  301. case TYPE_TCP_CLIENT:
  302. case TYPE_TCP_SERVER:
  303. case TYPE_UDP_SOCKET:
  304. break;
  305. default: return NULL;
  306. }
  307. const char *mt = NET_TABLES[ud->type];
  308. ud = luaL_checkudata(L, stack, mt);
  309. return ud;
  310. }
  311. #define net_get_udata(L) net_get_udata_s(L, 1)
  312. #pragma mark - Lua API
  313. // Lua: server:listen(port, addr, function(c)), socket:listen(port, addr)
  314. int net_listen( lua_State *L ) {
  315. lnet_userdata *ud = net_get_udata(L);
  316. if (!ud || ud->type == TYPE_TCP_CLIENT)
  317. return luaL_error(L, "invalid user data");
  318. if (ud->pcb)
  319. return luaL_error(L, "already listening");
  320. int stack = 2;
  321. uint16_t port = 0;
  322. const char *domain = "0.0.0.0";
  323. if (lua_isnumber(L, stack))
  324. port = lua_tointeger(L, stack++);
  325. if (lua_isstring(L, stack)) {
  326. size_t dl = 0;
  327. domain = luaL_checklstring(L, stack++, &dl);
  328. }
  329. ip_addr_t addr;
  330. if (!ipaddr_aton(domain, &addr))
  331. return luaL_error(L, "invalid IP address");
  332. if (ud->type == TYPE_TCP_SERVER) {
  333. if (lua_isfunction(L, stack) || lua_islightfunction(L, stack)) {
  334. lua_pushvalue(L, stack++);
  335. luaL_unref(L, LUA_REGISTRYINDEX, ud->server.cb_accept_ref);
  336. ud->server.cb_accept_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  337. } else {
  338. return luaL_error(L, "need callback");
  339. }
  340. }
  341. err_t err = ERR_OK;
  342. switch (ud->type) {
  343. case TYPE_TCP_SERVER:
  344. ud->tcp_pcb = tcp_new();
  345. if (!ud->tcp_pcb)
  346. return luaL_error(L, "cannot allocate PCB");
  347. err = tcp_bind(ud->tcp_pcb, &addr, port);
  348. if (err == ERR_OK) {
  349. tcp_arg(ud->tcp_pcb, ud);
  350. struct tcp_pcb *pcb = tcp_listen(ud->tcp_pcb);
  351. if (!pcb) {
  352. err = ERR_MEM;
  353. } else {
  354. ud->tcp_pcb = pcb;
  355. tcp_accept(ud->tcp_pcb, net_accept_cb);
  356. }
  357. }
  358. break;
  359. case TYPE_UDP_SOCKET:
  360. ud->udp_pcb = udp_new();
  361. if (!ud->udp_pcb)
  362. return luaL_error(L, "cannot allocate PCB");
  363. udp_recv(ud->udp_pcb, net_udp_recv_cb, ud);
  364. err = udp_bind(ud->udp_pcb, &addr, port);
  365. break;
  366. }
  367. if (err != ERR_OK) {
  368. switch (ud->type) {
  369. case TYPE_TCP_SERVER:
  370. tcp_close(ud->tcp_pcb);
  371. ud->tcp_pcb = NULL;
  372. break;
  373. case TYPE_UDP_SOCKET:
  374. udp_remove(ud->udp_pcb);
  375. ud->udp_pcb = NULL;
  376. break;
  377. }
  378. return lwip_lua_checkerr(L, err);
  379. }
  380. if (ud->self_ref == LUA_NOREF) {
  381. lua_pushvalue(L, 1);
  382. ud->self_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  383. }
  384. return 0;
  385. }
  386. // Lua: client:connect(port, addr)
  387. int net_connect( lua_State *L ) {
  388. lnet_userdata *ud = net_get_udata(L);
  389. if (!ud || ud->type != TYPE_TCP_CLIENT)
  390. return luaL_error(L, "invalid user data");
  391. if (ud->pcb)
  392. return luaL_error(L, "already connected");
  393. uint16_t port = luaL_checkinteger(L, 2);
  394. if (port == 0)
  395. return luaL_error(L, "specify port");
  396. const char *domain = "127.0.0.1";
  397. if (lua_isstring(L, 3)) {
  398. size_t dl = 0;
  399. domain = luaL_checklstring(L, 3, &dl);
  400. }
  401. if (lua_gettop(L) > 3) {
  402. luaL_argcheck(L, lua_isfunction(L, 4) || lua_islightfunction(L, 4), 4, "not a function");
  403. lua_pushvalue(L, 4);
  404. luaL_unref(L, LUA_REGISTRYINDEX, ud->client.cb_connect_ref);
  405. ud->client.cb_connect_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  406. }
  407. ud->tcp_pcb = tcp_new();
  408. if (!ud->tcp_pcb)
  409. return luaL_error(L, "cannot allocate PCB");
  410. tcp_arg(ud->tcp_pcb, ud);
  411. tcp_err(ud->tcp_pcb, net_err_cb);
  412. tcp_recv(ud->tcp_pcb, net_tcp_recv_cb);
  413. tcp_sent(ud->tcp_pcb, net_sent_cb);
  414. ud->tcp_pcb->remote_port = port;
  415. ip_addr_t addr;
  416. ud->client.wait_dns ++;
  417. int unref = 0;
  418. if (ud->self_ref == LUA_NOREF) {
  419. unref = 1;
  420. lua_pushvalue(L, 1);
  421. ud->self_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  422. }
  423. err_t err = dns_gethostbyname(domain, &addr, net_dns_cb, ud);
  424. if (err == ERR_OK) {
  425. net_dns_cb(domain, &addr, ud);
  426. } else if (err != ERR_INPROGRESS) {
  427. ud->client.wait_dns --;
  428. if (unref) {
  429. luaL_unref(L, LUA_REGISTRYINDEX, ud->self_ref);
  430. ud->self_ref = LUA_NOREF;
  431. }
  432. tcp_abort(ud->tcp_pcb);
  433. ud->tcp_pcb = NULL;
  434. return lwip_lua_checkerr(L, err);
  435. }
  436. return 0;
  437. }
  438. // Lua: client/socket:on(name, callback)
  439. int net_on( lua_State *L ) {
  440. lnet_userdata *ud = net_get_udata(L);
  441. if (!ud || ud->type == TYPE_TCP_SERVER)
  442. return luaL_error(L, "invalid user data");
  443. int *refptr = NULL;
  444. const char *name = luaL_checkstring(L, 2);
  445. if (!name) return luaL_error(L, "need callback name");
  446. switch (ud->type) {
  447. case TYPE_TCP_CLIENT:
  448. if (strcmp("connection",name)==0)
  449. { refptr = &ud->client.cb_connect_ref; break; }
  450. if (strcmp("disconnection",name)==0)
  451. { refptr = &ud->client.cb_disconnect_ref; break; }
  452. if (strcmp("reconnection",name)==0)
  453. { refptr = &ud->client.cb_reconnect_ref; break; }
  454. case TYPE_UDP_SOCKET:
  455. if (strcmp("dns",name)==0)
  456. { refptr = &ud->client.cb_dns_ref; break; }
  457. if (strcmp("receive",name)==0)
  458. { refptr = &ud->client.cb_receive_ref; break; }
  459. if (strcmp("sent",name)==0)
  460. { refptr = &ud->client.cb_sent_ref; break; }
  461. break;
  462. default: return luaL_error(L, "invalid user data");
  463. }
  464. if (refptr == NULL)
  465. return luaL_error(L, "invalid callback name");
  466. if (lua_isfunction(L, 3) || lua_islightfunction(L, 3)) {
  467. lua_pushvalue(L, 3);
  468. luaL_unref(L, LUA_REGISTRYINDEX, *refptr);
  469. *refptr = luaL_ref(L, LUA_REGISTRYINDEX);
  470. } else if (lua_isnil(L, 3)) {
  471. luaL_unref(L, LUA_REGISTRYINDEX, *refptr);
  472. *refptr = LUA_NOREF;
  473. } else {
  474. return luaL_error(L, "invalid callback function");
  475. }
  476. return 0;
  477. }
  478. // Lua: client:send(data, function(c)), socket:send(port, ip, data, function(s))
  479. int net_send( lua_State *L ) {
  480. lnet_userdata *ud = net_get_udata(L);
  481. if (!ud || ud->type == TYPE_TCP_SERVER)
  482. return luaL_error(L, "invalid user data");
  483. ip_addr_t addr;
  484. uint16_t port;
  485. const char *data;
  486. size_t datalen = 0;
  487. int stack = 2;
  488. if (ud->type == TYPE_UDP_SOCKET) {
  489. size_t dl = 0;
  490. port = luaL_checkinteger(L, stack++);
  491. if (port == 0) return luaL_error(L, "need port");
  492. const char *domain = luaL_checklstring(L, stack++, &dl);
  493. if (!domain) return luaL_error(L, "need IP address");
  494. if (!ipaddr_aton(domain, &addr)) return luaL_error(L, "invalid IP address");
  495. }
  496. data = luaL_checklstring(L, stack++, &datalen);
  497. if (!data || datalen == 0) return luaL_error(L, "no data to send");
  498. if (lua_isfunction(L, stack) || lua_islightfunction(L, stack)) {
  499. lua_pushvalue(L, stack++);
  500. luaL_unref(L, LUA_REGISTRYINDEX, ud->client.cb_sent_ref);
  501. ud->client.cb_sent_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  502. }
  503. if (ud->type == TYPE_UDP_SOCKET && !ud->pcb) {
  504. ud->udp_pcb = udp_new();
  505. if (!ud->udp_pcb)
  506. return luaL_error(L, "cannot allocate PCB");
  507. udp_recv(ud->udp_pcb, net_udp_recv_cb, ud);
  508. ip_addr_t laddr = {0};
  509. err_t err = udp_bind(ud->udp_pcb, &laddr, 0);
  510. if (err != ERR_OK) {
  511. udp_remove(ud->udp_pcb);
  512. ud->udp_pcb = NULL;
  513. return lwip_lua_checkerr(L, err);
  514. }
  515. if (ud->self_ref == LUA_NOREF) {
  516. lua_pushvalue(L, 1);
  517. ud->self_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  518. }
  519. }
  520. if (!ud->pcb || ud->self_ref == LUA_NOREF)
  521. return luaL_error(L, "not connected");
  522. err_t err;
  523. if (ud->type == TYPE_UDP_SOCKET) {
  524. struct pbuf *pb = pbuf_alloc(PBUF_TRANSPORT, datalen, PBUF_RAM);
  525. if (!pb)
  526. return luaL_error(L, "cannot allocate message buffer");
  527. pbuf_take(pb, data, datalen);
  528. err = udp_sendto(ud->udp_pcb, pb, &addr, port);
  529. pbuf_free(pb);
  530. if (ud->client.cb_sent_ref != LUA_NOREF) {
  531. lua_rawgeti(L, LUA_REGISTRYINDEX, ud->client.cb_sent_ref);
  532. lua_rawgeti(L, LUA_REGISTRYINDEX, ud->self_ref);
  533. lua_call(L, 1, 0);
  534. }
  535. } else if (ud->type == TYPE_TCP_CLIENT) {
  536. err = tcp_write(ud->tcp_pcb, data, datalen, TCP_WRITE_FLAG_COPY);
  537. }
  538. return lwip_lua_checkerr(L, err);
  539. }
  540. // Lua: client:hold()
  541. int net_hold( lua_State *L ) {
  542. lnet_userdata *ud = net_get_udata(L);
  543. if (!ud || ud->type != TYPE_TCP_CLIENT)
  544. return luaL_error(L, "invalid user data");
  545. if (!ud->client.hold && ud->tcp_pcb) {
  546. ud->client.hold = 1;
  547. }
  548. return 0;
  549. }
  550. // Lua: client:unhold()
  551. int net_unhold( lua_State *L ) {
  552. lnet_userdata *ud = net_get_udata(L);
  553. if (!ud || ud->type != TYPE_TCP_CLIENT)
  554. return luaL_error(L, "invalid user data");
  555. if (ud->client.hold && ud->tcp_pcb) {
  556. ud->client.hold = 0;
  557. ud->tcp_pcb->flags |= TF_ACK_NOW;
  558. tcp_recved(ud->tcp_pcb, TCP_WND);
  559. }
  560. return 0;
  561. }
  562. // Lua: client/socket:dns(domain, callback(socket, addr))
  563. int net_dns( lua_State *L ) {
  564. lnet_userdata *ud = net_get_udata(L);
  565. if (!ud || ud->type == TYPE_TCP_SERVER)
  566. return luaL_error(L, "invalid user data");
  567. size_t dl = 0;
  568. const char *domain = luaL_checklstring(L, 2, &dl);
  569. if (!domain)
  570. return luaL_error(L, "no domain specified");
  571. if (lua_isfunction(L, 3) || lua_islightfunction(L, 3)) {
  572. luaL_unref(L, LUA_REGISTRYINDEX, ud->client.cb_dns_ref);
  573. lua_pushvalue(L, 3);
  574. ud->client.cb_dns_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  575. }
  576. if (ud->client.cb_dns_ref == LUA_NOREF)
  577. return luaL_error(L, "no callback specified");
  578. ud->client.wait_dns ++;
  579. int unref = 0;
  580. if (ud->self_ref == LUA_NOREF) {
  581. unref = 1;
  582. lua_pushvalue(L, 1);
  583. ud->self_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  584. }
  585. ip_addr_t addr;
  586. err_t err = dns_gethostbyname(domain, &addr, net_dns_cb, ud);
  587. if (err == ERR_OK) {
  588. net_dns_cb(domain, &addr, ud);
  589. } else if (err != ERR_INPROGRESS) {
  590. ud->client.wait_dns --;
  591. if (unref) {
  592. luaL_unref(L, LUA_REGISTRYINDEX, ud->self_ref);
  593. ud->self_ref = LUA_NOREF;
  594. }
  595. return lwip_lua_checkerr(L, err);
  596. }
  597. return 0;
  598. }
  599. // Lua: client/socket:ttl([ttl])
  600. int net_ttl( lua_State *L ) {
  601. lnet_userdata *ud = net_get_udata(L);
  602. if (!ud || ud->type == TYPE_TCP_SERVER)
  603. return luaL_error(L, "invalid user data");
  604. if (!ud->pcb)
  605. return luaL_error(L, "socket is not open/bound yet");
  606. int ttl = luaL_optinteger(L, 2, -1);
  607. // Since `ttl` field is part of IP_PCB macro
  608. // (which are at beginning of both udp_pcb/tcp_pcb)
  609. // and PCBs declared as `union` there is safe to
  610. // access ttl field without checking for type.
  611. if (ttl == -1) {
  612. ttl = ud->udp_pcb->ttl;
  613. } else {
  614. ud->udp_pcb->ttl = ttl;
  615. }
  616. lua_pushinteger(L, ttl);
  617. return 1;
  618. }
  619. // Lua: client:getpeer()
  620. int net_getpeer( lua_State *L ) {
  621. lnet_userdata *ud = net_get_udata(L);
  622. if (!ud || ud->type != TYPE_TCP_CLIENT)
  623. return luaL_error(L, "invalid user data");
  624. if (!ud->pcb) {
  625. lua_pushnil(L);
  626. lua_pushnil(L);
  627. return 2;
  628. }
  629. uint16_t port = ud->tcp_pcb->remote_port;
  630. ip_addr_t addr = ud->tcp_pcb->remote_ip;
  631. if (port == 0) {
  632. lua_pushnil(L);
  633. lua_pushnil(L);
  634. return 2;
  635. }
  636. char addr_str[16];
  637. bzero(addr_str, 16);
  638. ets_sprintf(addr_str, IPSTR, IP2STR(&addr.addr));
  639. lua_pushinteger(L, port);
  640. lua_pushstring(L, addr_str);
  641. return 2;
  642. }
  643. // Lua: client/server/socket:getaddr()
  644. int net_getaddr( lua_State *L ) {
  645. lnet_userdata *ud = net_get_udata(L);
  646. if (!ud) return luaL_error(L, "invalid user data");
  647. if (!ud->pcb) {
  648. lua_pushnil(L);
  649. lua_pushnil(L);
  650. return 2;
  651. }
  652. uint16_t port;
  653. ip_addr_t addr;
  654. switch (ud->type) {
  655. case TYPE_TCP_CLIENT:
  656. case TYPE_TCP_SERVER:
  657. addr = ud->tcp_pcb->local_ip;
  658. port = ud->tcp_pcb->local_port;
  659. break;
  660. case TYPE_UDP_SOCKET:
  661. addr = ud->udp_pcb->local_ip;
  662. port = ud->udp_pcb->local_port;
  663. break;
  664. }
  665. if (port == 0) {
  666. lua_pushnil(L);
  667. lua_pushnil(L);
  668. return 2;
  669. }
  670. char addr_str[16];
  671. bzero(addr_str, 16);
  672. ets_sprintf(addr_str, IPSTR, IP2STR(&addr.addr));
  673. lua_pushinteger(L, port);
  674. lua_pushstring(L, addr_str);
  675. return 2;
  676. }
  677. // Lua: client/server/socket:close()
  678. int net_close( lua_State *L ) {
  679. lnet_userdata *ud = net_get_udata(L);
  680. if (!ud) return luaL_error(L, "invalid user data");
  681. if (ud->pcb) {
  682. switch (ud->type) {
  683. case TYPE_TCP_CLIENT:
  684. if (ERR_OK != tcp_close(ud->tcp_pcb)) {
  685. tcp_arg(ud->tcp_pcb, NULL);
  686. tcp_abort(ud->tcp_pcb);
  687. }
  688. ud->tcp_pcb = NULL;
  689. break;
  690. case TYPE_TCP_SERVER:
  691. tcp_close(ud->tcp_pcb);
  692. ud->tcp_pcb = NULL;
  693. break;
  694. case TYPE_UDP_SOCKET:
  695. udp_remove(ud->udp_pcb);
  696. ud->udp_pcb = NULL;
  697. break;
  698. }
  699. } else {
  700. return luaL_error(L, "not connected");
  701. }
  702. if (ud->type == TYPE_TCP_SERVER ||
  703. (ud->pcb == NULL && ud->client.wait_dns == 0)) {
  704. lua_gc(L, LUA_GCSTOP, 0);
  705. luaL_unref(L, LUA_REGISTRYINDEX, ud->self_ref);
  706. ud->self_ref = LUA_NOREF;
  707. lua_gc(L, LUA_GCRESTART, 0);
  708. }
  709. return 0;
  710. }
  711. int net_delete( lua_State *L ) {
  712. lnet_userdata *ud = net_get_udata(L);
  713. if (!ud) return luaL_error(L, "no user data");
  714. if (ud->pcb) {
  715. switch (ud->type) {
  716. case TYPE_TCP_CLIENT:
  717. tcp_arg(ud->tcp_pcb, NULL);
  718. tcp_abort(ud->tcp_pcb);
  719. ud->tcp_pcb = NULL;
  720. break;
  721. case TYPE_TCP_SERVER:
  722. tcp_close(ud->tcp_pcb);
  723. ud->tcp_pcb = NULL;
  724. break;
  725. case TYPE_UDP_SOCKET:
  726. udp_remove(ud->udp_pcb);
  727. ud->udp_pcb = NULL;
  728. break;
  729. }
  730. }
  731. switch (ud->type) {
  732. case TYPE_TCP_CLIENT:
  733. luaL_unref(L, LUA_REGISTRYINDEX, ud->client.cb_connect_ref);
  734. ud->client.cb_connect_ref = LUA_NOREF;
  735. luaL_unref(L, LUA_REGISTRYINDEX, ud->client.cb_disconnect_ref);
  736. ud->client.cb_disconnect_ref = LUA_NOREF;
  737. luaL_unref(L, LUA_REGISTRYINDEX, ud->client.cb_reconnect_ref);
  738. ud->client.cb_reconnect_ref = LUA_NOREF;
  739. case TYPE_UDP_SOCKET:
  740. luaL_unref(L, LUA_REGISTRYINDEX, ud->client.cb_dns_ref);
  741. ud->client.cb_dns_ref = LUA_NOREF;
  742. luaL_unref(L, LUA_REGISTRYINDEX, ud->client.cb_receive_ref);
  743. ud->client.cb_receive_ref = LUA_NOREF;
  744. luaL_unref(L, LUA_REGISTRYINDEX, ud->client.cb_sent_ref);
  745. ud->client.cb_sent_ref = LUA_NOREF;
  746. break;
  747. case TYPE_TCP_SERVER:
  748. luaL_unref(L, LUA_REGISTRYINDEX, ud->server.cb_accept_ref);
  749. ud->server.cb_accept_ref = LUA_NOREF;
  750. break;
  751. }
  752. lua_gc(L, LUA_GCSTOP, 0);
  753. luaL_unref(L, LUA_REGISTRYINDEX, ud->self_ref);
  754. ud->self_ref = LUA_NOREF;
  755. lua_gc(L, LUA_GCRESTART, 0);
  756. return 0;
  757. }
  758. #pragma mark - Multicast
  759. static int net_multicastJoinLeave( lua_State *L, int join) {
  760. size_t il;
  761. ip_addr_t multicast_addr;
  762. ip_addr_t if_addr;
  763. const char *multicast_ip;
  764. const char *if_ip;
  765. NODE_DBG("net_multicastJoin is called.\n");
  766. if(! lua_isstring(L,1) ) return luaL_error( L, "wrong arg type" );
  767. if_ip = luaL_checklstring( L, 1, &il );
  768. if (if_ip != NULL)
  769. if ( if_ip[0] == '\0' || stricmp(if_ip,"any") == 0)
  770. {
  771. if_ip = "0.0.0.0";
  772. il = 7;
  773. }
  774. if (if_ip == NULL || il > 15 || il < 7) return luaL_error( L, "invalid if ip" );
  775. if_addr.addr = ipaddr_addr(if_ip);
  776. if(! lua_isstring(L,2) ) return luaL_error( L, "wrong arg type" );
  777. multicast_ip = luaL_checklstring( L, 2, &il );
  778. if (multicast_ip == NULL || il > 15 || il < 7) return luaL_error( L, "invalid multicast ip" );
  779. multicast_addr.addr = ipaddr_addr(multicast_ip);
  780. if (join)
  781. {
  782. igmp_joingroup(&if_addr, &multicast_addr);
  783. }
  784. else
  785. {
  786. igmp_leavegroup(&if_addr, &multicast_addr);
  787. }
  788. return 0;
  789. }
  790. // Lua: net.multicastJoin(ifip, multicastip)
  791. // if ifip "" or "any" all interfaces are affected
  792. static int net_multicastJoin( lua_State* L ) {
  793. return net_multicastJoinLeave(L,1);
  794. }
  795. // Lua: net.multicastLeave(ifip, multicastip)
  796. // if ifip "" or "any" all interfaces are affected
  797. static int net_multicastLeave( lua_State* L ) {
  798. return net_multicastJoinLeave(L,0);
  799. }
  800. #pragma mark - DNS
  801. static void net_dns_static_cb(const char *name, ip_addr_t *ipaddr, void *callback_arg) {
  802. ip_addr_t addr;
  803. if (ipaddr != NULL)
  804. addr = *ipaddr;
  805. else addr.addr = 0xFFFFFFFF;
  806. int cb_ref = ((int*)callback_arg)[0];
  807. c_free(callback_arg);
  808. lua_State *L = lua_getstate();
  809. lua_rawgeti(L, LUA_REGISTRYINDEX, cb_ref);
  810. lua_pushnil(L);
  811. if (addr.addr != 0xFFFFFFFF) {
  812. char iptmp[20];
  813. size_t ipl = c_sprintf(iptmp, IPSTR, IP2STR(&addr.addr));
  814. lua_pushlstring(L, iptmp, ipl);
  815. } else {
  816. lua_pushnil(L);
  817. }
  818. lua_call(L, 2, 0);
  819. luaL_unref(L, LUA_REGISTRYINDEX, cb_ref);
  820. }
  821. // Lua: net.dns.resolve( domain, function(sk, ip) )
  822. static int net_dns_static( lua_State* L ) {
  823. size_t dl;
  824. const char* domain = luaL_checklstring(L, 1, &dl);
  825. if (!domain && dl > 128) {
  826. return luaL_error(L, "wrong domain");
  827. }
  828. luaL_checkanyfunction(L, 2);
  829. lua_pushvalue(L, 2); // copy argument (func) to the top of stack
  830. int cbref = luaL_ref(L, LUA_REGISTRYINDEX);
  831. if (cbref == LUA_NOREF) {
  832. return luaL_error(L, "wrong callback");
  833. }
  834. int *cbref_ptr = c_zalloc(sizeof(int));
  835. cbref_ptr[0] = cbref;
  836. ip_addr_t addr;
  837. err_t err = dns_gethostbyname(domain, &addr, net_dns_static_cb, cbref_ptr);
  838. if (err == ERR_OK) {
  839. net_dns_static_cb(domain, &addr, cbref_ptr);
  840. return 0;
  841. } else if (err == ERR_INPROGRESS) {
  842. return 0;
  843. } else {
  844. int e = lwip_lua_checkerr(L, err);
  845. c_free(cbref_ptr);
  846. return e;
  847. }
  848. return 0;
  849. }
  850. // Lua: s = net.dns.setdnsserver(ip_addr, [index])
  851. static int net_setdnsserver( lua_State* L ) {
  852. size_t l;
  853. u32_t ip32;
  854. const char *server = luaL_checklstring( L, 1, &l );
  855. if (l>16 || server == NULL || (ip32 = ipaddr_addr(server)) == IPADDR_NONE || ip32 == IPADDR_ANY)
  856. return luaL_error( L, "invalid dns server ip" );
  857. int numdns = luaL_optint(L, 2, 0);
  858. if (numdns >= DNS_MAX_SERVERS)
  859. return luaL_error( L, "server index out of range [0-%d]", DNS_MAX_SERVERS - 1);
  860. ip_addr_t ipaddr;
  861. ip4_addr_set_u32(&ipaddr, ip32);
  862. dns_setserver(numdns,&ipaddr);
  863. return 0;
  864. }
  865. // Lua: s = net.dns.getdnsserver([index])
  866. static int net_getdnsserver( lua_State* L ) {
  867. int numdns = luaL_optint(L, 1, 0);
  868. if (numdns >= DNS_MAX_SERVERS)
  869. return luaL_error( L, "server index out of range [0-%d]", DNS_MAX_SERVERS - 1);
  870. // ip_addr_t ipaddr;
  871. // dns_getserver(numdns,&ipaddr);
  872. // Bug fix by @md5crypt https://github.com/nodemcu/nodemcu-firmware/pull/500
  873. ip_addr_t ipaddr = dns_getserver(numdns);
  874. if ( ip_addr_isany(&ipaddr) ) {
  875. lua_pushnil( L );
  876. } else {
  877. char temp[20] = {0};
  878. c_sprintf(temp, IPSTR, IP2STR( &ipaddr.addr ) );
  879. lua_pushstring( L, temp );
  880. }
  881. return 1;
  882. }
  883. #pragma mark - Tables
  884. #ifdef TLS_MODULE_PRESENT
  885. extern const LUA_REG_TYPE tls_cert_map[];
  886. #endif
  887. // Module function map
  888. static const LUA_REG_TYPE net_tcpserver_map[] = {
  889. { LSTRKEY( "listen" ), LFUNCVAL( net_listen ) },
  890. { LSTRKEY( "getaddr" ), LFUNCVAL( net_getaddr ) },
  891. { LSTRKEY( "close" ), LFUNCVAL( net_close ) },
  892. { LSTRKEY( "__gc" ), LFUNCVAL( net_delete ) },
  893. { LSTRKEY( "__index" ), LROVAL( net_tcpserver_map ) },
  894. { LNILKEY, LNILVAL }
  895. };
  896. static const LUA_REG_TYPE net_tcpsocket_map[] = {
  897. { LSTRKEY( "connect" ), LFUNCVAL( net_connect ) },
  898. { LSTRKEY( "close" ), LFUNCVAL( net_close ) },
  899. { LSTRKEY( "on" ), LFUNCVAL( net_on ) },
  900. { LSTRKEY( "send" ), LFUNCVAL( net_send ) },
  901. { LSTRKEY( "hold" ), LFUNCVAL( net_hold ) },
  902. { LSTRKEY( "unhold" ), LFUNCVAL( net_unhold ) },
  903. { LSTRKEY( "dns" ), LFUNCVAL( net_dns ) },
  904. { LSTRKEY( "ttl" ), LFUNCVAL( net_ttl ) },
  905. { LSTRKEY( "getpeer" ), LFUNCVAL( net_getpeer ) },
  906. { LSTRKEY( "getaddr" ), LFUNCVAL( net_getaddr ) },
  907. { LSTRKEY( "__gc" ), LFUNCVAL( net_delete ) },
  908. { LSTRKEY( "__index" ), LROVAL( net_tcpsocket_map ) },
  909. { LNILKEY, LNILVAL }
  910. };
  911. static const LUA_REG_TYPE net_udpsocket_map[] = {
  912. { LSTRKEY( "listen" ), LFUNCVAL( net_listen ) },
  913. { LSTRKEY( "close" ), LFUNCVAL( net_close ) },
  914. { LSTRKEY( "on" ), LFUNCVAL( net_on ) },
  915. { LSTRKEY( "send" ), LFUNCVAL( net_send ) },
  916. { LSTRKEY( "dns" ), LFUNCVAL( net_dns ) },
  917. { LSTRKEY( "ttl" ), LFUNCVAL( net_ttl ) },
  918. { LSTRKEY( "getaddr" ), LFUNCVAL( net_getaddr ) },
  919. { LSTRKEY( "__gc" ), LFUNCVAL( net_delete ) },
  920. { LSTRKEY( "__index" ), LROVAL( net_udpsocket_map ) },
  921. { LNILKEY, LNILVAL }
  922. };
  923. static const LUA_REG_TYPE net_dns_map[] = {
  924. { LSTRKEY( "setdnsserver" ), LFUNCVAL( net_setdnsserver ) },
  925. { LSTRKEY( "getdnsserver" ), LFUNCVAL( net_getdnsserver ) },
  926. { LSTRKEY( "resolve" ), LFUNCVAL( net_dns_static ) },
  927. { LNILKEY, LNILVAL }
  928. };
  929. static const LUA_REG_TYPE net_map[] = {
  930. { LSTRKEY( "createServer" ), LFUNCVAL( net_createServer ) },
  931. { LSTRKEY( "createConnection" ), LFUNCVAL( net_createConnection ) },
  932. { LSTRKEY( "createUDPSocket" ), LFUNCVAL( net_createUDPSocket ) },
  933. { LSTRKEY( "multicastJoin"), LFUNCVAL( net_multicastJoin ) },
  934. { LSTRKEY( "multicastLeave"), LFUNCVAL( net_multicastLeave ) },
  935. { LSTRKEY( "dns" ), LROVAL( net_dns_map ) },
  936. #ifdef TLS_MODULE_PRESENT
  937. { LSTRKEY( "cert" ), LROVAL( tls_cert_map ) },
  938. #endif
  939. { LSTRKEY( "TCP" ), LNUMVAL( TYPE_TCP ) },
  940. { LSTRKEY( "UDP" ), LNUMVAL( TYPE_UDP ) },
  941. { LSTRKEY( "__metatable" ), LROVAL( net_map ) },
  942. { LNILKEY, LNILVAL }
  943. };
  944. int luaopen_net( lua_State *L ) {
  945. igmp_init();
  946. luaL_rometatable(L, NET_TABLE_TCP_SERVER, (void *)net_tcpserver_map);
  947. luaL_rometatable(L, NET_TABLE_TCP_CLIENT, (void *)net_tcpsocket_map);
  948. luaL_rometatable(L, NET_TABLE_UDP_SOCKET, (void *)net_udpsocket_map);
  949. return 0;
  950. }
  951. NODEMCU_MODULE(NET, "net", net_map, luaopen_net);