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 | } | ||