aboutsummaryrefslogtreecommitdiff
path: root/vendor/luasocket/src/select.c
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/luasocket/src/select.c')
-rw-r--r--vendor/luasocket/src/select.c214
1 files changed, 214 insertions, 0 deletions
diff --git a/vendor/luasocket/src/select.c b/vendor/luasocket/src/select.c
new file mode 100644
index 00000000..bb47c459
--- /dev/null
+++ b/vendor/luasocket/src/select.c
@@ -0,0 +1,214 @@
1/*=========================================================================*\
2* Select implementation
3* LuaSocket toolkit
4\*=========================================================================*/
5#include "luasocket.h"
6
7#include "socket.h"
8#include "timeout.h"
9#include "select.h"
10
11#include <string.h>
12
13/*=========================================================================*\
14* Internal function prototypes.
15\*=========================================================================*/
16static t_socket getfd(lua_State *L);
17static int dirty(lua_State *L);
18static void collect_fd(lua_State *L, int tab, int itab,
19 fd_set *set, t_socket *max_fd);
20static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set);
21static void return_fd(lua_State *L, fd_set *set, t_socket max_fd,
22 int itab, int tab, int start);
23static void make_assoc(lua_State *L, int tab);
24static int global_select(lua_State *L);
25
26/* functions in library namespace */
27static luaL_Reg func[] = {
28 {"select", global_select},
29 {NULL, NULL}
30};
31
32/*-------------------------------------------------------------------------*\
33* Initializes module
34\*-------------------------------------------------------------------------*/
35int select_open(lua_State *L) {
36 lua_pushstring(L, "_SETSIZE");
37 lua_pushinteger(L, FD_SETSIZE);
38 lua_rawset(L, -3);
39 lua_pushstring(L, "_SOCKETINVALID");
40 lua_pushinteger(L, SOCKET_INVALID);
41 lua_rawset(L, -3);
42 luaL_setfuncs(L, func, 0);
43 return 0;
44}
45
46/*=========================================================================*\
47* Global Lua functions
48\*=========================================================================*/
49/*-------------------------------------------------------------------------*\
50* Waits for a set of sockets until a condition is met or timeout.
51\*-------------------------------------------------------------------------*/
52static int global_select(lua_State *L) {
53 int rtab, wtab, itab, ret, ndirty;
54 t_socket max_fd = SOCKET_INVALID;
55 fd_set rset, wset;
56 t_timeout tm;
57 double t = luaL_optnumber(L, 3, -1);
58 FD_ZERO(&rset); FD_ZERO(&wset);
59 lua_settop(L, 3);
60 lua_newtable(L); itab = lua_gettop(L);
61 lua_newtable(L); rtab = lua_gettop(L);
62 lua_newtable(L); wtab = lua_gettop(L);
63 collect_fd(L, 1, itab, &rset, &max_fd);
64 collect_fd(L, 2, itab, &wset, &max_fd);
65 ndirty = check_dirty(L, 1, rtab, &rset);
66 t = ndirty > 0? 0.0: t;
67 timeout_init(&tm, t, -1);
68 timeout_markstart(&tm);
69 ret = socket_select(max_fd+1, &rset, &wset, NULL, &tm);
70 if (ret > 0 || ndirty > 0) {
71 return_fd(L, &rset, max_fd+1, itab, rtab, ndirty);
72 return_fd(L, &wset, max_fd+1, itab, wtab, 0);
73 make_assoc(L, rtab);
74 make_assoc(L, wtab);
75 return 2;
76 } else if (ret == 0) {
77 lua_pushstring(L, "timeout");
78 return 3;
79 } else {
80 luaL_error(L, "select failed");
81 return 3;
82 }
83}
84
85/*=========================================================================*\
86* Internal functions
87\*=========================================================================*/
88static t_socket getfd(lua_State *L) {
89 t_socket fd = SOCKET_INVALID;
90 lua_pushstring(L, "getfd");
91 lua_gettable(L, -2);
92 if (!lua_isnil(L, -1)) {
93 lua_pushvalue(L, -2);
94 lua_call(L, 1, 1);
95 if (lua_isnumber(L, -1)) {
96 double numfd = lua_tonumber(L, -1);
97 fd = (numfd >= 0.0)? (t_socket) numfd: SOCKET_INVALID;
98 }
99 }
100 lua_pop(L, 1);
101 return fd;
102}
103
104static int dirty(lua_State *L) {
105 int is = 0;
106 lua_pushstring(L, "dirty");
107 lua_gettable(L, -2);
108 if (!lua_isnil(L, -1)) {
109 lua_pushvalue(L, -2);
110 lua_call(L, 1, 1);
111 is = lua_toboolean(L, -1);
112 }
113 lua_pop(L, 1);
114 return is;
115}
116
117static void collect_fd(lua_State *L, int tab, int itab,
118 fd_set *set, t_socket *max_fd) {
119 int i = 1, n = 0;
120 /* nil is the same as an empty table */
121 if (lua_isnil(L, tab)) return;
122 /* otherwise we need it to be a table */
123 luaL_checktype(L, tab, LUA_TTABLE);
124 for ( ;; ) {
125 t_socket fd;
126 lua_pushnumber(L, i);
127 lua_gettable(L, tab);
128 if (lua_isnil(L, -1)) {
129 lua_pop(L, 1);
130 break;
131 }
132 /* getfd figures out if this is a socket */
133 fd = getfd(L);
134 if (fd != SOCKET_INVALID) {
135 /* make sure we don't overflow the fd_set */
136#ifdef _WIN32
137 if (n >= FD_SETSIZE)
138 luaL_argerror(L, tab, "too many sockets");
139#else
140 if (fd >= FD_SETSIZE)
141 luaL_argerror(L, tab, "descriptor too large for set size");
142#endif
143 FD_SET(fd, set);
144 n++;
145 /* keep track of the largest descriptor so far */
146 if (*max_fd == SOCKET_INVALID || *max_fd < fd)
147 *max_fd = fd;
148 /* make sure we can map back from descriptor to the object */
149 lua_pushnumber(L, (lua_Number) fd);
150 lua_pushvalue(L, -2);
151 lua_settable(L, itab);
152 }
153 lua_pop(L, 1);
154 i = i + 1;
155 }
156}
157
158static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set) {
159 int ndirty = 0, i = 1;
160 if (lua_isnil(L, tab))
161 return 0;
162 for ( ;; ) {
163 t_socket fd;
164 lua_pushnumber(L, i);
165 lua_gettable(L, tab);
166 if (lua_isnil(L, -1)) {
167 lua_pop(L, 1);
168 break;
169 }
170 fd = getfd(L);
171 if (fd != SOCKET_INVALID && dirty(L)) {
172 lua_pushnumber(L, ++ndirty);
173 lua_pushvalue(L, -2);
174 lua_settable(L, dtab);
175 FD_CLR(fd, set);
176 }
177 lua_pop(L, 1);
178 i = i + 1;
179 }
180 return ndirty;
181}
182
183static void return_fd(lua_State *L, fd_set *set, t_socket max_fd,
184 int itab, int tab, int start) {
185 t_socket fd;
186 for (fd = 0; fd < max_fd; fd++) {
187 if (FD_ISSET(fd, set)) {
188 lua_pushnumber(L, ++start);
189 lua_pushnumber(L, (lua_Number) fd);
190 lua_gettable(L, itab);
191 lua_settable(L, tab);
192 }
193 }
194}
195
196static void make_assoc(lua_State *L, int tab) {
197 int i = 1, atab;
198 lua_newtable(L); atab = lua_gettop(L);
199 for ( ;; ) {
200 lua_pushnumber(L, i);
201 lua_gettable(L, tab);
202 if (!lua_isnil(L, -1)) {
203 lua_pushnumber(L, i);
204 lua_pushvalue(L, -2);
205 lua_settable(L, atab);
206 lua_pushnumber(L, i);
207 lua_settable(L, atab);
208 } else {
209 lua_pop(L, 1);
210 break;
211 }
212 i = i+1;
213 }
214}