From 8b02c057c6aa21d8256c18f225d53e58531ba0f2 Mon Sep 17 00:00:00 2001 From: Yury Popov Date: Fri, 22 Jul 2016 20:26:48 +0300 Subject: [PATCH] Net module on LWIP --- app/modules/net.c | 1903 ++++++++++++++++------------------------ docs/en/modules/net.md | 106 ++- 2 files changed, 832 insertions(+), 1177 deletions(-) diff --git a/app/modules/net.c b/app/modules/net.c index a93bb1dee8..6461b200cf 100644 --- a/app/modules/net.c +++ b/app/modules/net.c @@ -10,1023 +10,803 @@ #include "c_types.h" #include "mem.h" +#include "osapi.h" +#include "lwip/err.h" #include "lwip/ip_addr.h" -#include "espconn.h" #include "lwip/dns.h" #include "lwip/igmp.h" +#include "lwip/tcp.h" +#include "lwip/udp.h" -#define TCP ESPCONN_TCP -#define UDP ESPCONN_UDP +typedef enum net_type { + TYPE_TCP_SERVER = 0, + TYPE_TCP_CLIENT, + TYPE_UDP_SOCKET +} net_type; -static ip_addr_t host_ip; // for dns +typedef const char net_table_name[14]; -#define MAX_SOCKET 5 -static int socket_num = 0; -static int socket[MAX_SOCKET]; -static lua_State *gL = NULL; -static int tcpserver_cb_connect_ref = LUA_NOREF; // for tcp server connected callback -static uint16_t tcp_server_timeover = 30; +static const net_table_name NET_TABLES[] = { + "net.tcpserver", + "net.tcpsocket", + "net.udpsocket" +}; +#define NET_TABLE_TCP_SERVER NET_TABLES[0] +#define NET_TABLE_TCP_CLIENT NET_TABLES[1] +#define NET_TABLE_UDP_SOCKET NET_TABLES[2] -static struct espconn *pTcpServer = NULL; -static struct espconn *pUdpServer = NULL; +#define TYPE_TCP TYPE_TCP_CLIENT +#define TYPE_UDP TYPE_UDP_SOCKET -typedef struct lnet_userdata -{ - struct espconn *pesp_conn; +typedef struct lnet_userdata { + enum net_type type; int self_ref; - int cb_connect_ref; - int cb_reconnect_ref; - int cb_disconnect_ref; - int cb_receive_ref; - int cb_send_ref; - int cb_dns_found_ref; -}lnet_userdata; - -static void net_server_disconnected(void *arg) // for tcp server only -{ - NODE_DBG("net_server_disconnected is called.\n"); - struct espconn *pesp_conn = arg; - if(pesp_conn == NULL) - return; - lnet_userdata *nud = (lnet_userdata *)pesp_conn->reverse; - if(nud == NULL) - return; - if(gL == NULL) - return; - if(nud->cb_disconnect_ref != LUA_NOREF && nud->self_ref != LUA_NOREF) - { - lua_rawgeti(gL, LUA_REGISTRYINDEX, nud->cb_disconnect_ref); - lua_rawgeti(gL, LUA_REGISTRYINDEX, nud->self_ref); // pass the userdata(client) to callback func in lua - lua_call(gL, 1, 0); - } - int i; - lua_gc(gL, LUA_GCSTOP, 0); - for(i=0;iself_ref) ){ - // found the saved client - nud->pesp_conn->reverse = NULL; - nud->pesp_conn = NULL; // the espconn is made by low level sdk, do not need to free, delete() will not free it. - nud->self_ref = LUA_NOREF; // unref this, and the net.socket userdata will delete it self - luaL_unref(gL, LUA_REGISTRYINDEX, socket[i]); - socket[i] = LUA_NOREF; - socket_num--; - break; - } - } - lua_gc(gL, LUA_GCRESTART, 0); -} - -static void net_socket_disconnected(void *arg) // tcp only -{ - NODE_DBG("net_socket_disconnected is called.\n"); - struct espconn *pesp_conn = arg; - if(pesp_conn == NULL) - return; - lnet_userdata *nud = (lnet_userdata *)pesp_conn->reverse; - if(nud == NULL) - return; - if(nud->cb_disconnect_ref != LUA_NOREF && nud->self_ref != LUA_NOREF) - { - lua_rawgeti(gL, LUA_REGISTRYINDEX, nud->cb_disconnect_ref); - lua_rawgeti(gL, LUA_REGISTRYINDEX, nud->self_ref); // pass the userdata(client) to callback func in lua - lua_call(gL, 1, 0); - } + union { + struct tcp_pcb *tcp_pcb; + struct udp_pcb *udp_pcb; + void *pcb; + }; + union { + struct { + int cb_accept_ref; + } server; + struct { + int wait_dns; + int cb_dns_ref; + int cb_receive_ref; + int cb_sent_ref; + // Only for TCP: + int hold; + int cb_connect_ref; + int cb_disconnect_ref; + int cb_reconnect_ref; + } client; + }; +} lnet_userdata; + +#pragma mark - LWIP errors + +int luaL_lwip_checkerr (err_t err, lua_State *L) { + switch (err) { + case ERR_OK: return 0; + case ERR_MEM: return luaL_error(L, "out of memory"); + case ERR_BUF: return luaL_error(L, "buffer error"); + case ERR_TIMEOUT: return luaL_error(L, "timeout"); + case ERR_RTE: return luaL_error(L, "routing problem"); + case ERR_INPROGRESS: return luaL_error(L, "in progress"); + case ERR_VAL: return luaL_error(L, "illegal value"); + case ERR_WOULDBLOCK: return luaL_error(L, "would block"); + case ERR_ABRT: return luaL_error(L, "connection aborted"); + case ERR_RST: return luaL_error(L, "connection reset"); + case ERR_CLSD: return luaL_error(L, "connection closed"); + case ERR_CONN: return luaL_error(L, "not connected"); + case ERR_ARG: return luaL_error(L, "illegal argument"); + case ERR_USE: return luaL_error(L, "address in use"); + case ERR_IF: return luaL_error(L, "netif error"); + case ERR_ISCONN: return luaL_error(L, "already connected"); + default: return luaL_error(L, "unknown error"); + } +} + +#pragma mark - Create + +lnet_userdata *net_create( lua_State *L, enum net_type type ) { + const char *mt = NET_TABLES[type]; + lnet_userdata *ud = (lnet_userdata *)lua_newuserdata(L, sizeof(lnet_userdata)); + if (!ud) return NULL; + luaL_getmetatable(L, mt); + lua_setmetatable(L, -2); - if(pesp_conn->proto.tcp) - c_free(pesp_conn->proto.tcp); - pesp_conn->proto.tcp = NULL; - if(nud->pesp_conn) - c_free(nud->pesp_conn); - nud->pesp_conn = NULL; // espconn is already disconnected - lua_gc(gL, LUA_GCSTOP, 0); - if(nud->self_ref != LUA_NOREF){ - luaL_unref(gL, LUA_REGISTRYINDEX, nud->self_ref); - nud->self_ref = LUA_NOREF; // unref this, and the net.socket userdata will delete it self + ud->type = type; + ud->self_ref = LUA_NOREF; + ud->pcb = NULL; + + switch (type) { + case TYPE_TCP_CLIENT: + ud->client.cb_connect_ref = LUA_NOREF; + ud->client.cb_reconnect_ref = LUA_NOREF; + ud->client.cb_disconnect_ref = LUA_NOREF; + ud->client.hold = 0; + case TYPE_UDP_SOCKET: + ud->client.wait_dns = 0; + ud->client.cb_dns_ref = LUA_NOREF; + ud->client.cb_receive_ref = LUA_NOREF; + ud->client.cb_sent_ref = LUA_NOREF; + break; + case TYPE_TCP_SERVER: + ud->server.cb_accept_ref = LUA_NOREF; + break; } - lua_gc(gL, LUA_GCRESTART, 0); -} - -static void net_server_reconnected(void *arg, sint8_t err) -{ - NODE_DBG("net_server_reconnected is called.\n"); - net_server_disconnected(arg); + return ud; } -static void net_socket_reconnected(void *arg, sint8_t err) -{ - NODE_DBG("net_socket_reconnected is called.\n"); - net_socket_disconnected(arg); -} +#pragma mark - LWIP callbacks -static void net_socket_received(void *arg, char *pdata, unsigned short len) -{ - NODE_DBG("net_socket_received is called.\n"); - struct espconn *pesp_conn = arg; - if(pesp_conn == NULL) - return; - lnet_userdata *nud = (lnet_userdata *)pesp_conn->reverse; - if(nud == NULL) - return; - if(nud->cb_receive_ref == LUA_NOREF) - return; - if(nud->self_ref == LUA_NOREF) - return; - lua_rawgeti(gL, LUA_REGISTRYINDEX, nud->cb_receive_ref); - lua_rawgeti(gL, LUA_REGISTRYINDEX, nud->self_ref); // pass the userdata(server) to callback func in lua - lua_pushlstring(gL, pdata, len); - lua_call(gL, 2, 0); -} - -static void net_socket_sent(void *arg) -{ - NODE_DBG("net_socket_sent is called.\n"); - struct espconn *pesp_conn = arg; - if(pesp_conn == NULL) - return; - lnet_userdata *nud = (lnet_userdata *)pesp_conn->reverse; - if(nud == NULL) - return; - if(nud->cb_send_ref == LUA_NOREF) - return; - if(nud->self_ref == LUA_NOREF) - return; - lua_rawgeti(gL, LUA_REGISTRYINDEX, nud->cb_send_ref); - lua_rawgeti(gL, LUA_REGISTRYINDEX, nud->self_ref); // pass the userdata(server) to callback func in lua - lua_call(gL, 1, 0); -} - -static void net_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) -{ - NODE_DBG("net_dns_found is called.\n"); - struct espconn *pesp_conn = arg; - if(pesp_conn == NULL){ - NODE_DBG("pesp_conn null.\n"); - return; - } - lnet_userdata *nud = (lnet_userdata *)pesp_conn->reverse; - if(nud == NULL){ - NODE_DBG("nud null.\n"); - return; - } - if(nud->cb_dns_found_ref == LUA_NOREF){ - NODE_DBG("cb_dns_found_ref null.\n"); - return; +static void net_err_cb(void *arg, err_t err) { + lnet_userdata *ud = (lnet_userdata*)arg; + if (!ud || ud->type != TYPE_TCP_CLIENT || ud->self_ref == LUA_NOREF) return; + ud->pcb = NULL; // Will be freed at LWIP level + lua_State *L = lua_getstate(); + int ref; + if (err != ERR_OK && ud->client.cb_reconnect_ref != LUA_NOREF) + ref = ud->client.cb_reconnect_ref; + else ref = ud->client.cb_disconnect_ref; + if (ref != LUA_NOREF) { + lua_rawgeti(L, LUA_REGISTRYINDEX, ref); + lua_rawgeti(L, LUA_REGISTRYINDEX, ud->self_ref); + lua_pushinteger(L, err); + lua_call(L, 2, 0); + } + if (ud->client.wait_dns == 0) { + lua_gc(L, LUA_GCSTOP, 0); + luaL_unref(L, LUA_REGISTRYINDEX, ud->self_ref); + ud->self_ref = LUA_NOREF; + lua_gc(L, LUA_GCRESTART, 0); + } +} + +static err_t net_connected_cb(void *arg, struct tcp_pcb *tpcb, err_t err) { + lnet_userdata *ud = (lnet_userdata*)arg; + if (!ud || ud->pcb != tpcb) return ERR_ABRT; + if (err != ERR_OK) { + net_err_cb(arg, err); + return ERR_ABRT; } - - if(nud->self_ref == LUA_NOREF){ - NODE_DBG("self_ref null.\n"); - return; + lua_State *L = lua_getstate(); + if (ud->self_ref != LUA_NOREF && ud->client.cb_connect_ref != LUA_NOREF) { + lua_rawgeti(L, LUA_REGISTRYINDEX, ud->client.cb_connect_ref); + lua_rawgeti(L, LUA_REGISTRYINDEX, ud->self_ref); + lua_call(L, 1, 0); } + return ERR_OK; +} - lua_rawgeti(gL, LUA_REGISTRYINDEX, nud->cb_dns_found_ref); // the callback function - lua_rawgeti(gL, LUA_REGISTRYINDEX, nud->self_ref); // pass the userdata(conn) to callback func in lua - - if(ipaddr == NULL) - { - NODE_DBG( "DNS Fail!\n" ); - lua_pushnil(gL); - }else{ - // ipaddr->addr is a uint32_t ip - char ip_str[20]; - c_memset(ip_str, 0, sizeof(ip_str)); - if(ipaddr->addr != 0) - { - c_sprintf(ip_str, IPSTR, IP2STR(&(ipaddr->addr))); +static void net_dns_cb(const char *name, ip_addr_t *ipaddr, void *arg) { + ip_addr_t addr; + if (ipaddr != NULL) addr = *ipaddr; + else addr.addr = 0xFFFFFFFF; + lnet_userdata *ud = (lnet_userdata*)arg; + if (!ud) return; + lua_State *L = lua_getstate(); + if (ud->self_ref != LUA_NOREF && ud->client.cb_dns_ref != LUA_NOREF) { + lua_rawgeti(L, LUA_REGISTRYINDEX, ud->client.cb_dns_ref); + lua_rawgeti(L, LUA_REGISTRYINDEX, ud->self_ref); + if (addr.addr != 0xFFFFFFFF) { + char iptmp[16]; + bzero(iptmp, 16); + ets_sprintf(iptmp, IPSTR, IP2STR(&addr.addr)); + lua_pushstring(L, iptmp); + } else { + lua_pushnil(L); } - lua_pushstring(gL, ip_str); // the ip para + lua_call(L, 2, 0); } - - lua_call(gL, 2, 0); - -end: - if((pesp_conn->type == ESPCONN_TCP && pesp_conn->proto.tcp->remote_port == 0) - || (pesp_conn->type == ESPCONN_UDP && pesp_conn->proto.udp->remote_port == 0) ){ - lua_gc(gL, LUA_GCSTOP, 0); - if(nud->self_ref != LUA_NOREF){ - luaL_unref(gL, LUA_REGISTRYINDEX, nud->self_ref); - nud->self_ref = LUA_NOREF; // unref this, and the net.socket userdata will delete it self - } - lua_gc(gL, LUA_GCRESTART, 0); + ud->client.wait_dns --; + if (ud->pcb && ud->type == TYPE_TCP_CLIENT && ud->tcp_pcb->state == CLOSED) { + tcp_connect(ud->tcp_pcb, &addr, ud->tcp_pcb->remote_port, net_connected_cb); + } else if (!ud->pcb && ud->client.wait_dns == 0) { + lua_gc(L, LUA_GCSTOP, 0); + luaL_unref(L, LUA_REGISTRYINDEX, ud->self_ref); + ud->self_ref = LUA_NOREF; + lua_gc(L, LUA_GCRESTART, 0); } } -static void net_server_connected(void *arg) // for tcp only -{ - NODE_DBG("net_server_connected is called.\n"); - struct espconn *pesp_conn = arg; - int i = 0; - lnet_userdata *skt = NULL; - if(pesp_conn == NULL) +static void net_recv_cb(lnet_userdata *ud, struct pbuf *p, ip_addr_t *addr, u16_t port) { + if (ud->client.cb_receive_ref == LUA_NOREF) { + pbuf_free(p); return; - - for(i=0;i=MAX_SOCKET) // can't create more socket - { - NODE_ERR("MAX_SOCKET\n"); - pesp_conn->reverse = NULL; // not accept this conn - if(pesp_conn->proto.tcp->remote_port || pesp_conn->proto.tcp->local_port) - espconn_disconnect(pesp_conn); - return; + lua_State *L = lua_getstate(); + int num_args = 2; + lua_rawgeti(L, LUA_REGISTRYINDEX, ud->client.cb_receive_ref); + lua_rawgeti(L, LUA_REGISTRYINDEX, ud->self_ref); + if (ud->type == TYPE_UDP_SOCKET) { + num_args += 2; + char iptmp[16]; + bzero(iptmp, 16); + ets_sprintf(iptmp, IPSTR, IP2STR(&addr->addr)); + lua_pushinteger(L, port); + lua_pushstring(L, iptmp); } + lua_pushlstring(L, p->payload, p->len); + lua_call(L, num_args, 0); + pbuf_free(p); +} - if(tcpserver_cb_connect_ref == LUA_NOREF) - return; - if(!gL) - return; - - lua_rawgeti(gL, LUA_REGISTRYINDEX, tcpserver_cb_connect_ref); // get function - // create a new client object - skt = (lnet_userdata *)lua_newuserdata(gL, sizeof(lnet_userdata)); - - if(!skt){ - NODE_ERR("can't newudata\n"); - lua_pop(gL, 1); +static void net_udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port) { + lnet_userdata *ud = (lnet_userdata*)arg; + if (!ud || !ud->pcb || ud->type != TYPE_UDP_SOCKET || ud->self_ref == LUA_NOREF) { + if (p) pbuf_free(p); return; } - // set its metatable - luaL_getmetatable(gL, "net.socket"); - lua_setmetatable(gL, -2); - // pre-initialize it, in case of errors - skt->self_ref = LUA_NOREF; - lua_pushvalue(gL, -1); // copy the top of stack - skt->self_ref = luaL_ref(gL, LUA_REGISTRYINDEX); // ref to it self, for module api to find the userdata - socket[i] = skt->self_ref; // save to socket array - socket_num++; - skt->cb_connect_ref = LUA_NOREF; // this socket already connected - skt->cb_reconnect_ref = LUA_NOREF; - skt->cb_disconnect_ref = LUA_NOREF; - - skt->cb_receive_ref = LUA_NOREF; - skt->cb_send_ref = LUA_NOREF; - skt->cb_dns_found_ref = LUA_NOREF; - - skt->pesp_conn = pesp_conn; // point to the espconn made by low level sdk - pesp_conn->reverse = skt; // let espcon carray the info of this userdata(net.socket) - - espconn_regist_recvcb(pesp_conn, net_socket_received); - espconn_regist_sentcb(pesp_conn, net_socket_sent); - espconn_regist_disconcb(pesp_conn, net_server_disconnected); - espconn_regist_reconcb(pesp_conn, net_server_reconnected); - - // now socket[i] has the client ref, and stack top has the userdata - lua_call(gL, 1, 0); // function(conn) + net_recv_cb(ud, p, addr, port); } -static void net_socket_connected(void *arg) -{ - NODE_DBG("net_socket_connected is called.\n"); - struct espconn *pesp_conn = arg; - if(pesp_conn == NULL) - return; - lnet_userdata *nud = (lnet_userdata *)pesp_conn->reverse; - if(nud == NULL) - return; - // can receive and send data, even if there is no connected callback in lua. - espconn_regist_recvcb(pesp_conn, net_socket_received); - espconn_regist_sentcb(pesp_conn, net_socket_sent); - espconn_regist_disconcb(pesp_conn, net_socket_disconnected); +static err_t net_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) { + lnet_userdata *ud = (lnet_userdata*)arg; + if (!ud || !ud->pcb || ud->type != TYPE_TCP_CLIENT || ud->self_ref == LUA_NOREF) + return ERR_ABRT; + if (!p) { + net_err_cb(arg, err); + return tcp_close(tpcb); + } + net_recv_cb(ud, p, 0, 0); + tcp_recved(tpcb, p->len); + return ERR_OK; +} - if(nud->cb_connect_ref == LUA_NOREF) - return; - if(nud->self_ref == LUA_NOREF) - return; - lua_rawgeti(gL, LUA_REGISTRYINDEX, nud->cb_connect_ref); - lua_rawgeti(gL, LUA_REGISTRYINDEX, nud->self_ref); // pass the userdata(client) to callback func in lua - lua_call(gL, 1, 0); +static err_t net_sent_cb(void *arg, struct tcp_pcb *tpcb, u16_t len) { + lnet_userdata *ud = (lnet_userdata*)arg; + if (!ud || !ud->pcb || ud->type != TYPE_TCP_CLIENT || ud->self_ref == LUA_NOREF) return ERR_ABRT; + if (ud->client.cb_sent_ref == LUA_NOREF) return ERR_OK; + lua_State *L = lua_getstate(); + lua_rawgeti(L, LUA_REGISTRYINDEX, ud->client.cb_sent_ref); + lua_rawgeti(L, LUA_REGISTRYINDEX, ud->self_ref); + lua_call(L, 1, 0); + return ERR_OK; } -extern int tls_socket_create( lua_State *L ); +static err_t net_accept_cb(void *arg, struct tcp_pcb *newpcb, err_t err) { + lnet_userdata *ud = (lnet_userdata*)arg; + if (!ud || ud->type != TYPE_TCP_SERVER || !ud->pcb) return ERR_ABRT; + if (ud->self_ref == LUA_NOREF || ud->server.cb_accept_ref == LUA_NOREF) return ERR_ABRT; -// Lua: s = net.create(type, secure/timeout, function(conn)) -static int net_create( lua_State* L, const char* mt ) -{ - NODE_DBG("net_create is called.\n"); - struct espconn *pesp_conn = NULL; - lnet_userdata *nud, *temp = NULL; - unsigned type; - uint8_t stack = 1; - bool isserver = false; - - if (mt!=NULL && c_strcmp(mt, "net.server")==0) - isserver = true; - else if (mt!=NULL && c_strcmp(mt, "net.socket")==0) - isserver = false; - else - { - NODE_DBG("wrong metatable for net_create.\n"); - return 0; - } + lua_State *L = lua_getstate(); + lua_rawgeti(L, LUA_REGISTRYINDEX, ud->server.cb_accept_ref); - type = luaL_checkinteger( L, stack ); - if ( type != ESPCONN_TCP && type != ESPCONN_UDP ) - return luaL_error( L, "wrong arg type" ); - stack++; -#ifdef CLIENT_SSL_ENABLE - if(!isserver){ - if ( lua_isnumber(L, stack) ) - { - unsigned secure = lua_tointeger(L, stack); - stack++; - if ( secure != 0 && secure != 1 ){ - return luaL_error( L, "wrong arg type" ); - } - if ( secure == 1 ) { - return tls_socket_create(L); - } - } - } -#endif + lnet_userdata *nud = net_create(L, TYPE_TCP_CLIENT); + lua_pushvalue(L, 2); + nud->self_ref = luaL_ref(L, LUA_REGISTRYINDEX); + nud->tcp_pcb = newpcb; + tcp_arg(nud->tcp_pcb, nud); + tcp_err(nud->tcp_pcb, net_err_cb); + tcp_recv(nud->tcp_pcb, net_tcp_recv_cb); + tcp_sent(nud->tcp_pcb, net_sent_cb); - if(isserver && type == ESPCONN_TCP){ - if ( lua_isnumber(L, stack) ) - { - unsigned to = lua_tointeger(L, stack); - stack++; - if ( to < 1 || to > 28800 ){ - return luaL_error( L, "wrong arg type" ); - } - tcp_server_timeover = (uint16_t)to; - } else { - tcp_server_timeover = 30; // default to 30 - } - } + tcp_accepted(ud->tcp_pcb); - // create a object - nud = (lnet_userdata *)lua_newuserdata(L, sizeof(lnet_userdata)); - // pre-initialize it, in case of errors - nud->self_ref = LUA_NOREF; - nud->cb_connect_ref = LUA_NOREF; - nud->cb_reconnect_ref = LUA_NOREF; - nud->cb_disconnect_ref = LUA_NOREF; - nud->cb_receive_ref = LUA_NOREF; - nud->cb_send_ref = LUA_NOREF; - nud->cb_dns_found_ref = LUA_NOREF; - nud->pesp_conn = NULL; - - // set its metatable - luaL_getmetatable(L, mt); - lua_setmetatable(L, -2); + lua_call(L, 1, 0); - // create the espconn struct - if(isserver && type==ESPCONN_TCP && pTcpServer){ - if(tcpserver_cb_connect_ref != LUA_NOREF){ // self_ref should be unref in close() - lua_pop(L,1); - return luaL_error(L, "only one tcp server allowed"); - } - pesp_conn = nud->pesp_conn = pTcpServer; - } else if(isserver && type==ESPCONN_UDP && pUdpServer){ - temp = (lnet_userdata *)pUdpServer->reverse; - if(temp && temp->self_ref != LUA_NOREF){ - lua_pop(L,1); - return luaL_error(L, "only one udp server allowed"); - } - pesp_conn = nud->pesp_conn = pUdpServer; - } else { - pesp_conn = nud->pesp_conn = (struct espconn *)c_zalloc(sizeof(struct espconn)); - if(!pesp_conn) - return luaL_error(L, "not enough memory"); - - pesp_conn->proto.tcp = NULL; - pesp_conn->proto.udp = NULL; - pesp_conn->reverse = NULL; - if( type==ESPCONN_TCP ) - { - pesp_conn->proto.tcp = (esp_tcp *)c_zalloc(sizeof(esp_tcp)); - if(!pesp_conn->proto.tcp){ - c_free(pesp_conn); - pesp_conn = nud->pesp_conn = NULL; - return luaL_error(L, "not enough memory"); - } - NODE_DBG("TCP server/socket is set.\n"); - } - else if( type==ESPCONN_UDP ) - { - pesp_conn->proto.udp = (esp_udp *)c_zalloc(sizeof(esp_udp)); - if(!pesp_conn->proto.udp){ - c_free(pesp_conn); - pesp_conn = nud->pesp_conn = NULL; - return luaL_error(L, "not enough memory"); - } - NODE_DBG("UDP server/socket is set.\n"); - } - } - pesp_conn->type = type; - pesp_conn->state = ESPCONN_NONE; - // reverse is for the callback function - pesp_conn->reverse = nud; - - if(isserver && type==ESPCONN_TCP && pTcpServer==NULL){ - pTcpServer = pesp_conn; - } else if(isserver && type==ESPCONN_UDP && pUdpServer==NULL){ - pUdpServer = pesp_conn; - } + return net_connected_cb(nud, nud->tcp_pcb, ERR_OK); +} - gL = L; // global L for net module. +#pragma mark - Lua API - create - // if call back function is specified, call it with para userdata - // luaL_checkanyfunction(L, 2); - if (lua_type(L, stack) == LUA_TFUNCTION || lua_type(L, stack) == LUA_TLIGHTFUNCTION){ - lua_pushvalue(L, stack); // copy argument (func) to the top of stack - lua_pushvalue(L, -2); // copy the self_ref(userdata) to the top - lua_call(L, 1, 0); - } +extern int tls_socket_create( lua_State *L ); - return 1; +// Lua: net.createUDPSocket() +int net_createUDPSocket( lua_State *L ) { + net_create(L, TYPE_UDP_SOCKET); + return 1; } -// static int net_close( lua_State* L, const char* mt ); -// Lua: net.delete( socket/server ) -// call close() first -// server: disconnect server, unref everything -// socket: unref everything -static int net_delete( lua_State* L, const char* mt ) -{ - NODE_DBG("net_delete is called.\n"); - bool isserver = false; - if (mt!=NULL && c_strcmp(mt, "net.server")==0) - isserver = true; - else if (mt!=NULL && c_strcmp(mt, "net.socket")==0) - isserver = false; - else - { - NODE_DBG("wrong metatable for net_delete.\n"); - return 0; - } +// Lua: net.createServer(type, timeout) +int net_createServer( lua_State *L ) { + int type, timeout; - // net_close( L, mt ); // close it first + type = luaL_optlong(L, 1, TYPE_TCP); + timeout = luaL_optlong(L, 2, 30); - lnet_userdata *nud = (lnet_userdata *)luaL_checkudata(L, 1, mt); - luaL_argcheck(L, nud, 1, "Server/Socket expected"); - if(nud==NULL){ - NODE_DBG("userdata is nil.\n"); - return 0; - } - if(nud->pesp_conn){ // for client connected to tcp server, this should set NULL in disconnect cb - nud->pesp_conn->reverse = NULL; - if(!isserver) // socket is freed here - { - if(nud->pesp_conn->type == ESPCONN_UDP){ - if(nud->pesp_conn->proto.udp) - c_free(nud->pesp_conn->proto.udp); - nud->pesp_conn->proto.udp = NULL; - } else if (nud->pesp_conn->type == ESPCONN_TCP) { - if(nud->pesp_conn->proto.tcp) - c_free(nud->pesp_conn->proto.tcp); - nud->pesp_conn->proto.tcp = NULL; - } - c_free(nud->pesp_conn); - } - nud->pesp_conn = NULL; // for socket, it will free this when disconnected - } + if (type == TYPE_UDP) return net_createUDPSocket( L ); + if (type != TYPE_TCP) return luaL_error(L, "invalid type"); - // free (unref) callback ref - if(LUA_NOREF!=nud->cb_connect_ref){ - luaL_unref(L, LUA_REGISTRYINDEX, nud->cb_connect_ref); - nud->cb_connect_ref = LUA_NOREF; - } - if(LUA_NOREF!=nud->cb_reconnect_ref){ - luaL_unref(L, LUA_REGISTRYINDEX, nud->cb_reconnect_ref); - nud->cb_reconnect_ref = LUA_NOREF; - } - if(LUA_NOREF!=nud->cb_disconnect_ref){ - luaL_unref(L, LUA_REGISTRYINDEX, nud->cb_disconnect_ref); - nud->cb_disconnect_ref = LUA_NOREF; - } - if(LUA_NOREF!=nud->cb_receive_ref){ - luaL_unref(L, LUA_REGISTRYINDEX, nud->cb_receive_ref); - nud->cb_receive_ref = LUA_NOREF; - } - if(LUA_NOREF!=nud->cb_send_ref){ - luaL_unref(L, LUA_REGISTRYINDEX, nud->cb_send_ref); - nud->cb_send_ref = LUA_NOREF; - } - if(LUA_NOREF!=nud->cb_dns_found_ref){ - luaL_unref(L, LUA_REGISTRYINDEX, nud->cb_dns_found_ref); - nud->cb_dns_found_ref = LUA_NOREF; - } - lua_gc(gL, LUA_GCSTOP, 0); - if(LUA_NOREF!=nud->self_ref){ - luaL_unref(L, LUA_REGISTRYINDEX, nud->self_ref); - nud->self_ref = LUA_NOREF; - } - lua_gc(gL, LUA_GCRESTART, 0); - return 0; + net_create(L, TYPE_TCP_SERVER); + // TODO: timeout + return 1; } -static void socket_connect(struct espconn *pesp_conn) -{ - if(pesp_conn == NULL) - return; - lnet_userdata *nud = (lnet_userdata *)pesp_conn->reverse; - if(nud == NULL) - return; +// Lua: net.createConnection(type, secure) +int net_createConnection( lua_State *L ) { + int type, secure; - if( pesp_conn->type == ESPCONN_TCP ) - { - espconn_connect(pesp_conn); - } - else if (pesp_conn->type == ESPCONN_UDP) - { - espconn_create(pesp_conn); - } - NODE_DBG("socket_connect is called.\n"); -} + type = luaL_optlong(L, 1, TYPE_TCP); + secure = luaL_optlong(L, 2, 0); -static void socket_dns_found(const char *name, ip_addr_t *ipaddr, void *arg); -static int dns_reconn_count = 0; -static void socket_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) -{ - NODE_DBG("socket_dns_found is called.\n"); - struct espconn *pesp_conn = arg; - if(pesp_conn == NULL){ - NODE_DBG("pesp_conn null.\n"); - return; - } - lnet_userdata *nud = (lnet_userdata *)pesp_conn->reverse; - if(nud == NULL) - return; - if(gL == NULL) - return; - if(ipaddr == NULL) - { - dns_reconn_count++; - if( dns_reconn_count >= 5 ){ - NODE_ERR( "DNS Fail!\n" ); - lua_gc(gL, LUA_GCSTOP, 0); - if(nud->self_ref != LUA_NOREF){ - luaL_unref(gL, LUA_REGISTRYINDEX, nud->self_ref); - nud->self_ref = LUA_NOREF; // unref this, and the net.socket userdata will delete it self - } - lua_gc(gL, LUA_GCRESTART, 0); - return; - } - NODE_ERR( "DNS retry %d!\n", dns_reconn_count ); - host_ip.addr = 0; - espconn_gethostbyname(pesp_conn, name, &host_ip, socket_dns_found); - return; - } - - // ipaddr->addr is a uint32_t ip - if(ipaddr->addr != 0) - { - dns_reconn_count = 0; - if( pesp_conn->type == ESPCONN_TCP ) - { - c_memcpy(pesp_conn->proto.tcp->remote_ip, &(ipaddr->addr), 4); - NODE_DBG("TCP ip is set: "); - NODE_DBG(IPSTR, IP2STR(&(ipaddr->addr))); - NODE_DBG("\n"); - } - else if (pesp_conn->type == ESPCONN_UDP) - { - c_memcpy(pesp_conn->proto.udp->remote_ip, &(ipaddr->addr), 4); - NODE_DBG("UDP ip is set: "); - NODE_DBG(IPSTR, IP2STR(&(ipaddr->addr))); - NODE_DBG("\n"); - } - socket_connect(pesp_conn); + if (type == TYPE_UDP) return net_createUDPSocket( L ); + if (type != TYPE_TCP) return luaL_error(L, "invalid type"); + if (secure) { +#ifdef CLIENT_SSL_ENABLE + return tls_socket_create( L ); +#else + return luaL_error(L, "secure connections not enabled"); +#endif } + net_create(L, TYPE_TCP_CLIENT); + return 1; } -// Lua: server:listen( port, ip, function(con) ) -// Lua: socket:connect( port, ip, function(con) ) -static int net_start( lua_State* L, const char* mt ) -{ - NODE_DBG("net_start is called.\n"); - struct espconn *pesp_conn = NULL; - lnet_userdata *nud; - unsigned port; - size_t il; - bool isserver = false; - ip_addr_t ipaddr; - const char *domain; - uint8_t stack = 1; - - if (mt!=NULL && c_strcmp(mt, "net.server")==0) - isserver = true; - else if (mt!=NULL && c_strcmp(mt, "net.socket")==0) - isserver = false; - else - { - NODE_DBG("wrong metatable for net_start.\n"); - return 0; - } - nud = (lnet_userdata *)luaL_checkudata(L, stack, mt); - luaL_argcheck(L, nud, stack, "Server/Socket expected"); - stack++; - - if(nud==NULL){ - NODE_DBG("userdata is nil.\n"); - return 0; - } +#pragma mark - Get & check userdata - if(nud->pesp_conn == NULL){ - NODE_DBG("nud->pesp_conn is NULL.\n"); - return 0; +lnet_userdata *net_get_udata_s( lua_State *L, int stack ) { + if (!lua_isuserdata(L, stack)) return NULL; + lnet_userdata *ud = (lnet_userdata *)lua_touserdata(L, stack); + switch (ud->type) { + case TYPE_TCP_CLIENT: + case TYPE_TCP_SERVER: + case TYPE_UDP_SOCKET: + break; + default: return NULL; + } + const char *mt = NET_TABLES[ud->type]; + ud = luaL_checkudata(L, stack, mt); + return ud; +} +#define net_get_udata(L) net_get_udata_s(L, 1) + +#pragma mark - Lua API + +// Lua: server:listen(port, addr, function(c)), socket:listen(port, addr) +int net_listen( lua_State *L ) { + lnet_userdata *ud = net_get_udata(L); + if (!ud || ud->type == TYPE_TCP_CLIENT) + return luaL_error(L, "invalid user data"); + if (ud->pcb) + return luaL_error(L, "already listening"); + int stack = 2; + uint16_t port = 0; + const char *domain = "0.0.0.0"; + if (lua_isnumber(L, stack)) + port = lua_tointeger(L, stack++); + if (lua_isstring(L, stack)) { + size_t dl = 0; + domain = luaL_checklstring(L, stack++, &dl); } - pesp_conn = nud->pesp_conn; - port = luaL_checkinteger( L, stack ); - stack++; - if( pesp_conn->type == ESPCONN_TCP ) - { - if(isserver) - pesp_conn->proto.tcp->local_port = port; - else{ - pesp_conn->proto.tcp->remote_port = port; - pesp_conn->proto.tcp->local_port = espconn_port(); + ip_addr_t addr; + if (!ipaddr_aton(domain, &addr)) + return luaL_error(L, "invalid IP address"); + if (ud->type == TYPE_TCP_SERVER) { + if (lua_isfunction(L, stack) || lua_islightfunction(L, stack)) { + lua_pushvalue(L, stack++); + luaL_unref(L, LUA_REGISTRYINDEX, ud->server.cb_accept_ref); + ud->server.cb_accept_ref = luaL_ref(L, LUA_REGISTRYINDEX); + } else { + return luaL_error(L, "need callback"); } - NODE_DBG("TCP port is set: %d.\n", port); } - else if (pesp_conn->type == ESPCONN_UDP) - { - if(isserver) - pesp_conn->proto.udp->local_port = port; - else{ - pesp_conn->proto.udp->remote_port = port; - pesp_conn->proto.udp->local_port = espconn_port(); - } - NODE_DBG("UDP port is set: %d.\n", port); + err_t err = ERR_OK; + switch (ud->type) { + case TYPE_TCP_SERVER: + ud->tcp_pcb = tcp_new(); + if (!ud->tcp_pcb) + return luaL_error(L, "cannot allocate PCB"); + err = tcp_bind(ud->tcp_pcb, &addr, port); + if (err == ERR_OK) { + tcp_arg(ud->tcp_pcb, ud); + struct tcp_pcb *pcb = tcp_listen(ud->tcp_pcb); + if (!pcb) { + err = ERR_MEM; + } else { + ud->tcp_pcb = pcb; + tcp_accept(ud->tcp_pcb, net_accept_cb); + } + } + break; + case TYPE_UDP_SOCKET: + ud->udp_pcb = udp_new(); + if (!ud->udp_pcb) + return luaL_error(L, "cannot allocate PCB"); + udp_recv(ud->udp_pcb, net_udp_recv_cb, ud); + err = udp_bind(ud->udp_pcb, &addr, port); + break; } - - if( lua_isstring(L,stack) ) // deal with the domain string - { - domain = luaL_checklstring( L, stack, &il ); - stack++; - if (domain == NULL) - { - if(isserver) - domain = "0.0.0.0"; - else - domain = "127.0.0.1"; - } - ipaddr.addr = ipaddr_addr(domain); - if( pesp_conn->type == ESPCONN_TCP ) - { - if(isserver) - c_memcpy(pesp_conn->proto.tcp->local_ip, &ipaddr.addr, 4); - else - c_memcpy(pesp_conn->proto.tcp->remote_ip, &ipaddr.addr, 4); - NODE_DBG("TCP ip is set: "); - NODE_DBG(IPSTR, IP2STR(&ipaddr.addr)); - NODE_DBG("\n"); - } - else if (pesp_conn->type == ESPCONN_UDP) - { - if(isserver) - c_memcpy(pesp_conn->proto.udp->local_ip, &ipaddr.addr, 4); - else - c_memcpy(pesp_conn->proto.udp->remote_ip, &ipaddr.addr, 4); - NODE_DBG("UDP ip is set: "); - NODE_DBG(IPSTR, IP2STR(&ipaddr.addr)); - NODE_DBG("\n"); + if (err != ERR_OK) { + switch (ud->type) { + case TYPE_TCP_SERVER: + tcp_close(ud->tcp_pcb); + ud->tcp_pcb = NULL; + break; + case TYPE_UDP_SOCKET: + udp_remove(ud->udp_pcb); + ud->udp_pcb = NULL; + break; } + return luaL_lwip_checkerr(err, L); } + if (ud->self_ref == LUA_NOREF) { + lua_pushvalue(L, 1); + ud->self_ref = luaL_ref(L, LUA_REGISTRYINDEX); + } + return 0; +} - // call back function when a connection is obtained, tcp only - if ( pesp_conn->type == ESPCONN_TCP ) { - if (lua_type(L, stack) == LUA_TFUNCTION || lua_type(L, stack) == LUA_TLIGHTFUNCTION){ - lua_pushvalue(L, stack); // copy argument (func) to the top of stack - if(isserver) // for tcp server connected callback - { - if(tcpserver_cb_connect_ref != LUA_NOREF) - luaL_unref(L, LUA_REGISTRYINDEX, tcpserver_cb_connect_ref); - tcpserver_cb_connect_ref = luaL_ref(L, LUA_REGISTRYINDEX); - } - else - { - if(nud->cb_connect_ref != LUA_NOREF) - luaL_unref(L, LUA_REGISTRYINDEX, nud->cb_connect_ref); - nud->cb_connect_ref = luaL_ref(L, LUA_REGISTRYINDEX); - } +// Lua: client:connect(port, addr) +int net_connect( lua_State *L ) { + lnet_userdata *ud = net_get_udata(L); + if (!ud || ud->type != TYPE_TCP_CLIENT) + return luaL_error(L, "invalid user data"); + if (ud->pcb) + return luaL_error(L, "already connected"); + uint16_t port = luaL_checkinteger(L, 2); + if (port == 0) + return luaL_error(L, "specify port"); + const char *domain = "127.0.0.1"; + if (lua_isstring(L, 3)) { + size_t dl = 0; + domain = luaL_checklstring(L, 3, &dl); + } + ud->tcp_pcb = tcp_new(); + if (!ud->tcp_pcb) + return luaL_error(L, "cannot allocate PCB"); + tcp_arg(ud->tcp_pcb, ud); + tcp_err(ud->tcp_pcb, net_err_cb); + tcp_recv(ud->tcp_pcb, net_tcp_recv_cb); + tcp_sent(ud->tcp_pcb, net_sent_cb); + ud->tcp_pcb->remote_port = port; + ip_addr_t addr; + ud->client.wait_dns ++; + int unref = 0; + if (ud->self_ref == LUA_NOREF) { + unref = 1; + lua_pushvalue(L, 1); + ud->self_ref = luaL_ref(L, LUA_REGISTRYINDEX); + } + err_t err = dns_gethostbyname(domain, &addr, net_dns_cb, ud); + if (err == ERR_OK) { + net_dns_cb(domain, &addr, ud); + } else if (err != ERR_INPROGRESS) { + ud->client.wait_dns --; + if (unref) { + luaL_unref(L, LUA_REGISTRYINDEX, ud->self_ref); + ud->self_ref = LUA_NOREF; } + tcp_abort(ud->tcp_pcb); + ud->tcp_pcb = NULL; + return luaL_lwip_checkerr(err, L); } + return 0; +} - if(!isserver || pesp_conn->type == ESPCONN_UDP){ // self_ref is only needed by socket userdata, or udp server - lua_pushvalue(L, 1); // copy to the top of stack - if(nud->self_ref != LUA_NOREF) - luaL_unref(L, LUA_REGISTRYINDEX, nud->self_ref); - nud->self_ref = luaL_ref(L, LUA_REGISTRYINDEX); +// Lua: client/socket:on(name, callback) +int net_on( lua_State *L ) { + lnet_userdata *ud = net_get_udata(L); + if (!ud || ud->type == TYPE_TCP_SERVER) + return luaL_error(L, "invalid user data"); + int *refptr = NULL; + const char *name = luaL_checkstring(L, 2); + if (!name) return luaL_error(L, "need callback name"); + switch (ud->type) { + case TYPE_TCP_CLIENT: + if (strcmp("connection",name)==0) + { refptr = &ud->client.cb_connect_ref; break; } + if (strcmp("disconnection",name)==0) + { refptr = &ud->client.cb_disconnect_ref; break; } + if (strcmp("reconnection",name)==0) + { refptr = &ud->client.cb_reconnect_ref; break; } + case TYPE_UDP_SOCKET: + if (strcmp("dns",name)==0) + { refptr = &ud->client.cb_dns_ref; break; } + if (strcmp("receive",name)==0) + { refptr = &ud->client.cb_receive_ref; break; } + if (strcmp("sent",name)==0) + { refptr = &ud->client.cb_sent_ref; break; } + break; + default: return luaL_error(L, "invalid user data"); + } + if (refptr == NULL) + return luaL_error(L, "invalid callback name"); + if (lua_isfunction(L, 3) || lua_islightfunction(L, 3)) { + lua_pushvalue(L, 3); + luaL_unref(L, LUA_REGISTRYINDEX, *refptr); + *refptr = luaL_ref(L, LUA_REGISTRYINDEX); + } else if (lua_isnil(L, 3)) { + luaL_unref(L, LUA_REGISTRYINDEX, *refptr); + *refptr = LUA_NOREF; + } else { + return luaL_error(L, "invalid callback function"); } + return 0; +} - if( pesp_conn->type == ESPCONN_TCP ) - { - if(isserver){ // no secure server support for now - espconn_regist_connectcb(pesp_conn, net_server_connected); - espconn_accept(pesp_conn); // if it's a server, no need to dns. - espconn_regist_time(pesp_conn, tcp_server_timeover, 0); +// Lua: client:send(data, function(c)), socket:send(port, ip, data, function(s)) +int net_send( lua_State *L ) { + lnet_userdata *ud = net_get_udata(L); + if (!ud || ud->type == TYPE_TCP_SERVER) + return luaL_error(L, "invalid user data"); + ip_addr_t addr; + uint16_t port; + const char *data; + size_t datalen = 0; + int stack = 2; + if (ud->type == TYPE_UDP_SOCKET) { + size_t dl = 0; + port = luaL_checkinteger(L, stack++); + if (port == 0) return luaL_error(L, "need port"); + const char *domain = luaL_checklstring(L, stack++, &dl); + if (!domain) return luaL_error(L, "need IP address"); + if (!ipaddr_aton(domain, &addr)) return luaL_error(L, "invalid IP address"); + } + data = luaL_checklstring(L, stack++, &datalen); + if (!data || datalen == 0) return luaL_error(L, "no data to send"); + if (lua_isfunction(L, stack) || lua_islightfunction(L, stack)) { + lua_pushvalue(L, stack++); + luaL_unref(L, LUA_REGISTRYINDEX, ud->client.cb_sent_ref); + ud->client.cb_sent_ref = luaL_ref(L, LUA_REGISTRYINDEX); + } + if (ud->type == TYPE_UDP_SOCKET && !ud->pcb) { + ud->udp_pcb = udp_new(); + if (!ud->udp_pcb) + return luaL_error(L, "cannot allocate PCB"); + udp_recv(ud->udp_pcb, net_udp_recv_cb, ud); + addr.addr = 0; + err_t err = udp_bind(ud->udp_pcb, &addr, 0); + if (err != ERR_OK) { + udp_remove(ud->udp_pcb); + ud->udp_pcb = NULL; + return luaL_lwip_checkerr(err, L); } - else{ - espconn_regist_connectcb(pesp_conn, net_socket_connected); - espconn_regist_reconcb(pesp_conn, net_socket_reconnected); - { - if(pesp_conn->proto.tcp->remote_port || pesp_conn->proto.tcp->local_port) - espconn_disconnect(pesp_conn); - // espconn_connect(pesp_conn); - } + if (ud->self_ref == LUA_NOREF) { + lua_pushvalue(L, 1); + ud->self_ref = luaL_ref(L, LUA_REGISTRYINDEX); } } - else if (pesp_conn->type == ESPCONN_UDP) - { - espconn_regist_recvcb(pesp_conn, net_socket_received); - espconn_regist_sentcb(pesp_conn, net_socket_sent); - if(pesp_conn->proto.tcp->remote_port || pesp_conn->proto.tcp->local_port) - espconn_delete(pesp_conn); - if(isserver) - espconn_create(pesp_conn); // if it's a server, no need to dns. - } - - if(!isserver){ - if((ipaddr.addr == IPADDR_NONE) && (c_memcmp(domain,"255.255.255.255",16) != 0)) - { - host_ip.addr = 0; - dns_reconn_count = 0; - if(ESPCONN_OK == espconn_gethostbyname(pesp_conn, domain, &host_ip, socket_dns_found)){ - socket_dns_found(domain, &host_ip, pesp_conn); // ip is returned in host_ip. - } - } - else - { - socket_connect(pesp_conn); + if (!ud->pcb || ud->self_ref == LUA_NOREF) + return luaL_error(L, "not connected"); + err_t err; + if (ud->type == TYPE_UDP_SOCKET) { + struct pbuf *pb = pbuf_alloc(PBUF_TRANSPORT, datalen, PBUF_RAM); + pbuf_take(pb, data, datalen); + err = udp_sendto(ud->udp_pcb, pb, &addr, port); + pbuf_free(pb); + if (ud->client.cb_sent_ref != LUA_NOREF) { + lua_rawgeti(L, LUA_REGISTRYINDEX, ud->client.cb_sent_ref); + lua_rawgeti(L, LUA_REGISTRYINDEX, ud->self_ref); + lua_call(L, 1, 0); } + } else if (ud->type == TYPE_TCP_CLIENT) { + err = tcp_write(ud->tcp_pcb, data, datalen, TCP_WRITE_FLAG_COPY); } - return 0; + return 0; } -// Lua: server/socket:close() -// server disconnect everything, unref everything -// client disconnect and unref itself -static int net_close( lua_State* L, const char* mt ) -{ - NODE_DBG("net_close is called.\n"); - bool isserver = false; - int i = 0; - lnet_userdata *nud = NULL, *skt = NULL; - - nud = (lnet_userdata *)luaL_checkudata(L, 1, mt); - luaL_argcheck(L, nud, 1, "Server/Socket expected"); - if(nud == NULL) - return 0; - - if(nud->pesp_conn == NULL) - return 0; +// Lua: client:hold() +int net_hold( lua_State *L ) { + lnet_userdata *ud = net_get_udata(L); + if (!ud || ud->type != TYPE_TCP_CLIENT) + return luaL_error(L, "invalid user data"); + ud->client.hold = 1; + return 0; +} - if (mt!=NULL && c_strcmp(mt, "net.server")==0) - isserver = true; - else if (mt!=NULL && c_strcmp(mt, "net.socket")==0) - isserver = false; - else - { - NODE_DBG("wrong metatable for net_close.\n"); - return 0; - } +// Lua: client:unhold() +int net_unhold( lua_State *L ) { + lnet_userdata *ud = net_get_udata(L); + if (!ud || ud->type != TYPE_TCP_CLIENT) + return luaL_error(L, "invalid user data"); + ud->client.hold = 0; + return 0; +} - if(isserver && nud->pesp_conn->type == ESPCONN_TCP && tcpserver_cb_connect_ref != LUA_NOREF){ - luaL_unref(L, LUA_REGISTRYINDEX, tcpserver_cb_connect_ref); - tcpserver_cb_connect_ref = LUA_NOREF; +// Lua: client/socket:dns(domain, callback(socket, addr)) +int net_dns( lua_State *L ) { + lnet_userdata *ud = net_get_udata(L); + if (!ud || ud->type == TYPE_TCP_SERVER) + return luaL_error(L, "invalid user data"); + size_t dl = 0; + const char *domain = luaL_checklstring(L, 2, &dl); + if (!domain) + return luaL_error(L, "no domain specified"); + if (lua_isfunction(L, 3) || lua_islightfunction(L, 3)) { + luaL_unref(L, LUA_REGISTRYINDEX, ud->client.cb_dns_ref); + lua_pushvalue(L, 3); + ud->client.cb_dns_ref = luaL_ref(L, LUA_REGISTRYINDEX); + } + if (ud->client.cb_dns_ref == LUA_NOREF) + return luaL_error(L, "no callback specified"); + ud->client.wait_dns ++; + int unref = 0; + if (ud->self_ref == LUA_NOREF) { + unref = 1; + lua_pushvalue(L, 1); + ud->self_ref = luaL_ref(L, LUA_REGISTRYINDEX); } - - int n = lua_gettop(L); - skt = nud; - - do{ - if(isserver && skt == NULL){ - if(socket[i] != LUA_NOREF){ // there is client socket exists - lua_rawgeti(L, LUA_REGISTRYINDEX, socket[i]); // get the referenced user_data to stack top - i++; - if(lua_isuserdata(L,-1)){ - skt = lua_touserdata(L,-1); - } else { - lua_pop(L, 1); - continue; - } - }else{ - // skip LUA_NOREF - i++; - continue; - } - } - - if(skt==NULL){ - NODE_DBG("userdata is nil.\n"); - continue; - } - - if(skt->pesp_conn) // disconnect the connection - { - if(skt->pesp_conn->type == ESPCONN_TCP) - { - { - if(skt->pesp_conn->proto.tcp->remote_port || skt->pesp_conn->proto.tcp->local_port) - espconn_disconnect(skt->pesp_conn); - } - }else if(skt->pesp_conn->type == ESPCONN_UDP) - { - if(skt->pesp_conn->proto.tcp->remote_port || skt->pesp_conn->proto.tcp->local_port) - espconn_delete(skt->pesp_conn); - - // a udp server/socket unref it self here. not in disconnect. - if(LUA_NOREF!=skt->self_ref){ // for a udp self_ref is NOREF - luaL_unref(L, LUA_REGISTRYINDEX, skt->self_ref); - skt->self_ref = LUA_NOREF; // for a socket, now only var in lua is ref to the userdata - } - } + ip_addr_t addr; + err_t err = dns_gethostbyname(domain, &addr, net_dns_cb, ud); + if (err == ERR_OK) { + net_dns_cb(domain, &addr, ud); + } else if (err != ERR_INPROGRESS) { + ud->client.wait_dns --; + if (unref) { + luaL_unref(L, LUA_REGISTRYINDEX, ud->self_ref); + ud->self_ref = LUA_NOREF; } - lua_settop(L, n); // reset the stack top - skt = NULL; - } while( isserver && itype != TYPE_TCP_CLIENT) + return luaL_error(L, "invalid user data"); + if (!ud->pcb) { + lua_pushnil(L); + lua_pushnil(L); + return 2; } - - const char *method = luaL_checklstring( L, 2, &sl ); - if (method == NULL) - return luaL_error( L, "wrong arg type" ); - - luaL_checkanyfunction(L, 3); - lua_pushvalue(L, 3); // copy argument (func) to the top of stack - - if(!isserver && nud->pesp_conn->type == ESPCONN_TCP && sl == 10 && c_strcmp(method, "connection") == 0){ - if(nud->cb_connect_ref != LUA_NOREF) - luaL_unref(L, LUA_REGISTRYINDEX, nud->cb_connect_ref); - nud->cb_connect_ref = luaL_ref(L, LUA_REGISTRYINDEX); - }else if(!isserver && nud->pesp_conn->type == ESPCONN_TCP && sl == 12 && c_strcmp(method, "reconnection") == 0){ - if(nud->cb_reconnect_ref != LUA_NOREF) - luaL_unref(L, LUA_REGISTRYINDEX, nud->cb_reconnect_ref); - nud->cb_reconnect_ref = luaL_ref(L, LUA_REGISTRYINDEX); - }else if(!isserver && nud->pesp_conn->type == ESPCONN_TCP && sl == 13 && c_strcmp(method, "disconnection") == 0){ - if(nud->cb_disconnect_ref != LUA_NOREF) - luaL_unref(L, LUA_REGISTRYINDEX, nud->cb_disconnect_ref); - nud->cb_disconnect_ref = luaL_ref(L, LUA_REGISTRYINDEX); - }else if((!isserver || nud->pesp_conn->type == ESPCONN_UDP) && sl == 7 && c_strcmp(method, "receive") == 0){ - if(nud->cb_receive_ref != LUA_NOREF) - luaL_unref(L, LUA_REGISTRYINDEX, nud->cb_receive_ref); - nud->cb_receive_ref = luaL_ref(L, LUA_REGISTRYINDEX); - }else if((!isserver || nud->pesp_conn->type == ESPCONN_UDP) && sl == 4 && c_strcmp(method, "sent") == 0){ - if(nud->cb_send_ref != LUA_NOREF) - luaL_unref(L, LUA_REGISTRYINDEX, nud->cb_send_ref); - nud->cb_send_ref = luaL_ref(L, LUA_REGISTRYINDEX); - }else if(!isserver && nud->pesp_conn->type == ESPCONN_TCP && sl == 3 && c_strcmp(method, "dns") == 0){ - if(nud->cb_dns_found_ref != LUA_NOREF) - luaL_unref(L, LUA_REGISTRYINDEX, nud->cb_dns_found_ref); - nud->cb_dns_found_ref = luaL_ref(L, LUA_REGISTRYINDEX); - }else{ - lua_pop(L, 1); - return luaL_error( L, "method not supported" ); + uint16_t port = ud->tcp_pcb->remote_port; + ip_addr_t addr = ud->tcp_pcb->remote_ip; + if (port == 0) { + lua_pushnil(L); + lua_pushnil(L); + return 2; } - - return 0; + char addr_str[16]; + bzero(addr_str, 16); + ets_sprintf(addr_str, IPSTR, IP2STR(&addr.addr)); + lua_pushinteger(L, port); + lua_pushstring(L, addr_str); + return 2; } -// Lua: server/socket:send( string, function(sent) ) -static int net_send( lua_State* L, const char* mt ) -{ - // NODE_DBG("net_send is called.\n"); - bool isserver = false; - struct espconn *pesp_conn = NULL; - lnet_userdata *nud; - size_t l; - - nud = (lnet_userdata *)luaL_checkudata(L, 1, mt); - luaL_argcheck(L, nud, 1, "Server/Socket expected"); - if(nud==NULL){ - NODE_DBG("userdata is nil.\n"); - return 0; - } - - if(nud->pesp_conn == NULL){ - NODE_DBG("nud->pesp_conn is NULL.\n"); - return 0; +// Lua: client/server/socket:getaddr() +int net_getaddr( lua_State *L ) { + lnet_userdata *ud = net_get_udata(L); + if (!ud) return luaL_error(L, "invalid user data"); + if (!ud->pcb) { + lua_pushnil(L); + lua_pushnil(L); + return 2; } - pesp_conn = nud->pesp_conn; - - if (mt!=NULL && c_strcmp(mt, "net.server")==0) - isserver = true; - else if (mt!=NULL && c_strcmp(mt, "net.socket")==0) - isserver = false; - else - { - NODE_DBG("wrong metatable for net_send.\n"); - return 0; + uint16_t port; + ip_addr_t addr; + switch (ud->type) { + case TYPE_TCP_CLIENT: + case TYPE_TCP_SERVER: + addr = ud->tcp_pcb->local_ip; + port = ud->tcp_pcb->local_port; + break; + case TYPE_UDP_SOCKET: + addr = ud->udp_pcb->local_ip; + port = ud->udp_pcb->local_port; + break; } - - if(isserver && nud->pesp_conn->type == ESPCONN_TCP){ - return luaL_error( L, "tcp server send not supported" ); + if (port == 0) { + lua_pushnil(L); + lua_pushnil(L); + return 2; } + char addr_str[16]; + bzero(addr_str, 16); + ets_sprintf(addr_str, IPSTR, IP2STR(&addr.addr)); + lua_pushinteger(L, port); + lua_pushstring(L, addr_str); + return 2; +} - const char *payload = luaL_checklstring( L, 2, &l ); - if (l>1460 || payload == NULL) - return luaL_error( L, "need <1460 payload" ); - - if (lua_type(L, 3) == LUA_TFUNCTION || lua_type(L, 3) == LUA_TLIGHTFUNCTION){ - lua_pushvalue(L, 3); // copy argument (func) to the top of stack - if(nud->cb_send_ref != LUA_NOREF) - luaL_unref(L, LUA_REGISTRYINDEX, nud->cb_send_ref); - nud->cb_send_ref = luaL_ref(L, LUA_REGISTRYINDEX); +// Lua: client/server/socket:close() +int net_close( lua_State *L ) { + lnet_userdata *ud = net_get_udata(L); + if (!ud) return luaL_error(L, "invalid user data"); + if (ud->pcb) { + switch (ud->type) { + case TYPE_TCP_CLIENT: + if (ERR_OK != tcp_close(ud->tcp_pcb)) { + tcp_arg(ud->tcp_pcb, NULL); + tcp_abort(ud->tcp_pcb); + } + ud->tcp_pcb = NULL; + break; + case TYPE_TCP_SERVER: + tcp_close(ud->tcp_pcb); + ud->tcp_pcb = NULL; + break; + case TYPE_UDP_SOCKET: + udp_remove(ud->udp_pcb); + ud->udp_pcb = NULL; + break; + } + } else { + return luaL_error(L, "not connected"); } - // SDK 1.4.0 changed behaviour, for UDP server need to look up remote ip/port - if (isserver && pesp_conn->type == ESPCONN_UDP) - { - remot_info *pr = 0; - if (espconn_get_connection_info (pesp_conn, &pr, 0) != ESPCONN_OK) - return luaL_error (L, "remote ip/port unavailable"); - pesp_conn->proto.udp->remote_port = pr->remote_port; - os_memmove (pesp_conn->proto.udp->remote_ip, pr->remote_ip, 4); - // The remot_info apparently should *not* be os_free()d, fyi + if (ud->type == TYPE_TCP_SERVER || + (ud->pcb == NULL && ud->client.wait_dns == 0)) { + lua_gc(L, LUA_GCSTOP, 0); + luaL_unref(L, LUA_REGISTRYINDEX, ud->self_ref); + ud->self_ref = LUA_NOREF; + lua_gc(L, LUA_GCRESTART, 0); } - espconn_sent(pesp_conn, (unsigned char *)payload, l); - - return 0; + return 0; } -// Lua: socket:dns( string, function(socket, ip) ) -static int net_dns( lua_State* L, const char* mt ) -{ - NODE_DBG("net_dns is called.\n"); - bool isserver = false; - struct espconn *pesp_conn = NULL; - lnet_userdata *nud; - size_t l; - - nud = (lnet_userdata *)luaL_checkudata(L, 1, mt); - luaL_argcheck(L, nud, 1, "Server/Socket expected"); - if(nud==NULL){ - NODE_DBG("userdata is nil.\n"); - return 0; - } - - if (mt!=NULL && c_strcmp(mt, "net.server")==0) - isserver = true; - else if (mt!=NULL && c_strcmp(mt, "net.socket")==0) - isserver = false; - else - { - NODE_DBG("wrong metatable for net_send.\n"); - return 0; +int net_delete( lua_State *L ) { + lnet_userdata *ud = net_get_udata(L); + if (!ud) return luaL_error(L, "no user data"); + if (ud->pcb) { + switch (ud->type) { + case TYPE_TCP_CLIENT: + tcp_arg(ud->tcp_pcb, NULL); + tcp_abort(ud->tcp_pcb); + ud->tcp_pcb = NULL; + break; + case TYPE_TCP_SERVER: + tcp_close(ud->tcp_pcb); + ud->tcp_pcb = NULL; + break; + case TYPE_UDP_SOCKET: + udp_remove(ud->udp_pcb); + ud->udp_pcb = NULL; + break; + } } - - if(nud->pesp_conn == NULL){ - NODE_DBG("nud->pesp_conn is NULL.\n"); - return 0; + switch (ud->type) { + case TYPE_TCP_CLIENT: + luaL_unref(L, LUA_REGISTRYINDEX, ud->client.cb_connect_ref); + ud->client.cb_connect_ref = LUA_NOREF; + luaL_unref(L, LUA_REGISTRYINDEX, ud->client.cb_disconnect_ref); + ud->client.cb_disconnect_ref = LUA_NOREF; + luaL_unref(L, LUA_REGISTRYINDEX, ud->client.cb_reconnect_ref); + ud->client.cb_reconnect_ref = LUA_NOREF; + case TYPE_UDP_SOCKET: + luaL_unref(L, LUA_REGISTRYINDEX, ud->client.cb_dns_ref); + ud->client.cb_dns_ref = LUA_NOREF; + luaL_unref(L, LUA_REGISTRYINDEX, ud->client.cb_receive_ref); + ud->client.cb_receive_ref = LUA_NOREF; + luaL_unref(L, LUA_REGISTRYINDEX, ud->client.cb_sent_ref); + ud->client.cb_sent_ref = LUA_NOREF; + break; + case TYPE_TCP_SERVER: + luaL_unref(L, LUA_REGISTRYINDEX, ud->server.cb_accept_ref); + ud->server.cb_accept_ref = LUA_NOREF; + break; } - pesp_conn = nud->pesp_conn; + lua_gc(L, LUA_GCSTOP, 0); + luaL_unref(L, LUA_REGISTRYINDEX, ud->self_ref); + ud->self_ref = LUA_NOREF; + lua_gc(L, LUA_GCRESTART, 0); + return 0; +} - if(!isserver || pesp_conn->type == ESPCONN_UDP){ // self_ref is only needed by socket userdata, or udp server - lua_pushvalue(L, 1); // copy to the top of stack - if(nud->self_ref != LUA_NOREF) - luaL_unref(L, LUA_REGISTRYINDEX, nud->self_ref); - nud->self_ref = luaL_ref(L, LUA_REGISTRYINDEX); - } +#pragma mark - Multicast - const char *domain = luaL_checklstring( L, 2, &l ); - if (l>128 || domain == NULL) - return luaL_error( L, "need <128 domain" ); +static int net_multicastJoinLeave( lua_State *L, int join) { + size_t il; + ip_addr_t multicast_addr; + ip_addr_t if_addr; + const char *multicast_ip; + const char *if_ip; - if (lua_type(L, 3) == LUA_TFUNCTION || lua_type(L, 3) == LUA_TLIGHTFUNCTION){ - lua_pushvalue(L, 3); // copy argument (func) to the top of stack - if(nud->cb_dns_found_ref != LUA_NOREF) - luaL_unref(L, LUA_REGISTRYINDEX, nud->cb_dns_found_ref); - nud->cb_dns_found_ref = luaL_ref(L, LUA_REGISTRYINDEX); - } + NODE_DBG("net_multicastJoin is called.\n"); + if(! lua_isstring(L,1) ) return luaL_error( L, "wrong arg type" ); + if_ip = luaL_checklstring( L, 1, &il ); + if (if_ip != NULL) + if ( if_ip[0] == '\0' || stricmp(if_ip,"any") == 0) + { + if_ip = "0.0.0.0"; + il = 7; + } + if (if_ip == NULL || il > 15 || il < 7) return luaL_error( L, "invalid if ip" ); + if_addr.addr = ipaddr_addr(if_ip); - host_ip.addr = 0; - if(ESPCONN_OK == espconn_gethostbyname(pesp_conn, domain, &host_ip, net_dns_found)) - net_dns_found(domain, &host_ip, pesp_conn); // ip is returned in host_ip. + if(! lua_isstring(L,2) ) return luaL_error( L, "wrong arg type" ); + multicast_ip = luaL_checklstring( L, 2, &il ); + if (multicast_ip == NULL || il > 15 || il < 7) return luaL_error( L, "invalid multicast ip" ); + multicast_addr.addr = ipaddr_addr(multicast_ip); + if (join) + { + igmp_joingroup(&if_addr, &multicast_addr); + } + else + { + igmp_leavegroup(&if_addr, &multicast_addr); + } + return 0; +} +// Lua: net.multicastJoin(ifip, multicastip) +// if ifip "" or "any" all interfaces are affected +static int net_multicastJoin( lua_State* L ) { + return net_multicastJoinLeave(L,1); +} - return 0; +// Lua: net.multicastLeave(ifip, multicastip) +// if ifip "" or "any" all interfaces are affected +static int net_multicastLeave( lua_State* L ) { + return net_multicastJoinLeave(L,0); } -static int luaL_lwip_checkerr(err_t res, lua_State *L); +#pragma mark - DNS static void net_dns_static_cb(const char *name, ip_addr_t *ipaddr, void *callback_arg) { ip_addr_t addr; @@ -1082,221 +862,8 @@ static int net_dns_static( lua_State* L ) { return 0; } -// Lua: s = net.createServer(type, function(server)) -static int net_createServer( lua_State* L ) -{ - const char *mt = "net.server"; - return net_create(L, mt); -} - -// Lua: server:delete() -static int net_server_delete( lua_State* L ) -{ - const char *mt = "net.server"; - return net_delete(L, mt); -} - -// Lua: server:listen( port, ip ) -static int net_server_listen( lua_State* L ) -{ - const char *mt = "net.server"; - return net_start(L, mt); -} - -// Lua: server:close() -static int net_server_close( lua_State* L ) -{ - const char *mt = "net.server"; - return net_close(L, mt); -} - -// Lua: udpserver:on( "method", function(udpserver) ) -static int net_udpserver_on( lua_State* L ) -{ - const char *mt = "net.server"; - return net_on(L, mt); -} - -// Lua: udpserver:send(string, function() ) -static int net_udpserver_send( lua_State* L ) -{ - const char *mt = "net.server"; - return net_send(L, mt);; -} - -// Lua: s = net.createConnection(type, function(conn)) -static int net_createConnection( lua_State* L ) -{ - const char *mt = "net.socket"; - return net_create(L, mt); -} - -// Lua: socket:delete() -static int net_socket_delete( lua_State* L ) -{ - const char *mt = "net.socket"; - return net_delete(L, mt); -} - -// Lua: socket:connect( port, ip ) -static int net_socket_connect( lua_State* L ) -{ - const char *mt = "net.socket"; - return net_start(L, mt); -} - -// Lua: socket:close() -static int net_socket_close( lua_State* L ) -{ - const char *mt = "net.socket"; - return net_close(L, mt); -} - -// Lua: socket:on( "method", function(socket) ) -static int net_socket_on( lua_State* L ) -{ - const char *mt = "net.socket"; - return net_on(L, mt); -} - -// Lua: socket:send( string, function() ) -static int net_socket_send( lua_State* L ) -{ - const char *mt = "net.socket"; - return net_send(L, mt); -} - -static int net_socket_hold( lua_State* L ) -{ - const char *mt = "net.socket"; - struct espconn *pesp_conn = NULL; - lnet_userdata *nud; - size_t l; - - nud = (lnet_userdata *)luaL_checkudata(L, 1, mt); - luaL_argcheck(L, nud, 1, "Server/Socket expected"); - if(nud==NULL){ - NODE_DBG("userdata is nil.\n"); - return 0; - } - - if(nud->pesp_conn == NULL){ - NODE_DBG("nud->pesp_conn is NULL.\n"); - return 0; - } - pesp_conn = nud->pesp_conn; - espconn_recv_hold(pesp_conn); - - return 0; -} - -static int net_socket_unhold( lua_State* L ) -{ - const char *mt = "net.socket"; - struct espconn *pesp_conn = NULL; - lnet_userdata *nud; - size_t l; - - nud = (lnet_userdata *)luaL_checkudata(L, 1, mt); - luaL_argcheck(L, nud, 1, "Server/Socket expected"); - if(nud==NULL){ - NODE_DBG("userdata is nil.\n"); - return 0; - } - - if(nud->pesp_conn == NULL){ - NODE_DBG("nud->pesp_conn is NULL.\n"); - return 0; - } - pesp_conn = nud->pesp_conn; - espconn_recv_unhold(pesp_conn); - - return 0; -} - -// Lua: ip,port = sk:getpeer() -static int net_socket_getpeer( lua_State* L ) -{ - lnet_userdata *nud; - const char *mt = "net.socket"; - nud = (lnet_userdata *)luaL_checkudata(L, 1, mt); - luaL_argcheck(L, nud, 1, "Server/Socket expected"); - - if(nud!=NULL && nud->pesp_conn!=NULL ){ - char temp[20] = {0}; - c_sprintf(temp, IPSTR, IP2STR( &(nud->pesp_conn->proto.tcp->remote_ip) ) ); - if ( nud->pesp_conn->proto.tcp->remote_port != 0 ) { - lua_pushstring( L, temp ); - lua_pushinteger( L, nud->pesp_conn->proto.tcp->remote_port ); - } else { - lua_pushnil( L ); - lua_pushnil( L ); - } - } else { - lua_pushnil( L ); - lua_pushnil( L ); - } - return 2; -} - -// Lua: socket:dns( string, function(ip) ) -static int net_socket_dns( lua_State* L ) -{ - const char *mt = "net.socket"; - return net_dns(L, mt); -} - -static int net_multicastJoinLeave( lua_State *L, int join) -{ - size_t il; - ip_addr_t multicast_addr; - ip_addr_t if_addr; - const char *multicast_ip; - const char *if_ip; - - NODE_DBG("net_multicastJoin is called.\n"); - if(! lua_isstring(L,1) ) return luaL_error( L, "wrong arg type" ); - if_ip = luaL_checklstring( L, 1, &il ); - if (if_ip != NULL) - if ( if_ip[0] == '\0' || stricmp(if_ip,"any") == 0) - { - if_ip = "0.0.0.0"; - il = 7; - } - if (if_ip == NULL || il > 15 || il < 7) return luaL_error( L, "invalid if ip" ); - if_addr.addr = ipaddr_addr(if_ip); - - if(! lua_isstring(L,2) ) return luaL_error( L, "wrong arg type" ); - multicast_ip = luaL_checklstring( L, 2, &il ); - if (multicast_ip == NULL || il > 15 || il < 7) return luaL_error( L, "invalid multicast ip" ); - multicast_addr.addr = ipaddr_addr(multicast_ip); - if (join) - { - igmp_joingroup(&if_addr, &multicast_addr); - } - else - { - igmp_leavegroup(&if_addr, &multicast_addr); - } - return 0; -} -// Lua: net.multicastJoin(ifip, multicastip) -// if ifip "" or "any" all interfaces are affected -static int net_multicastJoin( lua_State* L ) -{ - return net_multicastJoinLeave(L,1); -} - -// Lua: net.multicastLeave(ifip, multicastip) -// if ifip "" or "any" all interfaces are affected -static int net_multicastLeave( lua_State* L ) -{ - return net_multicastJoinLeave(L,0); -} - // Lua: s = net.dns.setdnsserver(ip_addr, [index]) -static int net_setdnsserver( lua_State* L ) -{ +static int net_setdnsserver( lua_State* L ) { size_t l; u32_t ip32; @@ -1316,8 +883,7 @@ static int net_setdnsserver( lua_State* L ) } // Lua: s = net.dns.getdnsserver([index]) -static int net_getdnsserver( lua_State* L ) -{ +static int net_getdnsserver( lua_State* L ) { int numdns = luaL_optint(L, 1, 0); if (numdns >= DNS_MAX_SERVERS) return luaL_error( L, "server index out of range [0-%d]", DNS_MAX_SERVERS - 1); @@ -1338,67 +904,76 @@ static int net_getdnsserver( lua_State* L ) return 1; } +#pragma mark - Tables + extern const LUA_REG_TYPE tls_cert_map[]; // Module function map -static const LUA_REG_TYPE net_server_map[] = { - { LSTRKEY( "listen" ), LFUNCVAL( net_server_listen ) }, - { LSTRKEY( "close" ), LFUNCVAL( net_server_close ) }, - { LSTRKEY( "on" ), LFUNCVAL( net_udpserver_on ) }, - { LSTRKEY( "send" ), LFUNCVAL( net_udpserver_send ) }, -//{ LSTRKEY( "delete" ), LFUNCVAL( net_server_delete ) }, - { LSTRKEY( "__gc" ), LFUNCVAL( net_server_delete ) }, - { LSTRKEY( "__index" ), LROVAL( net_server_map ) }, +static const LUA_REG_TYPE net_tcpserver_map[] = { + { LSTRKEY( "listen" ), LFUNCVAL( net_listen ) }, + { LSTRKEY( "getaddr" ), LFUNCVAL( net_getaddr ) }, + { LSTRKEY( "close" ), LFUNCVAL( net_close ) }, + { LSTRKEY( "__gc" ), LFUNCVAL( net_delete ) }, + { LSTRKEY( "__index" ), LROVAL( net_tcpserver_map ) }, { LNILKEY, LNILVAL } }; -static const LUA_REG_TYPE net_socket_map[] = { - { LSTRKEY( "connect" ), LFUNCVAL( net_socket_connect ) }, - { LSTRKEY( "close" ), LFUNCVAL( net_socket_close ) }, - { LSTRKEY( "on" ), LFUNCVAL( net_socket_on ) }, - { LSTRKEY( "send" ), LFUNCVAL( net_socket_send ) }, - { LSTRKEY( "hold" ), LFUNCVAL( net_socket_hold ) }, - { LSTRKEY( "unhold" ), LFUNCVAL( net_socket_unhold ) }, - { LSTRKEY( "dns" ), LFUNCVAL( net_socket_dns ) }, - { LSTRKEY( "getpeer" ), LFUNCVAL( net_socket_getpeer ) }, -//{ LSTRKEY( "delete" ), LFUNCVAL( net_socket_delete ) }, - { LSTRKEY( "__gc" ), LFUNCVAL( net_socket_delete ) }, - { LSTRKEY( "__index" ), LROVAL( net_socket_map ) }, +static const LUA_REG_TYPE net_tcpsocket_map[] = { + { LSTRKEY( "connect" ), LFUNCVAL( net_connect ) }, + { LSTRKEY( "close" ), LFUNCVAL( net_close ) }, + { LSTRKEY( "on" ), LFUNCVAL( net_on ) }, + { LSTRKEY( "send" ), LFUNCVAL( net_send ) }, + { LSTRKEY( "hold" ), LFUNCVAL( net_hold ) }, + { LSTRKEY( "unhold" ), LFUNCVAL( net_unhold ) }, + { LSTRKEY( "dns" ), LFUNCVAL( net_dns ) }, + { LSTRKEY( "getpeer" ), LFUNCVAL( net_getpeer ) }, + { LSTRKEY( "getaddr" ), LFUNCVAL( net_getaddr ) }, + { LSTRKEY( "__gc" ), LFUNCVAL( net_delete ) }, + { LSTRKEY( "__index" ), LROVAL( net_tcpsocket_map ) }, + { LNILKEY, LNILVAL } +}; + +static const LUA_REG_TYPE net_udpsocket_map[] = { + { LSTRKEY( "listen" ), LFUNCVAL( net_listen ) }, + { LSTRKEY( "close" ), LFUNCVAL( net_close ) }, + { LSTRKEY( "on" ), LFUNCVAL( net_on ) }, + { LSTRKEY( "send" ), LFUNCVAL( net_send ) }, + { LSTRKEY( "dns" ), LFUNCVAL( net_dns ) }, + { LSTRKEY( "getaddr" ), LFUNCVAL( net_getaddr ) }, + { LSTRKEY( "__gc" ), LFUNCVAL( net_delete ) }, + { LSTRKEY( "__index" ), LROVAL( net_udpsocket_map ) }, { LNILKEY, LNILVAL } }; static const LUA_REG_TYPE net_dns_map[] = { - { LSTRKEY( "setdnsserver" ), LFUNCVAL( net_setdnsserver ) }, - { LSTRKEY( "getdnsserver" ), LFUNCVAL( net_getdnsserver ) }, - { LSTRKEY( "resolve" ), LFUNCVAL( net_dns_static ) }, + { LSTRKEY( "setdnsserver" ), LFUNCVAL( net_setdnsserver ) }, + { LSTRKEY( "getdnsserver" ), LFUNCVAL( net_getdnsserver ) }, + { LSTRKEY( "resolve" ), LFUNCVAL( net_dns_static ) }, { LNILKEY, LNILVAL } }; static const LUA_REG_TYPE net_map[] = { { LSTRKEY( "createServer" ), LFUNCVAL( net_createServer ) }, { LSTRKEY( "createConnection" ), LFUNCVAL( net_createConnection ) }, + { LSTRKEY( "createUDPSocket" ), LFUNCVAL( net_createUDPSocket ) }, { LSTRKEY( "multicastJoin"), LFUNCVAL( net_multicastJoin ) }, { LSTRKEY( "multicastLeave"), LFUNCVAL( net_multicastLeave ) }, { LSTRKEY( "dns" ), LROVAL( net_dns_map ) }, #ifdef CLIENT_SSL_ENABLE { LSTRKEY( "cert" ), LROVAL( tls_cert_map ) }, #endif - { LSTRKEY( "TCP" ), LNUMVAL( TCP ) }, - { LSTRKEY( "UDP" ), LNUMVAL( UDP ) }, + { LSTRKEY( "TCP" ), LNUMVAL( TYPE_TCP ) }, + { LSTRKEY( "UDP" ), LNUMVAL( TYPE_UDP ) }, { LSTRKEY( "__metatable" ), LROVAL( net_map ) }, { LNILKEY, LNILVAL } }; int luaopen_net( lua_State *L ) { - int i; - for(i=0;i