aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--TODO2
-rw-r--r--doc/tcp.html4
-rw-r--r--src/inet.c45
-rw-r--r--src/inet.h1
-rw-r--r--src/tcp.c4
-rw-r--r--src/udp.c35
-rw-r--r--test/udpconnectclnt.lua19
-rw-r--r--test/udpconnectsrvr.lua16
9 files changed, 96 insertions, 31 deletions
diff --git a/.gitignore b/.gitignore
index 705ce5b..0050a8a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
1*.o 1*.o
2*.so 2*.so
3*.so.* 3*.so.*
4mac
diff --git a/TODO b/TODO
index cc49daa..886fd1e 100644
--- a/TODO
+++ b/TODO
@@ -1,3 +1,5 @@
1- bizarre default values for getnameinfo should throw error instead!
2
1- document the new bind and connect behavior. 3- document the new bind and connect behavior.
2- shouldn't we instead make the code compatible to Lua 5.2 4- shouldn't we instead make the code compatible to Lua 5.2
3 without any compat stuff, and use a compatibility layer to 5 without any compat stuff, and use a compatibility layer to
diff --git a/doc/tcp.html b/doc/tcp.html
index 5f39d0e..151a4c9 100644
--- a/doc/tcp.html
+++ b/doc/tcp.html
@@ -125,7 +125,9 @@ local host.
125<tt>Port</tt> must be an integer number in the range [0..64K). 125<tt>Port</tt> must be an integer number in the range [0..64K).
126If <tt>address</tt> 126If <tt>address</tt>
127is '<tt>*</tt>', the system binds to all local interfaces 127is '<tt>*</tt>', the system binds to all local interfaces
128using the <tt>INADDR_ANY</tt> constant. If <tt>port</tt> is 0, the system automatically 128using the <tt>INADDR_ANY</tt> constant or
129<tt>IN6ADDR_ANY_INIT</tt>, according to the family.
130If <tt>port</tt> is 0, the system automatically
129chooses an ephemeral port. 131chooses an ephemeral port.
130</p> 132</p>
131 133
diff --git a/src/inet.c b/src/inet.c
index e769cd8..dfee700 100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -177,8 +177,8 @@ static int inet_global_getaddrinfo(lua_State *L)
177 lua_newtable(L); 177 lua_newtable(L);
178 for (iterator = resolved; iterator; iterator = iterator->ai_next) { 178 for (iterator = resolved; iterator; iterator = iterator->ai_next) {
179 char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; 179 char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
180 getnameinfo(iterator->ai_addr, iterator->ai_addrlen, hbuf, sizeof(hbuf), 180 getnameinfo(iterator->ai_addr, iterator->ai_addrlen, hbuf,
181 sbuf, 0, NI_NUMERICHOST); 181 sizeof(hbuf), sbuf, 0, NI_NUMERICHOST);
182 lua_pushnumber(L, i); 182 lua_pushnumber(L, i);
183 lua_newtable(L); 183 lua_newtable(L);
184 switch (iterator->ai_family) { 184 switch (iterator->ai_family) {
@@ -368,6 +368,34 @@ const char *inet_trycreate(p_socket ps, int family, int type) {
368} 368}
369 369
370/*-------------------------------------------------------------------------*\ 370/*-------------------------------------------------------------------------*\
371* "Disconnects" a DGRAM socket
372\*-------------------------------------------------------------------------*/
373const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm)
374{
375 switch (family) {
376 case PF_INET: {
377 struct sockaddr_in sin;
378 memset((char *) &sin, 0, sizeof(sin));
379 sin.sin_family = AF_UNSPEC;
380 sin.sin_addr.s_addr = INADDR_ANY;
381 return socket_strerror(socket_connect(ps, (SA *) &sin,
382 sizeof(sin), tm));
383 }
384 case PF_INET6: {
385 struct sockaddr_in6 sin6;
386 struct in6_addr addrany = IN6ADDR_ANY_INIT;
387 memset((char *) &sin6, 0, sizeof(sin6));
388 sin6.sin6_family = AF_UNSPEC;
389fprintf(stderr, "disconnecting\n");
390 sin6.sin6_addr = addrany;
391 return socket_strerror(socket_connect(ps, (SA *) &sin6,
392 sizeof(sin6), tm));
393 }
394 }
395 return NULL;
396}
397
398/*-------------------------------------------------------------------------*\
371* Tries to connect to remote address (address, port) 399* Tries to connect to remote address (address, port)
372\*-------------------------------------------------------------------------*/ 400\*-------------------------------------------------------------------------*/
373const char *inet_tryconnect(p_socket ps, const char *address, 401const char *inet_tryconnect(p_socket ps, const char *address,
@@ -382,17 +410,14 @@ const char *inet_tryconnect(p_socket ps, const char *address,
382 if (resolved) freeaddrinfo(resolved); 410 if (resolved) freeaddrinfo(resolved);
383 return err; 411 return err;
384 } 412 }
385 /* iterate over all returned addresses trying to connect */
386 for (iterator = resolved; iterator; iterator = iterator->ai_next) { 413 for (iterator = resolved; iterator; iterator = iterator->ai_next) {
387 timeout_markstart(tm); 414 timeout_markstart(tm);
388 /* try connecting to remote address */ 415 /* try connecting to remote address */
389 err = socket_strerror(socket_connect(ps, 416 err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr,
390 (SA *) iterator->ai_addr,
391 iterator->ai_addrlen, tm)); 417 iterator->ai_addrlen, tm));
392 /* if success, break out of loop */ 418 /* if success, break out of loop */
393 if (err == NULL) break; 419 if (err == NULL) break;
394 } 420 }
395
396 freeaddrinfo(resolved); 421 freeaddrinfo(resolved);
397 /* here, if err is set, we failed */ 422 /* here, if err is set, we failed */
398 return err; 423 return err;
@@ -407,12 +432,8 @@ const char *inet_trybind(p_socket ps, const char *address, const char *serv,
407 struct addrinfo *iterator = NULL, *resolved = NULL; 432 struct addrinfo *iterator = NULL, *resolved = NULL;
408 const char *err = NULL; 433 const char *err = NULL;
409 t_socket sock = *ps; 434 t_socket sock = *ps;
410 /* translate luasocket special values to C */
411 if (strcmp(address, "*") == 0) address = NULL;
412 if (!serv) serv = "0";
413 /* try resolving */ 435 /* try resolving */
414 err = socket_gaistrerror(getaddrinfo(address, serv, 436 err = socket_gaistrerror(getaddrinfo(address, serv, bindhints, &resolved));
415 bindhints, &resolved));
416 if (err) { 437 if (err) {
417 if (resolved) freeaddrinfo(resolved); 438 if (resolved) freeaddrinfo(resolved);
418 return err; 439 return err;
@@ -420,7 +441,7 @@ const char *inet_trybind(p_socket ps, const char *address, const char *serv,
420 /* iterate over resolved addresses until one is good */ 441 /* iterate over resolved addresses until one is good */
421 for (iterator = resolved; iterator; iterator = iterator->ai_next) { 442 for (iterator = resolved; iterator; iterator = iterator->ai_next) {
422 if(sock == SOCKET_INVALID) { 443 if(sock == SOCKET_INVALID) {
423 err = socket_strerror( socket_create(&sock, iterator->ai_family, 444 err = socket_strerror(socket_create(&sock, iterator->ai_family,
424 iterator->ai_socktype, iterator->ai_protocol)); 445 iterator->ai_socktype, iterator->ai_protocol));
425 if(err) 446 if(err)
426 continue; 447 continue;
diff --git a/src/inet.h b/src/inet.h
index 05633bb..2346734 100644
--- a/src/inet.h
+++ b/src/inet.h
@@ -29,6 +29,7 @@ const char *inet_tryconnect(p_socket ps, const char *address,
29 const char *serv, p_timeout tm, struct addrinfo *connecthints); 29 const char *serv, p_timeout tm, struct addrinfo *connecthints);
30const char *inet_trybind(p_socket ps, const char *address, const char *serv, 30const char *inet_trybind(p_socket ps, const char *address, const char *serv,
31 struct addrinfo *bindhints); 31 struct addrinfo *bindhints);
32const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm);
32 33
33int inet_meth_getpeername(lua_State *L, p_socket ps, int family); 34int inet_meth_getpeername(lua_State *L, p_socket ps, int family);
34int inet_meth_getsockname(lua_State *L, p_socket ps, int family); 35int inet_meth_getsockname(lua_State *L, p_socket ps, int family);
diff --git a/src/tcp.c b/src/tcp.c
index 2085937..5c85ae0 100644
--- a/src/tcp.c
+++ b/src/tcp.c
@@ -222,6 +222,7 @@ static int meth_bind(lua_State *L)
222 bindhints.ai_socktype = SOCK_STREAM; 222 bindhints.ai_socktype = SOCK_STREAM;
223 bindhints.ai_family = tcp->family; 223 bindhints.ai_family = tcp->family;
224 bindhints.ai_flags = AI_PASSIVE; 224 bindhints.ai_flags = AI_PASSIVE;
225 address = strcmp(address, "*")? address: NULL;
225 err = inet_trybind(&tcp->sock, address, port, &bindhints); 226 err = inet_trybind(&tcp->sock, address, port, &bindhints);
226 if (err) { 227 if (err) {
227 lua_pushnil(L); 228 lua_pushnil(L);
@@ -247,8 +248,7 @@ static int meth_connect(lua_State *L)
247 /* make sure we try to connect only to the same family */ 248 /* make sure we try to connect only to the same family */
248 connecthints.ai_family = tcp->family; 249 connecthints.ai_family = tcp->family;
249 timeout_markstart(&tcp->tm); 250 timeout_markstart(&tcp->tm);
250 err = inet_tryconnect(&tcp->sock, address, port, 251 err = inet_tryconnect(&tcp->sock, address, port, &tcp->tm, &connecthints);
251 &tcp->tm, &connecthints);
252 /* have to set the class even if it failed due to non-blocking connects */ 252 /* have to set the class even if it failed due to non-blocking connects */
253 auxiliar_setclass(L, "tcp{client}", 1); 253 auxiliar_setclass(L, "tcp{client}", 1);
254 if (err) { 254 if (err) {
diff --git a/src/udp.c b/src/udp.c
index bdf584b..4cd9a41 100644
--- a/src/udp.c
+++ b/src/udp.c
@@ -275,10 +275,10 @@ static int meth_receivefrom(lua_State *L) {
275 } 275 }
276 break; 276 break;
277 } 277 }
278 default: 278 default:
279 lua_pushnil(L); 279 lua_pushnil(L);
280 lua_pushfstring(L, "unknown family %d", udp->family); 280 lua_pushfstring(L, "unknown family %d", udp->family);
281 return 2; 281 return 2;
282 } 282 }
283 lua_pushnil(L); 283 lua_pushnil(L);
284 lua_pushstring(L, udp_strerror(err)); 284 lua_pushstring(L, udp_strerror(err));
@@ -366,27 +366,30 @@ static int meth_settimeout(lua_State *L) {
366static int meth_setpeername(lua_State *L) { 366static int meth_setpeername(lua_State *L) {
367 p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); 367 p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
368 p_timeout tm = &udp->tm; 368 p_timeout tm = &udp->tm;
369 const char *address = luaL_checkstring(L, 2); 369 const char *address = luaL_checkstring(L, 2);
370 int connecting = strcmp(address, "*"); 370 int connecting = strcmp(address, "*");
371 const char *port = connecting ? 371 const char *port = connecting? luaL_checkstring(L, 3): "0";
372 luaL_checkstring(L, 3) :
373 luaL_optstring(L, 3, "0");
374 struct addrinfo connecthints; 372 struct addrinfo connecthints;
375 const char *err; 373 const char *err;
376 memset(&connecthints, 0, sizeof(connecthints)); 374 memset(&connecthints, 0, sizeof(connecthints));
377 connecthints.ai_socktype = SOCK_DGRAM; 375 connecthints.ai_socktype = SOCK_DGRAM;
378 /* make sure we try to connect only to the same family */ 376 /* make sure we try to connect only to the same family */
379 connecthints.ai_family = udp->family; 377 connecthints.ai_family = udp->family;
380 err = inet_tryconnect(&udp->sock, address, port, 378 if (connecting) {
381 tm, &connecthints); 379 err = inet_tryconnect(&udp->sock, address, port, tm, &connecthints);
382 if (err) { 380 if (err) {
383 lua_pushnil(L); 381 lua_pushnil(L);
384 lua_pushstring(L, err); 382 lua_pushstring(L, err);
385 return 2; 383 return 2;
384 }
385 auxiliar_setclass(L, "udp{connected}", 1);
386 } else {
387 /* we ignore possible errors because Mac OS X always
388 * returns EAFNOSUPPORT */
389 inet_trydisconnect(&udp->sock, udp->family, tm);
390 auxiliar_setclass(L, "udp{unconnected}", 1);
386 } 391 }
387 /* change class to connected or unconnected depending on address */ 392 /* change class to connected or unconnected depending on address */
388 if (connecting) auxiliar_setclass(L, "udp{connected}", 1);
389 else auxiliar_setclass(L, "udp{unconnected}", 1);
390 lua_pushnumber(L, 1); 393 lua_pushnumber(L, 1);
391 return 1; 394 return 1;
392} 395}
diff --git a/test/udpconnectclnt.lua b/test/udpconnectclnt.lua
new file mode 100644
index 0000000..effe13a
--- /dev/null
+++ b/test/udpconnectclnt.lua
@@ -0,0 +1,19 @@
1local socket = require"socket"
2local udp = socket.udp
3local localhost = "127.0.0.1"
4local port = arg[1]
5
6se = udp(); se:setoption("reuseaddr", true)
7se:setsockname(localhost, 5062)
8print("se", se:getsockname())
9sc = udp(); sc:setoption("reuseaddr", true)
10sc:setsockname(localhost, 5061)
11print("sc", sc:getsockname())
12
13se:sendto("this is a test from se", localhost, port)
14socket.sleep(1)
15sc:sendto("this is a test from sc", localhost, port)
16socket.sleep(1)
17se:sendto("this is a test from se", localhost, port)
18socket.sleep(1)
19sc:sendto("this is a test from sc", localhost, port)
diff --git a/test/udpconnectsrvr.lua b/test/udpconnectsrvr.lua
new file mode 100644
index 0000000..5a9772e
--- /dev/null
+++ b/test/udpconnectsrvr.lua
@@ -0,0 +1,16 @@
1local socket = require"socket"
2local udp = socket.udp
3local localhost = "127.0.0.1"
4local s = assert(udp())
5assert(tostring(s):find("udp{unconnected}"))
6print("setpeername", s:setpeername(localhost, 5061))
7print("getsockname", s:getsockname())
8assert(tostring(s):find("udp{connected}"))
9print(s:receive())
10print("setpeername", s:setpeername("*"))
11print("getsockname", s:getsockname())
12s:sendto("a", localhost, 12345)
13print("getsockname", s:getsockname())
14assert(tostring(s):find("udp{unconnected}"))
15print(s:receivefrom())
16s:close()