1 /*=========================================================================*\
2 * Common option interface
3 * LuaSocket toolkit
4 *
5 * RCS ID: $Id: options.c,v 1.6 2005/11/20 07:20:23 diego Exp $
6 \*=========================================================================*/
7 #include <string.h>
8 
9 #include "lauxlib.h"
10 
11 #include "auxiliar.h"
12 #include "options.h"
13 #include "inet.h"
14 
15 
16 /*=========================================================================*\
17 * Internal functions prototypes
18 \*=========================================================================*/
19 static int opt_setmembership(lua_State *L, p_socket ps, int level, int name);
20 static int opt_setboolean(lua_State *L, p_socket ps, int level, int name);
21 static int opt_set(lua_State *L, p_socket ps, int level, int name,
22         void *val, int len);
23 
24 /*=========================================================================*\
25 * Exported functions
26 \*=========================================================================*/
27 /*-------------------------------------------------------------------------*\
28 * Calls appropriate option handler
29 \*-------------------------------------------------------------------------*/
opt_meth_setoption(lua_State * L,p_opt opt,p_socket ps)30 int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps)
31 {
32     const char *name = luaL_checkstring(L, 2);      /* obj, name, ... */
33     while (opt->name && strcmp(name, opt->name))
34         opt++;
35     if (!opt->func) {
36         char msg[45];
37         sprintf(msg, "unsupported option `%.35s'", name);
38         luaL_argerror(L, 2, msg);
39     }
40     return opt->func(L, ps);
41 }
42 
43 /* enables reuse of local address */
opt_reuseaddr(lua_State * L,p_socket ps)44 int opt_reuseaddr(lua_State *L, p_socket ps)
45 {
46     return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEADDR);
47 }
48 
49 /* disables the Naggle algorithm */
opt_tcp_nodelay(lua_State * L,p_socket ps)50 int opt_tcp_nodelay(lua_State *L, p_socket ps)
51 {
52     return opt_setboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
53 }
54 
opt_keepalive(lua_State * L,p_socket ps)55 int opt_keepalive(lua_State *L, p_socket ps)
56 {
57     return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
58 }
59 
opt_dontroute(lua_State * L,p_socket ps)60 int opt_dontroute(lua_State *L, p_socket ps)
61 {
62     return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE);
63 }
64 
opt_broadcast(lua_State * L,p_socket ps)65 int opt_broadcast(lua_State *L, p_socket ps)
66 {
67     return opt_setboolean(L, ps, SOL_SOCKET, SO_BROADCAST);
68 }
69 
opt_ip_multicast_loop(lua_State * L,p_socket ps)70 int opt_ip_multicast_loop(lua_State *L, p_socket ps)
71 {
72     return opt_setboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP);
73 }
74 
opt_linger(lua_State * L,p_socket ps)75 int opt_linger(lua_State *L, p_socket ps)
76 {
77     struct linger li;                      /* obj, name, table */
78     if (!lua_istable(L, 3)) luaL_typerror(L, 3, lua_typename(L, LUA_TTABLE));
79     lua_pushstring(L, "on");
80     lua_gettable(L, 3);
81     if (!lua_isboolean(L, -1))
82         luaL_argerror(L, 3, "boolean 'on' field expected");
83     li.l_onoff = (u_short) lua_toboolean(L, -1);
84     lua_pushstring(L, "timeout");
85     lua_gettable(L, 3);
86     if (!lua_isnumber(L, -1))
87         luaL_argerror(L, 3, "number 'timeout' field expected");
88     li.l_linger = (u_short) lua_tonumber(L, -1);
89     return opt_set(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(li));
90 }
91 
opt_ip_multicast_ttl(lua_State * L,p_socket ps)92 int opt_ip_multicast_ttl(lua_State *L, p_socket ps)
93 {
94     int val = (int) luaL_checknumber(L, 3);    /* obj, name, int */
95     return opt_set(L, ps, SOL_SOCKET, SO_LINGER, (char *) &val, sizeof(val));
96 }
97 
opt_ip_add_membership(lua_State * L,p_socket ps)98 int opt_ip_add_membership(lua_State *L, p_socket ps)
99 {
100     return opt_setmembership(L, ps, IPPROTO_IP, IP_ADD_MEMBERSHIP);
101 }
102 
opt_ip_drop_membersip(lua_State * L,p_socket ps)103 int opt_ip_drop_membersip(lua_State *L, p_socket ps)
104 {
105     return opt_setmembership(L, ps, IPPROTO_IP, IP_DROP_MEMBERSHIP);
106 }
107 
108 /*=========================================================================*\
109 * Auxiliar functions
110 \*=========================================================================*/
opt_setmembership(lua_State * L,p_socket ps,int level,int name)111 static int opt_setmembership(lua_State *L, p_socket ps, int level, int name)
112 {
113     struct ip_mreq val;                   /* obj, name, table */
114     if (!lua_istable(L, 3)) luaL_typerror(L, 3, lua_typename(L, LUA_TTABLE));
115     lua_pushstring(L, "multiaddr");
116     lua_gettable(L, 3);
117     if (!lua_isstring(L, -1))
118         luaL_argerror(L, 3, "string 'multiaddr' field expected");
119     if (!inet_aton(lua_tostring(L, -1), &val.imr_multiaddr))
120         luaL_argerror(L, 3, "invalid 'multiaddr' ip address");
121     lua_pushstring(L, "interface");
122     lua_gettable(L, 3);
123     if (!lua_isstring(L, -1))
124         luaL_argerror(L, 3, "string 'interface' field expected");
125     val.imr_interface.s_addr = htonl(INADDR_ANY);
126     if (strcmp(lua_tostring(L, -1), "*") &&
127             !inet_aton(lua_tostring(L, -1), &val.imr_interface))
128         luaL_argerror(L, 3, "invalid 'interface' ip address");
129     return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
130 }
131 
132 static
opt_set(lua_State * L,p_socket ps,int level,int name,void * val,int len)133 int opt_set(lua_State *L, p_socket ps, int level, int name, void *val, int len)
134 {
135     if (setsockopt(*ps, level, name, (char *) val, len) < 0) {
136         lua_pushnil(L);
137         lua_pushstring(L, "setsockopt failed");
138         return 2;
139     }
140     lua_pushnumber(L, 1);
141     return 1;
142 }
143 
opt_setboolean(lua_State * L,p_socket ps,int level,int name)144 static int opt_setboolean(lua_State *L, p_socket ps, int level, int name)
145 {
146     int val = auxiliar_checkboolean(L, 3);             /* obj, name, bool */
147     return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
148 }
149 
150