aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDiego Nehab <diego@tecgraf.puc-rio.br>2002-03-22 20:07:43 +0000
committerDiego Nehab <diego@tecgraf.puc-rio.br>2002-03-22 20:07:43 +0000
commit3bd99ec59996653011f0eb40a0be4a523fe82897 (patch)
tree71030ee34cbc705517111fe8c6e4a459a6defe20 /src
parente2d21b237d0457fde60c1803ee4153ef7238e0eb (diff)
downloadluasocket-3bd99ec59996653011f0eb40a0be4a523fe82897.tar.gz
luasocket-3bd99ec59996653011f0eb40a0be4a523fe82897.tar.bz2
luasocket-3bd99ec59996653011f0eb40a0be4a523fe82897.zip
Initial revision
Diffstat (limited to 'src')
-rw-r--r--src/select.c194
1 files changed, 194 insertions, 0 deletions
diff --git a/src/select.c b/src/select.c
new file mode 100644
index 0000000..1f83b7a
--- /dev/null
+++ b/src/select.c
@@ -0,0 +1,194 @@
1/*-------------------------------------------------------------------------*\
2* Marks type as selectable
3* Input
4* name: type name
5\*-------------------------------------------------------------------------*/
6void slct_addclass(lua_State *L, cchar *lsclass)
7{
8 lua_pushstring(L, "selectable sockets");
9 lua_gettable(L, LUA_REGISTRYINDEX);
10 lua_pushstring(L, lsclass);
11 lua_pushnumber(L, 1);
12 lua_settable(L, -3);
13 lua_pop(L, 2);
14}
15
16/*-------------------------------------------------------------------------*\
17* Gets a pointer to a socket structure from a userdata
18* Input
19* pos: userdata stack index
20* Returns
21* pointer to structure, or NULL if invalid type
22\*-------------------------------------------------------------------------*/
23static p_sock ls_toselectable(lua_State *L)
24{
25 lua_getregistry(L);
26 lua_pushstring(L, "sock(selectable)");
27 lua_gettable(L, -2);
28 lua_pushstring(L, lua_type(L, -3));
29 lua_gettable(L, -2);
30 if (lua_isnil(L, -1)) {
31 lua_pop(L, 3);
32 return NULL;
33 } else {
34 lua_pop(L, 3);
35 return (p_sock) lua_touserdata(L, -1);
36 }
37}
38
39/*-------------------------------------------------------------------------*\
40* Waits for a set of sockets until a condition is met or timeout.
41* Lua Input: {input}, {output} [, timeout]
42* {input}: table of sockets to be tested for input
43* {output}: table of sockets to be tested for output
44* timeout: maximum amount of time to wait for condition, in seconds
45* Lua Returns: {input}, {output}, err
46* {input}: table with sockets ready for input
47* {output}: table with sockets ready for output
48* err: "timeout" or nil
49\*-------------------------------------------------------------------------*/
50int global_select(lua_State *L)
51{
52 int ms = lua_isnil(L, 3) ? -1 : (int) (luaL_opt_number(L, 3, -1) * 1000);
53 fd_set rfds, *prfds = NULL, wfds, *pwfds = NULL;
54 struct timeval tv, *ptv = NULL;
55 unsigned max = 0;
56 int byfds, readable, writable;
57 int toread = 1, towrite = 2;
58 lua_newtable(L); byfds = lua_gettop(L); /* sockets indexed by descriptor */
59 lua_newtable(L); readable = lua_gettop(L);
60 lua_newtable(L); writable = lua_gettop(L);
61 /* collect sockets to be tested into FD_SET structures and fill byfds */
62 if (lua_istable(L, toread))
63 prfds = tab2rfds(L, toread, &rfds, &max, byfds, readable, &ms);
64 else if (!lua_isnil(L, toread))
65 luaL_argerror(L, toread, "expected table or nil");
66 if (lua_istable(L, towrite))
67 pwfds = tab2wfds(L, towrite, &wfds, &max, byfds);
68 else if (!lua_isnil(L, towrite))
69 luaL_argerror(L, towrite, "expected table or nil");
70 /* fill timeval structure */
71 if (ms >= 0) {
72 tv.tv_sec = ms / 1000;
73 tv.tv_usec = (ms % 1000) * 1000;
74 ptv = &tv;
75 } else ptv = NULL; /* ptv == NULL when we don't have timeout */
76 /* see if we can read, write or if we timedout */
77 if (select(max+1, prfds, pwfds, NULL, ptv) <= 0 && ms >= 0) {
78 ls_pusherror(L, LS_TIMEOUT);
79 return 3;
80 }
81 /* collect readable and writable sockets into result tables */
82 fds2tab(L, prfds, max+1, byfds, readable);
83 fds2tab(L, pwfds, max+1, byfds, writable);
84 lua_pushnil(L);
85 return 3;
86}
87
88/*=========================================================================*\
89* Select auxiliar functions
90\*=========================================================================*/
91/*-------------------------------------------------------------------------*\
92* Converts a FD_SET structure into a socket table set
93* Input
94* fds: pointer to FD_SET structure
95* max: 1 plus the largest descriptor value in FD_SET
96* byfds: table indexed by descriptor number, with corresponding socket tables
97* can: table to receive corresponding socket table set
98\*-------------------------------------------------------------------------*/
99static void fds2tab(lua_State *L, fd_set *fds, int max, int byfds, int can)
100{
101 int s;
102 if (!fds) return;
103 for (s = 0; s < max; s++) {
104 if (FD_ISSET(s, fds)) {
105 lua_pushnumber(L, lua_getn(L, can) + 1);
106 lua_pushnumber(L, s);
107 lua_gettable(L, byfds);
108 lua_settable(L, can);
109 }
110 }
111}
112
113/*-------------------------------------------------------------------------*\
114* Converts a socket table set ito a FD_SET structure
115* Input
116* towrite: socket table set
117* Output
118* wfds: pointer to FD_SET structure to be filled
119* max: largest descriptor value found in wfds
120* byfds: table indexed by descriptor number, with corresponding socket tables
121\*-------------------------------------------------------------------------*/
122static fd_set *tab2wfds(lua_State *L, int towrite, fd_set *wfds,
123 int *max, int byfds)
124{
125 int empty = 1;
126 FD_ZERO(wfds);
127 lua_pushnil(L);
128 while (lua_next(L, towrite)) {
129 p_sock sock = ls_toselectable(L);
130 if (sock) { /* skip strange fields */
131 NET_FD s = sock->fd;
132 if (s != NET_INVALIDFD) { /* skip closed sockets */
133 lua_pushnumber(L, s);
134 lua_pushvalue(L, -2);
135 lua_settable(L, byfds);
136 if (s > *max) *max = s;
137 FD_SET(s, wfds);
138 empty = 0;
139 }
140 }
141 /* get rid of value and expose index */
142 lua_pop(L, 1);
143 }
144 if (empty) return NULL;
145 else return wfds;
146}
147
148/*-------------------------------------------------------------------------*\
149* Converts a socket table set ito a FD_SET structure
150* Input
151* toread: socket table set
152* Output
153* rfds: pointer to FD_SET structure to be filled
154* max: largest descriptor value found in rfds
155* byfds: table indexed by descriptor number, with corresponding socket tables
156* readable: table to receive socket table if socket is obviously readable
157* ms: will be zeroed if a readable socket is detected
158\*-------------------------------------------------------------------------*/
159static fd_set *tab2rfds(lua_State *L, int toread, fd_set *rfds,
160 int *max, int byfds, int readable, int *ms)
161{
162 int empty = 1;
163 FD_ZERO(rfds);
164 lua_pushnil(L);
165 while (lua_next(L, toread)) {
166 p_sock sock = ls_toselectable(L);
167 if (sock) { /* skip strange fields */
168 NET_FD s = sock->fd;
169 if (s != NET_INVALID) { /* skip closed sockets */
170 /* a socket can have unread data in our internal buffer. we
171 pass them straight to the readable set, and test only to
172 find out which of the other sockets can be written to or
173 read from immediately. */
174 if (sock->vt->readable(sock)) {
175 *ms = 0;
176 lua_pushnumber(L, lua_getn(L, readable) + 1);
177 lua_pushvalue(L, -2);
178 lua_settable(L, readable);
179 } else {
180 lua_pushnumber(L, s);
181 lua_pushvalue(L, -2);
182 lua_settable(L, byfds);
183 if (s > *max) *max = s;
184 FD_SET(s, rfds);
185 empty = 0;
186 }
187 }
188 }
189 /* get rid of value and exposed index */
190 lua_pop(L, 1);
191 }
192 if (empty) return NULL;
193 else return rfds;
194}