Select re-implemented in a nicer way.

Few changes in internal class and group registration.
Lua modules are compiled and built into library.
Dynamic library tested in Linux and Mac OS X.
This commit is contained in:
Diego Nehab 2003-06-09 18:23:40 +00:00
parent b2724ad2d1
commit 58bdb658aa
28 changed files with 496 additions and 397 deletions

View File

@ -1,6 +1,8 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- Little program that checks links in HTML files -- Little program that checks links in HTML files
-- LuaSocket 1.5 sample files. -- LuaSocket 1.5 sample files.
-- Author: Diego Nehab
-- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
socket.http.TIMEOUT = 10 socket.http.TIMEOUT = 10

View File

@ -1,6 +1,8 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- Little program to download DICT word definitions -- Little program to download DICT word definitions
-- LuaSocket 1.5 sample files -- LuaSocket 1.5 sample files
-- Author: Diego Nehab
-- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
function get_status(sock, valid) function get_status(sock, valid)
local line, err = sock:receive() local line, err = sock:receive()

View File

@ -1,6 +1,8 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- Little program to download files from URLs -- Little program to download files from URLs
-- LuaSocket 1.5 sample files -- LuaSocket 1.5 sample files
-- Author: Diego Nehab
-- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- formats a number of seconds into human readable form -- formats a number of seconds into human readable form
function nicetime(s) function nicetime(s)

View File

@ -2,22 +2,81 @@
# Distribution makefile # Distribution makefile
#-------------------------------------------------------------------------- #--------------------------------------------------------------------------
DIST = luasocket-1.5-work DIST = luasocket-1.5-alpha
LUA = concat.lua code.lua url.lua http.lua smtp.lua ftp.lua lsselect.lua \ LUA = \
cl-compat.lua concat.lua \
code.lua \
url.lua \
http.lua \
smtp.lua \
ftp.lua \
select.lua \
luasocket.lua
TESTS = testclnt.lua testsrvr.lua testcmd.lua codetest.lua \ TESTS = \
urltest.lua concattest.lua testclnt.lua \
testsrvr.lua \
testcmd.lua \
codetest.lua \
urltest.lua \
concattest.lua \
ftptest.lua \
httptest.lua \
smtptest.lua \
mbox.lua \
udptest.lua
EXAMPLES = check-links.lua daytimeclnt.lua dict.lua echoclnt.lua \ EXAMPLES = \
echosrvr.lua get.lua listener.lua talker.lua tinyirc.lua tftpclnt.lua check-links.lua \
daytimeclnt.lua \
echoclnt.lua \
echosrvr.lua \
get.lua \
listener.lua \
talker.lua \
tinyirc.lua
ETC = \
cl-compat.lua \
tftp.lua \
dict.lua
MAIN = \
auxiliar.c \
auxiliar.h \
buffer.c \
buffer.h \
error.c \
error.h \
inet.c \
inet.h \
io.c \
io.h \
lua.c \
luasocket.c \
luasocket.h \
makefile \
select.c \
select.h \
socket.h \
tcp.c \
tcp.h \
timeout.c \
timeout.h \
udp.c \
udp.h \
usocket.c \
usocket.h \
wsocket.c \
wsocket.h \
dist: dist:
mkdir -p $(DIST)/examples mkdir -p $(DIST)/examples
mkdir -p $(DIST)/tests mkdir -p $(DIST)/tests
cp -vf *.c $(DIST) mkdir -p $(DIST)/etc
cp -vf *.h $(DIST) mkdir -p $(DIST)/lua
cp -vf $(MAIN) $(DIST)
cp -vf $(LUA) $(DIST) cp -vf $(LUA) $(DIST)
cp -vf makefile $(DIST) cp -vf makefile $(DIST)
cp -vf README $(DIST) cp -vf README $(DIST)
@ -25,6 +84,8 @@ dist:
cp -vf README.examples $(DIST)/examples/README cp -vf README.examples $(DIST)/examples/README
cp -vf $(TESTS) $(DIST)/tests cp -vf $(TESTS) $(DIST)/tests
cp -vf README.tests $(DIST)/tests/README cp -vf README.tests $(DIST)/tests/README
cp -vf $(ETC) $(DIST)/etc
cp -vf README.etc $(DIST)/etc/README
tar -zcvf $(DIST).tar.gz $(DIST) tar -zcvf $(DIST).tar.gz $(DIST)
zip -r $(DIST).zip $(DIST) zip -r $(DIST).zip $(DIST)

View File

@ -1,3 +1,9 @@
-----------------------------------------------------------------------------
-- UDP sample: daytime protocol client
-- LuaSocket 1.5 sample files.
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
host = host or "127.0.0.1" host = host or "127.0.0.1"
port = port or 13 port = port or 13
if arg then if arg then

View File

@ -1,3 +1,9 @@
-----------------------------------------------------------------------------
-- UDP sample: echo protocol client
-- LuaSocket 1.5 sample files
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
host = host or "localhost" host = host or "localhost"
port = port or 7 port = port or 7
if arg then if arg then

View File

@ -1,3 +1,9 @@
-----------------------------------------------------------------------------
-- UDP sample: echo protocol server
-- LuaSocket 1.5 sample files
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
host = host or "127.0.0.1" host = host or "127.0.0.1"
port = port or 7 port = port or 7
if arg then if arg then

View File

@ -1,6 +1,8 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- Little program to dump lines received at a given port -- TCP sample: Little program to dump lines received at a given port
-- LuaSocket 1.5 sample files -- LuaSocket 1.5 sample files
-- Author: Diego Nehab
-- RCS ID: $Id$
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
host = host or "*" host = host or "*"
port = port or 8080 port = port or 8080

View File

@ -1,3 +1,9 @@
-----------------------------------------------------------------------------
-- TCP sample: Little program to send text lines to a given host/port
-- LuaSocket 1.5 sample files
-- Author: Diego Nehab
-- RCS ID: $Id$
-----------------------------------------------------------------------------
host = host or "localhost" host = host or "localhost"
port = port or 8080 port = port or 8080
if arg then if arg then

View File

