Added support for arbitrary datagram sizes.

The maximum size is still constant per UDP object, but the
size can be speficied at creation time.
This commit is contained in:
Diego Nehab 2015-10-05 11:47:51 +08:00
parent d1ec29be7f
commit fd729b32a8
3 changed files with 68 additions and 29 deletions

View File

@ -42,7 +42,7 @@
<!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="socket.udp"> <p class="name" id="socket.udp">
socket.<b>udp()</b> socket.<b>udp(</b>[buffersize]<b>)</b>
</p> </p>
<p class="description"> <p class="description">
@ -62,6 +62,13 @@ The <a href="#setpeername"><tt>setpeername</tt></a>
is used to connect the object. is used to connect the object.
</p> </p>
<p class="parameters">
The optional <tt>buffersize</tt> parameter
specifies the size of the largest datagram that will
ever be received by the UDP object. The default value is
8192.
</p>
<p class="return"> <p class="return">
In case of success, a new unconnected UDP object In case of success, a new unconnected UDP object
returned. In case of error, <b><tt>nil</tt></b> is returned, followed by 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.
<!-- socket.udp4 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- socket.udp4 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="socket.udp"> <p class="name" id="socket.udp">
socket.<b>udp4()</b> socket.<b>udp4(</b>[buffersize]<b>)</b>
</p> </p>
<p class="description"> <p class="description">
@ -105,6 +112,13 @@ The <a href="#setpeername"><tt>setpeername</tt></a>
is used to connect the object. is used to connect the object.
</p> </p>
<p class="parameters">
The optional <tt>buffersize</tt> parameter
specifies the size of the largest datagram that will
ever be received by the UDP object. The default value is
8192.
</p>
<p class="return"> <p class="return">
In case of success, a new unconnected UDP object In case of success, a new unconnected UDP object
returned. In case of error, <b><tt>nil</tt></b> is returned, followed by returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
@ -114,7 +128,7 @@ an error message.
<!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="socket.udp6"> <p class="name" id="socket.udp6">
socket.<b>udp6()</b> socket.<b>udp6(</b>[buffersize]<b>)</b>
</p> </p>
<p class="description"> <p class="description">
@ -134,6 +148,13 @@ The <a href="#setpeername"><tt>setpeername</tt></a>
is used to connect the object. is used to connect the object.
</p> </p>
<p class="parameters">
The optional <tt>buffersize</tt> parameter
specifies the size of the largest datagram that will
ever be received by the UDP object. The default value is
8192.
</p>
<p class="return"> <p class="return">
In case of success, a new unconnected UDP object In case of success, a new unconnected UDP object
returned. In case of error, <b><tt>nil</tt></b> is returned, followed by 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
there are more than <tt>size</tt> bytes available in the datagram, there are more than <tt>size</tt> bytes available in the datagram,
the excess bytes are discarded. If there are less then the excess bytes are discarded. If there are less then
<tt>size</tt> bytes available in the current datagram, the <tt>size</tt> bytes available in the current datagram, the
available bytes are returned. If <tt>size</tt> is omitted, the available bytes are returned.
maximum datagram size is used (which is currently limited by the If <tt>size</tt> is omitted, the
implementation to 8192 bytes). <tt>buffersize</tt> argument at creation time is used
(which defaults to 8192 bytes).
</p> </p>
<p class="return"> <p class="return">

View File

