aboutsummaryrefslogtreecommitdiff
path: root/src/select.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/select.c')
-rw-r--r--src/select.c191
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 */ 15static int meth_set(lua_State *L);
17static int local_select(lua_State *L); 16static int meth_isset(lua_State *L);
18static int local_getfd(lua_State *L); 17static int c_select(lua_State *L);
19static int local_pending(lua_State *L); 18static int global_select(lua_State *L);
20static int local_FD_SET(lua_State *L); 19static void check_obj_tab(lua_State *L, int tabidx);
21static int local_FD_ISSET(lua_State *L);
22 20
23static int select_lua_select(lua_State *L); 21/* fd_set object methods */
22static 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 29static luaL_reg func[] = {
27* Input 30 {"select", global_select},
28* name: type name 31 {NULL, NULL}
29\*-------------------------------------------------------------------------*/ 32};
30void 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
40void select_open(lua_State *L) 34void 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\*-------------------------------------------------------------------------*/
72static int select_lua_select(lua_State *L) 51static 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
99static int local_getfd(lua_State *L) 79static 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
110static 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
122static 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
139static int local_FD_SET(lua_State *L) 93static 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
147static int local_FD_ISSET(lua_State *L) 101static 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
110static 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}