diff options
Diffstat (limited to 'src/select.c')
-rw-r--r-- | src/select.c | 221 |
1 files changed, 146 insertions, 75 deletions
diff --git a/src/select.c b/src/select.c index 1ebd82c..13f9d6e 100644 --- a/src/select.c +++ b/src/select.c | |||
@@ -9,26 +9,21 @@ | |||
9 | #include <lua.h> | 9 | #include <lua.h> |
10 | #include <lauxlib.h> | 10 | #include <lauxlib.h> |
11 | 11 | ||
12 | #include "luasocket.h" | ||
13 | #include "socket.h" | 12 | #include "socket.h" |
14 | #include "auxiliar.h" | ||
15 | #include "select.h" | 13 | #include "select.h" |
16 | 14 | ||
17 | /*=========================================================================*\ | 15 | /*=========================================================================*\ |
18 | * Internal function prototypes. | 16 | * Internal function prototypes. |
19 | \*=========================================================================*/ | 17 | \*=========================================================================*/ |
20 | static int meth_set(lua_State *L); | 18 | static int getfd(lua_State *L); |
21 | static int meth_isset(lua_State *L); | 19 | static int dirty(lua_State *L); |
22 | static int c_select(lua_State *L); | 20 | static int collect_fd(lua_State *L, int tab, int max_fd, int itab, fd_set *set); |
21 | static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set); | ||
22 | static void return_fd(lua_State *L, fd_set *set, int max_fd, | ||
23 | int itab, int tab, int start); | ||
24 | static void make_assoc(lua_State *L, int tab); | ||
23 | static int global_select(lua_State *L); | 25 | static int global_select(lua_State *L); |
24 | 26 | ||
25 | /* fd_set object methods */ | ||
26 | static luaL_reg set[] = { | ||
27 | {"set", meth_set}, | ||
28 | {"isset", meth_isset}, | ||
29 | {NULL, NULL} | ||
30 | }; | ||
31 | |||
32 | /* functions in library namespace */ | 27 | /* functions in library namespace */ |
33 | static luaL_reg func[] = { | 28 | static luaL_reg func[] = { |
34 | {"select", global_select}, | 29 | {"select", global_select}, |
@@ -36,22 +31,13 @@ static luaL_reg func[] = { | |||
36 | }; | 31 | }; |
37 | 32 | ||
38 | /*=========================================================================*\ | 33 | /*=========================================================================*\ |
39 | * Internal function prototypes. | 34 | * Exported functions |
40 | \*=========================================================================*/ | 35 | \*=========================================================================*/ |
41 | /*-------------------------------------------------------------------------*\ | 36 | /*-------------------------------------------------------------------------*\ |
42 | * Initializes module | 37 | * Initializes module |
43 | \*-------------------------------------------------------------------------*/ | 38 | \*-------------------------------------------------------------------------*/ |
44 | int select_open(lua_State *L) | 39 | int select_open(lua_State *L) { |
45 | { | 40 | luaL_openlib(L, NULL, func, 0); |
46 | /* get select auxiliar lua function from lua code and register | ||
47 | * pass it as an upvalue to global_select */ | ||
48 | #ifdef LUASOCKET_COMPILED | ||
49 | #include "select.lch" | ||
50 | #else | ||
51 | lua_dofile(L, "select.lua"); | ||
52 | #endif | ||
53 | luaL_openlib(L, NULL, func, 1); | ||
54 | aux_newclass(L, "select{fd_set}", set); | ||
55 | return 0; | 41 | return 0; |
56 | } | 42 | } |
57 | 43 | ||
@@ -61,64 +47,149 @@ int select_open(lua_State *L) | |||
61 | /*-------------------------------------------------------------------------*\ | 47 | /*-------------------------------------------------------------------------*\ |
62 | * Waits for a set of sockets until a condition is met or timeout. | 48 | * Waits for a set of sockets until a condition is met or timeout. |
63 | \*-------------------------------------------------------------------------*/ | 49 | \*-------------------------------------------------------------------------*/ |
64 | static int global_select(lua_State *L) | 50 | static int global_select(lua_State *L) { |
65 | { | 51 | int timeout, rtab, wtab, itab, max_fd, ret, ndirty; |
66 | fd_set *read_fd_set, *write_fd_set; | 52 | fd_set rset, wset; |
67 | /* make sure we have enough arguments (nil is the default) */ | 53 | FD_ZERO(&rset); FD_ZERO(&wset); |
68 | lua_settop(L, 3); | 54 | lua_settop(L, 3); |
69 | /* check timeout */ | 55 | timeout = lua_isnil(L, 3) ? -1 : (int)(luaL_checknumber(L, 3) * 1000); |
70 | if (!lua_isnil(L, 3) && !lua_isnumber(L, 3)) | 56 | lua_newtable(L); itab = lua_gettop(L); |
71 | luaL_argerror(L, 3, "number or nil expected"); | 57 | lua_newtable(L); rtab = lua_gettop(L); |
72 | /* select auxiliar lua function to be called comes first */ | 58 | lua_newtable(L); wtab = lua_gettop(L); |
73 | lua_pushvalue(L, lua_upvalueindex(1)); | 59 | max_fd = collect_fd(L, 1, -1, itab, &rset); |
74 | lua_insert(L, 1); | 60 | ndirty = check_dirty(L, 1, rtab, &rset); |
75 | /* pass fd_set objects */ | 61 | timeout = ndirty > 0? 0: timeout; |
76 | read_fd_set = (fd_set *) lua_newuserdata(L, sizeof(fd_set)); | 62 | max_fd = collect_fd(L, 2, max_fd, itab, &wset); |
77 | FD_ZERO(read_fd_set); | 63 | ret = sock_select(max_fd+1, &rset, &wset, NULL, timeout); |
78 | aux_setclass(L, "select{fd_set}", -1); | 64 | if (ret > 0 || (ret == 0 && ndirty > 0)) { |
79 | write_fd_set = (fd_set *) lua_newuserdata(L, sizeof(fd_set)); | 65 | return_fd(L, &rset, max_fd+1, itab, rtab, ndirty); |
80 | FD_ZERO(write_fd_set); | 66 | return_fd(L, &wset, max_fd+1, itab, wtab, 0); |
81 | aux_setclass(L, "select{fd_set}", -1); | 67 | make_assoc(L, rtab); |
82 | /* pass select auxiliar C function */ | 68 | make_assoc(L, wtab); |
83 | lua_pushcfunction(L, c_select); | 69 | return 2; |
84 | /* call select auxiliar lua function */ | 70 | } else if (ret == 0) { |
85 | lua_call(L, 6, 3); | 71 | lua_pushstring(L, "timeout"); |
86 | return 3; | 72 | return 3; |
73 | } else { | ||
74 | lua_pushnil(L); | ||
75 | lua_pushnil(L); | ||
76 | lua_pushstring(L, "error"); | ||
77 | return 3; | ||
78 | } | ||
87 | } | 79 | } |
88 | 80 | ||
89 | /*=========================================================================*\ | 81 | /*=========================================================================*\ |
90 | * Lua methods | 82 | * Internal functions |
91 | \*=========================================================================*/ | 83 | \*=========================================================================*/ |
92 | static int meth_set(lua_State *L) | 84 | static int getfd(lua_State *L) { |
93 | { | 85 | int fd = -1; |
94 | fd_set *set = (fd_set *) aux_checkclass(L, "select{fd_set}", 1); | 86 | lua_pushstring(L, "getfd"); |
95 | t_sock fd = (t_sock) lua_tonumber(L, 2); | 87 | lua_gettable(L, -2); |
96 | if (fd >= 0) FD_SET(fd, set); | 88 | if (!lua_isnil(L, -1)) { |
97 | return 0; | 89 | lua_pushvalue(L, -2); |
90 | lua_call(L, 1, 1); | ||
91 | if (lua_isnumber(L, -1)) | ||
92 | fd = lua_tonumber(L, -1); | ||
93 | } | ||
94 | lua_pop(L, 1); | ||
95 | return fd; | ||
98 | } | 96 | } |
99 | 97 | ||
100 | static int meth_isset(lua_State *L) | 98 | static int dirty(lua_State *L) { |
101 | { | 99 | int is = 0; |
102 | fd_set *set = (fd_set *) aux_checkclass(L, "select{fd_set}", 1); | 100 | lua_pushstring(L, "dirty"); |
103 | t_sock fd = (t_sock) lua_tonumber(L, 2); | 101 | lua_gettable(L, -2); |
104 | if (fd >= 0 && FD_ISSET(fd, set)) lua_pushnumber(L, 1); | 102 | if (!lua_isnil(L, -1)) { |
105 | else lua_pushnil(L); | 103 | lua_pushvalue(L, -2); |
106 | return 1; | 104 | lua_call(L, 1, 1); |
105 | is = lua_toboolean(L, -1); | ||
106 | } | ||
107 | lua_pop(L, 1); | ||
108 | return is; | ||
107 | } | 109 | } |
108 | 110 | ||
109 | /*=========================================================================*\ | 111 | static int collect_fd(lua_State *L, int tab, int max_fd, |
110 | * Internal functions | 112 | int itab, fd_set *set) { |
111 | \*=========================================================================*/ | 113 | int i = 1; |
112 | static int c_select(lua_State *L) | 114 | if (lua_isnil(L, tab)) |
113 | { | 115 | return max_fd; |
114 | int max_fd = (int) lua_tonumber(L, 1); | 116 | while (1) { |
115 | fd_set *read_fd_set = (fd_set *) aux_checkclass(L, "select{fd_set}", 2); | 117 | int fd; |
116 | fd_set *write_fd_set = (fd_set *) aux_checkclass(L, "select{fd_set}", 3); | 118 | lua_pushnumber(L, i); |
117 | int timeout = lua_isnil(L, 4) ? -1 : (int)(lua_tonumber(L, 4) * 1000); | 119 | lua_gettable(L, tab); |
118 | struct timeval tv; | 120 | if (lua_isnil(L, -1)) { |
119 | tv.tv_sec = timeout / 1000; | 121 | lua_pop(L, 1); |
120 | tv.tv_usec = (timeout % 1000) * 1000; | 122 | break; |
121 | lua_pushnumber(L, select(max_fd, read_fd_set, write_fd_set, NULL, | 123 | } |
122 | timeout < 0 ? NULL : &tv)); | 124 | fd = getfd(L); |
123 | return 1; | 125 | if (fd > 0) { |
126 | FD_SET(fd, set); | ||
127 | if (max_fd < fd) max_fd = fd; | ||
128 | lua_pushnumber(L, fd); | ||
129 | lua_pushvalue(L, -2); | ||
130 | lua_settable(L, itab); | ||
131 | } | ||
132 | lua_pop(L, 1); | ||
133 | i = i + 1; | ||
134 | } | ||
135 | return max_fd; | ||
136 | } | ||
137 | |||
138 | static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set) { | ||
139 | int ndirty = 0, i = 1; | ||
140 | if (lua_isnil(L, tab)) | ||
141 | return 0; | ||
142 | while (1) { | ||
143 | int fd; | ||
144 | lua_pushnumber(L, i); | ||
145 | lua_gettable(L, tab); | ||
146 | if (lua_isnil(L, -1)) { | ||
147 | lua_pop(L, 1); | ||
148 | break; | ||
149 | } | ||
150 | fd = getfd(L); | ||
151 | if (fd > 0 && dirty(L)) { | ||
152 | lua_pushnumber(L, ++ndirty); | ||
153 | lua_pushvalue(L, -2); | ||
154 | lua_settable(L, dtab); | ||
155 | FD_CLR(fd, set); | ||
156 | } | ||
157 | lua_pop(L, 1); | ||
158 | i = i + 1; | ||
159 | } | ||
160 | return ndirty; | ||
161 | } | ||
162 | |||
163 | static void return_fd(lua_State *L, fd_set *set, int max_fd, | ||
164 | int itab, int tab, int start) { | ||
165 | int fd; | ||
166 | for (fd = 0; fd < max_fd; fd++) { | ||
167 | if (FD_ISSET(fd, set)) { | ||
168 | lua_pushnumber(L, ++start); | ||
169 | lua_pushnumber(L, fd); | ||
170 | lua_gettable(L, itab); | ||
171 | lua_settable(L, tab); | ||
172 | } | ||
173 | } | ||
174 | } | ||
175 | |||
176 | static void make_assoc(lua_State *L, int tab) { | ||
177 | int i = 1, atab; | ||
178 | lua_newtable(L); atab = lua_gettop(L); | ||
179 | while (1) { | ||
180 | lua_pushnumber(L, i); | ||
181 | lua_gettable(L, tab); | ||
182 | if (!lua_isnil(L, -1)) { | ||
183 | lua_pushnumber(L, i); | ||
184 | lua_pushvalue(L, -2); | ||
185 | lua_settable(L, atab); | ||
186 | lua_pushnumber(L, i); | ||
187 | lua_settable(L, atab); | ||
188 | } else { | ||
189 | lua_pop(L, 1); | ||
190 | break; | ||
191 | } | ||
192 | i = i+1; | ||
193 | } | ||
124 | } | 194 | } |
195 | |||