2003-03-28 22:08:50 +01:00
|
|
|
/*=========================================================================*\
|
|
|
|
* Select implementation
|
2003-06-26 20:47:49 +02:00
|
|
|
* LuaSocket toolkit
|
|
|
|
*
|
2003-03-28 22:08:50 +01:00
|
|
|
* RCS ID: $Id$
|
|
|
|
\*=========================================================================*/
|
2003-03-28 23:14:06 +01:00
|
|
|
#include <string.h>
|
2003-06-09 20:23:40 +02:00
|
|
|
|
2005-09-29 08:11:42 +02:00
|
|
|
#include "lua.h"
|
|
|
|
#include "lauxlib.h"
|
2003-03-21 00:11:25 +01:00
|
|
|
|
2003-06-09 20:23:40 +02:00
|
|
|
#include "socket.h"
|
2004-07-01 05:32:09 +02:00
|
|
|
#include "timeout.h"
|
2003-06-09 20:23:40 +02:00
|
|
|
#include "select.h"
|
2002-07-03 21:06:53 +02:00
|
|
|
|
2003-06-26 20:47:49 +02:00
|
|
|
/*=========================================================================*\
|
|
|
|
* Internal function prototypes.
|
|
|
|
\*=========================================================================*/
|
2004-06-15 08:24:00 +02:00
|
|
|
static int getfd(lua_State *L);
|
|
|
|
static int dirty(lua_State *L);
|
|
|
|
static int collect_fd(lua_State *L, int tab, int max_fd, int itab, fd_set *set);
|
|
|
|
static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set);
|
|
|
|
static void return_fd(lua_State *L, fd_set *set, int max_fd,
|
|
|
|
int itab, int tab, int start);
|
|
|
|
static void make_assoc(lua_State *L, int tab);
|
2003-06-09 20:23:40 +02:00
|
|
|
static int global_select(lua_State *L);
|
2002-07-03 21:06:53 +02:00
|
|
|
|
2003-06-09 20:23:40 +02:00
|
|
|
/* functions in library namespace */
|
|
|
|
static luaL_reg func[] = {
|
|
|
|
{"select", global_select},
|
|
|
|
{NULL, NULL}
|
|
|
|
};
|
2002-03-22 21:07:43 +01:00
|
|
|
|
2003-06-26 20:47:49 +02:00
|
|
|
/*=========================================================================*\
|
2004-06-15 08:24:00 +02:00
|
|
|
* Exported functions
|
2003-06-26 20:47:49 +02:00
|
|
|
\*=========================================================================*/
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Initializes module
|
|
|
|
\*-------------------------------------------------------------------------*/
|
2004-06-15 08:24:00 +02:00
|
|
|
int select_open(lua_State *L) {
|
|
|
|
luaL_openlib(L, NULL, func, 0);
|
2004-02-04 15:29:11 +01:00
|
|
|
return 0;
|
2002-03-22 21:07:43 +01:00
|
|
|
}
|
|
|
|
|
2003-06-26 20:47:49 +02:00
|
|
|
/*=========================================================================*\
|
|
|
|
* Global Lua functions
|
|
|
|
\*=========================================================================*/
|
2002-03-22 21:07:43 +01:00
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Waits for a set of sockets until a condition is met or timeout.
|
|
|
|
\*-------------------------------------------------------------------------*/
|
2004-06-15 08:24:00 +02:00
|
|
|
static int global_select(lua_State *L) {
|
2004-07-01 05:32:09 +02:00
|
|
|
int rtab, wtab, itab, max_fd, ret, ndirty;
|
2004-06-15 08:24:00 +02:00
|
|
|
fd_set rset, wset;
|
2005-10-07 06:40:59 +02:00
|
|
|
t_timeout tm;
|
2004-07-01 05:32:09 +02:00
|
|
|
double t = luaL_optnumber(L, 3, -1);
|
2004-06-15 08:24:00 +02:00
|
|
|
FD_ZERO(&rset); FD_ZERO(&wset);
|
2003-06-09 20:23:40 +02:00
|
|
|
lua_settop(L, 3);
|
2004-06-15 08:24:00 +02:00
|
|
|
lua_newtable(L); itab = lua_gettop(L);
|
|
|
|
lua_newtable(L); rtab = lua_gettop(L);
|
|
|
|
lua_newtable(L); wtab = lua_gettop(L);
|
|
|
|
max_fd = collect_fd(L, 1, -1, itab, &rset);
|
|
|
|
ndirty = check_dirty(L, 1, rtab, &rset);
|
2004-07-01 05:32:09 +02:00
|
|
|
t = ndirty > 0? 0.0: t;
|
2005-10-07 06:40:59 +02:00
|
|
|
timeout_init(&tm, t, -1);
|
|
|
|
timeout_markstart(&tm);
|
2004-06-15 08:24:00 +02:00
|
|
|
max_fd = collect_fd(L, 2, max_fd, itab, &wset);
|
2005-10-07 06:40:59 +02:00
|
|
|
ret = socket_select(max_fd+1, &rset, &wset, NULL, &tm);
|
2004-07-16 08:48:48 +02:00
|
|
|
if (ret > 0 || ndirty > 0) {
|
2004-06-15 08:24:00 +02:00
|
|
|
return_fd(L, &rset, max_fd+1, itab, rtab, ndirty);
|
|
|
|
return_fd(L, &wset, max_fd+1, itab, wtab, 0);
|
|
|
|
make_assoc(L, rtab);
|
|
|
|
make_assoc(L, wtab);
|
|
|
|
return 2;
|
|
|
|
} else if (ret == 0) {
|
|
|
|
lua_pushstring(L, "timeout");
|
|
|
|
return 3;
|
|
|
|
} else {
|
|
|
|
lua_pushstring(L, "error");
|
|
|
|
return 3;
|
|
|
|
}
|
2002-03-22 21:07:43 +01:00
|
|
|
}
|
|
|
|
|
2003-06-26 20:47:49 +02:00
|
|
|
/*=========================================================================*\
|
2004-06-15 08:24:00 +02:00
|
|
|
* Internal functions
|
2003-06-26 20:47:49 +02:00
|
|
|
\*=========================================================================*/
|
2004-06-15 08:24:00 +02:00
|
|
|
static int getfd(lua_State *L) {
|
|
|
|
int fd = -1;
|
|
|
|
lua_pushstring(L, "getfd");
|
|
|
|
lua_gettable(L, -2);
|
|
|
|
if (!lua_isnil(L, -1)) {
|
|
|
|
lua_pushvalue(L, -2);
|
|
|
|
lua_call(L, 1, 1);
|
|
|
|
if (lua_isnumber(L, -1))
|
2004-06-17 02:18:48 +02:00
|
|
|
fd = (int) lua_tonumber(L, -1);
|
2004-06-15 08:24:00 +02:00
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
return fd;
|
2002-07-03 21:06:53 +02:00
|
|
|
}
|
|
|
|
|
2004-06-15 08:24:00 +02:00
|
|
|
static int dirty(lua_State *L) {
|
|
|
|
int is = 0;
|
|
|
|
lua_pushstring(L, "dirty");
|
|
|
|
lua_gettable(L, -2);
|
|
|
|
if (!lua_isnil(L, -1)) {
|
|
|
|
lua_pushvalue(L, -2);
|
|
|
|
lua_call(L, 1, 1);
|
|
|
|
is = lua_toboolean(L, -1);
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
return is;
|
2002-03-22 21:07:43 +01:00
|
|
|
}
|
2003-06-09 20:23:40 +02:00
|
|
|
|
2004-06-15 08:24:00 +02:00
|
|
|
static int collect_fd(lua_State *L, int tab, int max_fd,
|
|
|
|
int itab, fd_set *set) {
|
|
|
|
int i = 1;
|
|
|
|
if (lua_isnil(L, tab))
|
|
|
|
return max_fd;
|
|
|
|
while (1) {
|
|
|
|
int fd;
|
|
|
|
lua_pushnumber(L, i);
|
|
|
|
lua_gettable(L, tab);
|
|
|
|
if (lua_isnil(L, -1)) {
|
|
|
|
lua_pop(L, 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
fd = getfd(L);
|
2005-06-13 00:02:21 +02:00
|
|
|
if (fd >= 0) {
|
2004-06-15 08:24:00 +02:00
|
|
|
FD_SET(fd, set);
|
|
|
|
if (max_fd < fd) max_fd = fd;
|
|
|
|
lua_pushnumber(L, fd);
|
|
|
|
lua_pushvalue(L, -2);
|
|
|
|
lua_settable(L, itab);
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
i = i + 1;
|
|
|
|
}
|
|
|
|
return max_fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set) {
|
|
|
|
int ndirty = 0, i = 1;
|
|
|
|
if (lua_isnil(L, tab))
|
|
|
|
return 0;
|
|
|
|
while (1) {
|
|
|
|
int fd;
|
|
|
|
lua_pushnumber(L, i);
|
|
|
|
lua_gettable(L, tab);
|
|
|
|
if (lua_isnil(L, -1)) {
|
|
|
|
lua_pop(L, 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
fd = getfd(L);
|
2005-06-13 00:02:21 +02:00
|
|
|
if (fd >= 0 && dirty(L)) {
|
2004-06-15 08:24:00 +02:00
|
|
|
lua_pushnumber(L, ++ndirty);
|
|
|
|
lua_pushvalue(L, -2);
|
|
|
|
lua_settable(L, dtab);
|
|
|
|
FD_CLR(fd, set);
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
i = i + 1;
|
|
|
|
}
|
|
|
|
return ndirty;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void return_fd(lua_State *L, fd_set *set, int max_fd,
|
|
|
|
int itab, int tab, int start) {
|
|
|
|
int fd;
|
|
|
|
for (fd = 0; fd < max_fd; fd++) {
|
|
|
|
if (FD_ISSET(fd, set)) {
|
|
|
|
lua_pushnumber(L, ++start);
|
|
|
|
lua_pushnumber(L, fd);
|
|
|
|
lua_gettable(L, itab);
|
|
|
|
lua_settable(L, tab);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void make_assoc(lua_State *L, int tab) {
|
|
|
|
int i = 1, atab;
|
|
|
|
lua_newtable(L); atab = lua_gettop(L);
|
|
|
|
while (1) {
|
|
|
|
lua_pushnumber(L, i);
|
|
|
|
lua_gettable(L, tab);
|
|
|
|
if (!lua_isnil(L, -1)) {
|
|
|
|
lua_pushnumber(L, i);
|
|
|
|
lua_pushvalue(L, -2);
|
|
|
|
lua_settable(L, atab);
|
|
|
|
lua_pushnumber(L, i);
|
|
|
|
lua_settable(L, atab);
|
|
|
|
} else {
|
|
|
|
lua_pop(L, 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
i = i+1;
|
|
|
|
}
|
2003-06-26 20:47:49 +02:00
|
|
|
}
|
2004-06-15 08:24:00 +02:00
|
|
|
|