diff options
Diffstat (limited to 'src/select.c')
| -rw-r--r-- | src/select.c | 191 |
1 files changed, 83 insertions, 108 deletions
diff --git a/src/select.c b/src/select.c index 9f56b47..3cabbd1 100644 --- a/src/select.c +++ b/src/select.c | |||
| @@ -1,154 +1,129 @@ | |||
| 1 | /*=========================================================================*\ | 1 | /*=========================================================================*\ |
| 2 | * Select implementation | 2 | * Select implementation |
| 3 | * Global Lua fuctions: | ||
| 4 | * select: waits until socket ready | ||
| 5 | * RCS ID: $Id$ | 3 | * RCS ID: $Id$ |
| 6 | \*=========================================================================*/ | 4 | \*=========================================================================*/ |
| 7 | #include <string.h> | 5 | #include <string.h> |
| 6 | |||
| 8 | #include <lua.h> | 7 | #include <lua.h> |
| 9 | #include <lauxlib.h> | 8 | #include <lauxlib.h> |
| 10 | 9 | ||
| 11 | #include "luasocket.h" | 10 | #include "luasocket.h" |
| 12 | #include "lspriv.h" | 11 | #include "socket.h" |
| 13 | #include "lsselect.h" | 12 | #include "auxiliar.h" |
| 14 | #include "lsfd.h" | 13 | #include "select.h" |
| 15 | 14 | ||
| 16 | /* auxiliar functions */ | 15 | static int meth_set(lua_State *L); |
| 17 | static int local_select(lua_State *L); | 16 | static int meth_isset(lua_State *L); |
| 18 | static int local_getfd(lua_State *L); | 17 | static int c_select(lua_State *L); |
| 19 | static int local_pending(lua_State *L); | 18 | static int global_select(lua_State *L); |
| 20 | static int local_FD_SET(lua_State *L); | 19 | static void check_obj_tab(lua_State *L, int tabidx); |
| 21 | static int local_FD_ISSET(lua_State *L); | ||
| 22 | 20 | ||
| 23 | static int select_lua_select(lua_State *L); | 21 | /* fd_set object methods */ |
| 22 | static luaL_reg set[] = { | ||
| 23 | {"set", meth_set}, | ||
| 24 | {"isset", meth_isset}, | ||
| 25 | {NULL, NULL} | ||
| 26 | }; | ||
| 24 | 27 | ||
| 25 | /*-------------------------------------------------------------------------*\ | 28 | /* functions in library namespace */ |
| 26 | * Marks type as selectable | 29 | static luaL_reg func[] = { |
| 27 | * Input | 30 | {"select", global_select}, |
| 28 | * name: type name | 31 | {NULL, NULL} |
| 29 | \*-------------------------------------------------------------------------*/ | 32 | }; |
| 30 | void select_addclass(lua_State *L, cchar *lsclass) | ||
| 31 | { | ||
| 32 | lua_pushstring(L, "luasocket(select)"); | ||
| 33 | lua_gettable(L, LUA_REGISTRYINDEX); | ||
| 34 | lua_pushstring(L, lsclass); | ||
| 35 | lua_pushnumber(L, 1); | ||
| 36 | lua_settable(L, -3); | ||
| 37 | lua_pop(L, 1); | ||
| 38 | } | ||
| 39 | 33 | ||
| 40 | void select_open(lua_State *L) | 34 | void select_open(lua_State *L) |
| 41 | { | 35 | { |
| 42 | /* push select auxiliar lua function and register | 36 | /* get select auxiliar lua function from lua code and register |
| 43 | * select_lua_select with it as an upvalue */ | 37 | * pass it as an upvalue to global_select */ |
| 44 | #ifdef LUASOCKET_DOFILE | 38 | #ifdef LUASOCKET_COMPILED |
| 45 | lua_dofile(L, "lsselect.lua"); | 39 | #include "select.lch" |
| 46 | #else | 40 | #else |
| 47 | #include "lsselect.loh" | 41 | lua_dofile(L, "select.lua"); |
| 48 | #endif | 42 | #endif |
| 49 | lua_getglobal(L, LUASOCKET_LIBNAME); | 43 | luaL_openlib(L, LUASOCKET_LIBNAME, func, 1); |
| 50 | lua_pushstring(L, "_select"); | ||
| 51 | lua_gettable(L, -2); | ||
| 52 | lua_pushcclosure(L, select_lua_select, 1); | ||
| 53 | priv_newglobal(L, "select"); | ||
| 54 | lua_pop(L, 1); | 44 | lua_pop(L, 1); |
| 55 | /* create luasocket(select) table */ | 45 | aux_newclass(L, "select{fd_set}", set); |
| 56 | lua_pushstring(L, "luasocket(select)"); | ||
| 57 | lua_newtable(L); | ||
| 58 | lua_settable(L, LUA_REGISTRYINDEX); | ||
| 59 | } | 46 | } |
| 60 | 47 | ||
| 61 | /*-------------------------------------------------------------------------*\ | 48 | /*-------------------------------------------------------------------------*\ |
| 62 | * Waits for a set of sockets until a condition is met or timeout. | 49 | * Waits for a set of sockets until a condition is met or timeout. |
| 63 | * Lua Input: {input}, {output} [, timeout] | ||
| 64 | * {input}: table of sockets to be tested for input | ||
| 65 | * {output}: table of sockets to be tested for output | ||
| 66 | * timeout: maximum amount of time to wait for condition, in seconds | ||
| 67 | * Lua Returns: {input}, {output}, err | ||
| 68 | * {input}: table with sockets ready for input | ||
| 69 | * {output}: table with sockets ready for output | ||
| 70 | * err: "timeout" or nil | ||
| 71 | \*-------------------------------------------------------------------------*/ | 50 | \*-------------------------------------------------------------------------*/ |
| 72 | static int select_lua_select(lua_State *L) | 51 | static int global_select(lua_State *L) |
| 73 | { | 52 | { |
| 74 | fd_set read, write; | 53 | fd_set *read_fd_set, *write_fd_set; |
| 75 | FD_ZERO(&read); | ||
| 76 | FD_ZERO(&write); | ||
| 77 | /* push select lua auxiliar function */ | ||
| 78 | lua_pushvalue(L, lua_upvalueindex(1)); lua_insert(L, 1); | ||
| 79 | /* make sure we have enough arguments (nil is the default) */ | 54 | /* make sure we have enough arguments (nil is the default) */ |
| 80 | lua_settop(L, 4); | 55 | lua_settop(L, 3); |
| 81 | /* pass FD_SET and manipulation functions */ | 56 | /* check object tables */ |
| 82 | lua_boxpointer(L, &read); | 57 | check_obj_tab(L, 1); |
| 83 | lua_boxpointer(L, &write); | 58 | check_obj_tab(L, 2); |
| 84 | lua_pushcfunction(L, local_FD_SET); | 59 | /* check timeout */ |
| 85 | lua_pushcfunction(L, local_FD_ISSET); | 60 | if (!lua_isnil(L, 3) && !lua_isnumber(L, 3)) |
| 86 | /* pass getfd function with selectable table as upvalue */ | 61 | luaL_argerror(L, 3, "number or nil expected"); |
| 87 | lua_pushstring(L, "luasocket(select)"); lua_gettable(L, LUA_REGISTRYINDEX); | 62 | /* select auxiliar lua function to be called comes first */ |
| 88 | lua_pushcclosure(L, local_getfd, 1); | 63 | lua_pushvalue(L, lua_upvalueindex(1)); |
| 89 | /* pass pending function */ | 64 | lua_insert(L, 1); |
| 90 | lua_pushstring(L, "luasocket(select)"); lua_gettable(L, LUA_REGISTRYINDEX); | 65 | /* pass fd_set objects */ |
| 91 | lua_pushcclosure(L, local_pending, 1); | 66 | read_fd_set = lua_newuserdata(L, sizeof(fd_set)); |
| 67 | FD_ZERO(read_fd_set); | ||
| 68 | aux_setclass(L, "select{fd_set}", -1); | ||
| 69 | write_fd_set = lua_newuserdata(L, sizeof(fd_set)); | ||
| 70 | FD_ZERO(write_fd_set); | ||
| 71 | aux_setclass(L, "select{fd_set}", -1); | ||
| 92 | /* pass select auxiliar C function */ | 72 | /* pass select auxiliar C function */ |
| 93 | lua_pushcfunction(L, local_select); | 73 | lua_pushcfunction(L, c_select); |
| 94 | /* call select auxiliar lua function */ | 74 | /* call select auxiliar lua function */ |
| 95 | lua_call(L, 10, 3); | 75 | lua_call(L, 6, 3); |
| 96 | return 3; | 76 | return 3; |
| 97 | } | 77 | } |
| 98 | 78 | ||
| 99 | static int local_getfd(lua_State *L) | 79 | static int c_select(lua_State *L) |
| 100 | { | ||
| 101 | priv_pushclass(L, 1); | ||
| 102 | lua_gettable(L, lua_upvalueindex(1)); | ||
| 103 | if (!lua_isnil(L, -1)) { | ||
| 104 | p_fd sock = (p_fd) lua_touserdata(L, 1); | ||
| 105 | lua_pushnumber(L, sock->fd); | ||
| 106 | } | ||
| 107 | return 1; | ||
| 108 | } | ||
| 109 | |||
| 110 | static int local_pending(lua_State *L) | ||
| 111 | { | ||
| 112 | priv_pushclass(L, 1); | ||
| 113 | lua_gettable(L, lua_upvalueindex(1)); | ||
| 114 | if (!lua_isnil(L, -1)) { | ||
| 115 | p_fd sock = (p_fd) lua_touserdata(L, 1); | ||
| 116 | if (sock->fd_pending(L, sock)) lua_pushnumber(L, 1); | ||
| 117 | else lua_pushnil(L); | ||
| 118 | } | ||
| 119 | return 1; | ||
| 120 | } | ||
| 121 | |||
| 122 | static int local_select(lua_State *L) | ||
| 123 | { | 80 | { |
| 124 | int max_fd = (int) lua_tonumber(L, 1); | 81 | int max_fd = (int) lua_tonumber(L, 1); |
| 125 | fd_set *read_set = (fd_set *) lua_touserdata(L, 2); | 82 | fd_set *read_fd_set = (fd_set *) aux_checkclass(L, "select{fd_set}", 2); |
| 126 | fd_set *write_set = (fd_set *) lua_touserdata(L, 3); | 83 | fd_set *write_fd_set = (fd_set *) aux_checkclass(L, "select{fd_set}", 3); |
| 127 | int deadline = lua_isnil(L, 4) ? -1 : (int)(lua_tonumber(L, 4) * 1000); | 84 | int timeout = lua_isnil(L, 4) ? -1 : (int)(lua_tonumber(L, 4) * 1000); |
| 128 | struct timeval tv; | 85 | struct timeval tv; |
| 129 | if (deadline >= 0) { | 86 | tv.tv_sec = timeout / 1000; |
| 130 | tv.tv_sec = deadline / 1000; | 87 | tv.tv_usec = (timeout % 1000) * 1000; |
| 131 | tv.tv_usec = (deadline % 1000) * 1000; | 88 | lua_pushnumber(L, select(max_fd, read_fd_set, write_fd_set, NULL, |
| 132 | lua_pushnumber(L, select(max_fd, read_set, write_set, NULL, &tv)); | 89 | timeout < 0 ? NULL : &tv)); |
| 133 | } else { | ||
| 134 | lua_pushnumber(L, select(max_fd, read_set, write_set, NULL, NULL)); | ||
| 135 | } | ||
| 136 | return 1; | 90 | return 1; |
| 137 | } | 91 | } |
| 138 | 92 | ||
| 139 | static int local_FD_SET(lua_State *L) | 93 | static int meth_set(lua_State *L) |
| 140 | { | 94 | { |
| 141 | COMPAT_FD fd = (COMPAT_FD) lua_tonumber(L, 1); | 95 | fd_set *set = (fd_set *) aux_checkclass(L, "select{fd_set}", 1); |
| 142 | fd_set *set = (fd_set *) lua_topointer(L, 2); | 96 | t_sock fd = (t_sock) lua_tonumber(L, 2); |
| 143 | if (fd >= 0) FD_SET(fd, set); | 97 | if (fd >= 0) FD_SET(fd, set); |
| 144 | return 0; | 98 | return 0; |
| 145 | } | 99 | } |
| 146 | 100 | ||
| 147 | static int local_FD_ISSET(lua_State *L) | 101 | static int meth_isset(lua_State *L) |
| 148 | { | 102 | { |
| 149 | COMPAT_FD fd = (COMPAT_FD) lua_tonumber(L, 1); | 103 | fd_set *set = (fd_set *) aux_checkclass(L, "select{fd_set}", 1); |
| 150 | fd_set *set = (fd_set *) lua_topointer(L, 2); | 104 | t_sock fd = (t_sock) lua_tonumber(L, 2); |
| 151 | if (fd >= 0 && FD_ISSET(fd, set)) lua_pushnumber(L, 1); | 105 | if (fd >= 0 && FD_ISSET(fd, set)) lua_pushnumber(L, 1); |
| 152 | else lua_pushnil(L); | 106 | else lua_pushnil(L); |
| 153 | return 1; | 107 | return 1; |
| 154 | } | 108 | } |
| 109 | |||
| 110 | static void check_obj_tab(lua_State *L, int tabidx) | ||
| 111 | { | ||
| 112 | if (tabidx < 0) tabidx = lua_gettop(L) + tabidx + 1; | ||
| 113 | if (lua_istable(L, tabidx)) { | ||
| 114 | lua_pushnil(L); | ||
| 115 | while (lua_next(L, tabidx) != 0) { | ||
| 116 | if (aux_getgroupudata(L, "select{able}", -1) == NULL) { | ||
| 117 | char msg[45]; | ||
| 118 | if (lua_isnumber(L, -2)) | ||
| 119 | sprintf(msg, "table entry #%g is invalid", | ||
| 120 | lua_tonumber(L, -2)); | ||
| 121 | else | ||
| 122 | sprintf(msg, "invalid entry found in table"); | ||
| 123 | luaL_argerror(L, tabidx, msg); | ||
| 124 | } | ||
| 125 | lua_pop(L, 1); | ||
| 126 | } | ||
| 127 | } else if (!lua_isnil(L, tabidx)) | ||
| 128 | luaL_argerror(L, tabidx, "table or nil expected"); | ||
| 129 | } | ||
