diff options
| author | unknown <diego.nehab@gmail.com> | 2013-05-28 00:09:30 +0800 |
|---|---|---|
| committer | unknown <diego.nehab@gmail.com> | 2013-05-28 00:09:30 +0800 |
| commit | 734cc23e1f03372314ebad07ffd35117c152afcd (patch) | |
| tree | 808531d9c0c84aae57657aff353b08d466a3dcfb | |
| parent | 66cd8cfcee1f14b59450147c16a6bc44ef298edc (diff) | |
| download | luasocket-734cc23e1f03372314ebad07ffd35117c152afcd.tar.gz luasocket-734cc23e1f03372314ebad07ffd35117c152afcd.tar.bz2 luasocket-734cc23e1f03372314ebad07ffd35117c152afcd.zip | |
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.
| -rw-r--r-- | src/inet.c | 17 | ||||
| -rw-r--r-- | src/io.h | 2 | ||||
| -rw-r--r-- | src/udp.c | 122 | ||||
| -rw-r--r-- | src/wsocket.c | 12 |
4 files changed, 84 insertions, 69 deletions
| @@ -558,18 +558,23 @@ const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt) | |||
| 558 | 558 | ||
| 559 | int inet_pton(int af, const char *src, void *dst) | 559 | int inet_pton(int af, const char *src, void *dst) |
| 560 | { | 560 | { |
| 561 | struct addrinfo hints, *res, *ressave; | 561 | struct addrinfo hints, *res; |
| 562 | memset(&hints, 0, sizeof(struct addrinfo)); | 562 | memset(&hints, 0, sizeof(struct addrinfo)); |
| 563 | hints.ai_family = af; | 563 | hints.ai_family = af; |
| 564 | hints.ai_flags = AI_NUMERICHOST; | ||
| 564 | if (getaddrinfo(src, NULL, &hints, &res) != 0) { | 565 | if (getaddrinfo(src, NULL, &hints, &res) != 0) { |
| 565 | return -1; | 566 | return -1; |
| 566 | } | 567 | } |
| 567 | ressave = res; | 568 | if (af == AF_INET) { |
| 568 | while (res) { | 569 | struct sockaddr_in *in = (struct sockaddr_in *) res->ai_addr; |
| 569 | memcpy(dst, res->ai_addr, res->ai_addrlen); | 570 | memcpy(dst, &in->sin_addr, sizeof(in->sin_addr)); |
| 570 | res = res->ai_next; | 571 | } else if (af == AF_INET6) { |
| 572 | struct sockaddr_in6 *in = (struct sockaddr_in6 *) res->ai_addr; | ||
| 573 | memcpy(dst, &in->sin6_addr, sizeof(in->sin6_addr)); | ||
| 574 | } else { | ||
| 575 | return -1; | ||
| 571 | } | 576 | } |
| 572 | freeaddrinfo(ressave); | 577 | freeaddrinfo(res); |
| 573 | return 0; | 578 | return 0; |
| 574 | } | 579 | } |
| 575 | 580 | ||
| @@ -22,7 +22,7 @@ enum { | |||
| 22 | IO_DONE = 0, /* operation completed successfully */ | 22 | IO_DONE = 0, /* operation completed successfully */ |
| 23 | IO_TIMEOUT = -1, /* operation timed out */ | 23 | IO_TIMEOUT = -1, /* operation timed out */ |
| 24 | IO_CLOSED = -2, /* the connection has been closed */ | 24 | IO_CLOSED = -2, /* the connection has been closed */ |
| 25 | IO_UNKNOWN = -3 | 25 | IO_UNKNOWN = -3 |
| 26 | }; | 26 | }; |
| 27 | 27 | ||
| 28 | /* interface to error message function */ | 28 | /* interface to error message function */ |
| @@ -155,31 +155,31 @@ static int meth_sendto(lua_State *L) { | |||
| 155 | p_timeout tm = &udp->tm; | 155 | p_timeout tm = &udp->tm; |
| 156 | int err; | 156 | int err; |
| 157 | switch (udp->family) { | 157 | switch (udp->family) { |
| 158 | case PF_INET: { | 158 | case PF_INET: { |
| 159 | struct sockaddr_in addr; | 159 | struct sockaddr_in addr; |
| 160 | memset(&addr, 0, sizeof(addr)); | 160 | memset(&addr, 0, sizeof(addr)); |
| 161 | if (inet_pton(AF_INET, ip, &addr.sin_addr) != 1) | 161 | if (inet_pton(AF_INET, ip, &addr.sin_addr) != 1) |
| 162 | luaL_argerror(L, 3, "invalid ip address"); | 162 | luaL_argerror(L, 3, "invalid ip address"); |
| 163 | addr.sin_family = AF_INET; | 163 | addr.sin_family = AF_INET; |
| 164 | addr.sin_port = htons(port); | 164 | addr.sin_port = htons(port); |
| 165 | timeout_markstart(tm); | 165 | timeout_markstart(tm); |
| 166 | err = socket_sendto(&udp->sock, data, count, &sent, | 166 | err = socket_sendto(&udp->sock, data, count, &sent, |
| 167 | (SA *) &addr, sizeof(addr), tm); | 167 | (SA *) &addr, sizeof(addr), tm); |
| 168 | break; | 168 | break; |
| 169 | } | 169 | } |
| 170 | case PF_INET6: { | 170 | case PF_INET6: { |
| 171 | struct sockaddr_in6 addr; | 171 | struct sockaddr_in6 addr; |
| 172 | memset(&addr, 0, sizeof(addr)); | 172 | memset(&addr, 0, sizeof(addr)); |
| 173 | if (!inet_pton(AF_INET6, ip, &addr.sin6_addr) != 1) | 173 | if (!inet_pton(AF_INET6, ip, &addr.sin6_addr) != 1) |
| 174 | luaL_argerror(L, 3, "invalid ip address"); | 174 | luaL_argerror(L, 3, "invalid ip address"); |
| 175 | addr.sin6_family = AF_INET6; | 175 | addr.sin6_family = AF_INET6; |
| 176 | addr.sin6_port = htons(port); | 176 | addr.sin6_port = htons(port); |
| 177 | timeout_markstart(tm); | 177 | timeout_markstart(tm); |
| 178 | err = socket_sendto(&udp->sock, data, count, &sent, | 178 | err = socket_sendto(&udp->sock, data, count, &sent, |
| 179 | (SA *) &addr, sizeof(addr), tm); | 179 | (SA *) &addr, sizeof(addr), tm); |
| 180 | break; | 180 | break; |
| 181 | } | 181 | } |
| 182 | default: | 182 | default: |
| 183 | lua_pushnil(L); | 183 | lua_pushnil(L); |
| 184 | lua_pushfstring(L, "unknown family %d", udp->family); | 184 | lua_pushfstring(L, "unknown family %d", udp->family); |
| 185 | return 2; | 185 | return 2; |
| @@ -229,38 +229,40 @@ static int meth_receivefrom(lua_State *L) { | |||
| 229 | timeout_markstart(tm); | 229 | timeout_markstart(tm); |
| 230 | count = MIN(count, sizeof(buffer)); | 230 | count = MIN(count, sizeof(buffer)); |
| 231 | switch (udp->family) { | 231 | switch (udp->family) { |
| 232 | case PF_INET: { | 232 | case PF_INET: { |
| 233 | struct sockaddr_in addr; | 233 | struct sockaddr_in addr; |
| 234 | socklen_t addr_len = sizeof(addr); | 234 | socklen_t addr_len = sizeof(addr); |
| 235 | err = socket_recvfrom(&udp->sock, buffer, count, &got, | 235 | err = socket_recvfrom(&udp->sock, buffer, count, &got, |
| 236 | (SA *) &addr, &addr_len, tm); | 236 | (SA *) &addr, &addr_len, tm); |
| 237 | /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ | 237 | /* Unlike TCP, recv() of zero is not closed, |
| 238 | if (err == IO_CLOSED) | 238 | * but a zero-length packet. */ |
| 239 | err = IO_DONE; | 239 | if (err == IO_CLOSED) |
| 240 | if (err == IO_DONE) { | 240 | err = IO_DONE; |
| 241 | char addrstr[INET_ADDRSTRLEN]; | 241 | if (err == IO_DONE) { |
| 242 | lua_pushlstring(L, buffer, got); | 242 | char addrstr[INET_ADDRSTRLEN]; |
| 243 | if (!inet_ntop(AF_INET, &addr.sin_addr, | 243 | lua_pushlstring(L, buffer, got); |
| 244 | addrstr, sizeof(addrstr))) { | 244 | if (!inet_ntop(AF_INET, &addr.sin_addr, |
| 245 | lua_pushnil(L); | 245 | addrstr, sizeof(addrstr))) { |
| 246 | lua_pushstring(L, "invalid source address"); | 246 | lua_pushnil(L); |
| 247 | return 2; | 247 | lua_pushstring(L, "invalid source address"); |
| 248 | } | 248 | return 2; |
| 249 | lua_pushstring(L, addrstr); | 249 | } |
| 250 | lua_pushnumber(L, ntohs(addr.sin_port)); | 250 | lua_pushstring(L, addrstr); |
| 251 | return 3; | 251 | lua_pushnumber(L, ntohs(addr.sin_port)); |
| 252 | } | 252 | return 3; |
| 253 | break; | 253 | } |
| 254 | } | 254 | break; |
| 255 | case PF_INET6: { | 255 | } |
| 256 | struct sockaddr_in6 addr; | 256 | case PF_INET6: { |
| 257 | socklen_t addr_len = sizeof(addr); | 257 | struct sockaddr_in6 addr; |
| 258 | err = socket_recvfrom(&udp->sock, buffer, count, &got, | 258 | socklen_t addr_len = sizeof(addr); |
| 259 | (SA *) &addr, &addr_len, tm); | 259 | err = socket_recvfrom(&udp->sock, buffer, count, &got, |
| 260 | /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ | 260 | (SA *) &addr, &addr_len, tm); |
| 261 | if (err == IO_CLOSED) | 261 | /* Unlike TCP, recv() of zero is not closed, |
| 262 | * but a zero-length packet. */ | ||
| 263 | if (err == IO_CLOSED) | ||
| 262 | err = IO_DONE; | 264 | err = IO_DONE; |
| 263 | if (err == IO_DONE) { | 265 | if (err == IO_DONE) { |
| 264 | char addrstr[INET6_ADDRSTRLEN]; | 266 | char addrstr[INET6_ADDRSTRLEN]; |
| 265 | lua_pushlstring(L, buffer, got); | 267 | lua_pushlstring(L, buffer, got); |
| 266 | if (!inet_ntop(AF_INET6, &addr.sin6_addr, | 268 | if (!inet_ntop(AF_INET6, &addr.sin6_addr, |
| @@ -272,9 +274,9 @@ static int meth_receivefrom(lua_State *L) { | |||
| 272 | lua_pushstring(L, addrstr); | 274 | lua_pushstring(L, addrstr); |
| 273 | lua_pushnumber(L, ntohs(addr.sin6_port)); | 275 | lua_pushnumber(L, ntohs(addr.sin6_port)); |
| 274 | return 3; | 276 | return 3; |
| 275 | } | 277 | } |
| 276 | break; | 278 | break; |
| 277 | } | 279 | } |
| 278 | default: | 280 | default: |
| 279 | lua_pushnil(L); | 281 | lua_pushnil(L); |
| 280 | lua_pushfstring(L, "unknown family %d", udp->family); | 282 | lua_pushfstring(L, "unknown family %d", udp->family); |
| @@ -413,7 +415,7 @@ static int meth_setsockname(lua_State *L) { | |||
| 413 | const char *address = luaL_checkstring(L, 2); | 415 | const char *address = luaL_checkstring(L, 2); |
| 414 | const char *port = luaL_checkstring(L, 3); | 416 | const char *port = luaL_checkstring(L, 3); |
| 415 | const char *err; | 417 | const char *err; |
| 416 | struct addrinfo bindhints; | 418 | struct addrinfo bindhints; |
| 417 | memset(&bindhints, 0, sizeof(bindhints)); | 419 | memset(&bindhints, 0, sizeof(bindhints)); |
| 418 | bindhints.ai_socktype = SOCK_DGRAM; | 420 | bindhints.ai_socktype = SOCK_DGRAM; |
| 419 | bindhints.ai_family = udp->family; | 421 | bindhints.ai_family = udp->family; |
| @@ -461,9 +463,9 @@ static int udp_create(lua_State *L, int family) { | |||
| 461 | } | 463 | } |
| 462 | 464 | ||
| 463 | static int global_create(lua_State *L) { | 465 | static int global_create(lua_State *L) { |
| 464 | return udp_create(L, AF_INET); | 466 | return udp_create(L, AF_INET); |
| 465 | } | 467 | } |
| 466 | 468 | ||
| 467 | static int global_create6(lua_State *L) { | 469 | static int global_create6(lua_State *L) { |
| 468 | return udp_create(L, AF_INET6); | 470 | return udp_create(L, AF_INET6); |
| 469 | } | 471 | } |
diff --git a/src/wsocket.c b/src/wsocket.c index 65f76bc..d34724b 100644 --- a/src/wsocket.c +++ b/src/wsocket.c | |||
| @@ -250,7 +250,11 @@ int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm | |||
| 250 | } | 250 | } |
| 251 | if (taken == 0) return IO_CLOSED; | 251 | if (taken == 0) return IO_CLOSED; |
| 252 | err = WSAGetLastError(); | 252 | err = WSAGetLastError(); |
| 253 | if (err != WSAEWOULDBLOCK) return err; | 253 | /* On Windows, and on UDP, a connreset simply means the |
| 254 | * previous send failed. On TCP, it means our socket | ||
| 255 | * is now useless, so the error must pass. I am | ||
| 256 | * hoping waitfd will still get the error. */ | ||
| 257 | if (err != WSAEWOULDBLOCK && err != WSAECONNRESET) return err; | ||
| 254 | if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; | 258 | if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; |
| 255 | } | 259 | } |
| 256 | } | 260 | } |
| @@ -271,7 +275,11 @@ int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got, | |||
| 271 | } | 275 | } |
| 272 | if (taken == 0) return IO_CLOSED; | 276 | if (taken == 0) return IO_CLOSED; |
| 273 | err = WSAGetLastError(); | 277 | err = WSAGetLastError(); |
| 274 | if (err != WSAEWOULDBLOCK) return err; | 278 | /* On Windows, and on UDP, a connreset simply means the |
| 279 | * previous send failed. On TCP, it means our socket | ||
| 280 | * is now useless, so the error must pass. I am | ||
| 281 | * hoping waitfd will still get the error. */ | ||
| 282 | if (err != WSAEWOULDBLOCK && err != WSAECONNRESET) return err; | ||
| 275 | if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; | 283 | if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; |
| 276 | } | 284 | } |
| 277 | } | 285 | } |
