diff --git a/doc/reference.html b/doc/reference.html index 078d40c..d7e0923 100644 --- a/doc/reference.html +++ b/doc/reference.html @@ -172,6 +172,7 @@ Support, Manual"> connect, dirty, getfd, +getoption, getpeername, getsockname, getstats, diff --git a/doc/tcp.html b/doc/tcp.html index 9583b1f..11a0428 100644 --- a/doc/tcp.html +++ b/doc/tcp.html @@ -396,7 +396,40 @@ disables the Nagle's algorithm for the connection.

-The method returns 1 in case of success, or nil otherwise. +The method returns 1 in case of success, or nil +followed by an error message otherwise. +

+ +

+Note: The descriptions above come from the man pages. +

+ + + +

+client:getoption(option)
+server:getoption(option) +

+ +

+Gets options for the TCP object. +See setoption for description of the +option names and values. +

+ +

+Option is a string with the option name. +

+ +

+The method returns the option value in case of success, or +nil followed by an error message otherwise.

diff --git a/src/options.c b/src/options.c index a464a4b..2085fdc 100644 --- a/src/options.c +++ b/src/options.c @@ -18,8 +18,11 @@ \*=========================================================================*/ static int opt_setmembership(lua_State *L, p_socket ps, int level, int name); static int opt_setboolean(lua_State *L, p_socket ps, int level, int name); +static int opt_getboolean(lua_State *L, p_socket ps, int level, int name); static int opt_set(lua_State *L, p_socket ps, int level, int name, void *val, int len); +static int opt_get(lua_State *L, p_socket ps, int level, int name, + void *val, int* len); /*=========================================================================*\ * Exported functions @@ -40,23 +43,51 @@ int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps) return opt->func(L, ps); } +int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps) +{ + const char *name = luaL_checkstring(L, 2); /* obj, name, ... */ + while (opt->name && strcmp(name, opt->name)) + opt++; + if (!opt->func) { + char msg[45]; + sprintf(msg, "unsupported option `%.35s'", name); + luaL_argerror(L, 2, msg); + } + return opt->func(L, ps); +} + /* enables reuse of local address */ int opt_reuseaddr(lua_State *L, p_socket ps) { return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEADDR); } +int opt_get_reuseaddr(lua_State *L, p_socket ps) +{ + return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEADDR); +} + /* disables the Naggle algorithm */ int opt_tcp_nodelay(lua_State *L, p_socket ps) { return opt_setboolean(L, ps, IPPROTO_TCP, TCP_NODELAY); } +int opt_get_tcp_nodelay(lua_State *L, p_socket ps) +{ + return opt_getboolean(L, ps, IPPROTO_TCP, TCP_NODELAY); +} + int opt_keepalive(lua_State *L, p_socket ps) { return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE); } +int opt_get_keepalive(lua_State *L, p_socket ps) +{ + return opt_getboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE); +} + int opt_dontroute(lua_State *L, p_socket ps) { return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE); @@ -105,6 +136,21 @@ int opt_ip_drop_membersip(lua_State *L, p_socket ps) return opt_setmembership(L, ps, IPPROTO_IP, IP_DROP_MEMBERSHIP); } +int opt_get_linger(lua_State *L, p_socket ps) +{ + struct linger li; /* obj, name */ + int len = sizeof(li); + int err = opt_get(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, &len); + if (err) + return err; + lua_newtable(L); + lua_pushboolean(L, li.l_onoff); + lua_setfield(L, -2, "on"); + lua_pushinteger(L, li.l_linger); + lua_setfield(L, -2, "timeout"); + return 1; +} + /*=========================================================================*\ * Auxiliar functions \*=========================================================================*/ @@ -129,6 +175,19 @@ static int opt_setmembership(lua_State *L, p_socket ps, int level, int name) return opt_set(L, ps, level, name, (char *) &val, sizeof(val)); } +static +int opt_get(lua_State *L, p_socket ps, int level, int name, void *val, int* len) +{ + socklen_t socklen = *len; + if (getsockopt(*ps, level, name, (char *) val, &socklen) < 0) { + lua_pushnil(L); + lua_pushstring(L, "getsockopt failed"); + return 2; + } + *len = socklen; + return 0; +} + static int opt_set(lua_State *L, p_socket ps, int level, int name, void *val, int len) { @@ -141,6 +200,17 @@ int opt_set(lua_State *L, p_socket ps, int level, int name, void *val, int len) return 1; } +static int opt_getboolean(lua_State *L, p_socket ps, int level, int name) +{ + int val = 0; + int len = sizeof(val); + int err = opt_get(L, ps, level, name, (char *) &val, &len); + if (err) + return err; + lua_pushboolean(L, val); + return 1; +} + static int opt_setboolean(lua_State *L, p_socket ps, int level, int name) { int val = auxiliar_checkboolean(L, 3); /* obj, name, bool */ diff --git a/src/options.h b/src/options.h index 900761e..c9b2e47 100644 --- a/src/options.h +++ b/src/options.h @@ -17,10 +17,17 @@ typedef struct t_opt { const char *name; int (*func)(lua_State *L, p_socket ps); + int (*get)(lua_State *L, p_socket ps); } t_opt; typedef t_opt *p_opt; /* supported options */ +int opt_get_reuseaddr(lua_State *L, p_socket ps); +int opt_get_tcp_nodelay(lua_State *L, p_socket ps); +int opt_get_keepalive(lua_State *L, p_socket ps); +int opt_get_linger(lua_State *L, p_socket ps); +int opt_get_reuseaddr(lua_State *L, p_socket ps); + int opt_dontroute(lua_State *L, p_socket ps); int opt_broadcast(lua_State *L, p_socket ps); int opt_reuseaddr(lua_State *L, p_socket ps); @@ -35,5 +42,6 @@ int opt_ip_drop_membersip(lua_State *L, p_socket ps); /* invokes the appropriate option handler */ int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps); +int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps); #endif diff --git a/src/tcp.c b/src/tcp.c index 539ad5e..4713b23 100644 --- a/src/tcp.c +++ b/src/tcp.c @@ -31,6 +31,7 @@ static int meth_shutdown(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_getoption(lua_State *L); static int meth_setoption(lua_State *L); static int meth_settimeout(lua_State *L); static int meth_getfd(lua_State *L); @@ -47,6 +48,7 @@ static luaL_reg tcp[] = { {"connect", meth_connect}, {"dirty", meth_dirty}, {"getfd", meth_getfd}, + {"getoption", meth_getoption}, {"getpeername", meth_getpeername}, {"getsockname", meth_getsockname}, {"getstats", meth_getstats}, @@ -64,6 +66,14 @@ static luaL_reg tcp[] = { }; /* socket option handlers */ +static t_opt optget[] = { + {"keepalive", opt_get_keepalive}, + {"reuseaddr", opt_get_reuseaddr}, + {"tcp-nodelay", opt_get_tcp_nodelay}, + {"linger", opt_get_linger}, + {NULL, NULL} +}; + static t_opt opt[] = { {"keepalive", opt_keepalive}, {"reuseaddr", opt_reuseaddr}, @@ -125,6 +135,12 @@ static int meth_setstats(lua_State *L) { /*-------------------------------------------------------------------------*\ * Just call option handler \*-------------------------------------------------------------------------*/ +static int meth_getoption(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + return opt_meth_getoption(L, optget, &tcp->sock); +} + static int meth_setoption(lua_State *L) { p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); diff --git a/test/tcp-getoptions b/test/tcp-getoptions new file mode 100755 index 0000000..f9b3d1b --- /dev/null +++ b/test/tcp-getoptions @@ -0,0 +1,41 @@ +#!/usr/bin/env lua + +require"socket" + +port = 8765 + +function options(o) + print("options for", o) + + for _, opt in ipairs{"keepalive", "reuseaddr", "tcp-nodelay"} do + print("getoption", opt, o:getoption(opt)) + end + + print("getoption", "linger", + "on", o:getoption("linger").on, + "timeout", o:getoption("linger").timeout) +end + +local m = socket.tcp() + +options(m) + +assert(m:bind("*", port)) +assert(m:listen()) + +options(m) + +m:close() + +local m = socket.bind("*", port) + +options(m) + +local c = socket.connect("localhost", port) + +options(c) + +local s = m:accept() + +options(s) +