aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <diego.nehab@gmail.com>2013-05-28 00:09:30 +0800
committerunknown <diego.nehab@gmail.com>2013-05-28 00:09:30 +0800
commit734cc23e1f03372314ebad07ffd35117c152afcd (patch)
tree808531d9c0c84aae57657aff353b08d466a3dcfb
parent66cd8cfcee1f14b59450147c16a6bc44ef298edc (diff)
downloadluasocket-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.c17
-rw-r--r--src/io.h2
-rw-r--r--src/udp.c122
-rw-r--r--src/wsocket.c12
4 files changed, 84 insertions, 69 deletions
diff --git a/src/inet.c b/src/inet.c
index fe9769b..1f55d2a 100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -558,18 +558,23 @@ const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
558 558
559int inet_pton(int af, const char *src, void *dst) 559int 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
diff --git a/src/io.h b/src/io.h
index 8cca08a..76a3e58 100644
--- a/src/io.h
+++ b/src/io.h
@@ -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 */
diff --git a/src/udp.c b/src/udp.c
index 6e74702..3051382 100644
--- a/src/udp.c
+++ b/src/udp.c
@@ -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
463static int global_create(lua_State *L) { 465static int global_create(lua_State *L) {
464 return udp_create(L, AF_INET); 466 return udp_create(L, AF_INET);
465} 467}
466 468
467static int global_create6(lua_State *L) { 469static 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}