diff options
author | Diego Nehab <diego.nehab@gmail.com> | 2015-10-05 11:47:51 +0800 |
---|---|---|
committer | Diego Nehab <diego.nehab@gmail.com> | 2015-10-05 11:47:51 +0800 |
commit | fd729b32a8966291f007567f72f3dc0158bdab35 (patch) | |
tree | 46737842ba3f9a5aaa2325a76724f12fbc53353e /src | |
parent | d1ec29be7f982db75864155dd61a058902e1cae2 (diff) | |
download | luasocket-fd729b32a8966291f007567f72f3dc0158bdab35.tar.gz luasocket-fd729b32a8966291f007567f72f3dc0158bdab35.tar.bz2 luasocket-fd729b32a8966291f007567f72f3dc0158bdab35.zip |
Added support for arbitrary datagram sizes.
The maximum size is still constant per UDP object, but the
size can be speficied at creation time.
Diffstat (limited to 'src')
-rw-r--r-- | src/udp.c | 58 | ||||
-rw-r--r-- | src/udp.h | 5 |
2 files changed, 40 insertions, 23 deletions
@@ -41,6 +41,7 @@ static int meth_setpeername(lua_State *L); | |||
41 | static int meth_close(lua_State *L); | 41 | static int meth_close(lua_State *L); |
42 | static int meth_setoption(lua_State *L); | 42 | static int meth_setoption(lua_State *L); |
43 | static int meth_getoption(lua_State *L); | 43 | static int meth_getoption(lua_State *L); |
44 | static int meth_getbufferlength(lua_State *L); | ||
44 | static int meth_settimeout(lua_State *L); | 45 | static int meth_settimeout(lua_State *L); |
45 | static int meth_getfd(lua_State *L); | 46 | static int meth_getfd(lua_State *L); |
46 | static int meth_setfd(lua_State *L); | 47 | static int meth_setfd(lua_State *L); |
@@ -63,6 +64,7 @@ static luaL_Reg udp_methods[] = { | |||
63 | {"setfd", meth_setfd}, | 64 | {"setfd", meth_setfd}, |
64 | {"setoption", meth_setoption}, | 65 | {"setoption", meth_setoption}, |
65 | {"getoption", meth_getoption}, | 66 | {"getoption", meth_getoption}, |
67 | {"getoption", meth_getbufferlength}, | ||
66 | {"setpeername", meth_setpeername}, | 68 | {"setpeername", meth_setpeername}, |
67 | {"setsockname", meth_setsockname}, | 69 | {"setsockname", meth_setsockname}, |
68 | {"settimeout", meth_settimeout}, | 70 | {"settimeout", meth_settimeout}, |
@@ -202,47 +204,55 @@ static int meth_sendto(lua_State *L) { | |||
202 | \*-------------------------------------------------------------------------*/ | 204 | \*-------------------------------------------------------------------------*/ |
203 | static int meth_receive(lua_State *L) { | 205 | static int meth_receive(lua_State *L) { |
204 | p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); | 206 | p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); |
205 | char buffer[UDP_DATAGRAMSIZE]; | 207 | char buf[UDP_DATAGRAMSIZE]; |
206 | size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer)); | 208 | size_t len = MAX(udp->len, UDP_DATAGRAMSIZE); |
209 | char *dgram = len > sizeof(buf)? udp->buf: buf; | ||
210 | size_t got, wanted = (size_t) luaL_optnumber(L, 2, len); | ||
207 | int err; | 211 | int err; |
208 | p_timeout tm = &udp->tm; | 212 | p_timeout tm = &udp->tm; |
209 | count = MIN(count, sizeof(buffer)); | ||
210 | timeout_markstart(tm); | 213 | timeout_markstart(tm); |
211 | err = socket_recv(&udp->sock, buffer, count, &got, tm); | 214 | wanted = MIN(wanted, len); |
215 | err = socket_recv(&udp->sock, dgram, wanted, &got, tm); | ||
212 | /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ | 216 | /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ |
213 | if (err == IO_CLOSED) | 217 | if (err != IO_DONE && err != IO_CLOSED ) { |
214 | err = IO_DONE; | ||
215 | if (err != IO_DONE) { | ||
216 | lua_pushnil(L); | 218 | lua_pushnil(L); |
217 | lua_pushstring(L, udp_strerror(err)); | 219 | lua_pushstring(L, udp_strerror(err)); |
218 | return 2; | 220 | return 2; |
219 | } | 221 | } |
220 | lua_pushlstring(L, buffer, got); | 222 | lua_pushlstring(L, dgram, got); |
223 | return 1; | ||
224 | } | ||
225 | |||
226 | /*-------------------------------------------------------------------------*\ | ||
227 | * Receives data from a UDP socket | ||
228 | \*-------------------------------------------------------------------------*/ | ||
229 | static int meth_getbufferlength(lua_State *L) { | ||
230 | p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); | ||
231 | lua_pushinteger(L, MAX(UDP_DATAGRAMSIZE, udp->len)); | ||
221 | return 1; | 232 | return 1; |
222 | } | 233 | } |
223 | 234 | ||
224 | /*-------------------------------------------------------------------------*\ | 235 | /*-------------------------------------------------------------------------*\ |
225 | * Receives data and sender from a UDP socket | 236 | * Receives data and sender from a UDP socket |
226 | \*-------------------------------------------------------------------------*/ | 237 | \*-------------------------------------------------------------------------*/ |
227 | static int meth_receivefrom(lua_State *L) | 238 | static int meth_receivefrom(lua_State *L) { |
228 | { | ||
229 | p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); | 239 | p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); |
230 | char buffer[UDP_DATAGRAMSIZE]; | 240 | char buf[UDP_DATAGRAMSIZE]; |
231 | size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer)); | 241 | size_t len = MAX(udp->len, UDP_DATAGRAMSIZE); |
232 | int err; | 242 | char *dgram = len > sizeof(buf)? udp->buf: buf; |
233 | p_timeout tm = &udp->tm; | 243 | size_t got, wanted = (size_t) luaL_optnumber(L, 2, len); |
234 | struct sockaddr_storage addr; | 244 | struct sockaddr_storage addr; |
235 | socklen_t addr_len = sizeof(addr); | 245 | socklen_t addr_len = sizeof(addr); |
236 | char addrstr[INET6_ADDRSTRLEN]; | 246 | char addrstr[INET6_ADDRSTRLEN]; |
237 | char portstr[6]; | 247 | char portstr[6]; |
248 | int err; | ||
249 | p_timeout tm = &udp->tm; | ||
238 | timeout_markstart(tm); | 250 | timeout_markstart(tm); |
239 | count = MIN(count, sizeof(buffer)); | 251 | wanted = MIN(wanted, len); |
240 | err = socket_recvfrom(&udp->sock, buffer, count, &got, (SA *) &addr, | 252 | err = socket_recvfrom(&udp->sock, dgram, wanted, &got, (SA *) &addr, |
241 | &addr_len, tm); | 253 | &addr_len, tm); |
242 | /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ | 254 | /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ |
243 | if (err == IO_CLOSED) | 255 | if (err != IO_DONE && err != IO_CLOSED) { |
244 | err = IO_DONE; | ||
245 | if (err != IO_DONE) { | ||
246 | lua_pushnil(L); | 256 | lua_pushnil(L); |
247 | lua_pushstring(L, udp_strerror(err)); | 257 | lua_pushstring(L, udp_strerror(err)); |
248 | return 2; | 258 | return 2; |
@@ -254,7 +264,7 @@ static int meth_receivefrom(lua_State *L) | |||
254 | lua_pushstring(L, gai_strerror(err)); | 264 | lua_pushstring(L, gai_strerror(err)); |
255 | return 2; | 265 | return 2; |
256 | } | 266 | } |
257 | lua_pushlstring(L, buffer, got); | 267 | lua_pushlstring(L, dgram, got); |
258 | lua_pushstring(L, addrstr); | 268 | lua_pushstring(L, addrstr); |
259 | lua_pushinteger(L, (int) strtol(portstr, (char **) NULL, 10)); | 269 | lua_pushinteger(L, (int) strtol(portstr, (char **) NULL, 10)); |
260 | return 3; | 270 | return 3; |
@@ -409,13 +419,19 @@ static int meth_setsockname(lua_State *L) { | |||
409 | * Creates a master udp object | 419 | * Creates a master udp object |
410 | \*-------------------------------------------------------------------------*/ | 420 | \*-------------------------------------------------------------------------*/ |
411 | static int udp_create(lua_State *L, int family) { | 421 | static int udp_create(lua_State *L, int family) { |
422 | p_udp udp = NULL; | ||
423 | /* optional length for private datagram buffer. this is useful when | ||
424 | * you need larger datagrams than UDP_DATAGRAMSIZE */ | ||
425 | size_t len = (size_t) luaL_optinteger(L, 1, 0); | ||
426 | if (len <= UDP_DATAGRAMSIZE) len = 0; | ||
412 | /* allocate udp object */ | 427 | /* allocate udp object */ |
413 | p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp)); | 428 | udp = (p_udp) lua_newuserdata(L, sizeof(t_udp) + len - 1); |
414 | auxiliar_setclass(L, "udp{unconnected}", -1); | 429 | auxiliar_setclass(L, "udp{unconnected}", -1); |
415 | /* if family is AF_UNSPEC, we leave the socket invalid and | 430 | /* if family is AF_UNSPEC, we leave the socket invalid and |
416 | * store AF_UNSPEC into family. This will allow it to later be | 431 | * store AF_UNSPEC into family. This will allow it to later be |
417 | * replaced with an AF_INET6 or AF_INET socket upon first use. */ | 432 | * replaced with an AF_INET6 or AF_INET socket upon first use. */ |
418 | udp->sock = SOCKET_INVALID; | 433 | udp->sock = SOCKET_INVALID; |
434 | udp->len = len; | ||
419 | timeout_init(&udp->tm, -1, -1); | 435 | timeout_init(&udp->tm, -1, -1); |
420 | udp->family = family; | 436 | udp->family = family; |
421 | if (family != AF_UNSPEC) { | 437 | if (family != AF_UNSPEC) { |
@@ -8,7 +8,7 @@ | |||
8 | * (AF_INET, SOCK_DGRAM). | 8 | * (AF_INET, SOCK_DGRAM). |
9 | * | 9 | * |
10 | * Two classes are defined: connected and unconnected. UDP objects are | 10 | * Two classes are defined: connected and unconnected. UDP objects are |
11 | * originally unconnected. They can be "connected" to a given address | 11 | * originally unconnected. They can be "connected" to a given address |
12 | * with a call to the setpeername function. The same function can be used to | 12 | * with a call to the setpeername function. The same function can be used to |
13 | * break the connection. | 13 | * break the connection. |
14 | \*=========================================================================*/ | 14 | \*=========================================================================*/ |
@@ -17,13 +17,14 @@ | |||
17 | #include "timeout.h" | 17 | #include "timeout.h" |
18 | #include "socket.h" | 18 | #include "socket.h" |
19 | 19 | ||
20 | /* can't be larger than wsocket.c MAXCHUNK!!! */ | ||
21 | #define UDP_DATAGRAMSIZE 8192 | 20 | #define UDP_DATAGRAMSIZE 8192 |
22 | 21 | ||
23 | typedef struct t_udp_ { | 22 | typedef struct t_udp_ { |
24 | t_socket sock; | 23 | t_socket sock; |
25 | t_timeout tm; | 24 | t_timeout tm; |
26 | int family; | 25 | int family; |
26 | size_t len; /* length of datagram buffer below */ | ||
27 | char buf[1]; /* allocate larger structure to hold actual buffer */ | ||
27 | } t_udp; | 28 | } t_udp; |
28 | typedef t_udp *p_udp; | 29 | typedef t_udp *p_udp; |
29 | 30 | ||