// 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); } if (lua_gettop(L) > 3) { luaL_argcheck(L, lua_isfunction(L, 4) || lua_islightfunction(L, 4), 4, "not a function"); lua_pushvalue(L, 4); luaL_unref(L, LUA_REGISTRYINDEX, ud->client.cb_connect_ref); ud->client.cb_connect_ref = luaL_ref(L, LUA_REGISTRYINDEX); } 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 lwip_lua_checkerr(L, err); } return 0; }
static int traceback (lua_State *L) { if (!lua_isstring(L, 1)) /* 'message' not a string? */ return 1; /* keep it intact */ lua_getfield(L, LUA_GLOBALSINDEX, "debug"); if (!lua_istable(L, -1) && !lua_isrotable(L, -1)) { lua_pop(L, 1); return 1; } lua_getfield(L, -1, "traceback"); if (!lua_isfunction(L, -1) && !lua_islightfunction(L, -1)) { lua_pop(L, 2); return 1; } lua_pushvalue(L, 1); /* pass error message */ lua_pushinteger(L, 2); /* skip this function and traceback */ lua_call(L, 2, 1); /* call debug.traceback */ return 1; }
static int db_getinfo (lua_State *L) { lua_Debug ar; int arg; lua_State *L1 = getthread(L, &arg); const char *options = luaL_optstring(L, arg+2, "flnSu"); if (lua_isnumber(L, arg+1)) { if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) { lua_pushnil(L); /* level out of range */ return 1; } } else if (lua_isfunction(L, arg+1) || lua_islightfunction(L, arg+1)) { lua_pushfstring(L, ">%s", options); options = lua_tostring(L, -1); lua_pushvalue(L, arg+1); lua_xmove(L, L1, 1); } else return luaL_argerror(L, arg+1, "function or level expected"); if (!lua_getinfo(L1, options, &ar)) return luaL_argerror(L, arg+2, "invalid option"); lua_createtable(L, 0, 2); if (strchr(options, 'S')) { settabss(L, "source", ar.source); settabss(L, "short_src", ar.short_src); settabsi(L, "linedefined", ar.linedefined); settabsi(L, "lastlinedefined", ar.lastlinedefined); settabss(L, "what", ar.what); } if (strchr(options, 'l')) settabsi(L, "currentline", ar.currentline); if (strchr(options, 'u')) settabsi(L, "nups", ar.nups); if (strchr(options, 'n')) { settabss(L, "name", ar.name); settabss(L, "namewhat", ar.namewhat); } if (strchr(options, 'L')) treatstackoption(L, L1, "activelines"); if (strchr(options, 'f')) treatstackoption(L, L1, "func"); return 1; /* return table */ }
// 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; }
// 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); } 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; } return lwip_lua_checkerr(L, err); } return 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); ip_addr_t laddr = {0}; err_t err = udp_bind(ud->udp_pcb, &laddr, 0); if (err != ERR_OK) { udp_remove(ud->udp_pcb); ud->udp_pcb = NULL; return lwip_lua_checkerr(L, err); } if (ud->self_ref == LUA_NOREF) { lua_pushvalue(L, 1); ud->self_ref = luaL_ref(L, LUA_REGISTRYINDEX); } } 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); if (!pb) return luaL_error(L, "cannot allocate message buffer"); 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 lwip_lua_checkerr(L, err); }
// 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); } 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"); } } 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"); ud->tcp_pcb->so_options |= SOF_REUSEADDR; 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 (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 lwip_lua_checkerr(L, err); } if (ud->self_ref == LUA_NOREF) { lua_pushvalue(L, 1); ud->self_ref = luaL_ref(L, LUA_REGISTRYINDEX); } return 0; }