#include #include "lspriv.h" #include "lsselect.h" #include "lsfd.h" /* auxiliar functions */ static int local_select(lua_State *L); static int local_getfd(lua_State *L); static int local_pending(lua_State *L); static int local_FD_SET(lua_State *L); static int local_FD_ISSET(lua_State *L); static int select_lua_select(lua_State *L); /*-------------------------------------------------------------------------*\ * Marks type as selectable * Input * name: type name \*-------------------------------------------------------------------------*/ void select_addclass(lua_State *L, cchar *lsclass) { lua_pushstring(L, "luasocket(select)"); lua_gettable(L, LUA_REGISTRYINDEX); lua_pushstring(L, lsclass); lua_pushnumber(L, 1); lua_settable(L, -3); lua_pop(L, 1); } void select_open(lua_State *L) { /* push select auxiliar lua function and register * select_lua_select with it as an upvalue */ #include "lsselect.loh" lua_pushcclosure(L, select_lua_select, 1); lua_setglobal(L, "select"); /* create luasocket(select) table */ lua_pushstring(L, "luasocket(select)"); lua_newtable(L); lua_settable(L, LUA_REGISTRYINDEX); } /*-------------------------------------------------------------------------*\ * Waits for a set of sockets until a condition is met or timeout. * Lua Input: {input}, {output} [, timeout] * {input}: table of sockets to be tested for input * {output}: table of sockets to be tested for output * timeout: maximum amount of time to wait for condition, in seconds * Lua Returns: {input}, {output}, err * {input}: table with sockets ready for input * {output}: table with sockets ready for output * err: "timeout" or nil \*-------------------------------------------------------------------------*/ static int select_lua_select(lua_State *L) { fd_set read, write; FD_ZERO(&read); FD_ZERO(&write); /* push select lua auxiliar function */ lua_pushvalue(L, lua_upvalueindex(1)); lua_insert(L, 1); /* make sure we have enough arguments (nil is the default) */ lua_settop(L, 4); /* pass FD_SET and manipulation functions */ lua_newuserdatabox(L, &read); lua_newuserdatabox(L, &write); lua_pushcfunction(L, local_FD_SET); lua_pushcfunction(L, local_FD_ISSET); /* pass getfd function with selectable table as upvalue */ lua_pushstring(L, "luasocket(select)"); lua_gettable(L, LUA_REGISTRYINDEX); lua_pushcclosure(L, local_getfd, 1); /* pass pending function */ lua_pushstring(L, "luasocket(select)"); lua_gettable(L, LUA_REGISTRYINDEX); lua_pushcclosure(L, local_pending, 1); /* pass select auxiliar C function */ lua_pushcfunction(L, local_select); /* call select auxiliar lua function */ lua_call(L, 10, 3); return 3; } static int local_getfd(lua_State *L) { priv_pushclass(L, 1); lua_gettable(L, lua_upvalueindex(1)); if (!lua_isnil(L, -1)) { p_fd sock = (p_fd) lua_touserdata(L, 1); lua_pushnumber(L, sock->fd); } return 1; } static int local_pending(lua_State *L) { priv_pushclass(L, 1); lua_gettable(L, lua_upvalueindex(1)); if (!lua_isnil(L, -1)) { p_fd sock = (p_fd) lua_touserdata(L, 1); if (sock->fd_pending(L, sock)) lua_pushnumber(L, 1); else lua_pushnil(L); } return 1; } static int local_select(lua_State *L) { int max_fd = (int) lua_tonumber(L, 1); fd_set *read_set = (fd_set *) lua_touserdata(L, 2); fd_set *write_set = (fd_set *) lua_touserdata(L, 3); int deadline = lua_isnil(L, 4) ? -1 : (int)(lua_tonumber(L, 4) * 1000); struct timeval tv; if (deadline >= 0) { tv.tv_sec = deadline / 1000; tv.tv_usec = (deadline % 1000) * 1000; lua_pushnumber(L, select(max_fd, read_set, write_set, NULL, &tv)); } else { lua_pushnumber(L, select(max_fd, read_set, write_set, NULL, NULL)); } return 1; } static int local_FD_SET(lua_State *L) { COMPAT_FD fd = (COMPAT_FD) lua_tonumber(L, 1); fd_set *set = (fd_set *) lua_touserdata(L, 2); if (fd >= 0) FD_SET(fd, set); return 0; } static int local_FD_ISSET(lua_State *L) { COMPAT_FD fd = (COMPAT_FD) lua_tonumber(L, 1); fd_set *set = (fd_set *) lua_touserdata(L, 2); if (fd >= 0 && FD_ISSET(fd, set)) lua_pushnumber(L, 1); else lua_pushnil(L); return 1; }