diff --git a/etc/check-links.lua b/etc/check-links.lua index 705c0ce..4c96fdc 100644 --- a/etc/check-links.lua +++ b/etc/check-links.lua @@ -1,6 +1,8 @@ ----------------------------------------------------------------------------- -- Little program that checks links in HTML files -- LuaSocket 1.5 sample files. +-- Author: Diego Nehab +-- RCS ID: $Id$ ----------------------------------------------------------------------------- socket.http.TIMEOUT = 10 diff --git a/etc/dict.lua b/etc/dict.lua index 6790cab..89bdb4f 100644 --- a/etc/dict.lua +++ b/etc/dict.lua @@ -1,6 +1,8 @@ ----------------------------------------------------------------------------- -- Little program to download DICT word definitions -- LuaSocket 1.5 sample files +-- Author: Diego Nehab +-- RCS ID: $Id$ ----------------------------------------------------------------------------- function get_status(sock, valid) local line, err = sock:receive() diff --git a/etc/get.lua b/etc/get.lua index af46c16..e972d16 100644 --- a/etc/get.lua +++ b/etc/get.lua @@ -1,6 +1,8 @@ ----------------------------------------------------------------------------- -- Little program to download files from URLs -- LuaSocket 1.5 sample files +-- Author: Diego Nehab +-- RCS ID: $Id$ ----------------------------------------------------------------------------- -- formats a number of seconds into human readable form function nicetime(s) diff --git a/makefile.dist b/makefile.dist index 90ef7c2..e493305 100644 --- a/makefile.dist +++ b/makefile.dist @@ -2,22 +2,81 @@ # 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 \ - cl-compat.lua +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 \ - urltest.lua concattest.lua +TESTS = \ + 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 \ - echosrvr.lua get.lua listener.lua talker.lua tinyirc.lua tftpclnt.lua +EXAMPLES = \ + 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: mkdir -p $(DIST)/examples mkdir -p $(DIST)/tests - cp -vf *.c $(DIST) - cp -vf *.h $(DIST) + mkdir -p $(DIST)/etc + mkdir -p $(DIST)/lua + cp -vf $(MAIN) $(DIST) cp -vf $(LUA) $(DIST) cp -vf makefile $(DIST) cp -vf README $(DIST) @@ -25,6 +84,8 @@ dist: cp -vf README.examples $(DIST)/examples/README cp -vf $(TESTS) $(DIST)/tests 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) zip -r $(DIST).zip $(DIST) diff --git a/samples/daytimeclnt.lua b/samples/daytimeclnt.lua index 4debc81..85ddca1 100644 --- a/samples/daytimeclnt.lua +++ b/samples/daytimeclnt.lua @@ -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" port = port or 13 if arg then diff --git a/samples/echoclnt.lua b/samples/echoclnt.lua index cd8b450..bca0b4d 100644 --- a/samples/echoclnt.lua +++ b/samples/echoclnt.lua @@ -1,3 +1,9 @@ +----------------------------------------------------------------------------- +-- UDP sample: echo protocol client +-- LuaSocket 1.5 sample files +-- Author: Diego Nehab +-- RCS ID: $Id$ +----------------------------------------------------------------------------- host = host or "localhost" port = port or 7 if arg then diff --git a/samples/echosrvr.lua b/samples/echosrvr.lua index 6117557..18bd84e 100644 --- a/samples/echosrvr.lua +++ b/samples/echosrvr.lua @@ -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" port = port or 7 if arg then diff --git a/samples/listener.lua b/samples/listener.lua index c035ab2..4846419 100644 --- a/samples/listener.lua +++ b/samples/listener.lua @@ -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 +-- Author: Diego Nehab +-- RCS ID: $Id$ ----------------------------------------------------------------------------- host = host or "*" port = port or 8080 diff --git a/samples/talker.lua b/samples/talker.lua index 688824f..c7a239a 100644 --- a/samples/talker.lua +++ b/samples/talker.lua @@ -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" port = port or 8080 if arg then diff --git a/samples/tinyirc.lua b/samples/tinyirc.lua index d3e56e7..0b20303 100644 --- a/samples/tinyirc.lua +++ b/samples/tinyirc.lua @@ -1,16 +1,9 @@ -function set_add(set, sock) - table.insert(set, sock) -end - -function set_remove(set, sock) - for i = 1, table.getn(set) do - if set[i] == sock then - table.remove(set, i) - break - end - end -end - +----------------------------------------------------------------------------- +-- Select sample: simple text line server +-- LuaSocket 1.5 sample files. +-- Author: Diego Nehab +-- RCS ID: $Id$ +----------------------------------------------------------------------------- host = host or "*" port1 = port1 or 8080 port2 = port2 or 8081 @@ -21,49 +14,62 @@ if arg then end server1, error = socket.bind(host, port1) -if not server1 then print(error) exit() end +assert(server1, error) server1:timeout(1) server2, error = socket.bind(host, port2) -if not server2 then print(error) exit() end +assert(server2, error) 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 = {} -sock_id[server1] = 1 -sock_id[server2] = 2 -next_id = 3 +sockets = newset() + +sockets:insert(server1) +sockets:insert(server2) while 1 do - local readable, _, error = socket.select(sock_set, nil) - for _, sock in readable do - -- is it a server socket - if sock_id[sock] < 3 then - local incomming = sock:accept() - if incomming then - incomming:timeout(1) - sock_id[incomming] = next_id - set_add(sock_set, incomming) - io.write("Added client id ", next_id, ". ", - table.getn(sock_set)-2, " total.\n") - next_id = next_id + 1 + local readable, _, error = socket.select(sockets, nil) + for _, input in readable do + -- is it a server socket? + local id = sockets:id(input) + if input == server1 or input == server2 then + local new = input:accept() + if new then + new:timeout(1) + sockets:insert(new) + io.write("Server ", id, " got client ", sockets:id(new), "\n") end -- it is a client socket else - local line, error = sock:receive() - local id = sock_id[sock] + local line, error = input:receive() if error then - sock:close() - set_remove(sock_set, sock) - io.write("Removed client number ", id, ". ", - getn(sock_set)-2, " total.\n") + input:close() + io.write("Removing client ", id, "\n") + sockets:remove(input) else 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 - for ___, outgoing in writable do - io.write("Sending to client ", sock_id[outgoing], "\n") - outgoing:send(id, "> ", line, "\r\n") + for ___, output in writable do + io.write("Sending to client ", sockets:id(output), "\n") + output:send(id, "> ", line, "\r\n") end else io.write("No one ready to listen!!!\n") end end 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; - lua_pushstring(L, "group"); - lua_gettable(L, -2); - if (lua_isnil(L, -1)) { + 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_rawget(L, -2); + if (!lua_istable(L, -1)) { + lua_pop(L, 3); + return NULL; + } 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)) { 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;