net.c 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037
  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. ud->tcp_pcb->so_options |= SOF_REUSEADDR;
  348. err = tcp_bind(ud->tcp_pcb, &addr, port);
  349. if (err == ERR_OK) {
  350. tcp_arg(ud->tcp_pcb, ud);
  351. struct tcp_pcb *pcb = tcp_listen(ud->tcp_pcb);
  352. if (!pcb) {
  353. err = ERR_MEM;
  354. } else {
  355. ud->tcp_pcb = pcb;
  356. tcp_accept(ud->tcp_pcb, net_accept_cb);
  357. }
  358. }
  359. break;
  360. case TYPE_UDP_SOCKET:
  361. ud->udp_pcb = udp_new();
  362. if (!ud->udp_pcb)
  363. return luaL_error(L, "cannot allocate PCB");
  364. udp_recv(ud->udp_pcb, net_udp_recv_cb, ud);
  365. err = udp_bind(ud->udp_pcb, &addr, port);
  366. break;
  367. }
  368. if (err != ERR_OK) {
  369. switch (ud->type) {
  370. case TYPE_TCP_SERVER:
  371. tcp_close(ud->tcp_pcb);
  372. ud->tcp_pcb = NULL;
  373. break;
  374. case TYPE_UDP_SOCKET:
  375. udp_remove(ud->udp_pcb);
  376. ud->udp_pcb = NULL;
  377. break;
  378. }
  379. return lwip_lua_checkerr(L, err);
  380. }
  381. if (ud->self_ref == LUA_NOREF) {
  382. lua_pushvalue(L, 1);
  383. ud->self_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  384. }
  385. return 0;
  386. }
  387. // Lua: client:connect(port, addr)
  388. int net_connect( lua_State *L ) {
  389. lnet_userdata *ud = net_get_udata(L);
  390. if (!ud || ud->type != TYPE_TCP_CLIENT)
  391. return luaL_error(L, "invalid user data");
  392. if (ud->pcb)
  393. return luaL_error(L, "already connected");
  394. uint16_t port = luaL_checkinteger(L, 2);
  395. if (port == 0)
  396. return luaL_error(L, "specify port");
  397. const char *domain = "127.0.0.1";
  398. if (lua_isstring(L, 3)) {
  399. size_t dl = 0;
  400. domain = luaL_checklstring(L, 3, &dl);
  401. }
  402. if (lua_gettop(L) > 3) {
  403. luaL_argcheck(L, lua_isfunction(L, 4) || lua_islightfunction(L, 4), 4, "not a function");
  404. lua_pushvalue(L, 4);
  405. luaL_unref(L, LUA_REGISTRYINDEX, ud->client.cb_connect_ref);
  406. ud->client.cb_connect_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  407. }
  408. ud->tcp_pcb = tcp_new();
  409. if (!ud->tcp_pcb)
  410. return luaL_error(L, "cannot allocate PCB");
  411. tcp_arg(ud->tcp_pcb, ud);
  412. tcp_err(ud->tcp_pcb, net_err_cb);
  413. tcp_recv(ud->tcp_pcb, net_tcp_recv_cb);
  414. tcp_sent(ud->tcp_pcb, net_sent_cb);
  415. ud->tcp_pcb->remote_port = port;
  416. ip_addr_t addr;
  417. ud->client.wait_dns ++;
  418. int unref = 0;
  419. if (ud->self_ref == LUA_NOREF) {
  420. unref = 1;
  421. lua_pushvalue(L, 1);
  422. ud->self_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  423. }
  424. err_t err = dns_gethostbyname(domain, &addr, net_dns_cb, ud);
  425. if (err == ERR_OK) {
  426. net_dns_cb(domain, &addr, ud);
  427. } else if (err != ERR_INPROGRESS) {
  428. ud->client.wait_dns --;
  429. if (unref) {
  430. luaL_unref(L, LUA_REGISTRYINDEX, ud->self_ref);
  431. ud->self_ref = LUA_NOREF;
  432. }
  433. tcp_abort(ud->tcp_pcb);
  434. ud->tcp_pcb = NULL;
  435. return lwip_lua_checkerr(L, err);
  436. }
  437. return 0;
  438. }
  439. // Lua: client/socket:on(name, callback)
  440. int net_on( lua_State *L ) {
  441. lnet_userdata *ud = net_get_udata(L);
  442. if (!ud || ud->type == TYPE_TCP_SERVER)
  443. return luaL_error(L, "invalid user data");
  444. int *refptr = NULL;
  445. const char *name = luaL_checkstring(L, 2);
  446. if (!name) return luaL_error(L, "need callback name");
  447. switch (ud->type) {
  448. case TYPE_TCP_CLIENT:
  449. if (strcmp("connection",name)==0)
  450. { refptr = &ud->client.cb_connect_ref; break; }
  451. if (strcmp("disconnection",name)==0)
  452. { refptr = &ud->client.cb_disconnect_ref; break; }
  453. if (strcmp("reconnection",name)==0)
  454. { refptr = &ud->client.cb_reconnect_ref; break; }
  455. case TYPE_UDP_SOCKET:
  456. if (strcmp("dns",name)==0)
  457. { refptr = &ud->client.cb_dns_ref; break; }
  458. if (strcmp("receive",name)==0)
  459. { refptr = &ud->client.cb_receive_ref; break; }
  460. if (strcmp("sent",name)==0)
  461. { refptr = &ud->client.cb_sent_ref; break; }
  462. break;
  463. default: return luaL_error(L, "invalid user data");
  464. }
  465. if (refptr == NULL)
  466. return luaL_error(L, "invalid callback name");
  467. if (lua_isfunction(L, 3) || lua_islightfunction(L, 3)) {
  468. lua_pushvalue(L, 3);
  469. luaL_unref(L, LUA_REGISTRYINDEX, *refptr);
  470. *refptr = luaL_ref(L, LUA_REGISTRYINDEX);
  471. } else if (lua_isnil(L, 3)) {
  472. luaL_unref(L, LUA_REGISTRYINDEX, *refptr);
  473. *refptr = LUA_NOREF;
  474. } else {
  475. return luaL_error(L, "invalid callback function");
  476. }
  477. return 0;
  478. }
  479. // Lua: client:send(data, function(c)), socket:send(port, ip, data, function(s))
  480. int net_send( lua_State *L ) {
  481. lnet_userdata *ud = net_get_udata(L);
  482. if (!ud || ud->type == TYPE_TCP_SERVER)
  483. return luaL_error(L, "invalid user data");
  484. ip_addr_t addr;
  485. uint16_t port;
  486. const char *data;
  487. size_t datalen = 0;
  488. int stack = 2;
  489. if (ud->type == TYPE_UDP_SOCKET) {
  490. size_t dl = 0;
  491. port = luaL_checkinteger(L, stack++);
  492. if (port == 0) return luaL_error(L, "need port");
  493. const char *domain = luaL_checklstring(L, stack++, &dl);
  494. if (!domain) return luaL_error(L, "need IP address");
  495. if (!ipaddr_aton(domain, &addr)) return luaL_error(L, "invalid IP address");
  496. }
  497. data = luaL_checklstring(L, stack++, &datalen);
  498. if (!data || datalen == 0) return luaL_error(L, "no data to send");
  499. if (lua_isfunction(L, stack) || lua_islightfunction(L, stack)) {
  500. lua_pushvalue(L, stack++);
  501. luaL_unref(L, LUA_REGISTRYINDEX, ud->client.cb_sent_ref);
  502. ud->client.cb_sent_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  503. }
  504. if (ud->type == TYPE_UDP_SOCKET && !ud->pcb) {
  505. ud->udp_pcb = udp_new();
  506. if (!ud->udp_pcb)
  507. return luaL_error(L, "cannot allocate PCB");
  508. udp_recv(ud->udp_pcb, net_udp_recv_cb, ud);
  509. ip_addr_t laddr = {0};
  510. err_t err = udp_bind(ud->udp_pcb, &laddr, 0);
  511. if (err != ERR_OK) {
  512. udp_remove(ud->udp_pcb);
  513. ud->udp_pcb = NULL;
  514. return lwip_lua_checkerr(L, err);
  515. }
  516. if (ud->self_ref == LUA_NOREF) {
  517. lua_pushvalue(L, 1);
  518. ud->self_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  519. }
  520. }
  521. if (!ud->pcb || ud->self_ref == LUA_NOREF)
  522. return luaL_error(L, "not connected");
  523. err_t err;
  524. if (ud->type == TYPE_UDP_SOCKET) {
  525. struct pbuf *pb = pbuf_alloc(PBUF_TRANSPORT, datalen, PBUF_RAM);
  526. if (!pb)
  527. return luaL_error(L, "cannot allocate message buffer");
  528. pbuf_take(pb, data, datalen);
  529. err = udp_sendto(ud->udp_pcb, pb, &addr, port);
  530. pbuf_free(pb);
  531. if (ud->client.cb_sent_ref != LUA_NOREF) {
  532. lua_rawgeti(L, LUA_REGISTRYINDEX, ud->client.cb_sent_ref);
  533. lua_rawgeti(L, LUA_REGISTRYINDEX, ud->self_ref);
  534. lua_call(L, 1, 0);
  535. }
  536. } else if (ud->type == TYPE_TCP_CLIENT) {
  537. err = tcp_write(ud->tcp_pcb, data, datalen, TCP_WRITE_FLAG_COPY);
  538. }
  539. return lwip_lua_checkerr(L, err);
  540. }
  541. // Lua: client:hold()
  542. int net_hold( lua_State *L ) {
  543. lnet_userdata *ud = net_get_udata(L);
  544. if (!ud || ud->type != TYPE_TCP_CLIENT)
  545. return luaL_error(L, "invalid user data");
  546. if (!ud->client.hold && ud->tcp_pcb) {
  547. ud->client.hold = 1;
  548. }
  549. return 0;
  550. }
  551. // Lua: client:unhold()
  552. int net_unhold( lua_State *L ) {
  553. lnet_userdata *ud = net_get_udata(L);
  554. if (!ud || ud->type != TYPE_TCP_CLIENT)
  555. return luaL_error(L, "invalid user data");
  556. if (ud->client.hold && ud->tcp_pcb) {
  557. ud->client.hold = 0;
  558. ud->tcp_pcb->flags |= TF_ACK_NOW;
  559. tcp_recved(ud->tcp_pcb, TCP_WND);
  560. }
  561. return 0;
  562. }
  563. // Lua: client/socket:dns(domain, callback(socket, addr))
  564. int net_dns( lua_State *L ) {
  565. lnet_userdata *ud = net_get_udata(L);
  566. if (!ud || ud->type == TYPE_TCP_SERVER)
  567. return luaL_error(L, "invalid user data");
  568. size_t dl = 0;
  569. const char *domain = luaL_checklstring(L, 2, &dl);
  570. if (!domain)
  571. return luaL_error(L, "no domain specified");
  572. if (lua_isfunction(L, 3) || lua_islightfunction(L, 3)) {
  573. luaL_unref(L, LUA_REGISTRYINDEX, ud->client.cb_dns_ref);
  574. lua_pushvalue(L, 3);
  575. ud->client.cb_dns_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  576. }
  577. if (ud->client.cb_dns_ref == LUA_NOREF)
  578. return luaL_error(L, "no callback specified");
  579. ud->client.wait_dns ++;
  580. int unref = 0;
  581. if (ud->self_ref == LUA_NOREF) {
  582. unref = 1;
  583. lua_pushvalue(L, 1);
  584. ud->self_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  585. }
  586. ip_addr_t addr;
  587. err_t err = dns_gethostbyname(domain, &addr, net_dns_cb, ud);
  588. if (err == ERR_OK) {
  589. net_dns_cb(domain, &addr, ud);
  590. } else if (err != ERR_INPROGRESS) {
  591. ud->client.wait_dns --;
  592. if (unref) {
  593. luaL_unref(L, LUA_REGISTRYINDEX, ud->self_ref);
  594. ud->self_ref = LUA_NOREF;
  595. }
  596. return lwip_lua_checkerr(L, err);
  597. }
  598. return 0;
  599. }
  600. // Lua: client/socket:ttl([ttl])
  601. int net_ttl( lua_State *L ) {
  602. lnet_userdata *ud = net_get_udata(L);
  603. if (!ud || ud->type == TYPE_TCP_SERVER)
  604. return luaL_error(L, "invalid user data");
  605. if (!ud->pcb)
  606. return luaL_error(L, "socket is not open/bound yet");
  607. int ttl = luaL_optinteger(L, 2, -1);
  608. // Since `ttl` field is part of IP_PCB macro
  609. // (which are at beginning of both udp_pcb/tcp_pcb)
  610. // and PCBs declared as `union` there is safe to
  611. // access ttl field without checking for type.
  612. if (ttl == -1) {
  613. ttl = ud->udp_pcb->ttl;
  614. } else {
  615. ud->udp_pcb->ttl = ttl;
  616. }
  617. lua_pushinteger(L, ttl);
  618. return 1;
  619. }
  620. // Lua: client:getpeer()
  621. int net_getpeer( lua_State *L ) {
  622. lnet_userdata *ud = net_get_udata(L);
  623. if (!ud || ud->type != TYPE_TCP_CLIENT)
  624. return luaL_error(L, "invalid user data");
  625. if (!ud->pcb) {
  626. lua_pushnil(L);
  627. lua_pushnil(L);
  628. return 2;
  629. }
  630. uint16_t port = ud->tcp_pcb->remote_port;
  631. ip_addr_t addr = ud->tcp_pcb->remote_ip;
  632. if (port == 0) {
  633. lua_pushnil(L);
  634. lua_pushnil(L);
  635. return 2;
  636. }
  637. char addr_str[16];
  638. bzero(addr_str, 16);
  639. ets_sprintf(addr_str, IPSTR, IP2STR(&addr.addr));
  640. lua_pushinteger(L, port);
  641. lua_pushstring(L, addr_str);
  642. return 2;
  643. }
  644. // Lua: client/server/socket:getaddr()
  645. int net_getaddr( lua_State *L ) {
  646. lnet_userdata *ud = net_get_udata(L);
  647. if (!ud) return luaL_error(L, "invalid user data");
  648. if (!ud->pcb) {
  649. lua_pushnil(L);
  650. lua_pushnil(L);
  651. return 2;
  652. }
  653. uint16_t port;
  654. ip_addr_t addr;
  655. switch (ud->type) {
  656. case TYPE_TCP_CLIENT:
  657. case TYPE_TCP_SERVER:
  658. addr = ud->tcp_pcb->local_ip;
  659. port = ud->tcp_pcb->local_port;
  660. break;
  661. case TYPE_UDP_SOCKET:
  662. addr = ud->udp_pcb->local_ip;
  663. port = ud->udp_pcb->local_port;
  664. break;
  665. }
  666. if (port == 0) {
  667. lua_pushnil(L);
  668. lua_pushnil(L);
  669. return 2;
  670. }
  671. char addr_str[16];
  672. bzero(addr_str, 16);
  673. ets_sprintf(addr_str, IPSTR, IP2STR(&addr.addr));
  674. lua_pushinteger(L, port);
  675. lua_pushstring(L, addr_str);
  676. return 2;
  677. }
  678. // Lua: client/server/socket:close()
  679. int net_close( lua_State *L ) {
  680. lnet_userdata *ud = net_get_udata(L);
  681. if (!ud) return luaL_error(L, "invalid user data");
  682. if (ud->pcb) {
  683. switch (ud->type) {
  684. case TYPE_TCP_CLIENT:
  685. if (ERR_OK != tcp_close(ud->tcp_pcb)) {
  686. tcp_arg(ud->tcp_pcb, NULL);
  687. tcp_abort(ud->tcp_pcb);
  688. }
  689. ud->tcp_pcb = NULL;
  690. break;
  691. case TYPE_TCP_SERVER:
  692. tcp_close(ud->tcp_pcb);
  693. ud->tcp_pcb = NULL;
  694. break;
  695. case TYPE_UDP_SOCKET:
  696. udp_remove(ud->udp_pcb);
  697. ud->udp_pcb = NULL;
  698. break;
  699. }
  700. } else {
  701. return luaL_error(L, "not connected");
  702. }
  703. if (ud->type == TYPE_TCP_SERVER ||
  704. (ud->pcb == NULL && ud->client.wait_dns == 0)) {
  705. lua_gc(L, LUA_GCSTOP, 0);
  706. luaL_unref(L, LUA_REGISTRYINDEX, ud->self_ref);
  707. ud->self_ref = LUA_NOREF;
  708. lua_gc(L, LUA_GCRESTART, 0);
  709. }
  710. return 0;
  711. }
  712. int net_delete( lua_State *L ) {
  713. lnet_userdata *ud = net_get_udata(L);
  714. if (!ud) return luaL_error(L, "no user data");
  715. if (ud->pcb) {
  716. switch (ud->type) {
  717. case TYPE_TCP_CLIENT:
  718. tcp_arg(ud->tcp_pcb, NULL);
  719. tcp_abort(ud->tcp_pcb);
  720. ud->tcp_pcb = NULL;
  721. break;
  722. case TYPE_TCP_SERVER:
  723. tcp_close(ud->tcp_pcb);
  724. ud->tcp_pcb = NULL;
  725. break;
  726. case TYPE_UDP_SOCKET:
  727. udp_remove(ud->udp_pcb);
  728. ud->udp_pcb = NULL;
  729. break;
  730. }
  731. }
  732. switch (ud->type) {
  733. case TYPE_TCP_CLIENT:
  734. luaL_unref(L, LUA_REGISTRYINDEX, ud->client.cb_connect_ref);
  735. ud->client.cb_connect_ref = LUA_NOREF;
  736. luaL_unref(L, LUA_REGISTRYINDEX, ud->client.cb_disconnect_ref);
  737. ud->client.cb_disconnect_ref = LUA_NOREF;
  738. luaL_unref(L, LUA_REGISTRYINDEX, ud->client.cb_reconnect_ref);
  739. ud->client.cb_reconnect_ref = LUA_NOREF;
  740. case TYPE_UDP_SOCKET:
  741. luaL_unref(L, LUA_REGISTRYINDEX, ud->client.cb_dns_ref);
  742. ud->client.cb_dns_ref = LUA_NOREF;
  743. luaL_unref(L, LUA_REGISTRYINDEX, ud->client.cb_receive_ref);
  744. ud->client.cb_receive_ref = LUA_NOREF;
  745. luaL_unref(L, LUA_REGISTRYINDEX, ud->client.cb_sent_ref);
  746. ud->client.cb_sent_ref = LUA_NOREF;
  747. break;
  748. case TYPE_TCP_SERVER:
  749. luaL_unref(L, LUA_REGISTRYINDEX, ud->server.cb_accept_ref);
  750. ud->server.cb_accept_ref = LUA_NOREF;
  751. break;
  752. }
  753. lua_gc(L, LUA_GCSTOP, 0);
  754. luaL_unref(L, LUA_REGISTRYINDEX, ud->self_ref);
  755. ud->self_ref = LUA_NOREF;
  756. lua_gc(L, LUA_GCRESTART, 0);
  757. return 0;
  758. }
  759. #pragma mark - Multicast
  760. static int net_multicastJoinLeave( lua_State *L, int join) {
  761. size_t il;
  762. ip_addr_t multicast_addr;
  763. ip_addr_t if_addr;
  764. const char *multicast_ip;
  765. const char *if_ip;
  766. NODE_DBG("net_multicastJoin is called.\n");
  767. if(! lua_isstring(L,1) ) return luaL_error( L, "wrong arg type" );
  768. if_ip = luaL_checklstring( L, 1, &il );
  769. if (if_ip != NULL)
  770. if ( if_ip[0] == '\0' || stricmp(if_ip,"any") == 0)
  771. {
  772. if_ip = "0.0.0.0";
  773. il = 7;
  774. }
  775. if (if_ip == NULL || il > 15 || il < 7) return luaL_error( L, "invalid if ip" );
  776. if_addr.addr = ipaddr_addr(if_ip);
  777. if(! lua_isstring(L,2) ) return luaL_error( L, "wrong arg type" );
  778. multicast_ip = luaL_checklstring( L, 2, &il );
  779. if (multicast_ip == NULL || il > 15 || il < 7) return luaL_error( L, "invalid multicast ip" );
  780. multicast_addr.addr = ipaddr_addr(multicast_ip);
  781. if (join)
  782. {
  783. igmp_joingroup(&if_addr, &multicast_addr);
  784. }
  785. else
  786. {
  787. igmp_leavegroup(&if_addr, &multicast_addr);
  788. }
  789. return 0;
  790. }
  791. // Lua: net.multicastJoin(ifip, multicastip)
  792. // if ifip "" or "any" all interfaces are affected
  793. static int net_multicastJoin( lua_State* L ) {
  794. return net_multicastJoinLeave(L,1);
  795. }
  796. // Lua: net.multicastLeave(ifip, multicastip)
  797. // if ifip "" or "any" all interfaces are affected
  798. static int net_multicastLeave( lua_State* L ) {
  799. return net_multicastJoinLeave(L,0);
  800. }
  801. #pragma mark - DNS
  802. static void net_dns_static_cb(const char *name, ip_addr_t *ipaddr, void *callback_arg) {
  803. ip_addr_t addr;
  804. if (ipaddr != NULL)
  805. addr = *ipaddr;
  806. else addr.addr = 0xFFFFFFFF;
  807. int cb_ref = ((int*)callback_arg)[0];
  808. c_free(callback_arg);
  809. lua_State *L = lua_getstate();
  810. lua_rawgeti(L, LUA_REGISTRYINDEX, cb_ref);
  811. lua_pushnil(L);
  812. if (addr.addr != 0xFFFFFFFF) {
  813. char iptmp[20];
  814. size_t ipl = c_sprintf(iptmp, IPSTR, IP2STR(&addr.addr));
  815. lua_pushlstring(L, iptmp, ipl);
  816. } else {
  817. lua_pushnil(L);
  818. }
  819. lua_call(L, 2, 0);
  820. luaL_unref(L, LUA_REGISTRYINDEX, cb_ref);
  821. }
  822. // Lua: net.dns.resolve( domain, function(sk, ip) )
  823. static int net_dns_static( lua_State* L ) {
  824. size_t dl;
  825. const char* domain = luaL_checklstring(L, 1, &dl);
  826. if (!domain && dl > 128) {
  827. return luaL_error(L, "wrong domain");
  828. }
  829. luaL_checkanyfunction(L, 2);
  830. lua_pushvalue(L, 2); // copy argument (func) to the top of stack
  831. int cbref = luaL_ref(L, LUA_REGISTRYINDEX);
  832. if (cbref == LUA_NOREF) {
  833. return luaL_error(L, "wrong callback");
  834. }
  835. int *cbref_ptr = c_zalloc(sizeof(int));
  836. cbref_ptr[0] = cbref;
  837. ip_addr_t addr;
  838. err_t err = dns_gethostbyname(domain, &addr, net_dns_static_cb, cbref_ptr);
  839. if (err == ERR_OK) {
  840. net_dns_static_cb(domain, &addr, cbref_ptr);
  841. return 0;
  842. } else if (err == ERR_INPROGRESS) {
  843. return 0;
  844. } else {
  845. int e = lwip_lua_checkerr(L, err);
  846. c_free(cbref_ptr);
  847. return e;
  848. }
  849. return 0;
  850. }
  851. // Lua: s = net.dns.setdnsserver(ip_addr, [index])
  852. static int net_setdnsserver( lua_State* L ) {
  853. size_t l;
  854. u32_t ip32;
  855. const char *server = luaL_checklstring( L, 1, &l );
  856. if (l>16 || server == NULL || (ip32 = ipaddr_addr(server)) == IPADDR_NONE || ip32 == IPADDR_ANY)
  857. return luaL_error( L, "invalid dns server ip" );
  858. int numdns = luaL_optint(L, 2, 0);
  859. if (numdns >= DNS_MAX_SERVERS)
  860. return luaL_error( L, "server index out of range [0-%d]", DNS_MAX_SERVERS - 1);
  861. ip_addr_t ipaddr;
  862. ip4_addr_set_u32(&ipaddr, ip32);
  863. dns_setserver(numdns,&ipaddr);
  864. return 0;
  865. }
  866. // Lua: s = net.dns.getdnsserver([index])
  867. static int net_getdnsserver( lua_State* L ) {
  868. int numdns = luaL_optint(L, 1, 0);
  869. if (numdns >= DNS_MAX_SERVERS)
  870. return luaL_error( L, "server index out of range [0-%d]", DNS_MAX_SERVERS - 1);
  871. // ip_addr_t ipaddr;
  872. // dns_getserver(numdns,&ipaddr);
  873. // Bug fix by @md5crypt https://github.com/nodemcu/nodemcu-firmware/pull/500
  874. ip_addr_t ipaddr = dns_getserver(numdns);
  875. if ( ip_addr_isany(&ipaddr) ) {
  876. lua_pushnil( L );
  877. } else {
  878. char temp[20] = {0};
  879. c_sprintf(temp, IPSTR, IP2STR( &ipaddr.addr ) );
  880. lua_pushstring( L, temp );
  881. }
  882. return 1;
  883. }
  884. #pragma mark - Tables
  885. #ifdef TLS_MODULE_PRESENT
  886. extern const LUA_REG_TYPE tls_cert_map[];
  887. #endif
  888. // Module function map
  889. static const LUA_REG_TYPE net_tcpserver_map[] = {
  890. { LSTRKEY( "listen" ), LFUNCVAL( net_listen ) },
  891. { LSTRKEY( "getaddr" ), LFUNCVAL( net_getaddr ) },
  892. { LSTRKEY( "close" ), LFUNCVAL( net_close ) },
  893. { LSTRKEY( "__gc" ), LFUNCVAL( net_delete ) },
  894. { LSTRKEY( "__index" ), LROVAL( net_tcpserver_map ) },
  895. { LNILKEY, LNILVAL }
  896. };
  897. static const LUA_REG_TYPE net_tcpsocket_map[] = {
  898. { LSTRKEY( "connect" ), LFUNCVAL( net_connect ) },
  899. { LSTRKEY( "close" ), LFUNCVAL( net_close ) },
  900. { LSTRKEY( "on" ), LFUNCVAL( net_on ) },
  901. { LSTRKEY( "send" ), LFUNCVAL( net_send ) },
  902. { LSTRKEY( "hold" ), LFUNCVAL( net_hold ) },
  903. { LSTRKEY( "unhold" ), LFUNCVAL( net_unhold ) },
  904. { LSTRKEY( "dns" ), LFUNCVAL( net_dns ) },
  905. { LSTRKEY( "ttl" ), LFUNCVAL( net_ttl ) },
  906. { LSTRKEY( "getpeer" ), LFUNCVAL( net_getpeer ) },
  907. { LSTRKEY( "getaddr" ), LFUNCVAL( net_getaddr ) },
  908. { LSTRKEY( "__gc" ), LFUNCVAL( net_delete ) },
  909. { LSTRKEY( "__index" ), LROVAL( net_tcpsocket_map ) },
  910. { LNILKEY, LNILVAL }
  911. };
  912. static const LUA_REG_TYPE net_udpsocket_map[] = {
  913. { LSTRKEY( "listen" ), LFUNCVAL( net_listen ) },
  914. { LSTRKEY( "close" ), LFUNCVAL( net_close ) },
  915. { LSTRKEY( "on" ), LFUNCVAL( net_on ) },
  916. { LSTRKEY( "send" ), LFUNCVAL( net_send ) },
  917. { LSTRKEY( "dns" ), LFUNCVAL( net_dns ) },
  918. { LSTRKEY( "ttl" ), LFUNCVAL( net_ttl ) },
  919. { LSTRKEY( "getaddr" ), LFUNCVAL( net_getaddr ) },
  920. { LSTRKEY( "__gc" ), LFUNCVAL( net_delete ) },
  921. { LSTRKEY( "__index" ), LROVAL( net_udpsocket_map ) },
  922. { LNILKEY, LNILVAL }
  923. };
  924. static const LUA_REG_TYPE net_dns_map[] = {
  925. { LSTRKEY( "setdnsserver" ), LFUNCVAL( net_setdnsserver ) },
  926. { LSTRKEY( "getdnsserver" ), LFUNCVAL( net_getdnsserver ) },
  927. { LSTRKEY( "resolve" ), LFUNCVAL( net_dns_static ) },
  928. { LNILKEY, LNILVAL }
  929. };
  930. static const LUA_REG_TYPE net_map[] = {
  931. { LSTRKEY( "createServer" ), LFUNCVAL( net_createServer ) },
  932. { LSTRKEY( "createConnection" ), LFUNCVAL( net_createConnection ) },
  933. { LSTRKEY( "createUDPSocket" ), LFUNCVAL( net_createUDPSocket ) },
  934. { LSTRKEY( "multicastJoin"), LFUNCVAL( net_multicastJoin ) },
  935. { LSTRKEY( "multicastLeave"), LFUNCVAL( net_multicastLeave ) },
  936. { LSTRKEY( "dns" ), LROVAL( net_dns_map ) },
  937. #ifdef TLS_MODULE_PRESENT
  938. { LSTRKEY( "cert" ), LROVAL( tls_cert_map ) },
  939. #endif
  940. { LSTRKEY( "TCP" ), LNUMVAL( TYPE_TCP ) },
  941. { LSTRKEY( "UDP" ), LNUMVAL( TYPE_UDP ) },
  942. { LSTRKEY( "__metatable" ), LROVAL( net_map ) },
  943. { LNILKEY, LNILVAL }
  944. };
  945. int luaopen_net( lua_State *L ) {
  946. igmp_init();
  947. luaL_rometatable(L, NET_TABLE_TCP_SERVER, (void *)net_tcpserver_map);
  948. luaL_rometatable(L, NET_TABLE_TCP_CLIENT, (void *)net_tcpsocket_map);
  949. luaL_rometatable(L, NET_TABLE_UDP_SOCKET, (void *)net_udpsocket_map);
  950. return 0;
  951. }
  952. NODEMCU_MODULE(NET, "net", net_map, luaopen_net);