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 | } |