aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDiego Nehab <diego.nehab@gmail.com>2015-10-05 11:47:51 +0800
committerDiego Nehab <diego.nehab@gmail.com>2015-10-05 11:47:51 +0800
commitfd729b32a8966291f007567f72f3dc0158bdab35 (patch)
tree46737842ba3f9a5aaa2325a76724f12fbc53353e
parentd1ec29be7f982db75864155dd61a058902e1cae2 (diff)
downloadluasocket-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.html34
-rw-r--r--src/udp.c58
-rw-r--r--src/udp.h5
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">
45socket.<b>udp()</b> 45socket.<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>
62is used to connect the object. 62is used to connect the object.
63</p> 63</p>
64 64
65<p class="parameters">
66The optional <tt>buffersize</tt> parameter
67specifies the size of the largest datagram that will
68ever be received by the UDP object. The default value is
698192.
70</p>
71
65<p class="return"> 72<p class="return">
66In case of success, a new unconnected UDP object 73In case of success, a new unconnected UDP object
67returned. In case of error, <b><tt>nil</tt></b> is returned, followed by 74returned. 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">
88socket.<b>udp4()</b> 95socket.<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>
105is used to connect the object. 112is used to connect the object.
106</p> 113</p>
107 114
115<p class="parameters">
116The optional <tt>buffersize</tt> parameter
117specifies the size of the largest datagram that will
118ever be received by the UDP object. The default value is
1198192.
120</p>
121
108<p class="return"> 122<p class="return">
109In case of success, a new unconnected UDP object 123In case of success, a new unconnected UDP object
110returned. In case of error, <b><tt>nil</tt></b> is returned, followed by 124returned. 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">
117socket.<b>udp6()</b> 131socket.<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>
134is used to connect the object. 148is used to connect the object.
135</p> 149</p>
136 150
151<p class="parameters">
152The optional <tt>buffersize</tt> parameter
153specifies the size of the largest datagram that will
154ever be received by the UDP object. The default value is
1558192.
156</p>
157
137<p class="return"> 158<p class="return">
138In case of success, a new unconnected UDP object 159In case of success, a new unconnected UDP object
139returned. In case of error, <b><tt>nil</tt></b> is returned, followed by 160returned. 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
238there are more than <tt>size</tt> bytes available in the datagram, 259there are more than <tt>size</tt> bytes available in the datagram,
239the excess bytes are discarded. If there are less then 260the 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
241available bytes are returned. If <tt>size</tt> is omitted, the 262available bytes are returned.
242maximum datagram size is used (which is currently limited by the 263If <tt>size</tt> is omitted, the
243implementation 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">
diff --git a/src/udp.c b/src/udp.c
index 17d932a..9c27b60 100644
--- a/src/udp.c
+++ b/src/udp.c
@@ -41,6 +41,7 @@ static int meth_setpeername(lua_State *L);
41static int meth_close(lua_State *L); 41static int meth_close(lua_State *L);
42static int meth_setoption(lua_State *L); 42static int meth_setoption(lua_State *L);
43static int meth_getoption(lua_State *L); 43static int meth_getoption(lua_State *L);
44static int meth_getbufferlength(lua_State *L);
44static int meth_settimeout(lua_State *L); 45static int meth_settimeout(lua_State *L);
45static int meth_getfd(lua_State *L); 46static int meth_getfd(lua_State *L);
46static int meth_setfd(lua_State *L); 47static 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\*-------------------------------------------------------------------------*/
203static int meth_receive(lua_State *L) { 205static 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\*-------------------------------------------------------------------------*/
229static 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\*-------------------------------------------------------------------------*/
227static int meth_receivefrom(lua_State *L) 238static 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\*-------------------------------------------------------------------------*/
411static int udp_create(lua_State *L, int family) { 421static 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) {
diff --git a/src/udp.h b/src/udp.h
index 2b831a5..da27a7a 100644
--- a/src/udp.h
+++ b/src/udp.h
@@ -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
23typedef struct t_udp_ { 22typedef 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;
28typedef t_udp *p_udp; 29typedef t_udp *p_udp;
29 30