@ -1,16 +1,9 @@
function set_add(set, sock) -----------------------------------------------------------------------------
table.insert(set, sock) -- Select sample: simple text line server
end -- LuaSocket 1.5 sample files.
-- Author: Diego Nehab
function set_remove(set, sock) -- RCS ID: $Id$
for i = 1, table.getn(set) do -----------------------------------------------------------------------------
if set[i] == sock then
table.remove(set, i)
break
end
end
end
host = host or "*" host = host or "*"
port1 = port1 or 8080 port1 = port1 or 8080
port2 = port2 or 8081 port2 = port2 or 8081
@ -21,49 +14,62 @@ if arg then
end end
server1, error = socket.bind(host, port1) server1, error = socket.bind(host, port1)
if not server1 then print(error) exit() end assert(server1, error)
server1:timeout(1) server1:timeout(1)
server2, error = socket.bind(host, port2) server2, error = socket.bind(host, port2)
if not server2 then print(error) exit() end assert(server2, error)
server2:timeout(1) server2:timeout(1)
sock_set = {server1, server2} function newset()
local reverse = {}
local set = {}
setmetatable(set, { __index = {
insert = function(set, value)
table.insert(set, value)
reverse[value] = table.getn(set)
end,
remove = function(set, value)
table.remove(set, reverse[value])
reverse[value] = nil
end,
id = function(set, value)
return reverse[value]
end
}})
return set
end
sock_id = {} sockets = newset()
sock_id[server1] = 1
sock_id[server2] = 2 sockets:insert(server1)
next_id = 3 sockets:insert(server2)
while 1 do while 1 do
local readable, _, error = socket.select(sock_set, nil) local readable, _, error = socket.select(sockets, nil)
for _, sock in readable do for _, input in readable do
-- is it a server socket -- is it a server socket?
if sock_id[sock] < 3 then local id = sockets:id(input)
local incomming = sock:accept() if input == server1 or input == server2 then
if incomming then local new = input:accept()
incomming:timeout(1) if new then
sock_id[incomming] = next_id new:timeout(1)
set_add(sock_set, incomming) sockets:insert(new)
io.write("Added client id ", next_id, ". ", io.write("Server ", id, " got client ", sockets:id(new), "\n")
table.getn(sock_set)-2, " total.\n")
next_id = next_id + 1
end end
-- it is a client socket -- it is a client socket
else else
local line, error = sock:receive() local line, error = input:receive()
local id = sock_id[sock]
if error then if error then
sock:close() input:close()
set_remove(sock_set, sock) io.write("Removing client ", id, "\n")
io.write("Removed client number ", id, ". ", sockets:remove(input)
getn(sock_set)-2, " total.\n")
else else
io.write("Broadcasting line '", id, "> ", line, "'.\n") io.write("Broadcasting line '", id, "> ", line, "'.\n")
__, writable, error = socket.select(nil, sock_set, 1) __, writable, error = socket.select(nil, sockets, 1)
if not error then if not error then
for ___, outgoing in writable do for ___, output in writable do
io.write("Sending to client ", sock_id[outgoing], "\n") io.write("Sending to client ", sockets:id(output), "\n")
outgoing:send(id, "> ", line, "\r\n") output:send(id, "> ", line, "\r\n")
end end
else io.write("No one ready to listen!!!\n") end else io.write("No one ready to listen!!!\n") end
end end

View File

