aboutsummaryrefslogtreecommitdiff
path: root/ares
diff options
context:
space:
mode:
authorWilliam Ahern <william@25thandclement.com>2006-06-19 01:18:05 +0000
committerWilliam Ahern <william@25thandclement.com>2006-06-19 01:18:05 +0000
commit4524618bf212b92ba5c651833b289e33c60430ff (patch)
tree6f8747b8f49ca7ccad43cb7d476ce57722ef4475 /ares
parent55d22ba10c4560c1b7ffbcf8a0c1d4864b024a88 (diff)
Handle EAGAIN/EWOULDBLOCK readiness errors, which can occur for both TCP and
UDP even when a poll(2) or select(2) suggest otherwise.
Diffstat (limited to 'ares')
-rw-r--r--ares/CHANGES8
-rw-r--r--ares/ares_process.c43
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;