Fix "final" bug in pton and TCP connreset handling

This commit is contained in:
unknown 2013-05-28 17:27:06 +08:00
parent 27fd725c6d
commit 2d51d61688
2 changed files with 27 additions and 19 deletions

View File

@ -559,12 +559,11 @@ const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
int inet_pton(int af, const char *src, void *dst) int inet_pton(int af, const char *src, void *dst)
{ {
struct addrinfo hints, *res; struct addrinfo hints, *res;
int ret = 1;
memset(&hints, 0, sizeof(struct addrinfo)); memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = af; hints.ai_family = af;
hints.ai_flags = AI_NUMERICHOST; hints.ai_flags = AI_NUMERICHOST;
if (getaddrinfo(src, NULL, &hints, &res) != 0) { if (getaddrinfo(src, NULL, &hints, &res) != 0) return -1;
return -1;
}
if (af == AF_INET) { if (af == AF_INET) {
struct sockaddr_in *in = (struct sockaddr_in *) res->ai_addr; struct sockaddr_in *in = (struct sockaddr_in *) res->ai_addr;
memcpy(dst, &in->sin_addr, sizeof(in->sin_addr)); memcpy(dst, &in->sin_addr, sizeof(in->sin_addr));
@ -572,10 +571,10 @@ int inet_pton(int af, const char *src, void *dst)
struct sockaddr_in6 *in = (struct sockaddr_in6 *) res->ai_addr; struct sockaddr_in6 *in = (struct sockaddr_in6 *) res->ai_addr;
memcpy(dst, &in->sin6_addr, sizeof(in->sin6_addr)); memcpy(dst, &in->sin6_addr, sizeof(in->sin6_addr));
} else { } else {
return -1; ret = -1;
} }
freeaddrinfo(res); freeaddrinfo(res);
return 0; return ret;
} }
#endif #endif

View File

@ -238,8 +238,10 @@ int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent,
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Receive with timeout * Receive with timeout
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm) { int socket_recv(p_socket ps, char *data, size_t count, size_t *got,
int err; p_timeout tm)
{
int err, prev = IO_DONE;
*got = 0; *got = 0;
if (*ps == SOCKET_INVALID) return IO_CLOSED; if (*ps == SOCKET_INVALID) return IO_CLOSED;
for ( ;; ) { for ( ;; ) {
@ -250,11 +252,14 @@ int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm
} }
if (taken == 0) return IO_CLOSED; if (taken == 0) return IO_CLOSED;
err = WSAGetLastError(); err = WSAGetLastError();
/* On Windows, and on UDP, a connreset simply means the /* On UDP, a connreset simply means the previous send failed.
* previous send failed. On TCP, it means our socket * So we try again.
* is now useless, so the error must pass. I am * On TCP, it means our socket is now useless, so the error passes.
* hoping waitfd will still get the error. */ * (We will loop again, exiting because the same error will happen) */
if (err != WSAEWOULDBLOCK && err != WSAECONNRESET) return err; if (err != WSAEWOULDBLOCK) {
if (err != WSAECONNRESET || prev == WSAECONNRESET) return err;
prev = err;
}
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
} }
} }
@ -263,8 +268,9 @@ int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm
* Recvfrom with timeout * Recvfrom with timeout
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got, int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got,
SA *addr, socklen_t *len, p_timeout tm) { SA *addr, socklen_t *len, p_timeout tm)
int err; {
int err, prev = IO_DONE;
*got = 0; *got = 0;
if (*ps == SOCKET_INVALID) return IO_CLOSED; if (*ps == SOCKET_INVALID) return IO_CLOSED;
for ( ;; ) { for ( ;; ) {
@ -275,11 +281,14 @@ int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got,
} }
if (taken == 0) return IO_CLOSED; if (taken == 0) return IO_CLOSED;
err = WSAGetLastError(); err = WSAGetLastError();
/* On Windows, and on UDP, a connreset simply means the /* On UDP, a connreset simply means the previous send failed.
* previous send failed. On TCP, it means our socket * So we try again.
* is now useless, so the error must pass. I am * On TCP, it means our socket is now useless, so the error passes.
* hoping waitfd will still get the error. */ * (We will loop again, exiting because the same error will happen) */
if (err != WSAEWOULDBLOCK && err != WSAECONNRESET) return err; if (err != WSAEWOULDBLOCK) {
if (err != WSAECONNRESET || prev == WSAECONNRESET) return err;
prev = err;
}
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
} }
} }