@ -3,12 +3,7 @@
* *
* RCS ID: $Id$ * RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#include "aux.h" #include "auxiliar.h"
/*=========================================================================*\
* Internal function prototypes
\*=========================================================================*/
static void *aux_getgroupudata(lua_State *L, const char *group, int objidx);
/*=========================================================================*\ /*=========================================================================*\
* Exported functions * Exported functions
@ -20,18 +15,19 @@ static void *aux_getgroupudata(lua_State *L, const char *group, int objidx);
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
void aux_newclass(lua_State *L, const char *name, luaL_reg *func) void aux_newclass(lua_State *L, const char *name, luaL_reg *func)
{ {
luaL_newmetatable(L, name); lua_pushstring(L, name);
lua_newtable(L);
lua_pushstring(L, "__index"); lua_pushstring(L, "__index");
lua_newtable(L); lua_newtable(L);
luaL_openlib(L, NULL, func, 0); luaL_openlib(L, NULL, func, 0);
lua_pushstring(L, "class"); lua_pushstring(L, "class");
lua_pushstring(L, name); lua_pushstring(L, name);
lua_settable(L, -3); lua_rawset(L, -3);
lua_settable(L, -3);
lua_pushstring(L, "group"); lua_pushstring(L, "group");
lua_newtable(L); lua_newtable(L);
lua_settable(L, -3); lua_rawset(L, -3);
lua_pop(L, 1); lua_rawset(L, -3);
lua_rawset(L, LUA_REGISTRYINDEX);
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
@ -39,13 +35,16 @@ void aux_newclass(lua_State *L, const char *name, luaL_reg *func)
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
void aux_add2group(lua_State *L, const char *name, const char *group) void aux_add2group(lua_State *L, const char *name, const char *group)
{ {
luaL_getmetatable(L, name); lua_pushstring(L, name);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_pushstring(L, "__index");
lua_rawget(L, -2);
lua_pushstring(L, "group"); lua_pushstring(L, "group");
lua_gettable(L, -2); lua_rawget(L, -2);
lua_pushstring(L, group); lua_pushstring(L, group);
lua_pushnumber(L, 1); lua_pushnumber(L, 1);
lua_settable(L, -3); lua_rawset(L, -3);
lua_pop(L, 2); lua_pop(L, 3);
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
@ -53,7 +52,7 @@ void aux_add2group(lua_State *L, const char *name, const char *group)
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
void *aux_checkclass(lua_State *L, const char *name, int objidx) void *aux_checkclass(lua_State *L, const char *name, int objidx)
{ {
void *data = luaL_checkudata(L, objidx, name); void *data = aux_getclassudata(L, name, objidx);
if (!data) { if (!data) {
char msg[45]; char msg[45];
sprintf(msg, "%.35s expected", name); sprintf(msg, "%.35s expected", name);
@ -81,7 +80,8 @@ void *aux_checkgroup(lua_State *L, const char *group, int objidx)
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
void aux_setclass(lua_State *L, const char *name, int objidx) void aux_setclass(lua_State *L, const char *name, int objidx)
{ {
luaL_getmetatable(L, name); lua_pushstring(L, name);
lua_rawget(L, LUA_REGISTRYINDEX);
if (objidx < 0) objidx--; if (objidx < 0) objidx--;
lua_setmetatable(L, objidx); lua_setmetatable(L, objidx);
} }
@ -92,17 +92,47 @@ void aux_setclass(lua_State *L, const char *name, int objidx)
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Get a userdata if object belongs to a given group. * Get a userdata if object belongs to a given group.
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static void *aux_getgroupudata(lua_State *L, const char *group, int objidx) void *aux_getgroupudata(lua_State *L, const char *group, int objidx)
{ {
if (!lua_getmetatable(L, objidx)) return NULL; if (!lua_getmetatable(L, objidx))
lua_pushstring(L, "group"); return NULL;
lua_gettable(L, -2); lua_pushstring(L, "__index");
if (lua_isnil(L, -1)) { lua_rawget(L, -2);
if (!lua_istable(L, -1)) {
lua_pop(L, 2); lua_pop(L, 2);
return NULL; return NULL;
} }
lua_pushstring(L, "group");
lua_rawget(L, -2);
if (!lua_istable(L, -1)) {
lua_pop(L, 3);
return NULL;
}
lua_pushstring(L, group); lua_pushstring(L, group);
lua_gettable(L, -2); lua_rawget(L, -2);
if (lua_isnil(L, -1)) {
lua_pop(L, 4);
return NULL;
}
lua_pop(L, 4);
return lua_touserdata(L, objidx);
}
/*-------------------------------------------------------------------------*\
* Get a userdata if object belongs to a given class.
\*-------------------------------------------------------------------------*/
void *aux_getclassudata(lua_State *L, const char *group, int objidx)
{
if (!lua_getmetatable(L, objidx))
return NULL;
lua_pushstring(L, "__index");
lua_rawget(L, -2);
if (!lua_istable(L, -1)) {
lua_pop(L, 2);
return NULL;
}
lua_pushstring(L, "class");
lua_rawget(L, -2);
if (lua_isnil(L, -1)) { if (lua_isnil(L, -1)) {
lua_pop(L, 3); lua_pop(L, 3);
return NULL; return NULL;
@ -110,4 +140,3 @@ static void *aux_getgroupudata(lua_State *L, const char *group, int objidx)
lua_pop(L, 3); lua_pop(L, 3);
return lua_touserdata(L, objidx); return lua_touserdata(L, objidx);
} }

View File

@ -13,6 +13,8 @@ void aux_newclass(lua_State *L, const char *name, luaL_reg *func);
void aux_add2group(lua_State *L, const char *name, const char *group); void aux_add2group(lua_State *L, const char *name, const char *group);
void *aux_checkclass(lua_State *L, const char *name, int objidx); void *aux_checkclass(lua_State *L, const char *name, int objidx);
void *aux_checkgroup(lua_State *L, const char *group, int objidx); void *aux_checkgroup(lua_State *L, const char *group, int objidx);
void *aux_getclassudata(lua_State *L, const char *group, int objidx);
void *aux_getgroupudata(lua_State *L, const char *group, int objidx);
void aux_setclass(lua_State *L, const char *name, int objidx); void aux_setclass(lua_State *L, const char *name, int objidx);
/* min and max macros */ /* min and max macros */

View File

@ -7,8 +7,8 @@
#include <lauxlib.h> #include <lauxlib.h>
#include "error.h" #include "error.h"
#include "aux.h" #include "auxiliar.h"
#include "buf.h" #include "buffer.h"
/*=========================================================================*\ /*=========================================================================*\
* Internal function prototypes * Internal function prototypes

View File

@ -8,7 +8,7 @@
#include <lua.h> #include <lua.h>
#include "io.h" #include "io.h"
#include "tm.h" #include "timeout.h"
/* buffer size in bytes */ /* buffer size in bytes */
#define BUF_SIZE 8192 #define BUF_SIZE 8192

View File

@ -38,6 +38,7 @@ static luaL_reg func[] = {
void inet_open(lua_State *L) void inet_open(lua_State *L)
{ {
luaL_openlib(L, LUASOCKET_LIBNAME, func, 0); luaL_openlib(L, LUASOCKET_LIBNAME, func, 0);
lua_pop(L, 1);
} }
/*=========================================================================*\ /*=========================================================================*\
@ -114,7 +115,7 @@ static int inet_global_tohostname(lua_State *L)
int inet_meth_getpeername(lua_State *L, p_sock ps) int inet_meth_getpeername(lua_State *L, p_sock ps)
{ {
struct sockaddr_in peer; struct sockaddr_in peer;
size_t peer_len = sizeof(peer); socklen_t peer_len = sizeof(peer);
if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) { if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) {
lua_pushnil(L); lua_pushnil(L);
return 1; return 1;
@ -135,7 +136,7 @@ int inet_meth_getpeername(lua_State *L, p_sock ps)
int inet_meth_getsockname(lua_State *L, p_sock ps) int inet_meth_getsockname(lua_State *L, p_sock ps)
{ {
struct sockaddr_in local; struct sockaddr_in local;
size_t local_len = sizeof(local); socklen_t local_len = sizeof(local);
if (getsockname(*ps, (SA *) &local, &local_len) < 0) { if (getsockname(*ps, (SA *) &local, &local_len) < 0) {
lua_pushnil(L); lua_pushnil(L);
return 1; return 1;

View File

@ -7,7 +7,7 @@
#define INET_H #define INET_H
#include <lua.h> #include <lua.h>
#include "sock.h" #include "socket.h"
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Exported functions * Exported functions

View File

@ -1,7 +1,17 @@
#ifndef IO_H #ifndef IO_H
#define IO_H #define IO_H
#include "error.h" #include <stdio.h>
/* IO error codes */
enum {
IO_DONE, /* operation completed successfully */
IO_TIMEOUT, /* operation timed out */
IO_CLOSED, /* the connection has been closed */
IO_ERROR, /* something wrong... */
IO_REFUSED, /* transfer has been refused */
IO_LIMITED /* maximum number of bytes reached */
};
/* interface to send function */ /* interface to send function */
typedef int (*p_send) ( typedef int (*p_send) (

View File

@ -24,12 +24,13 @@
\*=========================================================================*/ \*=========================================================================*/
#include "luasocket.h" #include "luasocket.h"
#include "tm.h" #include "timeout.h"
#include "buf.h" #include "buffer.h"
#include "sock.h" #include "socket.h"
#include "inet.h" #include "inet.h"
#include "tcp.h" #include "tcp.h"
#include "udp.h" #include "udp.h"
#include "select.h"
/*=========================================================================*\ /*=========================================================================*\
* Exported functions * Exported functions
@ -39,6 +40,7 @@
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
LUASOCKET_API int luaopen_socketlib(lua_State *L) LUASOCKET_API int luaopen_socketlib(lua_State *L)
{ {
if (!sock_open()) return 0;
/* create namespace table */ /* create namespace table */
lua_pushstring(L, LUASOCKET_LIBNAME); lua_pushstring(L, LUASOCKET_LIBNAME);
lua_newtable(L); lua_newtable(L);
@ -53,13 +55,28 @@ LUASOCKET_API int luaopen_socketlib(lua_State *L)
lua_pushstring(L, LUASOCKET_LIBNAME); lua_pushstring(L, LUASOCKET_LIBNAME);
lua_settable(L, LUA_GLOBALSINDEX); lua_settable(L, LUA_GLOBALSINDEX);
/* initialize all modules */ /* initialize all modules */
sock_open(L);
tm_open(L); tm_open(L);
buf_open(L); buf_open(L);
inet_open(L); inet_open(L);
tcp_open(L); tcp_open(L);
udp_open(L); udp_open(L);
/* load all Lua code */ select_open(L);
lua_dofile(L, "luasocket.lua"); #ifdef LUASOCKET_COMPILED
return 0; #include "auxiliar.lch"
#include "concat.lch"
#include "code.lch"
#include "url.lch"
#include "smtp.lch"
#include "ftp.lch"
#include "http.lch"
#else
lua_dofile(L, "auxiliar.lua");
lua_dofile(L, "concat.lua");
lua_dofile(L, "code.lua");
lua_dofile(L, "url.lua");
lua_dofile(L, "smtp.lua");
lua_dofile(L, "ftp.lua");
lua_dofile(L, "http.lua");
#endif
return 1;
} }

View File

@ -1,154 +1,129 @@
/*=========================================================================*\ /*=========================================================================*\
* Select implementation * Select implementation
* Global Lua fuctions:
* select: waits until socket ready
* RCS ID: $Id$ * RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#include <string.h> #include <string.h>
#include <lua.h> #include <lua.h>
#include <lauxlib.h> #include <lauxlib.h>
#include "luasocket.h" #include "luasocket.h"
#include "lspriv.h" #include "socket.h"
#include "lsselect.h" #include "auxiliar.h"
#include "lsfd.h" #include "select.h"
/* auxiliar functions */ static int meth_set(lua_State *L);
static int local_select(lua_State *L); static int meth_isset(lua_State *L);
static int local_getfd(lua_State *L); static int c_select(lua_State *L);
static int local_pending(lua_State *L); static int global_select(lua_State *L);
static int local_FD_SET(lua_State *L); static void check_obj_tab(lua_State *L, int tabidx);
static int local_FD_ISSET(lua_State *L);
static int select_lua_select(lua_State *L); /* fd_set object methods */
static luaL_reg set[] = {
{"set", meth_set},
{"isset", meth_isset},
{NULL, NULL}
};
/*-------------------------------------------------------------------------*\ /* functions in library namespace */
* Marks type as selectable static luaL_reg func[] = {
* Input {"select", global_select},
* name: type name {NULL, NULL}
\*-------------------------------------------------------------------------*/ };
void select_addclass(lua_State *L, cchar *lsclass)
{
lua_pushstring(L, "luasocket(select)");
lua_gettable(L, LUA_REGISTRYINDEX);
lua_pushstring(L, lsclass);
lua_pushnumber(L, 1);
lua_settable(L, -3);
lua_pop(L, 1);
}
void select_open(lua_State *L) void select_open(lua_State *L)
{ {
/* push select auxiliar lua function and register /* get select auxiliar lua function from lua code and register
* select_lua_select with it as an upvalue */ * pass it as an upvalue to global_select */
#ifdef LUASOCKET_DOFILE #ifdef LUASOCKET_COMPILED
lua_dofile(L, "lsselect.lua"); #include "select.lch"
#else #else
#include "lsselect.loh" lua_dofile(L, "select.lua");
#endif #endif
lua_getglobal(L, LUASOCKET_LIBNAME); luaL_openlib(L, LUASOCKET_LIBNAME, func, 1);
lua_pushstring(L, "_select");
lua_gettable(L, -2);
lua_pushcclosure(L, select_lua_select, 1);
priv_newglobal(L, "select");
lua_pop(L, 1); lua_pop(L, 1);
/* create luasocket(select) table */ aux_newclass(L, "select{fd_set}", set);
lua_pushstring(L, "luasocket(select)");
lua_newtable(L);
lua_settable(L, LUA_REGISTRYINDEX);
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Waits for a set of sockets until a condition is met or timeout. * 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
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int select_lua_select(lua_State *L) static int global_select(lua_State *L)
{ {
fd_set read, write; fd_set *read_fd_set, *write_fd_set;
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) */ /* make sure we have enough arguments (nil is the default) */
lua_settop(L, 4); lua_settop(L, 3);
/* pass FD_SET and manipulation functions */ /* check object tables */
lua_boxpointer(L, &read); check_obj_tab(L, 1);
lua_boxpointer(L, &write); check_obj_tab(L, 2);
lua_pushcfunction(L, local_FD_SET); /* check timeout */
lua_pushcfunction(L, local_FD_ISSET); if (!lua_isnil(L, 3) && !lua_isnumber(L, 3))
/* pass getfd function with selectable table as upvalue */ luaL_argerror(L, 3, "number or nil expected");
lua_pushstring(L, "luasocket(select)"); lua_gettable(L, LUA_REGISTRYINDEX); /* select auxiliar lua function to be called comes first */
lua_pushcclosure(L, local_getfd, 1); lua_pushvalue(L, lua_upvalueindex(1));
/* pass pending function */ lua_insert(L, 1);
lua_pushstring(L, "luasocket(select)"); lua_gettable(L, LUA_REGISTRYINDEX); /* pass fd_set objects */
lua_pushcclosure(L, local_pending, 1); read_fd_set = lua_newuserdata(L, sizeof(fd_set));
FD_ZERO(read_fd_set);
aux_setclass(L, "select{fd_set}", -1);
write_fd_set = lua_newuserdata(L, sizeof(fd_set));
FD_ZERO(write_fd_set);
aux_setclass(L, "select{fd_set}", -1);
/* pass select auxiliar C function */ /* pass select auxiliar C function */
lua_pushcfunction(L, local_select); lua_pushcfunction(L, c_select);
/* call select auxiliar lua function */ /* call select auxiliar lua function */
lua_call(L, 10, 3); lua_call(L, 6, 3);
return 3; return 3;
} }
static int local_getfd(lua_State *L) static int c_select(lua_State *L)
{
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);
}
return 1;
}
static int local_pending(lua_State *L)
{
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);
}
return 1;
}
static int local_select(lua_State *L)
{ {
int max_fd = (int) lua_tonumber(L, 1); int max_fd = (int) lua_tonumber(L, 1);
fd_set *read_set = (fd_set *) lua_touserdata(L, 2); fd_set *read_fd_set = (fd_set *) aux_checkclass(L, "select{fd_set}", 2);
fd_set *write_set = (fd_set *) lua_touserdata(L, 3); fd_set *write_fd_set = (fd_set *) aux_checkclass(L, "select{fd_set}", 3);
int deadline = lua_isnil(L, 4) ? -1 : (int)(lua_tonumber(L, 4) * 1000); int timeout = lua_isnil(L, 4) ? -1 : (int)(lua_tonumber(L, 4) * 1000);
struct timeval tv; struct timeval tv;
if (deadline >= 0) { tv.tv_sec = timeout / 1000;
tv.tv_sec = deadline / 1000; tv.tv_usec = (timeout % 1000) * 1000;
tv.tv_usec = (deadline % 1000) * 1000; lua_pushnumber(L, select(max_fd, read_fd_set, write_fd_set, NULL,
lua_pushnumber(L, select(max_fd, read_set, write_set, NULL, &tv)); timeout < 0 ? NULL : &tv));
} else {
lua_pushnumber(L, select(max_fd, read_set, write_set, NULL, NULL));
}
return 1; return 1;
} }
static int local_FD_SET(lua_State *L) static int meth_set(lua_State *L)
{ {
COMPAT_FD fd = (COMPAT_FD) lua_tonumber(L, 1); fd_set *set = (fd_set *) aux_checkclass(L, "select{fd_set}", 1);
fd_set *set = (fd_set *) lua_topointer(L, 2); t_sock fd = (t_sock) lua_tonumber(L, 2);
if (fd >= 0) FD_SET(fd, set); if (fd >= 0) FD_SET(fd, set);
return 0; return 0;
} }
static int local_FD_ISSET(lua_State *L) static int meth_isset(lua_State *L)
{ {
COMPAT_FD fd = (COMPAT_FD) lua_tonumber(L, 1); fd_set *set = (fd_set *) aux_checkclass(L, "select{fd_set}", 1);
fd_set *set = (fd_set *) lua_topointer(L, 2); t_sock fd = (t_sock) lua_tonumber(L, 2);
if (fd >= 0 && FD_ISSET(fd, set)) lua_pushnumber(L, 1); if (fd >= 0 && FD_ISSET(fd, set)) lua_pushnumber(L, 1);
else lua_pushnil(L); else lua_pushnil(L);
return 1; return 1;
} }
static void check_obj_tab(lua_State *L, int tabidx)
{
if (tabidx < 0) tabidx = lua_gettop(L) + tabidx + 1;
if (lua_istable(L, tabidx)) {
lua_pushnil(L);
while (lua_next(L, tabidx) != 0) {
if (aux_getgroupudata(L, "select{able}", -1) == NULL) {
char msg[45];
if (lua_isnumber(L, -2))
sprintf(msg, "table entry #%g is invalid",
lua_tonumber(L, -2));
else
sprintf(msg, "invalid entry found in table");
luaL_argerror(L, tabidx, msg);
}
lua_pop(L, 1);
}
} else if (!lua_isnil(L, tabidx))
luaL_argerror(L, tabidx, "table or nil expected");
}