@ -41,6 +41,7 @@ static int meth_setpeername(lua_State *L);
static int meth_close(lua_State *L); static int meth_close(lua_State *L);
static int meth_setoption(lua_State *L); static int meth_setoption(lua_State *L);
static int meth_getoption(lua_State *L); static int meth_getoption(lua_State *L);
static int meth_getbufferlength(lua_State *L);
static int meth_settimeout(lua_State *L); static int meth_settimeout(lua_State *L);
static int meth_getfd(lua_State *L); static int meth_getfd(lua_State *L);
static int meth_setfd(lua_State *L); static int meth_setfd(lua_State *L);
@ -63,6 +64,7 @@ static luaL_Reg udp_methods[] = {
{"setfd", meth_setfd}, {"setfd", meth_setfd},
{"setoption", meth_setoption}, {"setoption", meth_setoption},
{"getoption", meth_getoption}, {"getoption", meth_getoption},
{"getoption", meth_getbufferlength},
{"setpeername", meth_setpeername}, {"setpeername", meth_setpeername},
{"setsockname", meth_setsockname}, {"setsockname", meth_setsockname},
{"settimeout", meth_settimeout}, {"settimeout", meth_settimeout},
@ -202,47 +204,55 @@ static int meth_sendto(lua_State *L) {
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int meth_receive(lua_State *L) { static int meth_receive(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
char buffer[UDP_DATAGRAMSIZE]; char buf[UDP_DATAGRAMSIZE];
size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer)); size_t len = MAX(udp->len, UDP_DATAGRAMSIZE);
char *dgram = len > sizeof(buf)? udp->buf: buf;
size_t got, wanted = (size_t) luaL_optnumber(L, 2, len);
int err; int err;
p_timeout tm = &udp->tm; p_timeout tm = &udp->tm;
count = MIN(count, sizeof(buffer));
timeout_markstart(tm); timeout_markstart(tm);
err = socket_recv(&udp->sock, buffer, count, &got, tm); wanted = MIN(wanted, len);
err = socket_recv(&udp->sock, dgram, wanted, &got, tm);
/* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
if (err == IO_CLOSED) if (err != IO_DONE && err != IO_CLOSED ) {
err = IO_DONE;
if (err != IO_DONE) {
lua_pushnil(L); lua_pushnil(L);
lua_pushstring(L, udp_strerror(err)); lua_pushstring(L, udp_strerror(err));
return 2; return 2;
} }
lua_pushlstring(L, buffer, got); lua_pushlstring(L, dgram, got);
return 1;
}
/*-------------------------------------------------------------------------*\
* Receives data from a UDP socket
\*-------------------------------------------------------------------------*/
static int meth_getbufferlength(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
lua_pushinteger(L, MAX(UDP_DATAGRAMSIZE, udp->len));
return 1; return 1;
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Receives data and sender from a UDP socket * Receives data and sender from a UDP socket
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int meth_receivefrom(lua_State *L) static int meth_receivefrom(lua_State *L) {
{
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1);
char buffer[UDP_DATAGRAMSIZE]; char buf[UDP_DATAGRAMSIZE];
size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer)); size_t len = MAX(udp->len, UDP_DATAGRAMSIZE);
int err; char *dgram = len > sizeof(buf)? udp->buf: buf;
p_timeout tm = &udp->tm; size_t got, wanted = (size_t) luaL_optnumber(L, 2, len);
struct sockaddr_storage addr; struct sockaddr_storage addr;
socklen_t addr_len = sizeof(addr); socklen_t addr_len = sizeof(addr);
char addrstr[INET6_ADDRSTRLEN]; char addrstr[INET6_ADDRSTRLEN];
char portstr[6]; char portstr[6];
int err;
p_timeout tm = &udp->tm;
timeout_markstart(tm); timeout_markstart(tm);
count = MIN(count, sizeof(buffer)); wanted = MIN(wanted, len);
err = socket_recvfrom(&udp->sock, buffer, count, &got, (SA *) &addr, err = socket_recvfrom(&udp->sock, dgram, wanted, &got, (SA *) &addr,
&addr_len, tm); &addr_len, tm);
/* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
if (err == IO_CLOSED) if (err != IO_DONE && err != IO_CLOSED) {
err = IO_DONE;
if (err != IO_DONE) {
lua_pushnil(L); lua_pushnil(L);
lua_pushstring(L, udp_strerror(err)); lua_pushstring(L, udp_strerror(err));
return 2; return 2;
@ -254,7 +264,7 @@ static int meth_receivefrom(lua_State *L)
lua_pushstring(L, gai_strerror(err)); lua_pushstring(L, gai_strerror(err));
return 2; return 2;
} }
lua_pushlstring(L, buffer, got); lua_pushlstring(L, dgram, got);
lua_pushstring(L, addrstr); lua_pushstring(L, addrstr);
lua_pushinteger(L, (int) strtol(portstr, (char **) NULL, 10)); lua_pushinteger(L, (int) strtol(portstr, (char **) NULL, 10));
return 3; return 3;
@ -409,13 +419,19 @@ static int meth_setsockname(lua_State *L) {
* Creates a master udp object * Creates a master udp object
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int udp_create(lua_State *L, int family) { static int udp_create(lua_State *L, int family) {
p_udp udp = NULL;
/* optional length for private datagram buffer. this is useful when
* you need larger datagrams than UDP_DATAGRAMSIZE */
size_t len = (size_t) luaL_optinteger(L, 1, 0);
if (len <= UDP_DATAGRAMSIZE) len = 0;
/* allocate udp object */ /* allocate udp object */
p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp)); udp = (p_udp) lua_newuserdata(L, sizeof(t_udp) + len - 1);
auxiliar_setclass(L, "udp{unconnected}", -1); auxiliar_setclass(L, "udp{unconnected}", -1);
/* if family is AF_UNSPEC, we leave the socket invalid and /* if family is AF_UNSPEC, we leave the socket invalid and
* store AF_UNSPEC into family. This will allow it to later be * store AF_UNSPEC into family. This will allow it to later be
* replaced with an AF_INET6 or AF_INET socket upon first use. */ * replaced with an AF_INET6 or AF_INET socket upon first use. */
udp->sock = SOCKET_INVALID; udp->sock = SOCKET_INVALID;
udp->len = len;
timeout_init(&udp->tm, -1, -1); timeout_init(&udp->tm, -1, -1);
udp->family = family; udp->family = family;
if (family != AF_UNSPEC) { if (family != AF_UNSPEC) {

View File

@ -17,13 +17,14 @@
#include "timeout.h" #include "timeout.h"
#include "socket.h" #include "socket.h"
/* can't be larger than wsocket.c MAXCHUNK!!! */
#define UDP_DATAGRAMSIZE 8192 #define UDP_DATAGRAMSIZE 8192
typedef struct t_udp_ { typedef struct t_udp_ {
t_socket sock; t_socket sock;
t_timeout tm; t_timeout tm;
int family; int family;
size_t len; /* length of datagram buffer below */
char buf[1]; /* allocate larger structure to hold actual buffer */
} t_udp; } t_udp;
typedef t_udp *p_udp; typedef t_udp *p_udp;