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 | |
| 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.
| -rw-r--r-- | doc/udp.html | 34 | ||||
| -rw-r--r-- | src/udp.c | 58 | ||||
| -rw-r--r-- | src/udp.h | 5 |
3 files changed, 68 insertions, 29 deletions
diff --git a/doc/udp.html b/doc/udp.html index a300f2f..22d7c72 100644 --- a/doc/udp.html +++ b/doc/udp.html | |||
| @@ -42,7 +42,7 @@ | |||
| 42 | <!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> | 42 | <!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> |
| 43 | 43 | ||
| 44 | <p class="name" id="socket.udp"> | 44 | <p class="name" id="socket.udp"> |
| 45 | socket.<b>udp()</b> | 45 | socket.<b>udp(</b>[buffersize]<b>)</b> |
| 46 | </p> | 46 | </p> |
| 47 | 47 | ||
| 48 | <p class="description"> | 48 | <p class="description"> |
| @@ -62,6 +62,13 @@ The <a href="#setpeername"><tt>setpeername</tt></a> | |||
| 62 | is used to connect the object. | 62 | is used to connect the object. |
| 63 | </p> | 63 | </p> |
| 64 | 64 | ||
| 65 | <p class="parameters"> | ||
| 66 | The optional <tt>buffersize</tt> parameter | ||
| 67 | specifies the size of the largest datagram that will | ||
| 68 | ever be received by the UDP object. The default value is | ||
| 69 | 8192. | ||
| 70 | </p> | ||
| 71 | |||
| 65 | <p class="return"> | 72 | <p class="return"> |
| 66 | In case of success, a new unconnected UDP object | 73 | In case of success, a new unconnected UDP object |
| 67 | returned. In case of error, <b><tt>nil</tt></b> is returned, followed by | 74 | returned. In case of error, <b><tt>nil</tt></b> is returned, followed by |
| @@ -85,7 +92,7 @@ href=#setoption><tt>setoption</tt></a> will fail. | |||
| 85 | <!-- socket.udp4 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> | 92 | <!-- socket.udp4 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> |
| 86 | 93 | ||
| 87 | <p class="name" id="socket.udp"> | 94 | <p class="name" id="socket.udp"> |
| 88 | socket.<b>udp4()</b> | 95 | socket.<b>udp4(</b>[buffersize]<b>)</b> |
| 89 | </p> | 96 | </p> |
| 90 | 97 | ||
| 91 | <p class="description"> | 98 | <p class="description"> |
| @@ -105,6 +112,13 @@ The <a href="#setpeername"><tt>setpeername</tt></a> | |||
| 105 | is used to connect the object. | 112 | is used to connect the object. |
| 106 | </p> | 113 | </p> |
| 107 | 114 | ||
| 115 | <p class="parameters"> | ||
| 116 | The optional <tt>buffersize</tt> parameter | ||
| 117 | specifies the size of the largest datagram that will | ||
| 118 | ever be received by the UDP object. The default value is | ||
| 119 | 8192. | ||
| 120 | </p> | ||
| 121 | |||
| 108 | <p class="return"> | 122 | <p class="return"> |
| 109 | In case of success, a new unconnected UDP object | 123 | In case of success, a new unconnected UDP object |
| 110 | returned. In case of error, <b><tt>nil</tt></b> is returned, followed by | 124 | returned. In case of error, <b><tt>nil</tt></b> is returned, followed by |
| @@ -114,7 +128,7 @@ an error message. | |||
| 114 | <!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> | 128 | <!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> |
| 115 | 129 | ||
| 116 | <p class="name" id="socket.udp6"> | 130 | <p class="name" id="socket.udp6"> |
| 117 | socket.<b>udp6()</b> | 131 | socket.<b>udp6(</b>[buffersize]<b>)</b> |
| 118 | </p> | 132 | </p> |
| 119 | 133 | ||
| 120 | <p class="description"> | 134 | <p class="description"> |
| @@ -134,6 +148,13 @@ The <a href="#setpeername"><tt>setpeername</tt></a> | |||
| 134 | is used to connect the object. | 148 | is used to connect the object. |
| 135 | </p> | 149 | </p> |
| 136 | 150 | ||
| 151 | <p class="parameters"> | ||
| 152 | The optional <tt>buffersize</tt> parameter | ||
| 153 | specifies the size of the largest datagram that will | ||
| 154 | ever be received by the UDP object. The default value is | ||
| 155 | 8192. | ||
| 156 | </p> | ||
| 157 | |||
| 137 | <p class="return"> | 158 | <p class="return"> |
| 138 | In case of success, a new unconnected UDP object | 159 | In case of success, a new unconnected UDP object |
| 139 | returned. In case of error, <b><tt>nil</tt></b> is returned, followed by | 160 | returned. In case of error, <b><tt>nil</tt></b> is returned, followed by |
| @@ -238,9 +259,10 @@ specifies the maximum size of the datagram to be retrieved. If | |||
| 238 | there are more than <tt>size</tt> bytes available in the datagram, | 259 | there are more than <tt>size</tt> bytes available in the datagram, |
| 239 | the excess bytes are discarded. If there are less then | 260 | the excess bytes are discarded. If there are less then |
| 240 | <tt>size</tt> bytes available in the current datagram, the | 261 | <tt>size</tt> bytes available in the current datagram, the |
| 241 | available bytes are returned. If <tt>size</tt> is omitted, the | 262 | available bytes are returned. |
| 242 | maximum datagram size is used (which is currently limited by the | 263 | If <tt>size</tt> is omitted, the |
| 243 | implementation to 8192 bytes). | 264 | <tt>buffersize</tt> argument at creation time is used |
| 265 | (which defaults to 8192 bytes). | ||
| 244 | </p> | 266 | </p> |
| 245 | 267 | ||
| 246 | <p class="return"> | 268 | <p class="return"> |
| @@ -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 | ||
