From 4524618bf212b92ba5c651833b289e33c60430ff Mon Sep 17 00:00:00 2001 From: William Ahern Date: Mon, 19 Jun 2006 01:18:05 +0000 Subject: [PATCH] Handle EAGAIN/EWOULDBLOCK readiness errors, which can occur for both TCP and UDP even when a poll(2) or select(2) suggest otherwise. --- ares/CHANGES | 8 ++++++++ ares/ares_process.c | 43 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/ares/CHANGES b/ares/CHANGES index d96078499..880d22839 100644 --- a/ares/CHANGES +++ b/ares/CHANGES @@ -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 diff --git a/ares/ares_process.c b/ares/ares_process.c index f38e591f2..533e78029 100644 --- a/ares/ares_process.c +++ b/ares/ares_process.c @@ -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;