2002-07-03 21:06:53 +02:00
|
|
|
#include <lua.h>
|
|
|
|
#include "lspriv.h"
|
|
|
|
#include "lsselect.h"
|
|
|
|
#include "lsfd.h"
|
|
|
|
|
|
|
|
/* auxiliar functions */
|
|
|
|
static int local_select(lua_State *L);
|
|
|
|
static int local_getfd(lua_State *L);
|
|
|
|
static int local_pending(lua_State *L);
|
|
|
|
static int local_FD_SET(lua_State *L);
|
|
|
|
static int local_FD_ISSET(lua_State *L);
|
|
|
|
|
|
|
|
static int select_lua_select(lua_State *L);
|
|
|
|
|
2002-03-22 21:07:43 +01:00
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Marks type as selectable
|
|
|
|
* Input
|
|
|
|
* name: type name
|
|
|
|
\*-------------------------------------------------------------------------*/
|
2002-07-03 21:06:53 +02:00
|
|
|
void select_addclass(lua_State *L, cchar *lsclass)
|
2002-03-22 21:07:43 +01:00
|
|
|
{
|
2002-07-03 21:06:53 +02:00
|
|
|
lua_pushstring(L, "luasocket(select)");
|
2002-03-22 21:07:43 +01:00
|
|
|
lua_gettable(L, LUA_REGISTRYINDEX);
|
|
|
|
lua_pushstring(L, lsclass);
|
|
|
|
lua_pushnumber(L, 1);
|
|
|
|
lua_settable(L, -3);
|
2002-07-03 21:06:53 +02:00
|
|
|
lua_pop(L, 1);
|
2002-03-22 21:07:43 +01:00
|
|
|
}
|
|
|
|
|
2002-07-03 21:06:53 +02:00
|
|
|
void select_open(lua_State *L)
|
2002-03-22 21:07:43 +01:00
|
|
|
{
|
2002-07-03 21:06:53 +02:00
|
|
|
/* push select auxiliar lua function and register
|
|
|
|
* select_lua_select with it as an upvalue */
|
|
|
|
#include "lsselect.loh"
|
|
|
|
lua_pushcclosure(L, select_lua_select, 1);
|
|
|
|
lua_setglobal(L, "select");
|
|
|
|
/* create luasocket(select) table */
|
|
|
|
lua_pushstring(L, "luasocket(select)");
|
|
|
|
lua_newtable(L);
|
|
|
|
lua_settable(L, LUA_REGISTRYINDEX);
|
2002-03-22 21:07:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Waits for a set of sockets until a condition is met or timeout.
|
|
|
|
* Lua Input: {input}, {output} [, timeout]
|
|
|
|
* {input}: table of sockets to be tested for input
|
|
|
|
* {output}: table of sockets to be tested for output
|
|
|
|
* timeout: maximum amount of time to wait for condition, in seconds
|
|
|
|
* Lua Returns: {input}, {output}, err
|
|
|
|
* {input}: table with sockets ready for input
|
|
|
|
* {output}: table with sockets ready for output
|
|
|
|
* err: "timeout" or nil
|
|
|
|
\*-------------------------------------------------------------------------*/
|
2002-07-03 21:06:53 +02:00
|
|
|
static int select_lua_select(lua_State *L)
|
2002-03-22 21:07:43 +01:00
|
|
|
{
|
2002-07-03 21:06:53 +02:00
|
|
|
fd_set read, write;
|
|
|
|
FD_ZERO(&read);
|
|
|
|
FD_ZERO(&write);
|
|
|
|
/* push select lua auxiliar function */
|
|
|
|
lua_pushvalue(L, lua_upvalueindex(1)); lua_insert(L, 1);
|
|
|
|
/* make sure we have enough arguments (nil is the default) */
|
|
|
|
lua_settop(L, 4);
|
|
|
|
/* pass FD_SET and manipulation functions */
|
|
|
|
lua_newuserdatabox(L, &read);
|
|
|
|
lua_newuserdatabox(L, &write);
|
|
|
|
lua_pushcfunction(L, local_FD_SET);
|
|
|
|
lua_pushcfunction(L, local_FD_ISSET);
|
|
|
|
/* pass getfd function with selectable table as upvalue */
|
|
|
|
lua_pushstring(L, "luasocket(select)"); lua_gettable(L, LUA_REGISTRYINDEX);
|
|
|
|
lua_pushcclosure(L, local_getfd, 1);
|
|
|
|
/* pass pending function */
|
|
|
|
lua_pushstring(L, "luasocket(select)"); lua_gettable(L, LUA_REGISTRYINDEX);
|
|
|
|
lua_pushcclosure(L, local_pending, 1);
|
|
|
|
/* pass select auxiliar C function */
|
|
|
|
lua_pushcfunction(L, local_select);
|
|
|
|
/* call select auxiliar lua function */
|
|
|
|
lua_call(L, 10, 3);
|
2002-03-22 21:07:43 +01:00
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
|
2002-07-03 21:06:53 +02:00
|
|
|
static int local_getfd(lua_State *L)
|
2002-03-22 21:07:43 +01:00
|
|
|
{
|
2002-07-03 21:06:53 +02:00
|
|
|
priv_pushclass(L, 1);
|
|
|
|
lua_gettable(L, lua_upvalueindex(1));
|
|
|
|
if (!lua_isnil(L, -1)) {
|
|
|
|
p_fd sock = (p_fd) lua_touserdata(L, 1);
|
|
|
|
lua_pushnumber(L, sock->fd);
|
2002-03-22 21:07:43 +01:00
|
|
|
}
|
2002-07-03 21:06:53 +02:00
|
|
|
return 1;
|
2002-03-22 21:07:43 +01:00
|
|
|
}
|
|
|
|
|
2002-07-03 21:06:53 +02:00
|
|
|
static int local_pending(lua_State *L)
|
2002-03-22 21:07:43 +01:00
|
|
|
{
|
2002-07-03 21:06:53 +02:00
|
|
|
priv_pushclass(L, 1);
|
|
|
|
lua_gettable(L, lua_upvalueindex(1));
|
|
|
|
if (!lua_isnil(L, -1)) {
|
|
|
|
p_fd sock = (p_fd) lua_touserdata(L, 1);
|
|
|
|
if (sock->fd_pending(L, sock)) lua_pushnumber(L, 1);
|
|
|
|
else lua_pushnil(L);
|
2002-03-22 21:07:43 +01:00
|
|
|
}
|
2002-07-03 21:06:53 +02:00
|
|
|
return 1;
|
2002-03-22 21:07:43 +01:00
|
|
|
}
|
|
|
|
|
2002-07-03 21:06:53 +02:00
|
|
|
static int local_select(lua_State *L)
|
2002-03-22 21:07:43 +01:00
|
|
|
{
|
2002-07-03 21:06:53 +02:00
|
|
|
int max_fd = (int) lua_tonumber(L, 1);
|
|
|
|
fd_set *read_set = (fd_set *) lua_touserdata(L, 2);
|
|
|
|
fd_set *write_set = (fd_set *) lua_touserdata(L, 3);
|
|
|
|
int deadline = lua_isnil(L, 4) ? -1 : (int)(lua_tonumber(L, 4) * 1000);
|
|
|
|
struct timeval tv;
|
|
|
|
if (deadline >= 0) {
|
|
|
|
tv.tv_sec = deadline / 1000;
|
|
|
|
tv.tv_usec = (deadline % 1000) * 1000;
|
|
|
|
lua_pushnumber(L, select(max_fd, read_set, write_set, NULL, &tv));
|
|
|
|
} else {
|
|
|
|
lua_pushnumber(L, select(max_fd, read_set, write_set, NULL, NULL));
|
2002-03-22 21:07:43 +01:00
|
|
|
}
|
2002-07-03 21:06:53 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int local_FD_SET(lua_State *L)
|
|
|
|
{
|
|
|
|
COMPAT_FD fd = (COMPAT_FD) lua_tonumber(L, 1);
|
|
|
|
fd_set *set = (fd_set *) lua_touserdata(L, 2);
|
|
|
|
if (fd >= 0) FD_SET(fd, set);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int local_FD_ISSET(lua_State *L)
|
|
|
|
{
|
|
|
|
COMPAT_FD fd = (COMPAT_FD) lua_tonumber(L, 1);
|
|
|
|
fd_set *set = (fd_set *) lua_touserdata(L, 2);
|
|
|
|
if (fd >= 0 && FD_ISSET(fd, set)) lua_pushnumber(L, 1);
|
|
|
|
else lua_pushnil(L);
|
|
|
|
return 1;
|
2002-03-22 21:07:43 +01:00
|
|
|
}
|