View File

@ -2,10 +2,9 @@
* Select implementation * Select implementation
* RCS ID: $Id$ * RCS ID: $Id$
\*=========================================================================*/ \*=========================================================================*/
#ifndef SLCT_H_ #ifndef SELECT_H
#define SLCT_H_ #define SELECT_H
void select_addclass(lua_State *L, cchar *lsclass);
void select_open(lua_State *L); void select_open(lua_State *L);
#endif #endif /* SELECT_H */

View File

@ -6,16 +6,15 @@
#ifndef SOCK_H #ifndef SOCK_H
#define SOCK_H #define SOCK_H
#include <lua.h> #include "io.h"
#include "error.h"
/*=========================================================================*\ /*=========================================================================*\
* Platform specific compatibilization * Platform specific compatibilization
\*=========================================================================*/ \*=========================================================================*/
#ifdef WIN32 #ifdef WIN32
#include "sockwin32.h" #include "wsocket.h"
#else #else
#include "sockunix.h" #include "usocket.h"
#endif #endif
/* we are lazy... */ /* we are lazy... */
@ -25,13 +24,13 @@ typedef struct sockaddr SA;
* Functions bellow implement a comfortable platform independent * Functions bellow implement a comfortable platform independent
* interface to sockets * interface to sockets
\*=========================================================================*/ \*=========================================================================*/
int sock_open(lua_State *L); int sock_open(void);
const char *sock_create(p_sock ps, int domain, int type, int protocol); const char *sock_create(p_sock ps, int domain, int type, int protocol);
void sock_destroy(p_sock ps); void sock_destroy(p_sock ps);
void sock_accept(p_sock ps, p_sock pa, SA *addr, size_t *addr_len, int timeout); int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len,
const char *sock_connect(p_sock ps, SA *addr, size_t addr_len); int timeout);
const char *sock_bind(p_sock ps, SA *addr, size_t addr_len); const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len);
const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len);
void sock_listen(p_sock ps, int backlog); void sock_listen(p_sock ps, int backlog);
int sock_send(p_sock ps, const char *data, size_t count, int sock_send(p_sock ps, const char *data, size_t count,
@ -39,9 +38,9 @@ int sock_send(p_sock ps, const char *data, size_t count,
int sock_recv(p_sock ps, char *data, size_t count, int sock_recv(p_sock ps, char *data, size_t count,
size_t *got, int timeout); size_t *got, int timeout);
int sock_sendto(p_sock ps, const char *data, size_t count, int sock_sendto(p_sock ps, const char *data, size_t count,
size_t *sent, SA *addr, size_t addr_len, int timeout); size_t *sent, SA *addr, socklen_t addr_len, int timeout);
int sock_recvfrom(p_sock ps, char *data, size_t count, int sock_recvfrom(p_sock ps, char *data, size_t count,
size_t *got, SA *addr, size_t *addr_len, int timeout); size_t *got, SA *addr, socklen_t *addr_len, int timeout);
void sock_setnonblocking(p_sock ps); void sock_setnonblocking(p_sock ps);
void sock_setblocking(p_sock ps); void sock_setblocking(p_sock ps);
@ -52,6 +51,4 @@ const char *sock_createstrerror(void);
const char *sock_bindstrerror(void); const char *sock_bindstrerror(void);
const char *sock_connectstrerror(void); const char *sock_connectstrerror(void);
const char *sock_trysetoptions(lua_State *L, p_sock ps);
#endif /* SOCK_H */ #endif /* SOCK_H */

View File

@ -10,43 +10,49 @@
#include "luasocket.h" #include "luasocket.h"
#include "aux.h" #include "auxiliar.h"
#include "socket.h"
#include "inet.h" #include "inet.h"
#include "error.h"
#include "tcp.h" #include "tcp.h"
/*=========================================================================*\ /*=========================================================================*\
* Internal function prototypes * Internal function prototypes
\*=========================================================================*/ \*=========================================================================*/
static int tcp_global_create(lua_State *L); static int global_create(lua_State *L);
static int tcp_meth_connect(lua_State *L); static int meth_connect(lua_State *L);
static int tcp_meth_bind(lua_State *L); static int meth_bind(lua_State *L);
static int tcp_meth_send(lua_State *L); static int meth_send(lua_State *L);
static int tcp_meth_getsockname(lua_State *L); static int meth_getsockname(lua_State *L);
static int tcp_meth_getpeername(lua_State *L); static int meth_getpeername(lua_State *L);
static int tcp_meth_receive(lua_State *L); static int meth_receive(lua_State *L);
static int tcp_meth_accept(lua_State *L); static int meth_accept(lua_State *L);
static int tcp_meth_close(lua_State *L); static int meth_close(lua_State *L);
static int tcp_meth_timeout(lua_State *L); static int meth_timeout(lua_State *L);
static int meth_fd(lua_State *L);
static int meth_dirty(lua_State *L);
/* tcp object methods */ /* tcp object methods */
static luaL_reg tcp[] = { static luaL_reg tcp[] = {
{"connect", tcp_meth_connect}, {"connect", meth_connect},
{"send", tcp_meth_send}, {"send", meth_send},
{"receive", tcp_meth_receive}, {"receive", meth_receive},
{"bind", tcp_meth_bind}, {"bind", meth_bind},
{"accept", tcp_meth_accept}, {"accept", meth_accept},
{"setpeername", tcp_meth_connect}, {"setpeername", meth_connect},
{"setsockname", tcp_meth_bind}, {"setsockname", meth_bind},
{"getpeername", tcp_meth_getpeername}, {"getpeername", meth_getpeername},
{"getsockname", tcp_meth_getsockname}, {"getsockname", meth_getsockname},
{"timeout", tcp_meth_timeout}, {"timeout", meth_timeout},
{"close", tcp_meth_close}, {"close", meth_close},
{"fd", meth_fd},
{"dirty", meth_dirty},
{NULL, NULL} {NULL, NULL}
}; };
/* functions in library namespace */ /* functions in library namespace */
static luaL_reg func[] = { static luaL_reg func[] = {
{"tcp", tcp_global_create}, {"tcp", global_create},
{NULL, NULL} {NULL, NULL}
}; };
@ -60,11 +66,13 @@ void tcp_open(lua_State *L)
aux_newclass(L, "tcp{client}", tcp); aux_newclass(L, "tcp{client}", tcp);
aux_newclass(L, "tcp{server}", tcp); aux_newclass(L, "tcp{server}", tcp);
/* create class groups */ /* create class groups */
aux_add2group(L, "tcp{client}", "tcp{client, server}");
aux_add2group(L, "tcp{server}", "tcp{client, server}");
aux_add2group(L, "tcp{master}", "tcp{any}"); aux_add2group(L, "tcp{master}", "tcp{any}");
aux_add2group(L, "tcp{client}", "tcp{any}"); aux_add2group(L, "tcp{client}", "tcp{any}");
aux_add2group(L, "tcp{server}", "tcp{any}"); aux_add2group(L, "tcp{server}", "tcp{any}");
aux_add2group(L, "tcp{client}", "tcp{client, server}");
aux_add2group(L, "tcp{server}", "tcp{client, server}");
aux_add2group(L, "tcp{client}", "select{able}");
aux_add2group(L, "tcp{server}", "select{able}");
/* define library functions */ /* define library functions */
luaL_openlib(L, LUASOCKET_LIBNAME, func, 0); luaL_openlib(L, LUASOCKET_LIBNAME, func, 0);
lua_pop(L, 1); lua_pop(L, 1);
@ -76,28 +84,45 @@ void tcp_open(lua_State *L)
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Just call buffered IO methods * Just call buffered IO methods
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int tcp_meth_send(lua_State *L) static int meth_send(lua_State *L)
{ {
p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{client}", 1); p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{client}", 1);
return buf_meth_send(L, &tcp->buf); return buf_meth_send(L, &tcp->buf);
} }
static int tcp_meth_receive(lua_State *L) static int meth_receive(lua_State *L)
{ {
p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{client}", 1); p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{client}", 1);
return buf_meth_receive(L, &tcp->buf); return buf_meth_receive(L, &tcp->buf);
} }
/*-------------------------------------------------------------------------*\
* Select support methods
\*-------------------------------------------------------------------------*/
static int meth_fd(lua_State *L)
{
p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{client, server}", 1);
lua_pushnumber(L, tcp->sock);
return 1;
}
static int meth_dirty(lua_State *L)
{
p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{client, server}", 1);
lua_pushboolean(L, !buf_isempty(&tcp->buf));
return 1;
}
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Just call inet methods * Just call inet methods
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int tcp_meth_getpeername(lua_State *L) static int meth_getpeername(lua_State *L)
{ {
p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{client}", 1); p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{client}", 1);
return inet_meth_getpeername(L, &tcp->sock); return inet_meth_getpeername(L, &tcp->sock);
} }
static int tcp_meth_getsockname(lua_State *L) static int meth_getsockname(lua_State *L)
{ {
p_tcp tcp = (p_tcp) aux_checkgroup(L, "tcp{client, server}", 1); p_tcp tcp = (p_tcp) aux_checkgroup(L, "tcp{client, server}", 1);
return inet_meth_getsockname(L, &tcp->sock); return inet_meth_getsockname(L, &tcp->sock);
@ -106,7 +131,7 @@ static int tcp_meth_getsockname(lua_State *L)
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Just call tm methods * Just call tm methods
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int tcp_meth_timeout(lua_State *L) static int meth_timeout(lua_State *L)
{ {
p_tcp tcp = (p_tcp) aux_checkgroup(L, "tcp{any}", 1); p_tcp tcp = (p_tcp) aux_checkgroup(L, "tcp{any}", 1);
return tm_meth_timeout(L, &tcp->tm); return tm_meth_timeout(L, &tcp->tm);
@ -115,7 +140,7 @@ static int tcp_meth_timeout(lua_State *L)
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Closes socket used by object * Closes socket used by object
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int tcp_meth_close(lua_State *L) static int meth_close(lua_State *L)
{ {
p_tcp tcp = (p_tcp) aux_checkgroup(L, "tcp{any}", 1); p_tcp tcp = (p_tcp) aux_checkgroup(L, "tcp{any}", 1);
sock_destroy(&tcp->sock); sock_destroy(&tcp->sock);
@ -125,7 +150,7 @@ static int tcp_meth_close(lua_State *L)
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Turns a master tcp object into a client object. * Turns a master tcp object into a client object.
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int tcp_meth_connect(lua_State *L) static int meth_connect(lua_State *L)
{ {
p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{master}", 1); p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{master}", 1);
const char *address = luaL_checkstring(L, 2); const char *address = luaL_checkstring(L, 2);
@ -145,7 +170,7 @@ static int tcp_meth_connect(lua_State *L)
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Turns a master object into a server object * Turns a master object into a server object
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int tcp_meth_bind(lua_State *L) static int meth_bind(lua_State *L)
{ {
p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{master}", 1); p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{master}", 1);
const char *address = luaL_checkstring(L, 2); const char *address = luaL_checkstring(L, 2);
@ -167,10 +192,10 @@ static int tcp_meth_bind(lua_State *L)
* Waits for and returns a client object attempting connection to the * Waits for and returns a client object attempting connection to the
* server object * server object
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int tcp_meth_accept(lua_State *L) static int meth_accept(lua_State *L)
{ {
struct sockaddr_in addr; struct sockaddr_in addr;
size_t addr_len = sizeof(addr); socklen_t addr_len = sizeof(addr);
p_tcp server = (p_tcp) aux_checkclass(L, "tcp{server}", 1); p_tcp server = (p_tcp) aux_checkclass(L, "tcp{server}", 1);
p_tm tm = &server->tm; p_tm tm = &server->tm;
p_tcp client = lua_newuserdata(L, sizeof(t_tcp)); p_tcp client = lua_newuserdata(L, sizeof(t_tcp));
@ -200,7 +225,7 @@ static int tcp_meth_accept(lua_State *L)
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Creates a master tcp object * Creates a master tcp object
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
int tcp_global_create(lua_State *L) int global_create(lua_State *L)
{ {
/* allocate tcp object */ /* allocate tcp object */
p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));

View File

@ -3,9 +3,9 @@
#include <lua.h> #include <lua.h>
#include "buf.h" #include "buffer.h"
#include "tm.h" #include "timeout.h"
#include "sock.h" #include "socket.h"
typedef struct t_tcp_ { typedef struct t_tcp_ {
t_sock sock; t_sock sock;

View File

@ -12,8 +12,8 @@
#include <lauxlib.h> #include <lauxlib.h>
#include "luasocket.h" #include "luasocket.h"
#include "aux.h" #include "auxiliar.h"
#include "tm.h" #include "timeout.h"
#ifdef WIN32 #ifdef WIN32
#include <windows.h> #include <windows.h>
@ -118,6 +118,7 @@ int tm_gettime(void)
void tm_open(lua_State *L) void tm_open(lua_State *L)
{ {
luaL_openlib(L, LUASOCKET_LIBNAME, func, 0); luaL_openlib(L, LUASOCKET_LIBNAME, func, 0);
lua_pop(L, 1);
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\

View File

@ -10,43 +10,49 @@
#include "luasocket.h" #include "luasocket.h"
#include "aux.h" #include "auxiliar.h"
#include "socket.h"
#include "inet.h" #include "inet.h"
#include "error.h"
#include "udp.h" #include "udp.h"
/*=========================================================================*\ /*=========================================================================*\
* Internal function prototypes * Internal function prototypes
\*=========================================================================*/ \*=========================================================================*/
static int udp_global_create(lua_State *L); static int global_create(lua_State *L);
static int udp_meth_send(lua_State *L); static int meth_send(lua_State *L);
static int udp_meth_sendto(lua_State *L); static int meth_sendto(lua_State *L);
static int udp_meth_receive(lua_State *L); static int meth_receive(lua_State *L);
static int udp_meth_receivefrom(lua_State *L); static int meth_receivefrom(lua_State *L);
static int udp_meth_getsockname(lua_State *L); static int meth_getsockname(lua_State *L);
static int udp_meth_getpeername(lua_State *L); static int meth_getpeername(lua_State *L);
static int udp_meth_setsockname(lua_State *L); static int meth_setsockname(lua_State *L);
static int udp_meth_setpeername(lua_State *L); static int meth_setpeername(lua_State *L);
static int udp_meth_close(lua_State *L); static int meth_close(lua_State *L);
static int udp_meth_timeout(lua_State *L); static int meth_timeout(lua_State *L);
static int meth_fd(lua_State *L);
static int meth_dirty(lua_State *L);
/* udp object methods */ /* udp object methods */
static luaL_reg udp[] = { static luaL_reg udp[] = {
{"setpeername", udp_meth_setpeername}, {"setpeername", meth_setpeername},
{"setsockname", udp_meth_setsockname}, {"setsockname", meth_setsockname},
{"getsockname", udp_meth_getsockname}, {"getsockname", meth_getsockname},
{"getpeername", udp_meth_getpeername}, {"getpeername", meth_getpeername},
{"send", udp_meth_send}, {"send", meth_send},
{"sendto", udp_meth_sendto}, {"sendto", meth_sendto},
{"receive", udp_meth_receive}, {"receive", meth_receive},
{"receivefrom", udp_meth_receivefrom}, {"receivefrom", meth_receivefrom},
{"timeout", udp_meth_timeout}, {"timeout", meth_timeout},
{"close", udp_meth_close}, {"close", meth_close},
{"fd", meth_fd},
{"dirty", meth_dirty},
{NULL, NULL} {NULL, NULL}
}; };
/* functions in library namespace */ /* functions in library namespace */
static luaL_reg func[] = { static luaL_reg func[] = {
{"udp", udp_global_create}, {"udp", global_create},
{NULL, NULL} {NULL, NULL}
}; };
@ -61,6 +67,8 @@ void udp_open(lua_State *L)
/* create class groups */ /* create class groups */
aux_add2group(L, "udp{connected}", "udp{any}"); aux_add2group(L, "udp{connected}", "udp{any}");
aux_add2group(L, "udp{unconnected}", "udp{any}"); aux_add2group(L, "udp{unconnected}", "udp{any}");
aux_add2group(L, "udp{connected}", "select{able}");
aux_add2group(L, "udp{unconnected}", "select{able}");
/* define library functions */ /* define library functions */
luaL_openlib(L, LUASOCKET_LIBNAME, func, 0); luaL_openlib(L, LUASOCKET_LIBNAME, func, 0);
lua_pop(L, 1); lua_pop(L, 1);
@ -72,7 +80,7 @@ void udp_open(lua_State *L)
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Send data through connected udp socket * Send data through connected udp socket
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int udp_meth_send(lua_State *L) static int meth_send(lua_State *L)
{ {
p_udp udp = (p_udp) aux_checkclass(L, "udp{connected}", 1); p_udp udp = (p_udp) aux_checkclass(L, "udp{connected}", 1);
p_tm tm = &udp->tm; p_tm tm = &udp->tm;
@ -90,7 +98,7 @@ static int udp_meth_send(lua_State *L)
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Send data through unconnected udp socket * Send data through unconnected udp socket
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int udp_meth_sendto(lua_State *L) static int meth_sendto(lua_State *L)
{ {
p_udp udp = (p_udp) aux_checkclass(L, "udp{unconnected}", 1); p_udp udp = (p_udp) aux_checkclass(L, "udp{unconnected}", 1);
size_t count, sent = 0; size_t count, sent = 0;
@ -117,7 +125,7 @@ static int udp_meth_sendto(lua_State *L)
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Receives data from a UDP socket * Receives data from a UDP socket
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int udp_meth_receive(lua_State *L) static int meth_receive(lua_State *L)
{ {
p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1); p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
char buffer[UDP_DATAGRAMSIZE]; char buffer[UDP_DATAGRAMSIZE];
@ -136,11 +144,11 @@ static int udp_meth_receive(lua_State *L)
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Receives data and sender from a UDP socket * Receives data and sender from a UDP socket
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int udp_meth_receivefrom(lua_State *L) static int meth_receivefrom(lua_State *L)
{ {
p_udp udp = (p_udp) aux_checkclass(L, "udp{unconnected}", 1); p_udp udp = (p_udp) aux_checkclass(L, "udp{unconnected}", 1);
struct sockaddr_in addr; struct sockaddr_in addr;
size_t addr_len = sizeof(addr); socklen_t addr_len = sizeof(addr);
char buffer[UDP_DATAGRAMSIZE]; char buffer[UDP_DATAGRAMSIZE];
size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer)); size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer));
int err; int err;
@ -161,16 +169,34 @@ static int udp_meth_receivefrom(lua_State *L)
} }
} }
/*-------------------------------------------------------------------------*\
* Select support methods
\*-------------------------------------------------------------------------*/
static int meth_fd(lua_State *L)
{
p_udp udp = (p_udp) aux_checkclass(L, "udp{any}", 1);
lua_pushnumber(L, udp->sock);
return 1;
}
static int meth_dirty(lua_State *L)
{
p_udp udp = (p_udp) aux_checkclass(L, "udp{any}", 1);
(void) udp;
lua_pushboolean(L, 0);
return 1;
}
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Just call inet methods * Just call inet methods
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int udp_meth_getpeername(lua_State *L) static int meth_getpeername(lua_State *L)
{ {
p_udp udp = (p_udp) aux_checkclass(L, "udp{connected}", 1); p_udp udp = (p_udp) aux_checkclass(L, "udp{connected}", 1);
return inet_meth_getpeername(L, &udp->sock); return inet_meth_getpeername(L, &udp->sock);
} }
static int udp_meth_getsockname(lua_State *L) static int meth_getsockname(lua_State *L)
{ {
p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1); p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
return inet_meth_getsockname(L, &udp->sock); return inet_meth_getsockname(L, &udp->sock);
@ -179,7 +205,7 @@ static int udp_meth_getsockname(lua_State *L)
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Just call tm methods * Just call tm methods
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int udp_meth_timeout(lua_State *L) static int meth_timeout(lua_State *L)
{ {
p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1); p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
return tm_meth_timeout(L, &udp->tm); return tm_meth_timeout(L, &udp->tm);
@ -188,7 +214,7 @@ static int udp_meth_timeout(lua_State *L)
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Turns a master udp object into a client object. * Turns a master udp object into a client object.
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int udp_meth_setpeername(lua_State *L) static int meth_setpeername(lua_State *L)
{ {
p_udp udp = (p_udp) aux_checkclass(L, "udp{unconnected}", 1); p_udp udp = (p_udp) aux_checkclass(L, "udp{unconnected}", 1);
const char *address = luaL_checkstring(L, 2); const char *address = luaL_checkstring(L, 2);
@ -211,7 +237,7 @@ static int udp_meth_setpeername(lua_State *L)
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Closes socket used by object * Closes socket used by object
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int udp_meth_close(lua_State *L) static int meth_close(lua_State *L)
{ {
p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1); p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
sock_destroy(&udp->sock); sock_destroy(&udp->sock);
@ -221,7 +247,7 @@ static int udp_meth_close(lua_State *L)
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Turns a master object into a server object * Turns a master object into a server object
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int udp_meth_setsockname(lua_State *L) static int meth_setsockname(lua_State *L)
{ {
p_udp udp = (p_udp) aux_checkclass(L, "udp{master}", 1); p_udp udp = (p_udp) aux_checkclass(L, "udp{master}", 1);
const char *address = luaL_checkstring(L, 2); const char *address = luaL_checkstring(L, 2);
@ -242,7 +268,7 @@ static int udp_meth_setsockname(lua_State *L)
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Creates a master udp object * Creates a master udp object
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
int udp_global_create(lua_State *L) int global_create(lua_State *L)
{ {
/* allocate udp object */ /* allocate udp object */
p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp)); p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp));

View File

@ -3,8 +3,8 @@
#include <lua.h> #include <lua.h>
#include "tm.h" #include "timeout.h"
#include "sock.h" #include "socket.h"
#define UDP_DATAGRAMSIZE 576 #define UDP_DATAGRAMSIZE 576

View File

@ -1,24 +1,8 @@
/*=========================================================================*\
* Socket compatibilization module for Unix
*
* RCS ID: $Id$
\*=========================================================================*/
#include <lua.h>
#include <lauxlib.h>
#include <string.h> #include <string.h>
#include "sock.h" #include "socket.h"
/*=========================================================================*\ int sock_open(void)
* Internal function prototypes
\*=========================================================================*/
static const char *try_setoption(lua_State *L, p_sock ps);
static const char *try_setbooloption(lua_State *L, p_sock ps, int name);
/*=========================================================================*\
* Exported functions.
\*=========================================================================*/
int sock_open(lua_State *L)
{ {
/* instals a handler to ignore sigpipe. */ /* instals a handler to ignore sigpipe. */
struct sigaction new; struct sigaction new;
@ -43,13 +27,13 @@ const char *sock_create(p_sock ps, int domain, int type, int protocol)
return NULL; return NULL;
} }
const char *sock_connect(p_sock ps, SA *addr, size_t addr_len) const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len)
{ {
if (connect(*ps, addr, addr_len) < 0) return sock_connectstrerror(); if (connect(*ps, addr, addr_len) < 0) return sock_connectstrerror();
else return NULL; else return NULL;
} }
const char *sock_bind(p_sock ps, SA *addr, size_t addr_len) const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len)
{ {
if (bind(*ps, addr, addr_len) < 0) return sock_bindstrerror(); if (bind(*ps, addr, addr_len) < 0) return sock_bindstrerror();
else return NULL; else return NULL;
@ -60,17 +44,25 @@ void sock_listen(p_sock ps, int backlog)
listen(*ps, backlog); listen(*ps, backlog);
} }
void sock_accept(p_sock ps, p_sock pa, SA *addr, size_t *addr_len, int timeout) int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len,
int timeout)
{ {
t_sock sock = *ps; t_sock sock = *ps;
struct timeval tv; struct timeval tv;
SA dummy_addr;
socklen_t dummy_len;
fd_set fds; fd_set fds;
tv.tv_sec = timeout / 1000; tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000; tv.tv_usec = (timeout % 1000) * 1000;
FD_ZERO(&fds); FD_ZERO(&fds);
FD_SET(sock, &fds); FD_SET(sock, &fds);
select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); if (select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL) <= 0)
return IO_TIMEOUT;
if (!addr) addr = &dummy_addr;
if (!addr_len) addr_len = &dummy_len;
*pa = accept(sock, addr, addr_len); *pa = accept(sock, addr, addr_len);
if (*pa == SOCK_INVALID) return IO_ERROR;
else return IO_DONE;
} }
int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, int sock_send(p_sock ps, const char *data, size_t count, size_t *sent,
@ -108,7 +100,7 @@ int sock_send(p_sock ps, const char *data, size_t count, size_t *sent,
} }
int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent,
SA *addr, size_t addr_len, int timeout) SA *addr, socklen_t addr_len, int timeout)
{ {
t_sock sock = *ps; t_sock sock = *ps;
struct timeval tv; struct timeval tv;
@ -169,7 +161,7 @@ int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout)
} }
int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got,
SA *addr, size_t *addr_len, int timeout) SA *addr, socklen_t *addr_len, int timeout)
{ {
t_sock sock = *ps; t_sock sock = *ps;
struct timeval tv; struct timeval tv;
@ -196,9 +188,6 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got,
} }
} }
/*-------------------------------------------------------------------------*\
* Returns a string describing the last host manipulation error.
\*-------------------------------------------------------------------------*/
const char *sock_hoststrerror(void) const char *sock_hoststrerror(void)
{ {
switch (h_errno) { switch (h_errno) {
@ -210,9 +199,6 @@ const char *sock_hoststrerror(void)
} }
} }
/*-------------------------------------------------------------------------*\
* Returns a string describing the last socket manipulation error.
\*-------------------------------------------------------------------------*/
const char *sock_createstrerror(void) const char *sock_createstrerror(void)
{ {
switch (errno) { switch (errno) {
@ -224,9 +210,6 @@ const char *sock_createstrerror(void)
} }
} }
/*-------------------------------------------------------------------------*\
* Returns a string describing the last bind command error.
\*-------------------------------------------------------------------------*/
const char *sock_bindstrerror(void) const char *sock_bindstrerror(void)
{ {
switch (errno) { switch (errno) {
@ -241,9 +224,6 @@ const char *sock_bindstrerror(void)
} }
} }
/*-------------------------------------------------------------------------*\
* Returns a string describing the last connect error.
\*-------------------------------------------------------------------------*/
const char *sock_connectstrerror(void) const char *sock_connectstrerror(void)
{ {
switch (errno) { switch (errno) {
@ -259,20 +239,12 @@ const char *sock_connectstrerror(void)
} }
} }
/*-------------------------------------------------------------------------*\
* Sets the SO_REUSEADDR socket option
* Input
* sock: socket descriptor
\*-------------------------------------------------------------------------*/
void sock_setreuseaddr(p_sock ps) void sock_setreuseaddr(p_sock ps)
{ {
int val = 1; int val = 1;
setsockopt(*ps, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val)); setsockopt(*ps, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
} }
/*-------------------------------------------------------------------------*\
* Put socket into blocking mode.
\*-------------------------------------------------------------------------*/
void sock_setblocking(p_sock ps) void sock_setblocking(p_sock ps)
{ {
int flags = fcntl(*ps, F_GETFL, 0); int flags = fcntl(*ps, F_GETFL, 0);
@ -280,68 +252,9 @@ void sock_setblocking(p_sock ps)
fcntl(*ps, F_SETFL, flags); fcntl(*ps, F_SETFL, flags);
} }
/*-------------------------------------------------------------------------*\
* Put socket into non-blocking mode.
\*-------------------------------------------------------------------------*/
void sock_setnonblocking(p_sock ps) void sock_setnonblocking(p_sock ps)
{ {
int flags = fcntl(*ps, F_GETFL, 0); int flags = fcntl(*ps, F_GETFL, 0);
flags |= O_NONBLOCK; flags |= O_NONBLOCK;
fcntl(*ps, F_SETFL, flags); fcntl(*ps, F_SETFL, flags);
} }
/*-------------------------------------------------------------------------*\
* Tries to set extended udp socket options
* Input
* udp: udp structure
* oldtop: top of stack
* Returns
* NULL if successfull, error message on error
\*-------------------------------------------------------------------------*/
const char *sock_trysetoptions(lua_State *L, p_sock ps)
{
if (!lua_istable(L, 1)) luaL_argerror(L, 1, "invalid options table");
lua_pushnil(L);
while (lua_next(L, 1)) {
const char *err = try_setoption(L, ps);
lua_pop(L, 1);
if (err) return err;
}
return NULL;
}
/*-------------------------------------------------------------------------*\
* Set socket options from a table on top of Lua stack.
* Supports SO_KEEPALIVE, SO_DONTROUTE, and SO_BROADCAST options.
* Input
* sock: socket
* Returns
* 1 if successful, 0 otherwise
\*-------------------------------------------------------------------------*/
static const char *try_setoption(lua_State *L, p_sock ps)
{
static const char *options[] = {
"SO_KEEPALIVE", "SO_DONTROUTE", "SO_BROADCAST", NULL
};
const char *option = lua_tostring(L, -2);
if (!lua_isstring(L, -2)) return "invalid option";
switch (luaL_findstring(option, options)) {
case 0: return try_setbooloption(L, ps, SO_KEEPALIVE);
case 1: return try_setbooloption(L, ps, SO_DONTROUTE);
case 2: return try_setbooloption(L, ps, SO_BROADCAST);
default: return "unsupported option";
}
}
/*=========================================================================*\
* Internal functions.
\*=========================================================================*/
static const char *try_setbooloption(lua_State *L, p_sock ps, int name)
{
int bool, res;
if (!lua_isnumber(L, -1)) luaL_error(L, "invalid option value");
bool = (int) lua_tonumber(L, -1);
res = setsockopt(*ps, SOL_SOCKET, name, (char *) &bool, sizeof(bool));
if (res < 0) return "error setting option";
else return NULL;
}

View File

@ -31,6 +31,11 @@
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#ifdef __APPLE__
/* for some reason socklen_t is not defined in mac os x */
typedef int socklen_t;
#endif
typedef int t_sock; typedef int t_sock;
typedef t_sock *p_sock; typedef t_sock *p_sock;