1 /*=========================================================================*\
2 * Common option interface
3 * LuaSocket toolkit
4 \*=========================================================================*/
5 #include <string.h>
6 
7 #include "lauxlib.h"
8 
9 #include "auxiliar.h"
10 #include "options.h"
11 #include "inet.h"
12 
13 
14 /*=========================================================================*\
15 * Internal functions prototypes
16 \*=========================================================================*/
17 static int opt_setmembership(lua_State *L, p_socket ps, int level, int name);
18 static int opt_ip6_setmembership(lua_State *L, p_socket ps, int level, int name);
19 static int opt_setboolean(lua_State *L, p_socket ps, int level, int name);
20 static int opt_getboolean(lua_State *L, p_socket ps, int level, int name);
21 static int opt_setint(lua_State *L, p_socket ps, int level, int name);
22 static int opt_getint(lua_State *L, p_socket ps, int level, int name);
23 static int opt_set(lua_State *L, p_socket ps, int level, int name,
24         void *val, int len);
25 static int opt_get(lua_State *L, p_socket ps, int level, int name,
26         void *val, int* len);
27 
28 /*=========================================================================*\
29 * Exported functions
30 \*=========================================================================*/
31 /*-------------------------------------------------------------------------*\
32 * Calls appropriate option handler
33 \*-------------------------------------------------------------------------*/
opt_meth_setoption(lua_State * L,p_opt opt,p_socket ps)34 int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps)
35 {
36     const char *name = luaL_checkstring(L, 2);      /* obj, name, ... */
37     while (opt->name && strcmp(name, opt->name))
38         opt++;
39     if (!opt->func) {
40         char msg[57];
41         sprintf(msg, "unsupported option `%.35s'", name);
42         luaL_argerror(L, 2, msg);
43     }
44     return opt->func(L, ps);
45 }
46 
opt_meth_getoption(lua_State * L,p_opt opt,p_socket ps)47 int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps)
48 {
49     const char *name = luaL_checkstring(L, 2);      /* obj, name, ... */
50     while (opt->name && strcmp(name, opt->name))
51         opt++;
52     if (!opt->func) {
53         char msg[57];
54         sprintf(msg, "unsupported option `%.35s'", name);
55         luaL_argerror(L, 2, msg);
56     }
57     return opt->func(L, ps);
58 }
59 
60 /* enables reuse of local address */
opt_set_reuseaddr(lua_State * L,p_socket ps)61 int opt_set_reuseaddr(lua_State *L, p_socket ps)
62 {
63     return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEADDR);
64 }
65 
opt_get_reuseaddr(lua_State * L,p_socket ps)66 int opt_get_reuseaddr(lua_State *L, p_socket ps)
67 {
68     return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEADDR);
69 }
70 
71 /* enables reuse of local port */
opt_set_reuseport(lua_State * L,p_socket ps)72 int opt_set_reuseport(lua_State *L, p_socket ps)
73 {
74     return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEPORT);
75 }
76 
opt_get_reuseport(lua_State * L,p_socket ps)77 int opt_get_reuseport(lua_State *L, p_socket ps)
78 {
79     return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEPORT);
80 }
81 
82 /* disables the Naggle algorithm */
opt_set_tcp_nodelay(lua_State * L,p_socket ps)83 int opt_set_tcp_nodelay(lua_State *L, p_socket ps)
84 {
85     return opt_setboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
86 }
87 
opt_get_tcp_nodelay(lua_State * L,p_socket ps)88 int opt_get_tcp_nodelay(lua_State *L, p_socket ps)
89 {
90     return opt_getboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
91 }
92 
opt_set_keepalive(lua_State * L,p_socket ps)93 int opt_set_keepalive(lua_State *L, p_socket ps)
94 {
95     return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
96 }
97 
opt_get_keepalive(lua_State * L,p_socket ps)98 int opt_get_keepalive(lua_State *L, p_socket ps)
99 {
100     return opt_getboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
101 }
102 
opt_set_dontroute(lua_State * L,p_socket ps)103 int opt_set_dontroute(lua_State *L, p_socket ps)
104 {
105     return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE);
106 }
107 
opt_get_dontroute(lua_State * L,p_socket ps)108 int opt_get_dontroute(lua_State *L, p_socket ps)
109 {
110     return opt_getboolean(L, ps, SOL_SOCKET, SO_DONTROUTE);
111 }
112 
opt_set_broadcast(lua_State * L,p_socket ps)113 int opt_set_broadcast(lua_State *L, p_socket ps)
114 {
115     return opt_setboolean(L, ps, SOL_SOCKET, SO_BROADCAST);
116 }
117 
opt_get_broadcast(lua_State * L,p_socket ps)118 int opt_get_broadcast(lua_State *L, p_socket ps)
119 {
120     return opt_getboolean(L, ps, SOL_SOCKET, SO_BROADCAST);
121 }
122 
opt_set_ip6_unicast_hops(lua_State * L,p_socket ps)123 int opt_set_ip6_unicast_hops(lua_State *L, p_socket ps)
124 {
125   return opt_setint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS);
126 }
127 
opt_get_ip6_unicast_hops(lua_State * L,p_socket ps)128 int opt_get_ip6_unicast_hops(lua_State *L, p_socket ps)
129 {
130   return opt_getint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS);
131 }
132 
opt_set_ip6_multicast_hops(lua_State * L,p_socket ps)133 int opt_set_ip6_multicast_hops(lua_State *L, p_socket ps)
134 {
135   return opt_setint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS);
136 }
137 
opt_get_ip6_multicast_hops(lua_State * L,p_socket ps)138 int opt_get_ip6_multicast_hops(lua_State *L, p_socket ps)
139 {
140   return opt_getint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS);
141 }
142 
opt_set_ip_multicast_loop(lua_State * L,p_socket ps)143 int opt_set_ip_multicast_loop(lua_State *L, p_socket ps)
144 {
145     return opt_setboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP);
146 }
147 
opt_get_ip_multicast_loop(lua_State * L,p_socket ps)148 int opt_get_ip_multicast_loop(lua_State *L, p_socket ps)
149 {
150     return opt_getboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP);
151 }
152 
opt_set_ip6_multicast_loop(lua_State * L,p_socket ps)153 int opt_set_ip6_multicast_loop(lua_State *L, p_socket ps)
154 {
155     return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP);
156 }
157 
opt_get_ip6_multicast_loop(lua_State * L,p_socket ps)158 int opt_get_ip6_multicast_loop(lua_State *L, p_socket ps)
159 {
160     return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP);
161 }
162 
opt_set_linger(lua_State * L,p_socket ps)163 int opt_set_linger(lua_State *L, p_socket ps)
164 {
165     struct linger li;                      /* obj, name, table */
166     if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE));
167     lua_pushstring(L, "on");
168     lua_gettable(L, 3);
169     if (!lua_isboolean(L, -1))
170         luaL_argerror(L, 3, "boolean 'on' field expected");
171     li.l_onoff = (u_short) lua_toboolean(L, -1);
172     lua_pushstring(L, "timeout");
173     lua_gettable(L, 3);
174     if (!lua_isnumber(L, -1))
175         luaL_argerror(L, 3, "number 'timeout' field expected");
176     li.l_linger = (u_short) lua_tonumber(L, -1);
177     return opt_set(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(li));
178 }
179 
opt_get_linger(lua_State * L,p_socket ps)180 int opt_get_linger(lua_State *L, p_socket ps)
181 {
182     struct linger li;                      /* obj, name */
183     int len = sizeof(li);
184     int err = opt_get(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, &len);
185     if (err)
186         return err;
187     lua_newtable(L);
188     lua_pushboolean(L, li.l_onoff);
189     lua_setfield(L, -2, "on");
190     lua_pushinteger(L, li.l_linger);
191     lua_setfield(L, -2, "timeout");
192     return 1;
193 }
194 
opt_set_ip_multicast_ttl(lua_State * L,p_socket ps)195 int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps)
196 {
197     return opt_setint(L, ps, IPPROTO_IP, IP_MULTICAST_TTL);
198 }
199 
opt_set_ip_multicast_if(lua_State * L,p_socket ps)200 int opt_set_ip_multicast_if(lua_State *L, p_socket ps)
201 {
202     const char *address = luaL_checkstring(L, 3);    /* obj, name, ip */
203     struct in_addr val;
204     val.s_addr = htonl(INADDR_ANY);
205     if (strcmp(address, "*") && !inet_aton(address, &val))
206         luaL_argerror(L, 3, "ip expected");
207     return opt_set(L, ps, IPPROTO_IP, IP_MULTICAST_IF,
208         (char *) &val, sizeof(val));
209 }
210 
opt_get_ip_multicast_if(lua_State * L,p_socket ps)211 int opt_get_ip_multicast_if(lua_State *L, p_socket ps)
212 {
213     struct in_addr val;
214     socklen_t len = sizeof(val);
215     if (getsockopt(*ps, IPPROTO_IP, IP_MULTICAST_IF, (char *) &val, &len) < 0) {
216         lua_pushnil(L);
217         lua_pushstring(L, "getsockopt failed");
218         return 2;
219     }
220     lua_pushstring(L, inet_ntoa(val));
221     return 1;
222 }
223 
opt_set_ip_add_membership(lua_State * L,p_socket ps)224 int opt_set_ip_add_membership(lua_State *L, p_socket ps)
225 {
226     return opt_setmembership(L, ps, IPPROTO_IP, IP_ADD_MEMBERSHIP);
227 }
228 
opt_set_ip_drop_membersip(lua_State * L,p_socket ps)229 int opt_set_ip_drop_membersip(lua_State *L, p_socket ps)
230 {
231     return opt_setmembership(L, ps, IPPROTO_IP, IP_DROP_MEMBERSHIP);
232 }
233 
opt_set_ip6_add_membership(lua_State * L,p_socket ps)234 int opt_set_ip6_add_membership(lua_State *L, p_socket ps)
235 {
236     return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP);
237 }
238 
opt_set_ip6_drop_membersip(lua_State * L,p_socket ps)239 int opt_set_ip6_drop_membersip(lua_State *L, p_socket ps)
240 {
241     return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP);
242 }
243 
opt_get_ip6_v6only(lua_State * L,p_socket ps)244 int opt_get_ip6_v6only(lua_State *L, p_socket ps)
245 {
246     return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY);
247 }
248 
opt_set_ip6_v6only(lua_State * L,p_socket ps)249 int opt_set_ip6_v6only(lua_State *L, p_socket ps)
250 {
251     return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY);
252 }
253 
254 /*=========================================================================*\
255 * Auxiliar functions
256 \*=========================================================================*/
opt_setmembership(lua_State * L,p_socket ps,int level,int name)257 static int opt_setmembership(lua_State *L, p_socket ps, int level, int name)
258 {
259     struct ip_mreq val;                   /* obj, name, table */
260     if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE));
261     lua_pushstring(L, "multiaddr");
262     lua_gettable(L, 3);
263     if (!lua_isstring(L, -1))
264         luaL_argerror(L, 3, "string 'multiaddr' field expected");
265     if (!inet_aton(lua_tostring(L, -1), &val.imr_multiaddr))
266         luaL_argerror(L, 3, "invalid 'multiaddr' ip address");
267     lua_pushstring(L, "interface");
268     lua_gettable(L, 3);
269     if (!lua_isstring(L, -1))
270         luaL_argerror(L, 3, "string 'interface' field expected");
271     val.imr_interface.s_addr = htonl(INADDR_ANY);
272     if (strcmp(lua_tostring(L, -1), "*") &&
273             !inet_aton(lua_tostring(L, -1), &val.imr_interface))
274         luaL_argerror(L, 3, "invalid 'interface' ip address");
275     return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
276 }
277 
opt_ip6_setmembership(lua_State * L,p_socket ps,int level,int name)278 static int opt_ip6_setmembership(lua_State *L, p_socket ps, int level, int name)
279 {
280     struct ipv6_mreq val;                   /* obj, opt-name, table */
281     memset(&val, 0, sizeof(val));
282     if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE));
283     lua_pushstring(L, "multiaddr");
284     lua_gettable(L, 3);
285     if (!lua_isstring(L, -1))
286         luaL_argerror(L, 3, "string 'multiaddr' field expected");
287     if (!inet_pton(AF_INET6, lua_tostring(L, -1), &val.ipv6mr_multiaddr))
288         luaL_argerror(L, 3, "invalid 'multiaddr' ip address");
289     lua_pushstring(L, "interface");
290     lua_gettable(L, 3);
291     /* By default we listen to interface on default route
292      * (sigh). However, interface= can override it. We should
293      * support either number, or name for it. Waiting for
294      * windows port of if_nametoindex */
295     if (!lua_isnil(L, -1)) {
296         if (lua_isnumber(L, -1)) {
297             val.ipv6mr_interface = (unsigned int) lua_tonumber(L, -1);
298         } else
299           luaL_argerror(L, -1, "number 'interface' field expected");
300     }
301     return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
302 }
303 
304 static
opt_get(lua_State * L,p_socket ps,int level,int name,void * val,int * len)305 int opt_get(lua_State *L, p_socket ps, int level, int name, void *val, int* len)
306 {
307     socklen_t socklen = *len;
308     if (getsockopt(*ps, level, name, (char *) val, &socklen) < 0) {
309         lua_pushnil(L);
310         lua_pushstring(L, "getsockopt failed");
311         return 2;
312     }
313     *len = socklen;
314     return 0;
315 }
316 
317 static
opt_set(lua_State * L,p_socket ps,int level,int name,void * val,int len)318 int opt_set(lua_State *L, p_socket ps, int level, int name, void *val, int len)
319 {
320     if (setsockopt(*ps, level, name, (char *) val, len) < 0) {
321         lua_pushnil(L);
322         lua_pushstring(L, "setsockopt failed");
323         return 2;
324     }
325     lua_pushnumber(L, 1);
326     return 1;
327 }
328 
opt_getboolean(lua_State * L,p_socket ps,int level,int name)329 static int opt_getboolean(lua_State *L, p_socket ps, int level, int name)
330 {
331     int val = 0;
332     int len = sizeof(val);
333     int err = opt_get(L, ps, level, name, (char *) &val, &len);
334     if (err)
335         return err;
336     lua_pushboolean(L, val);
337     return 1;
338 }
339 
opt_get_error(lua_State * L,p_socket ps)340 int opt_get_error(lua_State *L, p_socket ps)
341 {
342     int val = 0;
343     socklen_t len = sizeof(val);
344     if (getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *) &val, &len) < 0) {
345         lua_pushnil(L);
346         lua_pushstring(L, "getsockopt failed");
347         return 2;
348     }
349     lua_pushstring(L, socket_strerror(val));
350     return 1;
351 }
352 
opt_setboolean(lua_State * L,p_socket ps,int level,int name)353 static int opt_setboolean(lua_State *L, p_socket ps, int level, int name)
354 {
355     int val = auxiliar_checkboolean(L, 3);             /* obj, name, bool */
356     return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
357 }
358 
opt_getint(lua_State * L,p_socket ps,int level,int name)359 static int opt_getint(lua_State *L, p_socket ps, int level, int name)
360 {
361     int val = 0;
362     int len = sizeof(val);
363     int err = opt_get(L, ps, level, name, (char *) &val, &len);
364     if (err)
365         return err;
366     lua_pushnumber(L, val);
367     return 1;
368 }
369 
opt_setint(lua_State * L,p_socket ps,int level,int name)370 static int opt_setint(lua_State *L, p_socket ps, int level, int name)
371 {
372     int val = (int) lua_tonumber(L, 3);             /* obj, name, int */
373     return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
374 }
375