diff options
Diffstat (limited to 'vendor/luasocket/src/options.c')
-rw-r--r-- | vendor/luasocket/src/options.c | 480 |
1 files changed, 480 insertions, 0 deletions
diff --git a/vendor/luasocket/src/options.c b/vendor/luasocket/src/options.c new file mode 100644 index 00000000..3280c51d --- /dev/null +++ b/vendor/luasocket/src/options.c | |||
@@ -0,0 +1,480 @@ | |||
1 | /*=========================================================================*\ | ||
2 | * Common option interface | ||
3 | * LuaSocket toolkit | ||
4 | \*=========================================================================*/ | ||
5 | #include "luasocket.h" | ||
6 | #include "auxiliar.h" | ||
7 | #include "options.h" | ||
8 | #include "inet.h" | ||
9 | #include <string.h> | ||
10 | |||
11 | /*=========================================================================*\ | ||
12 | * Internal functions prototypes | ||
13 | \*=========================================================================*/ | ||
14 | static int opt_setmembership(lua_State *L, p_socket ps, int level, int name); | ||
15 | static int opt_ip6_setmembership(lua_State *L, p_socket ps, int level, int name); | ||
16 | static int opt_setboolean(lua_State *L, p_socket ps, int level, int name); | ||
17 | static int opt_getboolean(lua_State *L, p_socket ps, int level, int name); | ||
18 | static int opt_setint(lua_State *L, p_socket ps, int level, int name); | ||
19 | static int opt_getint(lua_State *L, p_socket ps, int level, int name); | ||
20 | static int opt_set(lua_State *L, p_socket ps, int level, int name, | ||
21 | void *val, int len); | ||
22 | static int opt_get(lua_State *L, p_socket ps, int level, int name, | ||
23 | void *val, int* len); | ||
24 | |||
25 | /*=========================================================================*\ | ||
26 | * Exported functions | ||
27 | \*=========================================================================*/ | ||
28 | /*-------------------------------------------------------------------------*\ | ||
29 | * Calls appropriate option handler | ||
30 | \*-------------------------------------------------------------------------*/ | ||
31 | int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps) | ||
32 | { | ||
33 | const char *name = luaL_checkstring(L, 2); /* obj, name, ... */ | ||
34 | while (opt->name && strcmp(name, opt->name)) | ||
35 | opt++; | ||
36 | if (!opt->func) { | ||
37 | char msg[57]; | ||
38 | sprintf(msg, "unsupported option `%.35s'", name); | ||
39 | luaL_argerror(L, 2, msg); | ||
40 | } | ||
41 | return opt->func(L, ps); | ||
42 | } | ||
43 | |||
44 | int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps) | ||
45 | { | ||
46 | const char *name = luaL_checkstring(L, 2); /* obj, name, ... */ | ||
47 | while (opt->name && strcmp(name, opt->name)) | ||
48 | opt++; | ||
49 | if (!opt->func) { | ||
50 | char msg[57]; | ||
51 | sprintf(msg, "unsupported option `%.35s'", name); | ||
52 | luaL_argerror(L, 2, msg); | ||
53 | } | ||
54 | return opt->func(L, ps); | ||
55 | } | ||
56 | |||
57 | /*------------------------------------------------------*/ | ||
58 | /* enables reuse of local address */ | ||
59 | int opt_set_reuseaddr(lua_State *L, p_socket ps) | ||
60 | { | ||
61 | return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEADDR); | ||
62 | } | ||
63 | |||
64 | int opt_get_reuseaddr(lua_State *L, p_socket ps) | ||
65 | { | ||
66 | return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEADDR); | ||
67 | } | ||
68 | |||
69 | /*------------------------------------------------------*/ | ||
70 | /* enables reuse of local port */ | ||
71 | int opt_set_reuseport(lua_State *L, p_socket ps) | ||
72 | { | ||
73 | return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEPORT); | ||
74 | } | ||
75 | |||
76 | int opt_get_reuseport(lua_State *L, p_socket ps) | ||
77 | { | ||
78 | return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEPORT); | ||
79 | } | ||
80 | |||
81 | /*------------------------------------------------------*/ | ||
82 | /* disables the Nagle algorithm */ | ||
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 | |||
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 | |||
93 | /*------------------------------------------------------*/ | ||
94 | #ifdef TCP_KEEPIDLE | ||
95 | |||
96 | int opt_get_tcp_keepidle(lua_State *L, p_socket ps) | ||
97 | { | ||
98 | return opt_getint(L, ps, IPPROTO_TCP, TCP_KEEPIDLE); | ||
99 | } | ||
100 | |||
101 | int opt_set_tcp_keepidle(lua_State *L, p_socket ps) | ||
102 | { | ||
103 | return opt_setint(L, ps, IPPROTO_TCP, TCP_KEEPIDLE); | ||
104 | } | ||
105 | |||
106 | #endif | ||
107 | |||
108 | /*------------------------------------------------------*/ | ||
109 | #ifdef TCP_KEEPCNT | ||
110 | |||
111 | int opt_get_tcp_keepcnt(lua_State *L, p_socket ps) | ||
112 | { | ||
113 | return opt_getint(L, ps, IPPROTO_TCP, TCP_KEEPCNT); | ||
114 | } | ||
115 | |||
116 | int opt_set_tcp_keepcnt(lua_State *L, p_socket ps) | ||
117 | { | ||
118 | return opt_setint(L, ps, IPPROTO_TCP, TCP_KEEPCNT); | ||
119 | } | ||
120 | |||
121 | #endif | ||
122 | |||
123 | /*------------------------------------------------------*/ | ||
124 | #ifdef TCP_KEEPINTVL | ||
125 | |||
126 | int opt_get_tcp_keepintvl(lua_State *L, p_socket ps) | ||
127 | { | ||
128 | return opt_getint(L, ps, IPPROTO_TCP, TCP_KEEPINTVL); | ||
129 | } | ||
130 | |||
131 | int opt_set_tcp_keepintvl(lua_State *L, p_socket ps) | ||
132 | { | ||
133 | return opt_setint(L, ps, IPPROTO_TCP, TCP_KEEPINTVL); | ||
134 | } | ||
135 | |||
136 | #endif | ||
137 | |||
138 | /*------------------------------------------------------*/ | ||
139 | int opt_set_keepalive(lua_State *L, p_socket ps) | ||
140 | { | ||
141 | return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE); | ||
142 | } | ||
143 | |||
144 | int opt_get_keepalive(lua_State *L, p_socket ps) | ||
145 | { | ||
146 | return opt_getboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE); | ||
147 | } | ||
148 | |||
149 | /*------------------------------------------------------*/ | ||
150 | int opt_set_dontroute(lua_State *L, p_socket ps) | ||
151 | { | ||
152 | return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE); | ||
153 | } | ||
154 | |||
155 | int opt_get_dontroute(lua_State *L, p_socket ps) | ||
156 | { | ||
157 | return opt_getboolean(L, ps, SOL_SOCKET, SO_DONTROUTE); | ||
158 | } | ||
159 | |||
160 | /*------------------------------------------------------*/ | ||
161 | int opt_set_broadcast(lua_State *L, p_socket ps) | ||
162 | { | ||
163 | return opt_setboolean(L, ps, SOL_SOCKET, SO_BROADCAST); | ||
164 | } | ||
165 | |||
166 | int opt_get_broadcast(lua_State *L, p_socket ps) | ||
167 | { | ||
168 | return opt_getboolean(L, ps, SOL_SOCKET, SO_BROADCAST); | ||
169 | } | ||
170 | |||
171 | /*------------------------------------------------------*/ | ||
172 | int opt_set_recv_buf_size(lua_State *L, p_socket ps) | ||
173 | { | ||
174 | return opt_setint(L, ps, SOL_SOCKET, SO_RCVBUF); | ||
175 | } | ||
176 | |||
177 | int opt_get_recv_buf_size(lua_State *L, p_socket ps) | ||
178 | { | ||
179 | return opt_getint(L, ps, SOL_SOCKET, SO_RCVBUF); | ||
180 | } | ||
181 | |||
182 | /*------------------------------------------------------*/ | ||
183 | int opt_get_send_buf_size(lua_State *L, p_socket ps) | ||
184 | { | ||
185 | return opt_getint(L, ps, SOL_SOCKET, SO_SNDBUF); | ||
186 | } | ||
187 | |||
188 | int opt_set_send_buf_size(lua_State *L, p_socket ps) | ||
189 | { | ||
190 | return opt_setint(L, ps, SOL_SOCKET, SO_SNDBUF); | ||
191 | } | ||
192 | |||
193 | // /*------------------------------------------------------*/ | ||
194 | |||
195 | #ifdef TCP_FASTOPEN | ||
196 | int opt_set_tcp_fastopen(lua_State *L, p_socket ps) | ||
197 | { | ||
198 | return opt_setint(L, ps, IPPROTO_TCP, TCP_FASTOPEN); | ||
199 | } | ||
200 | #endif | ||
201 | |||
202 | #ifdef TCP_FASTOPEN_CONNECT | ||
203 | int opt_set_tcp_fastopen_connect(lua_State *L, p_socket ps) | ||
204 | { | ||
205 | return opt_setint(L, ps, IPPROTO_TCP, TCP_FASTOPEN_CONNECT); | ||
206 | } | ||
207 | #endif | ||
208 | |||
209 | /*------------------------------------------------------*/ | ||
210 | |||
211 | #ifdef TCP_DEFER_ACCEPT | ||
212 | int opt_set_tcp_defer_accept(lua_State *L, p_socket ps) | ||
213 | { | ||
214 | return opt_setint(L, ps, IPPROTO_TCP, TCP_DEFER_ACCEPT); | ||
215 | } | ||
216 | #endif | ||
217 | |||
218 | /*------------------------------------------------------*/ | ||
219 | int opt_set_ip6_unicast_hops(lua_State *L, p_socket ps) | ||
220 | { | ||
221 | return opt_setint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS); | ||
222 | } | ||
223 | |||
224 | int opt_get_ip6_unicast_hops(lua_State *L, p_socket ps) | ||
225 | { | ||
226 | return opt_getint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS); | ||
227 | } | ||
228 | |||
229 | /*------------------------------------------------------*/ | ||
230 | int opt_set_ip6_multicast_hops(lua_State *L, p_socket ps) | ||
231 | { | ||
232 | return opt_setint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS); | ||
233 | } | ||
234 | |||
235 | int opt_get_ip6_multicast_hops(lua_State *L, p_socket ps) | ||
236 | { | ||
237 | return opt_getint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS); | ||
238 | } | ||
239 | |||
240 | /*------------------------------------------------------*/ | ||
241 | int opt_set_ip_multicast_loop(lua_State *L, p_socket ps) | ||
242 | { | ||
243 | return opt_setboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP); | ||
244 | } | ||
245 | |||
246 | int opt_get_ip_multicast_loop(lua_State *L, p_socket ps) | ||
247 | { | ||
248 | return opt_getboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP); | ||
249 | } | ||
250 | |||
251 | /*------------------------------------------------------*/ | ||
252 | int opt_set_ip6_multicast_loop(lua_State *L, p_socket ps) | ||
253 | { | ||
254 | return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP); | ||
255 | } | ||
256 | |||
257 | int opt_get_ip6_multicast_loop(lua_State *L, p_socket ps) | ||
258 | { | ||
259 | return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP); | ||
260 | } | ||
261 | |||
262 | /*------------------------------------------------------*/ | ||
263 | int opt_set_linger(lua_State *L, p_socket ps) | ||
264 | { | ||
265 | struct linger li; /* obj, name, table */ | ||
266 | if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE)); | ||
267 | lua_pushstring(L, "on"); | ||
268 | lua_gettable(L, 3); | ||
269 | if (!lua_isboolean(L, -1)) | ||
270 | luaL_argerror(L, 3, "boolean 'on' field expected"); | ||
271 | li.l_onoff = (u_short) lua_toboolean(L, -1); | ||
272 | lua_pushstring(L, "timeout"); | ||
273 | lua_gettable(L, 3); | ||
274 | if (!lua_isnumber(L, -1)) | ||
275 | luaL_argerror(L, 3, "number 'timeout' field expected"); | ||
276 | li.l_linger = (u_short) lua_tonumber(L, -1); | ||
277 | return opt_set(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(li)); | ||
278 | } | ||
279 | |||
280 | int opt_get_linger(lua_State *L, p_socket ps) | ||
281 | { | ||
282 | struct linger li; /* obj, name */ | ||
283 | int len = sizeof(li); | ||
284 | int err = opt_get(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, &len); | ||
285 | if (err) | ||
286 | return err; | ||
287 | lua_newtable(L); | ||
288 | lua_pushboolean(L, li.l_onoff); | ||
289 | lua_setfield(L, -2, "on"); | ||
290 | lua_pushinteger(L, li.l_linger); | ||
291 | lua_setfield(L, -2, "timeout"); | ||
292 | return 1; | ||
293 | } | ||
294 | |||
295 | /*------------------------------------------------------*/ | ||
296 | int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps) | ||
297 | { | ||
298 | return opt_setint(L, ps, IPPROTO_IP, IP_MULTICAST_TTL); | ||
299 | } | ||
300 | |||
301 | /*------------------------------------------------------*/ | ||
302 | int opt_set_ip_multicast_if(lua_State *L, p_socket ps) | ||
303 | { | ||
304 | const char *address = luaL_checkstring(L, 3); /* obj, name, ip */ | ||
305 | struct in_addr val; | ||
306 | val.s_addr = htonl(INADDR_ANY); | ||
307 | if (strcmp(address, "*") && !inet_aton(address, &val)) | ||
308 | luaL_argerror(L, 3, "ip expected"); | ||
309 | return opt_set(L, ps, IPPROTO_IP, IP_MULTICAST_IF, | ||
310 | (char *) &val, sizeof(val)); | ||
311 | } | ||
312 | |||
313 | int opt_get_ip_multicast_if(lua_State *L, p_socket ps) | ||
314 | { | ||
315 | struct in_addr val; | ||
316 | socklen_t len = sizeof(val); | ||
317 | if (getsockopt(*ps, IPPROTO_IP, IP_MULTICAST_IF, (char *) &val, &len) < 0) { | ||
318 | lua_pushnil(L); | ||
319 | lua_pushstring(L, "getsockopt failed"); | ||
320 | return 2; | ||
321 | } | ||
322 | lua_pushstring(L, inet_ntoa(val)); | ||
323 | return 1; | ||
324 | } | ||
325 | |||
326 | /*------------------------------------------------------*/ | ||
327 | int opt_set_ip_add_membership(lua_State *L, p_socket ps) | ||
328 | { | ||
329 | return opt_setmembership(L, ps, IPPROTO_IP, IP_ADD_MEMBERSHIP); | ||
330 | } | ||
331 | |||
332 | int opt_set_ip_drop_membersip(lua_State *L, p_socket ps) | ||
333 | { | ||
334 | return opt_setmembership(L, ps, IPPROTO_IP, IP_DROP_MEMBERSHIP); | ||
335 | } | ||
336 | |||
337 | /*------------------------------------------------------*/ | ||
338 | int opt_set_ip6_add_membership(lua_State *L, p_socket ps) | ||
339 | { | ||
340 | return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP); | ||
341 | } | ||
342 | |||
343 | int opt_set_ip6_drop_membersip(lua_State *L, p_socket ps) | ||
344 | { | ||
345 | return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP); | ||
346 | } | ||
347 | |||
348 | /*------------------------------------------------------*/ | ||
349 | int opt_get_ip6_v6only(lua_State *L, p_socket ps) | ||
350 | { | ||
351 | return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY); | ||
352 | } | ||
353 | |||
354 | int opt_set_ip6_v6only(lua_State *L, p_socket ps) | ||
355 | { | ||
356 | return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY); | ||
357 | } | ||
358 | |||
359 | /*------------------------------------------------------*/ | ||
360 | int opt_get_error(lua_State *L, p_socket ps) | ||
361 | { | ||
362 | int val = 0; | ||
363 | socklen_t len = sizeof(val); | ||
364 | if (getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *) &val, &len) < 0) { | ||
365 | lua_pushnil(L); | ||
366 | lua_pushstring(L, "getsockopt failed"); | ||
367 | return 2; | ||
368 | } | ||
369 | lua_pushstring(L, socket_strerror(val)); | ||
370 | return 1; | ||
371 | } | ||
372 | |||
373 | /*=========================================================================*\ | ||
374 | * Auxiliar functions | ||
375 | \*=========================================================================*/ | ||
376 | static int opt_setmembership(lua_State *L, p_socket ps, int level, int name) | ||
377 | { | ||
378 | struct ip_mreq val; /* obj, name, table */ | ||
379 | if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE)); | ||
380 | lua_pushstring(L, "multiaddr"); | ||
381 | lua_gettable(L, 3); | ||
382 | if (!lua_isstring(L, -1)) | ||
383 | luaL_argerror(L, 3, "string 'multiaddr' field expected"); | ||
384 | if (!inet_aton(lua_tostring(L, -1), &val.imr_multiaddr)) | ||
385 | luaL_argerror(L, 3, "invalid 'multiaddr' ip address"); | ||
386 | lua_pushstring(L, "interface"); | ||
387 | lua_gettable(L, 3); | ||
388 | if (!lua_isstring(L, -1)) | ||
389 | luaL_argerror(L, 3, "string 'interface' field expected"); | ||
390 | val.imr_interface.s_addr = htonl(INADDR_ANY); | ||
391 | if (strcmp(lua_tostring(L, -1), "*") && | ||
392 | !inet_aton(lua_tostring(L, -1), &val.imr_interface)) | ||
393 | luaL_argerror(L, 3, "invalid 'interface' ip address"); | ||
394 | return opt_set(L, ps, level, name, (char *) &val, sizeof(val)); | ||
395 | } | ||
396 | |||
397 | static int opt_ip6_setmembership(lua_State *L, p_socket ps, int level, int name) | ||
398 | { | ||
399 | struct ipv6_mreq val; /* obj, opt-name, table */ | ||
400 | memset(&val, 0, sizeof(val)); | ||
401 | if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE)); | ||
402 | lua_pushstring(L, "multiaddr"); | ||
403 | lua_gettable(L, 3); | ||
404 | if (!lua_isstring(L, -1)) | ||
405 | luaL_argerror(L, 3, "string 'multiaddr' field expected"); | ||
406 | if (!inet_pton(AF_INET6, lua_tostring(L, -1), &val.ipv6mr_multiaddr)) | ||
407 | luaL_argerror(L, 3, "invalid 'multiaddr' ip address"); | ||
408 | lua_pushstring(L, "interface"); | ||
409 | lua_gettable(L, 3); | ||
410 | /* By default we listen to interface on default route | ||
411 | * (sigh). However, interface= can override it. We should | ||
412 | * support either number, or name for it. Waiting for | ||
413 | * windows port of if_nametoindex */ | ||
414 | if (!lua_isnil(L, -1)) { | ||
415 | if (lua_isnumber(L, -1)) { | ||
416 | val.ipv6mr_interface = (unsigned int) lua_tonumber(L, -1); | ||
417 | } else | ||
418 | luaL_argerror(L, -1, "number 'interface' field expected"); | ||
419 | } | ||
420 | return opt_set(L, ps, level, name, (char *) &val, sizeof(val)); | ||
421 | } | ||
422 | |||
423 | static | ||
424 | int opt_get(lua_State *L, p_socket ps, int level, int name, void *val, int* len) | ||
425 | { | ||
426 | socklen_t socklen = *len; | ||
427 | if (getsockopt(*ps, level, name, (char *) val, &socklen) < 0) { | ||
428 | lua_pushnil(L); | ||
429 | lua_pushstring(L, "getsockopt failed"); | ||
430 | return 2; | ||
431 | } | ||
432 | *len = socklen; | ||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | static | ||
437 | int opt_set(lua_State *L, p_socket ps, int level, int name, void *val, int len) | ||
438 | { | ||
439 | if (setsockopt(*ps, level, name, (char *) val, len) < 0) { | ||
440 | lua_pushnil(L); | ||
441 | lua_pushstring(L, "setsockopt failed"); | ||
442 | return 2; | ||
443 | } | ||
444 | lua_pushnumber(L, 1); | ||
445 | return 1; | ||
446 | } | ||
447 | |||
448 | static int opt_getboolean(lua_State *L, p_socket ps, int level, int name) | ||
449 | { | ||
450 | int val = 0; | ||
451 | int len = sizeof(val); | ||
452 | int err = opt_get(L, ps, level, name, (char *) &val, &len); | ||
453 | if (err) | ||
454 | return err; | ||
455 | lua_pushboolean(L, val); | ||
456 | return 1; | ||
457 | } | ||
458 | |||
459 | static int opt_setboolean(lua_State *L, p_socket ps, int level, int name) | ||
460 | { | ||
461 | int val = auxiliar_checkboolean(L, 3); /* obj, name, bool */ | ||
462 | return opt_set(L, ps, level, name, (char *) &val, sizeof(val)); | ||
463 | } | ||
464 | |||
465 | static int opt_getint(lua_State *L, p_socket ps, int level, int name) | ||
466 | { | ||
467 | int val = 0; | ||
468 | int len = sizeof(val); | ||
469 | int err = opt_get(L, ps, level, name, (char *) &val, &len); | ||
470 | if (err) | ||
471 | return err; | ||
472 | lua_pushnumber(L, val); | ||
473 | return 1; | ||
474 | } | ||
475 | |||
476 | static int opt_setint(lua_State *L, p_socket ps, int level, int name) | ||
477 | { | ||
478 | int val = (int) lua_tonumber(L, 3); /* obj, name, int */ | ||
479 | return opt_set(L, ps, level, name, (char *) &val, sizeof(val)); | ||
480 | } | ||