diff options
Diffstat (limited to 'src/options.c')
-rw-r--r-- | src/options.c | 135 |
1 files changed, 123 insertions, 12 deletions
diff --git a/src/options.c b/src/options.c index 6f36ba4..8737d9c 100644 --- a/src/options.c +++ b/src/options.c | |||
@@ -3,6 +3,9 @@ | |||
3 | * LuaSocket toolkit | 3 | * LuaSocket toolkit |
4 | \*=========================================================================*/ | 4 | \*=========================================================================*/ |
5 | #include <string.h> | 5 | #include <string.h> |
6 | #include <sys/types.h> | ||
7 | #include <sys/socket.h> | ||
8 | #include <net/if.h> | ||
6 | 9 | ||
7 | #include "lauxlib.h" | 10 | #include "lauxlib.h" |
8 | 11 | ||
@@ -10,12 +13,30 @@ | |||
10 | #include "options.h" | 13 | #include "options.h" |
11 | #include "inet.h" | 14 | #include "inet.h" |
12 | 15 | ||
16 | /* Some platforms use IPV6_JOIN_GROUP instead if | ||
17 | * IPV6_ADD_MEMBERSHIP. The semantics are same, though. */ | ||
18 | #ifndef IPV6_ADD_MEMBERSHIP | ||
19 | #ifdef IPV6_JOIN_GROUP | ||
20 | #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP | ||
21 | #endif /* IPV6_JOIN_GROUP */ | ||
22 | #endif /* !IPV6_ADD_MEMBERSHIP */ | ||
23 | |||
24 | /* Same with IPV6_DROP_MEMBERSHIP / IPV6_LEAVE_GROUP. */ | ||
25 | #ifndef IPV6_DROP_MEMBERSHIP | ||
26 | #ifdef IPV6_LEAVE_GROUP | ||
27 | #define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP | ||
28 | #endif /* IPV6_LEAVE_GROUP */ | ||
29 | #endif /* !IPV6_DROP_MEMBERSHIP */ | ||
30 | |||
13 | /*=========================================================================*\ | 31 | /*=========================================================================*\ |
14 | * Internal functions prototypes | 32 | * Internal functions prototypes |
15 | \*=========================================================================*/ | 33 | \*=========================================================================*/ |
16 | static int opt_setmembership(lua_State *L, p_socket ps, int level, int name); | 34 | static int opt_setmembership(lua_State *L, p_socket ps, int level, int name); |
35 | static int opt_ip6_setmembership(lua_State *L, p_socket ps, int level, int name); | ||
17 | static int opt_setboolean(lua_State *L, p_socket ps, int level, int name); | 36 | static int opt_setboolean(lua_State *L, p_socket ps, int level, int name); |
18 | static int opt_getboolean(lua_State *L, p_socket ps, int level, int name); | 37 | static int opt_getboolean(lua_State *L, p_socket ps, int level, int name); |
38 | static int opt_setint(lua_State *L, p_socket ps, int level, int name); | ||
39 | static int opt_getint(lua_State *L, p_socket ps, int level, int name); | ||
19 | static int opt_set(lua_State *L, p_socket ps, int level, int name, | 40 | static int opt_set(lua_State *L, p_socket ps, int level, int name, |
20 | void *val, int len); | 41 | void *val, int len); |
21 | static int opt_get(lua_State *L, p_socket ps, int level, int name, | 42 | static int opt_get(lua_State *L, p_socket ps, int level, int name, |
@@ -106,6 +127,26 @@ int opt_set_broadcast(lua_State *L, p_socket ps) | |||
106 | return opt_setboolean(L, ps, SOL_SOCKET, SO_BROADCAST); | 127 | return opt_setboolean(L, ps, SOL_SOCKET, SO_BROADCAST); |
107 | } | 128 | } |
108 | 129 | ||
130 | int opt_set_ip6_unicast_hops(lua_State *L, p_socket ps) | ||
131 | { | ||
132 | return opt_setint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS); | ||
133 | } | ||
134 | |||
135 | int opt_get_ip6_unicast_hops(lua_State *L, p_socket ps) | ||
136 | { | ||
137 | return opt_getint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS); | ||
138 | } | ||
139 | |||
140 | int opt_set_ip6_multicast_hops(lua_State *L, p_socket ps) | ||
141 | { | ||
142 | return opt_setint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS); | ||
143 | } | ||
144 | |||
145 | int opt_get_ip6_multicast_hops(lua_State *L, p_socket ps) | ||
146 | { | ||
147 | return opt_getint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS); | ||
148 | } | ||
149 | |||
109 | int opt_set_ip_multicast_loop(lua_State *L, p_socket ps) | 150 | int opt_set_ip_multicast_loop(lua_State *L, p_socket ps) |
110 | { | 151 | { |
111 | return opt_setboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP); | 152 | return opt_setboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP); |
@@ -116,6 +157,16 @@ int opt_get_ip_multicast_loop(lua_State *L, p_socket ps) | |||
116 | return opt_getboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP); | 157 | return opt_getboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP); |
117 | } | 158 | } |
118 | 159 | ||
160 | int opt_set_ip6_multicast_loop(lua_State *L, p_socket ps) | ||
161 | { | ||
162 | return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP); | ||
163 | } | ||
164 | |||
165 | int opt_get_ip6_multicast_loop(lua_State *L, p_socket ps) | ||
166 | { | ||
167 | return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP); | ||
168 | } | ||
169 | |||
119 | int opt_set_linger(lua_State *L, p_socket ps) | 170 | int opt_set_linger(lua_State *L, p_socket ps) |
120 | { | 171 | { |
121 | struct linger li; /* obj, name, table */ | 172 | struct linger li; /* obj, name, table */ |
@@ -150,9 +201,7 @@ int opt_get_linger(lua_State *L, p_socket ps) | |||
150 | 201 | ||
151 | int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps) | 202 | int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps) |
152 | { | 203 | { |
153 | int val = (int) luaL_checknumber(L, 3); /* obj, name, int */ | 204 | return opt_setint(L, ps, IPPROTO_IP, IP_MULTICAST_TTL); |
154 | return opt_set(L, ps, IPPROTO_IP, IP_MULTICAST_TTL, | ||
155 | (char *) &val, sizeof(val)); | ||
156 | } | 205 | } |
157 | 206 | ||
158 | int opt_set_ip_multicast_if(lua_State *L, p_socket ps) | 207 | int opt_set_ip_multicast_if(lua_State *L, p_socket ps) |
@@ -189,6 +238,21 @@ int opt_set_ip_drop_membersip(lua_State *L, p_socket ps) | |||
189 | return opt_setmembership(L, ps, IPPROTO_IP, IP_DROP_MEMBERSHIP); | 238 | return opt_setmembership(L, ps, IPPROTO_IP, IP_DROP_MEMBERSHIP); |
190 | } | 239 | } |
191 | 240 | ||
241 | int opt_set_ip6_add_membership(lua_State *L, p_socket ps) | ||
242 | { | ||
243 | return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP); | ||
244 | } | ||
245 | |||
246 | int opt_set_ip6_drop_membersip(lua_State *L, p_socket ps) | ||
247 | { | ||
248 | return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP); | ||
249 | } | ||
250 | |||
251 | int opt_get_ip6_v6only(lua_State *L, p_socket ps) | ||
252 | { | ||
253 | return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY); | ||
254 | } | ||
255 | |||
192 | int opt_set_ip6_v6only(lua_State *L, p_socket ps) | 256 | int opt_set_ip6_v6only(lua_State *L, p_socket ps) |
193 | { | 257 | { |
194 | return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY); | 258 | return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY); |
@@ -218,6 +282,37 @@ static int opt_setmembership(lua_State *L, p_socket ps, int level, int name) | |||
218 | return opt_set(L, ps, level, name, (char *) &val, sizeof(val)); | 282 | return opt_set(L, ps, level, name, (char *) &val, sizeof(val)); |
219 | } | 283 | } |
220 | 284 | ||
285 | static int opt_ip6_setmembership(lua_State *L, p_socket ps, int level, int name) | ||
286 | { | ||
287 | struct ipv6_mreq val; /* obj, opt-name, table */ | ||
288 | memset(&val, 0, sizeof(val)); | ||
289 | if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE)); | ||
290 | lua_pushstring(L, "multiaddr"); | ||
291 | lua_gettable(L, 3); | ||
292 | if (!lua_isstring(L, -1)) | ||
293 | luaL_argerror(L, 3, "string 'multiaddr' field expected"); | ||
294 | if (!inet_pton(AF_INET6, lua_tostring(L, -1), &val.ipv6mr_multiaddr)) | ||
295 | luaL_argerror(L, 3, "invalid 'multiaddr' ip address"); | ||
296 | lua_pushstring(L, "interface"); | ||
297 | lua_gettable(L, 3); | ||
298 | /* By default we listen to interface on default route | ||
299 | * (sigh). However, interface= can override it. We support either | ||
300 | * number, or name for it. */ | ||
301 | if (!lua_isnil(L, -1)) { | ||
302 | if (lua_isnumber(L, -1)) { | ||
303 | val.ipv6mr_interface = lua_tonumber(L, -1); | ||
304 | } else if (lua_isstring(L, -1)) { | ||
305 | if (!(val.ipv6mr_interface = if_nametoindex(lua_tostring(L, -1)))) { | ||
306 | lua_pushnil(L); | ||
307 | lua_pushstring(L, "nonexistent interface"); | ||
308 | return 2; | ||
309 | } | ||
310 | } else | ||
311 | luaL_argerror(L, -1, "number/string 'interface' field expected"); | ||
312 | } | ||
313 | return opt_set(L, ps, level, name, (char *) &val, sizeof(val)); | ||
314 | } | ||
315 | |||
221 | static | 316 | static |
222 | int opt_get(lua_State *L, p_socket ps, int level, int name, void *val, int* len) | 317 | int opt_get(lua_State *L, p_socket ps, int level, int name, void *val, int* len) |
223 | { | 318 | { |
@@ -256,15 +351,15 @@ static int opt_getboolean(lua_State *L, p_socket ps, int level, int name) | |||
256 | 351 | ||
257 | int opt_get_error(lua_State *L, p_socket ps) | 352 | int opt_get_error(lua_State *L, p_socket ps) |
258 | { | 353 | { |
259 | int val = 0; | 354 | int val = 0; |
260 | socklen_t len = sizeof(val); | 355 | socklen_t len = sizeof(val); |
261 | if (getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *) &val, &len) < 0) { | 356 | if (getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *) &val, &len) < 0) { |
262 | lua_pushnil(L); | 357 | lua_pushnil(L); |
263 | lua_pushstring(L, "getsockopt failed"); | 358 | lua_pushstring(L, "getsockopt failed"); |
264 | return 2; | 359 | return 2; |
265 | } | 360 | } |
266 | lua_pushstring(L, socket_strerror(val)); | 361 | lua_pushstring(L, socket_strerror(val)); |
267 | return 1; | 362 | return 1; |
268 | } | 363 | } |
269 | 364 | ||
270 | static int opt_setboolean(lua_State *L, p_socket ps, int level, int name) | 365 | static int opt_setboolean(lua_State *L, p_socket ps, int level, int name) |
@@ -273,3 +368,19 @@ static int opt_setboolean(lua_State *L, p_socket ps, int level, int name) | |||
273 | return opt_set(L, ps, level, name, (char *) &val, sizeof(val)); | 368 | return opt_set(L, ps, level, name, (char *) &val, sizeof(val)); |
274 | } | 369 | } |
275 | 370 | ||
371 | static int opt_getint(lua_State *L, p_socket ps, int level, int name) | ||
372 | { | ||
373 | int val = 0; | ||
374 | int len = sizeof(val); | ||
375 | int err = opt_get(L, ps, level, name, (char *) &val, &len); | ||
376 | if (err) | ||
377 | return err; | ||
378 | lua_pushnumber(L, val); | ||
379 | return 1; | ||
380 | } | ||
381 | |||
382 | static int opt_setint(lua_State *L, p_socket ps, int level, int name) | ||
383 | { | ||
384 | int val = (int) lua_tonumber(L, 3); /* obj, name, int */ | ||
385 | return opt_set(L, ps, level, name, (char *) &val, sizeof(val)); | ||
386 | } | ||