Fixed inet_pton and a new Winsock UDP bug.

inet_pton was copying the entire sockaddr_in struct,
rather than just the sin_addr field...

I am a bit unsure about the UDP fix, because it may affect
TCP as well. On UDP sockets, when a sendto fails, the next
receive/receivefrom fails with CONNRESET. I changed
sock_recv/sock_recvfrom in wsocket.c to skip the CONNRESET
from the recv/recvfrom, hoping that if the socket is TCP,
sock_waitfd will get the CONNRESET again. The tests pass,
but this should be tested more thoroughly.
This commit is contained in:
unknown 2013-05-28 00:09:30 +08:00
parent 66cd8cfcee
commit 734cc23e1f
4 changed files with 84 additions and 69 deletions

122
src/udp.c
View file

@ -155,31 +155,31 @@ static int meth_sendto(lua_State *L) {
p_timeout tm = &udp->tm;
int err;
switch (udp->family) {
case PF_INET: {
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
if (inet_pton(AF_INET, ip, &addr.sin_addr) != 1)
case PF_INET: {
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
if (inet_pton(AF_INET, ip, &addr.sin_addr) != 1)
luaL_argerror(L, 3, "invalid ip address");
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
timeout_markstart(tm);
err = socket_sendto(&udp->sock, data, count, &sent,
(SA *) &addr, sizeof(addr), tm);
break;
}
case PF_INET6: {
struct sockaddr_in6 addr;
memset(&addr, 0, sizeof(addr));
if (!inet_pton(AF_INET6, ip, &addr.sin6_addr) != 1)
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
timeout_markstart(tm);
err = socket_sendto(&udp->sock, data, count, &sent,
(SA *) &addr, sizeof(addr), tm);
break;
}
case PF_INET6: {
struct sockaddr_in6 addr;
memset(&addr, 0, sizeof(addr));
if (!inet_pton(AF_INET6, ip, &addr.sin6_addr) != 1)
luaL_argerror(L, 3, "invalid ip address");
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(port);
timeout_markstart(tm);
err = socket_sendto(&udp->sock, data, count, &sent,
(SA *) &addr, sizeof(addr), tm);
break;
}
default:
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(port);
timeout_markstart(tm);
err = socket_sendto(&udp->sock, data, count, &sent,
(SA *) &addr, sizeof(addr), tm);
break;
}
default:
lua_pushnil(L);
lua_pushfstring(L, "unknown family %d", udp->family);
return 2;
@ -229,38 +229,40 @@ static int meth_receivefrom(lua_State *L) {
timeout_markstart(tm);
count = MIN(count, sizeof(buffer));
switch (udp->family) {
case PF_INET: {
struct sockaddr_in addr;
socklen_t addr_len = sizeof(addr);
err = socket_recvfrom(&udp->sock, buffer, count, &got,
(SA *) &addr, &addr_len, tm);
/* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
if (err == IO_CLOSED)
err = IO_DONE;
if (err == IO_DONE) {
char addrstr[INET_ADDRSTRLEN];
lua_pushlstring(L, buffer, got);
if (!inet_ntop(AF_INET, &addr.sin_addr,
addrstr, sizeof(addrstr))) {
lua_pushnil(L);
lua_pushstring(L, "invalid source address");
return 2;
}
lua_pushstring(L, addrstr);
lua_pushnumber(L, ntohs(addr.sin_port));
return 3;
}
break;
}
case PF_INET6: {
struct sockaddr_in6 addr;
socklen_t addr_len = sizeof(addr);
err = socket_recvfrom(&udp->sock, buffer, count, &got,
(SA *) &addr, &addr_len, tm);
/* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
if (err == IO_CLOSED)
case PF_INET: {
struct sockaddr_in addr;
socklen_t addr_len = sizeof(addr);
err = socket_recvfrom(&udp->sock, buffer, count, &got,
(SA *) &addr, &addr_len, tm);
/* Unlike TCP, recv() of zero is not closed,
* but a zero-length packet. */
if (err == IO_CLOSED)
err = IO_DONE;
if (err == IO_DONE) {
if (err == IO_DONE) {
char addrstr[INET_ADDRSTRLEN];
lua_pushlstring(L, buffer, got);
if (!inet_ntop(AF_INET, &addr.sin_addr,
addrstr, sizeof(addrstr))) {
lua_pushnil(L);
lua_pushstring(L, "invalid source address");
return 2;
}
lua_pushstring(L, addrstr);
lua_pushnumber(L, ntohs(addr.sin_port));
return 3;
}
break;
}
case PF_INET6: {
struct sockaddr_in6 addr;
socklen_t addr_len = sizeof(addr);
err = socket_recvfrom(&udp->sock, buffer, count, &got,
(SA *) &addr, &addr_len, tm);
/* Unlike TCP, recv() of zero is not closed,
* but a zero-length packet. */
if (err == IO_CLOSED)
err = IO_DONE;
if (err == IO_DONE) {
char addrstr[INET6_ADDRSTRLEN];
lua_pushlstring(L, buffer, got);
if (!inet_ntop(AF_INET6, &addr.sin6_addr,
@ -272,9 +274,9 @@ static int meth_receivefrom(lua_State *L) {
lua_pushstring(L, addrstr);
lua_pushnumber(L, ntohs(addr.sin6_port));
return 3;
}
break;
}
}
break;
}
default:
lua_pushnil(L);
lua_pushfstring(L, "unknown family %d", udp->family);
@ -413,7 +415,7 @@ static int meth_setsockname(lua_State *L) {
const char *address = luaL_checkstring(L, 2);
const char *port = luaL_checkstring(L, 3);
const char *err;
struct addrinfo bindhints;
struct addrinfo bindhints;
memset(&bindhints, 0, sizeof(bindhints));
bindhints.ai_socktype = SOCK_DGRAM;
bindhints.ai_family = udp->family;
@ -461,9 +463,9 @@ static int udp_create(lua_State *L, int family) {
}
static int global_create(lua_State *L) {
return udp_create(L, AF_INET);
return udp_create(L, AF_INET);
}
static int global_create6(lua_State *L) {
return udp_create(L, AF_INET6);
return udp_create(L, AF_INET6);
}