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