Handle EAGAIN/EWOULDBLOCK readiness errors, which can occur for both TCP and

UDP even when a poll(2) or select(2) suggest otherwise.
This commit is contained in:
William Ahern 2006-06-19 01:18:05 +00:00
parent 55d22ba10c
commit 4524618bf2
2 changed files with 46 additions and 5 deletions

View File

@ -1,5 +1,13 @@
Changelog for the c-ares project
* June 18, 2006
- William Ahern handles EAGAIN/EWOULDBLOCK errors in most of the I/O calls
from area_process.c.
TODO: Handle one last EAGAIN for a UDP socket send(2) in
ares__send_query().
* May 10, 2006
- Bram Matthys brought my attention to a libtool peculiarity where detecting

View File

@ -63,6 +63,7 @@
#define GET_ERRNO() errno
#endif
static int try_again(int errnum);
static void write_tcp_data(ares_channel channel, fd_set *write_fds,
time_t now);
static void read_tcp_data(ares_channel channel, fd_set *read_fds, time_t now);
@ -94,6 +95,31 @@ void ares_process(ares_channel channel, fd_set *read_fds, fd_set *write_fds)
process_timeouts(channel, now);
}
/* Return 1 if the specified errno describes a readiness error, or 0
* otherwise. This is mostly for HP-UX, which could return EAGAIN or
* EWOULDBLOCK. See this man page
*
* http://devrsrc1.external.hp.com/STKS/cgi-bin/man2html?manpage=/usr/share/man/man2.Z/send.2
*/
static int try_again(int errnum)
{
#if !defined EWOULDBLOCK && !defined EAGAIN
#error "Neither EWOULDBLOCK nor EAGAIN defined"
#endif
switch (errnum)
{
#ifdef EWOULDBLOCK
case EWOULDBLOCK:
return 1;
#endif
#if defined EAGAIN && EAGAIN != EWOULDBLOCK
case EAGAIN:
return 1;
#endif
}
return 0;
}
/* If any TCP sockets select true for writing, write out queued data
* we have for them.
*/
@ -136,7 +162,8 @@ static void write_tcp_data(ares_channel channel, fd_set *write_fds, time_t now)
free(vec);
if (wcount < 0)
{
handle_error(channel, i, now);
if (!try_again(GET_ERRNO()))
handle_error(channel, i, now);
continue;
}
@ -173,7 +200,8 @@ static void write_tcp_data(ares_channel channel, fd_set *write_fds, time_t now)
if (scount < 0)
{
handle_error(channel, i, now);
if (!try_again(GET_ERRNO()))
handle_error(channel, i, now);
continue;
}
@ -224,7 +252,8 @@ static void read_tcp_data(ares_channel channel, fd_set *read_fds, time_t now)
2 - server->tcp_lenbuf_pos, 0);
if (count <= 0)
{
handle_error(channel, i, now);
if (!(count == -1 && try_again(GET_ERRNO())))
handle_error(channel, i, now);
continue;
}
@ -250,7 +279,8 @@ static void read_tcp_data(ares_channel channel, fd_set *read_fds, time_t now)
server->tcp_length - server->tcp_buffer_pos, 0);
if (count <= 0)
{
handle_error(channel, i, now);
if (!(count == -1 && try_again(GET_ERRNO())))
handle_error(channel, i, now);
continue;
}
@ -289,7 +319,9 @@ static void read_udp_packets(ares_channel channel, fd_set *read_fds,
continue;
count = recv(server->udp_socket, (void *)buf, sizeof(buf), 0);
if (count <= 0)
if (count == -1 && try_again(GET_ERRNO()))
continue;
else if (count <= 0)
handle_error(channel, i, now);
process_answer(channel, buf, count, i, 0, now);
@ -479,6 +511,7 @@ void ares__send_query(ares_channel channel, struct query *query, time_t now)
if (send(server->udp_socket, (void *)query->qbuf,
query->qlen, 0) == -1)
{
/* FIXME: Handle EAGAIN here since it likely can happen. */
query->skip_server[query->server] = 1;
next_server(channel, query, now);
return;