diff options
Diffstat (limited to '')
-rwxr-xr-x[-rw-r--r--] | src/udp.c | 111 |
1 files changed, 78 insertions, 33 deletions
@@ -2,12 +2,7 @@ | |||
2 | * UDP object | 2 | * UDP object |
3 | * LuaSocket toolkit | 3 | * LuaSocket toolkit |
4 | \*=========================================================================*/ | 4 | \*=========================================================================*/ |
5 | #include <string.h> | 5 | #include "luasocket.h" |
6 | #include <stdlib.h> | ||
7 | |||
8 | #include "lua.h" | ||
9 | #include "lauxlib.h" | ||
10 | #include "compat.h" | ||
11 | 6 | ||
12 | #include "auxiliar.h" | 7 | #include "auxiliar.h" |
13 | #include "socket.h" | 8 | #include "socket.h" |
@@ -15,6 +10,9 @@ | |||
15 | #include "options.h" | 10 | #include "options.h" |
16 | #include "udp.h" | 11 | #include "udp.h" |
17 | 12 | ||
13 | #include <string.h> | ||
14 | #include <stdlib.h> | ||
15 | |||
18 | /* min and max macros */ | 16 | /* min and max macros */ |
19 | #ifndef MIN | 17 | #ifndef MIN |
20 | #define MIN(x, y) ((x) < (y) ? x : y) | 18 | #define MIN(x, y) ((x) < (y) ? x : y) |
@@ -36,6 +34,7 @@ static int meth_receivefrom(lua_State *L); | |||
36 | static int meth_getfamily(lua_State *L); | 34 | static int meth_getfamily(lua_State *L); |
37 | static int meth_getsockname(lua_State *L); | 35 | static int meth_getsockname(lua_State *L); |
38 | static int meth_getpeername(lua_State *L); | 36 | static int meth_getpeername(lua_State *L); |
37 | static int meth_gettimeout(lua_State *L); | ||
39 | static int meth_setsockname(lua_State *L); | 38 | static int meth_setsockname(lua_State *L); |
40 | static int meth_setpeername(lua_State *L); | 39 | static int meth_setpeername(lua_State *L); |
41 | static int meth_close(lua_State *L); | 40 | static int meth_close(lua_State *L); |
@@ -66,6 +65,7 @@ static luaL_Reg udp_methods[] = { | |||
66 | {"setpeername", meth_setpeername}, | 65 | {"setpeername", meth_setpeername}, |
67 | {"setsockname", meth_setsockname}, | 66 | {"setsockname", meth_setsockname}, |
68 | {"settimeout", meth_settimeout}, | 67 | {"settimeout", meth_settimeout}, |
68 | {"gettimeout", meth_gettimeout}, | ||
69 | {NULL, NULL} | 69 | {NULL, NULL} |
70 | }; | 70 | }; |
71 | 71 | ||
@@ -86,6 +86,8 @@ static t_opt optset[] = { | |||
86 | {"ipv6-add-membership", opt_set_ip6_add_membership}, | 86 | {"ipv6-add-membership", opt_set_ip6_add_membership}, |
87 | {"ipv6-drop-membership", opt_set_ip6_drop_membersip}, | 87 | {"ipv6-drop-membership", opt_set_ip6_drop_membersip}, |
88 | {"ipv6-v6only", opt_set_ip6_v6only}, | 88 | {"ipv6-v6only", opt_set_ip6_v6only}, |
89 | {"recv-buffer-size", opt_set_recv_buf_size}, | ||
90 | {"send-buffer-size", opt_set_send_buf_size}, | ||
89 | {NULL, NULL} | 91 | {NULL, NULL} |
90 | }; | 92 | }; |
91 | 93 | ||
@@ -102,6 +104,8 @@ static t_opt optget[] = { | |||
102 | {"ipv6-multicast-hops", opt_get_ip6_unicast_hops}, | 104 | {"ipv6-multicast-hops", opt_get_ip6_unicast_hops}, |
103 | {"ipv6-multicast-loop", opt_get_ip6_multicast_loop}, | 105 | {"ipv6-multicast-loop", opt_get_ip6_multicast_loop}, |
104 | {"ipv6-v6only", opt_get_ip6_v6only}, | 106 | {"ipv6-v6only", opt_get_ip6_v6only}, |
107 | {"recv-buffer-size", opt_get_recv_buf_size}, | ||
108 | {"send-buffer-size", opt_get_send_buf_size}, | ||
105 | {NULL, NULL} | 109 | {NULL, NULL} |
106 | }; | 110 | }; |
107 | 111 | ||
@@ -116,8 +120,7 @@ static luaL_Reg func[] = { | |||
116 | /*-------------------------------------------------------------------------*\ | 120 | /*-------------------------------------------------------------------------*\ |
117 | * Initializes module | 121 | * Initializes module |
118 | \*-------------------------------------------------------------------------*/ | 122 | \*-------------------------------------------------------------------------*/ |
119 | int udp_open(lua_State *L) | 123 | int udp_open(lua_State *L) { |
120 | { | ||
121 | /* create classes */ | 124 | /* create classes */ |
122 | auxiliar_newclass(L, "udp{connected}", udp_methods); | 125 | auxiliar_newclass(L, "udp{connected}", udp_methods); |
123 | auxiliar_newclass(L, "udp{unconnected}", udp_methods); | 126 | auxiliar_newclass(L, "udp{unconnected}", udp_methods); |
@@ -128,6 +131,10 @@ int udp_open(lua_State *L) | |||
128 | auxiliar_add2group(L, "udp{unconnected}", "select{able}"); | 131 | auxiliar_add2group(L, "udp{unconnected}", "select{able}"); |
129 | /* define library functions */ | 132 | /* define library functions */ |
130 | luaL_setfuncs(L, func, 0); | 133 | luaL_setfuncs(L, func, 0); |
134 | /* export default UDP size */ | ||
135 | lua_pushliteral(L, "_DATAGRAMSIZE"); | ||
136 | lua_pushinteger(L, UDP_DATAGRAMSIZE); | ||
137 | lua_rawset(L, -3); | ||
131 | return 0; | 138 | return 0; |
132 | } | 139 | } |
133 | 140 | ||
@@ -177,13 +184,37 @@ static int meth_sendto(lua_State *L) { | |||
177 | memset(&aihint, 0, sizeof(aihint)); | 184 | memset(&aihint, 0, sizeof(aihint)); |
178 | aihint.ai_family = udp->family; | 185 | aihint.ai_family = udp->family; |
179 | aihint.ai_socktype = SOCK_DGRAM; | 186 | aihint.ai_socktype = SOCK_DGRAM; |
180 | aihint.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV; | 187 | aihint.ai_flags = AI_NUMERICHOST; |
188 | #ifdef AI_NUMERICSERV | ||
189 | aihint.ai_flags |= AI_NUMERICSERV; | ||
190 | #endif | ||
181 | err = getaddrinfo(ip, port, &aihint, &ai); | 191 | err = getaddrinfo(ip, port, &aihint, &ai); |
182 | if (err) { | 192 | if (err) { |
183 | lua_pushnil(L); | 193 | lua_pushnil(L); |
184 | lua_pushstring(L, gai_strerror(err)); | 194 | lua_pushstring(L, LUA_GAI_STRERROR(err)); |
185 | return 2; | 195 | return 2; |
186 | } | 196 | } |
197 | |||
198 | /* create socket if on first sendto if AF_UNSPEC was set */ | ||
199 | if (udp->family == AF_UNSPEC && udp->sock == SOCKET_INVALID) { | ||
200 | struct addrinfo *ap; | ||
201 | const char *errstr = NULL; | ||
202 | for (ap = ai; ap != NULL; ap = ap->ai_next) { | ||
203 | errstr = inet_trycreate(&udp->sock, ap->ai_family, SOCK_DGRAM, 0); | ||
204 | if (errstr == NULL) { | ||
205 | socket_setnonblocking(&udp->sock); | ||
206 | udp->family = ap->ai_family; | ||
207 | break; | ||
208 | } | ||
209 | } | ||
210 | if (errstr != NULL) { | ||
211 | lua_pushnil(L); | ||
212 | lua_pushstring(L, errstr); | ||
213 | freeaddrinfo(ai); | ||
214 | return 2; | ||
215 | } | ||
216 | } | ||
217 | |||
187 | timeout_markstart(tm); | 218 | timeout_markstart(tm); |
188 | err = socket_sendto(&udp->sock, data, count, &sent, ai->ai_addr, | 219 | err = socket_sendto(&udp->sock, data, count, &sent, ai->ai_addr, |
189 | (socklen_t) ai->ai_addrlen, tm); | 220 | (socklen_t) ai->ai_addrlen, tm); |
@@ -202,69 +233,78 @@ static int meth_sendto(lua_State *L) { | |||
202 | \*-------------------------------------------------------------------------*/ | 233 | \*-------------------------------------------------------------------------*/ |
203 | static int meth_receive(lua_State *L) { | 234 | static int meth_receive(lua_State *L) { |
204 | p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); | 235 | p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); |
205 | char buffer[UDP_DATAGRAMSIZE]; | 236 | char buf[UDP_DATAGRAMSIZE]; |
206 | size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer)); | 237 | size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf)); |
238 | char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf; | ||
207 | int err; | 239 | int err; |
208 | p_timeout tm = &udp->tm; | 240 | p_timeout tm = &udp->tm; |
209 | count = MIN(count, sizeof(buffer)); | ||
210 | timeout_markstart(tm); | 241 | timeout_markstart(tm); |
211 | err = socket_recv(&udp->sock, buffer, count, &got, tm); | 242 | if (!dgram) { |
243 | lua_pushnil(L); | ||
244 | lua_pushliteral(L, "out of memory"); | ||
245 | return 2; | ||
246 | } | ||
247 | err = socket_recv(&udp->sock, dgram, wanted, &got, tm); | ||
212 | /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ | 248 | /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ |
213 | if (err == IO_CLOSED) | 249 | if (err != IO_DONE && err != IO_CLOSED) { |
214 | err = IO_DONE; | ||
215 | if (err != IO_DONE) { | ||
216 | lua_pushnil(L); | 250 | lua_pushnil(L); |
217 | lua_pushstring(L, udp_strerror(err)); | 251 | lua_pushstring(L, udp_strerror(err)); |
252 | if (wanted > sizeof(buf)) free(dgram); | ||
218 | return 2; | 253 | return 2; |
219 | } | 254 | } |
220 | lua_pushlstring(L, buffer, got); | 255 | lua_pushlstring(L, dgram, got); |
256 | if (wanted > sizeof(buf)) free(dgram); | ||
221 | return 1; | 257 | return 1; |
222 | } | 258 | } |
223 | 259 | ||
224 | /*-------------------------------------------------------------------------*\ | 260 | /*-------------------------------------------------------------------------*\ |
225 | * Receives data and sender from a UDP socket | 261 | * Receives data and sender from a UDP socket |
226 | \*-------------------------------------------------------------------------*/ | 262 | \*-------------------------------------------------------------------------*/ |
227 | static int meth_receivefrom(lua_State *L) | 263 | static int meth_receivefrom(lua_State *L) { |
228 | { | ||
229 | p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); | 264 | p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); |
230 | char buffer[UDP_DATAGRAMSIZE]; | 265 | char buf[UDP_DATAGRAMSIZE]; |
231 | size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer)); | 266 | size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf)); |
232 | int err; | 267 | char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf; |
233 | p_timeout tm = &udp->tm; | ||
234 | struct sockaddr_storage addr; | 268 | struct sockaddr_storage addr; |
235 | socklen_t addr_len = sizeof(addr); | 269 | socklen_t addr_len = sizeof(addr); |
236 | char addrstr[INET6_ADDRSTRLEN]; | 270 | char addrstr[INET6_ADDRSTRLEN]; |
237 | char portstr[6]; | 271 | char portstr[6]; |
272 | int err; | ||
273 | p_timeout tm = &udp->tm; | ||
238 | timeout_markstart(tm); | 274 | timeout_markstart(tm); |
239 | count = MIN(count, sizeof(buffer)); | 275 | if (!dgram) { |
240 | err = socket_recvfrom(&udp->sock, buffer, count, &got, (SA *) &addr, | 276 | lua_pushnil(L); |
277 | lua_pushliteral(L, "out of memory"); | ||
278 | return 2; | ||
279 | } | ||
280 | err = socket_recvfrom(&udp->sock, dgram, wanted, &got, (SA *) &addr, | ||
241 | &addr_len, tm); | 281 | &addr_len, tm); |
242 | /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ | 282 | /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ |
243 | if (err == IO_CLOSED) | 283 | if (err != IO_DONE && err != IO_CLOSED) { |
244 | err = IO_DONE; | ||
245 | if (err != IO_DONE) { | ||
246 | lua_pushnil(L); | 284 | lua_pushnil(L); |
247 | lua_pushstring(L, udp_strerror(err)); | 285 | lua_pushstring(L, udp_strerror(err)); |
286 | if (wanted > sizeof(buf)) free(dgram); | ||
248 | return 2; | 287 | return 2; |
249 | } | 288 | } |
250 | err = getnameinfo((struct sockaddr *)&addr, addr_len, addrstr, | 289 | err = getnameinfo((struct sockaddr *)&addr, addr_len, addrstr, |
251 | INET6_ADDRSTRLEN, portstr, 6, NI_NUMERICHOST | NI_NUMERICSERV); | 290 | INET6_ADDRSTRLEN, portstr, 6, NI_NUMERICHOST | NI_NUMERICSERV); |
252 | if (err) { | 291 | if (err) { |
253 | lua_pushnil(L); | 292 | lua_pushnil(L); |
254 | lua_pushstring(L, gai_strerror(err)); | 293 | lua_pushstring(L, LUA_GAI_STRERROR(err)); |
294 | if (wanted > sizeof(buf)) free(dgram); | ||
255 | return 2; | 295 | return 2; |
256 | } | 296 | } |
257 | lua_pushlstring(L, buffer, got); | 297 | lua_pushlstring(L, dgram, got); |
258 | lua_pushstring(L, addrstr); | 298 | lua_pushstring(L, addrstr); |
259 | lua_pushinteger(L, (int) strtol(portstr, (char **) NULL, 10)); | 299 | lua_pushinteger(L, (int) strtol(portstr, (char **) NULL, 10)); |
300 | if (wanted > sizeof(buf)) free(dgram); | ||
260 | return 3; | 301 | return 3; |
261 | } | 302 | } |
262 | 303 | ||
263 | /*-------------------------------------------------------------------------*\ | 304 | /*-------------------------------------------------------------------------*\ |
264 | * Returns family as string | 305 | * Returns family as string |
265 | \*-------------------------------------------------------------------------*/ | 306 | \*-------------------------------------------------------------------------*/ |
266 | static int meth_getfamily(lua_State *L) | 307 | static int meth_getfamily(lua_State *L) { |
267 | { | ||
268 | p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); | 308 | p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); |
269 | if (udp->family == AF_INET6) { | 309 | if (udp->family == AF_INET6) { |
270 | lua_pushliteral(L, "inet6"); | 310 | lua_pushliteral(L, "inet6"); |
@@ -335,6 +375,11 @@ static int meth_settimeout(lua_State *L) { | |||
335 | return timeout_meth_settimeout(L, &udp->tm); | 375 | return timeout_meth_settimeout(L, &udp->tm); |
336 | } | 376 | } |
337 | 377 | ||
378 | static int meth_gettimeout(lua_State *L) { | ||
379 | p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); | ||
380 | return timeout_meth_gettimeout(L, &udp->tm); | ||
381 | } | ||
382 | |||
338 | /*-------------------------------------------------------------------------*\ | 383 | /*-------------------------------------------------------------------------*\ |
339 | * Turns a master udp object into a client object. | 384 | * Turns a master udp object into a client object. |
340 | \*-------------------------------------------------------------------------*/ | 385 | \*-------------------------------------------------------------------------*/ |