From 58bdb658aaa1c30a8f3bed46eef880d308fae582 Mon Sep 17 00:00:00 2001 From: Diego Nehab Date: Mon, 9 Jun 2003 18:23:40 +0000 Subject: 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. --- src/auxiliar.c | 75 +++++++++++++++------- src/auxiliar.h | 2 + src/buffer.c | 4 +- src/buffer.h | 2 +- src/inet.c | 5 +- src/inet.h | 2 +- src/io.h | 12 +++- src/luasocket.c | 31 ++++++--- src/select.c | 191 ++++++++++++++++++++++++-------------------------------- src/select.h | 7 +-- src/socket.h | 23 +++---- src/tcp.c | 97 +++++++++++++++++----------- src/tcp.h | 6 +- src/timeout.c | 5 +- src/udp.c | 98 ++++++++++++++++++----------- src/udp.h | 4 +- src/usocket.c | 119 +++++------------------------------ src/usocket.h | 5 ++ 18 files changed, 344 insertions(+), 344 deletions(-) (limited to 'src') diff --git a/src/auxiliar.c b/src/auxiliar.c index 5e5ba1a..96138f1 100644 --- a/src/auxiliar.c +++ b/src/auxiliar.c @@ -3,12 +3,7 @@ * * RCS ID: $Id$ \*=========================================================================*/ -#include "aux.h" - -/*=========================================================================*\ -* Internal function prototypes -\*=========================================================================*/ -static void *aux_getgroupudata(lua_State *L, const char *group, int objidx); +#include "auxiliar.h" /*=========================================================================*\ * 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) { - luaL_newmetatable(L, name); + lua_pushstring(L, name); + lua_newtable(L); lua_pushstring(L, "__index"); lua_newtable(L); luaL_openlib(L, NULL, func, 0); lua_pushstring(L, "class"); lua_pushstring(L, name); - lua_settable(L, -3); - lua_settable(L, -3); + lua_rawset(L, -3); lua_pushstring(L, "group"); lua_newtable(L); - lua_settable(L, -3); - lua_pop(L, 1); + lua_rawset(L, -3); + 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) { - 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_gettable(L, -2); + lua_rawget(L, -2); lua_pushstring(L, group); lua_pushnumber(L, 1); - lua_settable(L, -3); - lua_pop(L, 2); + lua_rawset(L, -3); + 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 *data = luaL_checkudata(L, objidx, name); + void *data = aux_getclassudata(L, name, objidx); if (!data) { char msg[45]; 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) { - luaL_getmetatable(L, name); + lua_pushstring(L, name); + lua_rawget(L, LUA_REGISTRYINDEX); if (objidx < 0) 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. \*-------------------------------------------------------------------------*/ -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)) + return NULL; + lua_pushstring(L, "__index"); + lua_rawget(L, -2); + if (!lua_istable(L, -1)) { + lua_pop(L, 2); + return NULL; + } lua_pushstring(L, "group"); - lua_gettable(L, -2); + lua_rawget(L, -2); + if (!lua_istable(L, -1)) { + lua_pop(L, 3); + return NULL; + } + lua_pushstring(L, group); + 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, group); - lua_gettable(L, -2); + lua_pushstring(L, "class"); + lua_rawget(L, -2); if (lua_isnil(L, -1)) { lua_pop(L, 3); return NULL; @@ -110,4 +140,3 @@ static void *aux_getgroupudata(lua_State *L, const char *group, int objidx) lua_pop(L, 3); return lua_touserdata(L, objidx); } - diff --git a/src/auxiliar.h b/src/auxiliar.h index 2681a84..66be31d 100644 --- a/src/auxiliar.h +++ b/src/auxiliar.h @@ -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_checkclass(lua_State *L, const char *name, 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); /* min and max macros */ diff --git a/src/buffer.c b/src/buffer.c index c5ef66c..ab059bb 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -7,8 +7,8 @@ #include #include "error.h" -#include "aux.h" -#include "buf.h" +#include "auxiliar.h" +#include "buffer.h" /*=========================================================================*\ * Internal function prototypes diff --git a/src/buffer.h b/src/buffer.h index 3ffc145..1502ef0 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -8,7 +8,7 @@ #include #include "io.h" -#include "tm.h" +#include "timeout.h" /* buffer size in bytes */ #define BUF_SIZE 8192 diff --git a/src/inet.c b/src/inet.c index f20762f..60106f2 100644 --- a/src/inet.c +++ b/src/inet.c @@ -38,6 +38,7 @@ static luaL_reg func[] = { void inet_open(lua_State *L) { 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) { struct sockaddr_in peer; - size_t peer_len = sizeof(peer); + socklen_t peer_len = sizeof(peer); if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) { lua_pushnil(L); 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) { struct sockaddr_in local; - size_t local_len = sizeof(local); + socklen_t local_len = sizeof(local); if (getsockname(*ps, (SA *) &local, &local_len) < 0) { lua_pushnil(L); return 1; diff --git a/src/inet.h b/src/inet.h index bcefc5b..b8d8f19 100644 --- a/src/inet.h +++ b/src/inet.h @@ -7,7 +7,7 @@ #define INET_H #include -#include "sock.h" +#include "socket.h" /*-------------------------------------------------------------------------*\ * Exported functions diff --git a/src/io.h b/src/io.h index b5b7f1d..30d445b 100644 --- a/src/io.h +++ b/src/io.h @@ -1,7 +1,17 @@ #ifndef IO_H #define IO_H -#include "error.h" +#include + +/* 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 */ typedef int (*p_send) ( diff --git a/src/luasocket.c b/src/luasocket.c index 53f8c21..5541d7f 100644 --- a/src/luasocket.c +++ b/src/luasocket.c @@ -24,12 +24,13 @@ \*=========================================================================*/ #include "luasocket.h" -#include "tm.h" -#include "buf.h" -#include "sock.h" +#include "timeout.h" +#include "buffer.h" +#include "socket.h" #include "inet.h" #include "tcp.h" #include "udp.h" +#include "select.h" /*=========================================================================*\ * Exported functions @@ -39,6 +40,7 @@ \*-------------------------------------------------------------------------*/ LUASOCKET_API int luaopen_socketlib(lua_State *L) { + if (!sock_open()) return 0; /* create namespace table */ lua_pushstring(L, LUASOCKET_LIBNAME); lua_newtable(L); @@ -53,13 +55,28 @@ LUASOCKET_API int luaopen_socketlib(lua_State *L) lua_pushstring(L, LUASOCKET_LIBNAME); lua_settable(L, LUA_GLOBALSINDEX); /* initialize all modules */ - sock_open(L); tm_open(L); buf_open(L); inet_open(L); tcp_open(L); udp_open(L); - /* load all Lua code */ - lua_dofile(L, "luasocket.lua"); - return 0; + select_open(L); +#ifdef LUASOCKET_COMPILED +#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; } 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 @@ /*=========================================================================*\ * Select implementation -* Global Lua fuctions: -* select: waits until socket ready * RCS ID: $Id$ \*=========================================================================*/ #include + #include #include #include "luasocket.h" -#include "lspriv.h" -#include "lsselect.h" -#include "lsfd.h" +#include "socket.h" +#include "auxiliar.h" +#include "select.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 meth_set(lua_State *L); +static int meth_isset(lua_State *L); +static int c_select(lua_State *L); +static int global_select(lua_State *L); +static void check_obj_tab(lua_State *L, int tabidx); -static int select_lua_select(lua_State *L); +/* fd_set object methods */ +static luaL_reg set[] = { + {"set", meth_set}, + {"isset", meth_isset}, + {NULL, NULL} +}; -/*-------------------------------------------------------------------------*\ -* Marks type as selectable -* Input -* name: type name -\*-------------------------------------------------------------------------*/ -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); -} +/* functions in library namespace */ +static luaL_reg func[] = { + {"select", global_select}, + {NULL, NULL} +}; void select_open(lua_State *L) { - /* push select auxiliar lua function and register - * select_lua_select with it as an upvalue */ -#ifdef LUASOCKET_DOFILE - lua_dofile(L, "lsselect.lua"); + /* get select auxiliar lua function from lua code and register + * pass it as an upvalue to global_select */ +#ifdef LUASOCKET_COMPILED +#include "select.lch" #else -#include "lsselect.loh" + lua_dofile(L, "select.lua"); #endif - lua_getglobal(L, LUASOCKET_LIBNAME); - lua_pushstring(L, "_select"); - lua_gettable(L, -2); - lua_pushcclosure(L, select_lua_select, 1); - priv_newglobal(L, "select"); + luaL_openlib(L, LUASOCKET_LIBNAME, func, 1); lua_pop(L, 1); - /* create luasocket(select) table */ - lua_pushstring(L, "luasocket(select)"); - lua_newtable(L); - lua_settable(L, LUA_REGISTRYINDEX); + aux_newclass(L, "select{fd_set}", set); } /*-------------------------------------------------------------------------*\ * 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_ZERO(&read); - FD_ZERO(&write); - /* push select lua auxiliar function */ - lua_pushvalue(L, lua_upvalueindex(1)); lua_insert(L, 1); + fd_set *read_fd_set, *write_fd_set; /* make sure we have enough arguments (nil is the default) */ - lua_settop(L, 4); - /* pass FD_SET and manipulation functions */ - lua_boxpointer(L, &read); - lua_boxpointer(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); + lua_settop(L, 3); + /* check object tables */ + check_obj_tab(L, 1); + check_obj_tab(L, 2); + /* check timeout */ + if (!lua_isnil(L, 3) && !lua_isnumber(L, 3)) + luaL_argerror(L, 3, "number or nil expected"); + /* select auxiliar lua function to be called comes first */ + lua_pushvalue(L, lua_upvalueindex(1)); + lua_insert(L, 1); + /* pass fd_set objects */ + 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 */ - lua_pushcfunction(L, local_select); + lua_pushcfunction(L, c_select); /* call select auxiliar lua function */ - lua_call(L, 10, 3); + lua_call(L, 6, 3); return 3; } -static int local_getfd(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) +static int c_select(lua_State *L) { 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); + fd_set *read_fd_set = (fd_set *) aux_checkclass(L, "select{fd_set}", 2); + fd_set *write_fd_set = (fd_set *) aux_checkclass(L, "select{fd_set}", 3); + int timeout = 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)); - } + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + lua_pushnumber(L, select(max_fd, read_fd_set, write_fd_set, NULL, + timeout < 0 ? NULL : &tv)); 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 *) lua_topointer(L, 2); + fd_set *set = (fd_set *) aux_checkclass(L, "select{fd_set}", 1); + t_sock fd = (t_sock) lua_tonumber(L, 2); if (fd >= 0) FD_SET(fd, set); 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 *) lua_topointer(L, 2); + fd_set *set = (fd_set *) aux_checkclass(L, "select{fd_set}", 1); + t_sock fd = (t_sock) lua_tonumber(L, 2); if (fd >= 0 && FD_ISSET(fd, set)) lua_pushnumber(L, 1); else lua_pushnil(L); 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"); +} diff --git a/src/select.h b/src/select.h index 2b2ed19..9521fae 100644 --- a/src/select.h +++ b/src/select.h @@ -2,10 +2,9 @@ * Select implementation * RCS ID: $Id$ \*=========================================================================*/ -#ifndef SLCT_H_ -#define SLCT_H_ +#ifndef SELECT_H +#define SELECT_H -void select_addclass(lua_State *L, cchar *lsclass); void select_open(lua_State *L); -#endif +#endif /* SELECT_H */ diff --git a/src/socket.h b/src/socket.h index f8c5d8f..70ebc52 100644 --- a/src/socket.h +++ b/src/socket.h @@ -6,16 +6,15 @@ #ifndef SOCK_H #define SOCK_H -#include -#include "error.h" +#include "io.h" /*=========================================================================*\ * Platform specific compatibilization \*=========================================================================*/ #ifdef WIN32 -#include "sockwin32.h" +#include "wsocket.h" #else -#include "sockunix.h" +#include "usocket.h" #endif /* we are lazy... */ @@ -25,13 +24,13 @@ typedef struct sockaddr SA; * Functions bellow implement a comfortable platform independent * 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); void sock_destroy(p_sock ps); -void sock_accept(p_sock ps, p_sock pa, SA *addr, size_t *addr_len, int timeout); -const char *sock_connect(p_sock ps, SA *addr, size_t addr_len); -const char *sock_bind(p_sock ps, SA *addr, size_t addr_len); +int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len, + int timeout); +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); 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, size_t *got, int timeout); 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, - 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_setblocking(p_sock ps); @@ -52,6 +51,4 @@ const char *sock_createstrerror(void); const char *sock_bindstrerror(void); const char *sock_connectstrerror(void); -const char *sock_trysetoptions(lua_State *L, p_sock ps); - #endif /* SOCK_H */ diff --git a/src/tcp.c b/src/tcp.c index db6a38e..74857c9 100644 --- a/src/tcp.c +++ b/src/tcp.c @@ -10,43 +10,49 @@ #include "luasocket.h" -#include "aux.h" +#include "auxiliar.h" +#include "socket.h" #include "inet.h" +#include "error.h" #include "tcp.h" /*=========================================================================*\ * Internal function prototypes \*=========================================================================*/ -static int tcp_global_create(lua_State *L); -static int tcp_meth_connect(lua_State *L); -static int tcp_meth_bind(lua_State *L); -static int tcp_meth_send(lua_State *L); -static int tcp_meth_getsockname(lua_State *L); -static int tcp_meth_getpeername(lua_State *L); -static int tcp_meth_receive(lua_State *L); -static int tcp_meth_accept(lua_State *L); -static int tcp_meth_close(lua_State *L); -static int tcp_meth_timeout(lua_State *L); +static int global_create(lua_State *L); +static int meth_connect(lua_State *L); +static int meth_bind(lua_State *L); +static int meth_send(lua_State *L); +static int meth_getsockname(lua_State *L); +static int meth_getpeername(lua_State *L); +static int meth_receive(lua_State *L); +static int meth_accept(lua_State *L); +static int meth_close(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 */ static luaL_reg tcp[] = { - {"connect", tcp_meth_connect}, - {"send", tcp_meth_send}, - {"receive", tcp_meth_receive}, - {"bind", tcp_meth_bind}, - {"accept", tcp_meth_accept}, - {"setpeername", tcp_meth_connect}, - {"setsockname", tcp_meth_bind}, - {"getpeername", tcp_meth_getpeername}, - {"getsockname", tcp_meth_getsockname}, - {"timeout", tcp_meth_timeout}, - {"close", tcp_meth_close}, + {"connect", meth_connect}, + {"send", meth_send}, + {"receive", meth_receive}, + {"bind", meth_bind}, + {"accept", meth_accept}, + {"setpeername", meth_connect}, + {"setsockname", meth_bind}, + {"getpeername", meth_getpeername}, + {"getsockname", meth_getsockname}, + {"timeout", meth_timeout}, + {"close", meth_close}, + {"fd", meth_fd}, + {"dirty", meth_dirty}, {NULL, NULL} }; /* functions in library namespace */ static luaL_reg func[] = { - {"tcp", tcp_global_create}, + {"tcp", global_create}, {NULL, NULL} }; @@ -60,11 +66,13 @@ void tcp_open(lua_State *L) aux_newclass(L, "tcp{client}", tcp); aux_newclass(L, "tcp{server}", tcp); /* 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{client}", "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 */ luaL_openlib(L, LUASOCKET_LIBNAME, func, 0); lua_pop(L, 1); @@ -76,28 +84,45 @@ void tcp_open(lua_State *L) /*-------------------------------------------------------------------------*\ * 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); 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); 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 \*-------------------------------------------------------------------------*/ -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); 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); return inet_meth_getsockname(L, &tcp->sock); @@ -106,7 +131,7 @@ static int tcp_meth_getsockname(lua_State *L) /*-------------------------------------------------------------------------*\ * 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); return tm_meth_timeout(L, &tcp->tm); @@ -115,7 +140,7 @@ static int tcp_meth_timeout(lua_State *L) /*-------------------------------------------------------------------------*\ * 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); 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. \*-------------------------------------------------------------------------*/ -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); 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 \*-------------------------------------------------------------------------*/ -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); 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 * server object \*-------------------------------------------------------------------------*/ -static int tcp_meth_accept(lua_State *L) +static int meth_accept(lua_State *L) { 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_tm tm = &server->tm; 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 \*-------------------------------------------------------------------------*/ -int tcp_global_create(lua_State *L) +int global_create(lua_State *L) { /* allocate tcp object */ p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); diff --git a/src/tcp.h b/src/tcp.h index d4cc65c..f4319f3 100644 --- a/src/tcp.h +++ b/src/tcp.h @@ -3,9 +3,9 @@ #include -#include "buf.h" -#include "tm.h" -#include "sock.h" +#include "buffer.h" +#include "timeout.h" +#include "socket.h" typedef struct t_tcp_ { t_sock sock; diff --git a/src/timeout.c b/src/timeout.c index 17878aa..1553069 100644 --- a/src/timeout.c +++ b/src/timeout.c @@ -12,8 +12,8 @@ #include #include "luasocket.h" -#include "aux.h" -#include "tm.h" +#include "auxiliar.h" +#include "timeout.h" #ifdef WIN32 #include @@ -118,6 +118,7 @@ int tm_gettime(void) void tm_open(lua_State *L) { luaL_openlib(L, LUASOCKET_LIBNAME, func, 0); + lua_pop(L, 1); } /*-------------------------------------------------------------------------*\ diff --git a/src/udp.c b/src/udp.c index 1701d1b..bcf515b 100644 --- a/src/udp.c +++ b/src/udp.c @@ -10,43 +10,49 @@ #include "luasocket.h" -#include "aux.h" +#include "auxiliar.h" +#include "socket.h" #include "inet.h" +#include "error.h" #include "udp.h" /*=========================================================================*\ * Internal function prototypes \*=========================================================================*/ -static int udp_global_create(lua_State *L); -static int udp_meth_send(lua_State *L); -static int udp_meth_sendto(lua_State *L); -static int udp_meth_receive(lua_State *L); -static int udp_meth_receivefrom(lua_State *L); -static int udp_meth_getsockname(lua_State *L); -static int udp_meth_getpeername(lua_State *L); -static int udp_meth_setsockname(lua_State *L); -static int udp_meth_setpeername(lua_State *L); -static int udp_meth_close(lua_State *L); -static int udp_meth_timeout(lua_State *L); +static int global_create(lua_State *L); +static int meth_send(lua_State *L); +static int meth_sendto(lua_State *L); +static int meth_receive(lua_State *L); +static int meth_receivefrom(lua_State *L); +static int meth_getsockname(lua_State *L); +static int meth_getpeername(lua_State *L); +static int meth_setsockname(lua_State *L); +static int meth_setpeername(lua_State *L); +static int meth_close(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 */ static luaL_reg udp[] = { - {"setpeername", udp_meth_setpeername}, - {"setsockname", udp_meth_setsockname}, - {"getsockname", udp_meth_getsockname}, - {"getpeername", udp_meth_getpeername}, - {"send", udp_meth_send}, - {"sendto", udp_meth_sendto}, - {"receive", udp_meth_receive}, - {"receivefrom", udp_meth_receivefrom}, - {"timeout", udp_meth_timeout}, - {"close", udp_meth_close}, + {"setpeername", meth_setpeername}, + {"setsockname", meth_setsockname}, + {"getsockname", meth_getsockname}, + {"getpeername", meth_getpeername}, + {"send", meth_send}, + {"sendto", meth_sendto}, + {"receive", meth_receive}, + {"receivefrom", meth_receivefrom}, + {"timeout", meth_timeout}, + {"close", meth_close}, + {"fd", meth_fd}, + {"dirty", meth_dirty}, {NULL, NULL} }; /* functions in library namespace */ static luaL_reg func[] = { - {"udp", udp_global_create}, + {"udp", global_create}, {NULL, NULL} }; @@ -59,8 +65,10 @@ void udp_open(lua_State *L) aux_newclass(L, "udp{connected}", udp); aux_newclass(L, "udp{unconnected}", udp); /* 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{connected}", "select{able}"); + aux_add2group(L, "udp{unconnected}", "select{able}"); /* define library functions */ luaL_openlib(L, LUASOCKET_LIBNAME, func, 0); lua_pop(L, 1); @@ -72,7 +80,7 @@ void udp_open(lua_State *L) /*-------------------------------------------------------------------------*\ * 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_tm tm = &udp->tm; @@ -90,7 +98,7 @@ static int udp_meth_send(lua_State *L) /*-------------------------------------------------------------------------*\ * 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); size_t count, sent = 0; @@ -117,7 +125,7 @@ static int udp_meth_sendto(lua_State *L) /*-------------------------------------------------------------------------*\ * 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); char buffer[UDP_DATAGRAMSIZE]; @@ -136,11 +144,11 @@ static int udp_meth_receive(lua_State *L) /*-------------------------------------------------------------------------*\ * 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); struct sockaddr_in addr; - size_t addr_len = sizeof(addr); + socklen_t addr_len = sizeof(addr); char buffer[UDP_DATAGRAMSIZE]; size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer)); 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 \*-------------------------------------------------------------------------*/ -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); 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); return inet_meth_getsockname(L, &udp->sock); @@ -179,7 +205,7 @@ static int udp_meth_getsockname(lua_State *L) /*-------------------------------------------------------------------------*\ * 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); 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. \*-------------------------------------------------------------------------*/ -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); const char *address = luaL_checkstring(L, 2); @@ -211,7 +237,7 @@ static int udp_meth_setpeername(lua_State *L) /*-------------------------------------------------------------------------*\ * 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); sock_destroy(&udp->sock); @@ -221,7 +247,7 @@ static int udp_meth_close(lua_State *L) /*-------------------------------------------------------------------------*\ * 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); const char *address = luaL_checkstring(L, 2); @@ -242,7 +268,7 @@ static int udp_meth_setsockname(lua_State *L) /*-------------------------------------------------------------------------*\ * Creates a master udp object \*-------------------------------------------------------------------------*/ -int udp_global_create(lua_State *L) +int global_create(lua_State *L) { /* allocate udp object */ p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp)); diff --git a/src/udp.h b/src/udp.h index 4ba53e6..a6f17e2 100644 --- a/src/udp.h +++ b/src/udp.h @@ -3,8 +3,8 @@ #include -#include "tm.h" -#include "sock.h" +#include "timeout.h" +#include "socket.h" #define UDP_DATAGRAMSIZE 576 diff --git a/src/usocket.c b/src/usocket.c index b4b8d5a..062a0ff 100644 --- a/src/usocket.c +++ b/src/usocket.c @@ -1,24 +1,8 @@ -/*=========================================================================*\ -* Socket compatibilization module for Unix -* -* RCS ID: $Id$ -\*=========================================================================*/ -#include -#include #include -#include "sock.h" +#include "socket.h" -/*=========================================================================*\ -* 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) +int sock_open(void) { /* instals a handler to ignore sigpipe. */ struct sigaction new; @@ -43,13 +27,13 @@ const char *sock_create(p_sock ps, int domain, int type, int protocol) 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(); 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(); else return NULL; @@ -60,17 +44,25 @@ void sock_listen(p_sock ps, int 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; struct timeval tv; + SA dummy_addr; + socklen_t dummy_len; fd_set fds; tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; FD_ZERO(&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); + 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, @@ -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, - SA *addr, size_t addr_len, int timeout) + SA *addr, socklen_t addr_len, int timeout) { t_sock sock = *ps; 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, - SA *addr, size_t *addr_len, int timeout) + SA *addr, socklen_t *addr_len, int timeout) { t_sock sock = *ps; 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) { 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) { 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) { switch (errno) { @@ -241,9 +224,6 @@ const char *sock_bindstrerror(void) } } -/*-------------------------------------------------------------------------*\ -* Returns a string describing the last connect error. -\*-------------------------------------------------------------------------*/ const char *sock_connectstrerror(void) { 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) { int val = 1; setsockopt(*ps, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val)); } -/*-------------------------------------------------------------------------*\ -* Put socket into blocking mode. -\*-------------------------------------------------------------------------*/ void sock_setblocking(p_sock ps) { int flags = fcntl(*ps, F_GETFL, 0); @@ -280,68 +252,9 @@ void sock_setblocking(p_sock ps) fcntl(*ps, F_SETFL, flags); } -/*-------------------------------------------------------------------------*\ -* Put socket into non-blocking mode. -\*-------------------------------------------------------------------------*/ void sock_setnonblocking(p_sock ps) { int flags = fcntl(*ps, F_GETFL, 0); flags |= O_NONBLOCK; 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; -} diff --git a/src/usocket.h b/src/usocket.h index f124bce..9e4b75a 100644 --- a/src/usocket.h +++ b/src/usocket.h @@ -31,6 +31,11 @@ #include #include +#ifdef __APPLE__ +/* for some reason socklen_t is not defined in mac os x */ +typedef int socklen_t; +#endif + typedef int t_sock; typedef t_sock *p_sock; -- cgit v1.2.3-55-g6feb