added ares_process_fd() to allow applications to ask for processing on
authorDaniel Stenberg <daniel@haxx.se>
Wed, 30 May 2007 12:58:47 +0000 (12:58 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Wed, 30 May 2007 12:58:47 +0000 (12:58 +0000)
specific sockets and thus avoiding select() and associated functions/macros.
This function will be used by upcoming libcurl releases for this very
reason. It also made me export the ares_socket_t type in the public ares.h
header file, since ares_process_fd() uses that type for two of the arguments.

CHANGES
ares.h
ares_process.3
ares_process.c
setup.h

diff --git a/CHANGES b/CHANGES
index b4580c7..3f607b8 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,16 @@
   Changelog for the c-ares project
 
+* May 30 2007
+
+- Daniel S added ares_process_fd() to allow applications to ask for processing
+  on specific sockets and thus avoiding select() and associated
+  functions/macros.  This function will be used by upcoming libcurl releases
+  for this very reason. It also made me export the ares_socket_t type in the
+  public ares.h header file, since ares_process_fd() uses that type for two of
+  the arguments.
+
 * May 25 2007
+
 - Ravi Pratap fixed a flaw in the init_by_resolv_conf() function for windows
   that could cause it to return a bad return code.
 
diff --git a/ares.h b/ares.h
index 83a1c8e..73fc3e6 100644 (file)
--- a/ares.h
+++ b/ares.h
@@ -136,6 +136,22 @@ extern "C" {
 #define ARES_GETSOCK_WRITABLE(bits,num) (bits & (1 << ((num) + \
                                          ARES_GETSOCK_MAXNUM)))
 
+
+/*
+ * Typedef our socket type
+ */
+
+#ifndef ares_socket_typedef
+#ifdef WIN32
+typedef SOCKET ares_socket_t;
+#define ARES_SOCKET_BAD INVALID_SOCKET
+#else
+typedef int ares_socket_t;
+#define ARES_SOCKET_BAD -1
+#endif
+#define ares_socket_typedef
+#endif /* ares_socket_typedef */
+
 #ifdef WIN32
 typedef void (*ares_sock_state_cb)(void *data,
                                    SOCKET socket,
@@ -200,6 +216,8 @@ int ares_getsock(ares_channel channel, int *socks, int numsocks);
 struct timeval *ares_timeout(ares_channel channel, struct timeval *maxtv,
                              struct timeval *tv);
 void ares_process(ares_channel channel, fd_set *read_fds, fd_set *write_fds);
+void ares_process_fd(ares_channel channel, ares_socket_t read_fd,
+                     ares_socket_t write_fd);
 
 int ares_mkquery(const char *name, int dnsclass, int type, unsigned short id,
                  int rd, unsigned char **buf, int *buflen);
index 50216e1..c9cd547 100644 (file)
@@ -24,16 +24,16 @@ ares_process \- Process events for name resolution
 .B void ares_process(ares_channel \fIchannel\fP, fd_set *\fIread_fds\fP,
 .B     fd_set *\fIwrite_fds\fP)
 .fi
+.PP
+.B void ares_process_fd(ares_channel \fIchannel\fP,
+.B      ares_socket_t \fIread_fd\fP,
+.B     ares_socket_t \fIwrite_fd\fP)
+.fi
 .SH DESCRIPTION
-The
-.B ares_process
-function handles input/output events and timeouts associated with
-queries pending on the name service channel identified by
+The \fBares_process(3)\fP function handles input/output events and timeouts
+associated with queries pending on the name service channel identified by
 .IR channel .
-The file descriptor sets pointed to by
-.I read_fds
-and
-.I write_fds
+The file descriptor sets pointed to by \fIread_fds\fP and \fIwrite_fds\fP
 should have file descriptors set in them according to whether the file
 descriptors specified by \fIares_fds(3)\fP are ready for reading and writing.
 (The easiest way to determine this information is to invoke
@@ -44,6 +44,11 @@ The
 .B ares_process
 function will invoke callbacks for pending queries if they complete
 successfully or fail.
+
+\fBares_process_fd(3)\fP works the same way but acts and operates only on the
+specific file descriptors (sockets) you pass in to the function. Use
+ARES_SOCKET_BAD for "no action". This function is of course provided to allow
+users of c-ares to void select() in their applications and within c-ares.
 .SS EXAMPLE
 The following code fragment waits for all pending queries on a channel
 to complete:
index 8cb51c3..efc462a 100644 (file)
 
 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);
+                           ares_socket_t write_fd, time_t now);
+static void read_tcp_data(ares_channel channel, fd_set *read_fds,
+                          ares_socket_t read_fd, time_t now);
 static void read_udp_packets(ares_channel channel, fd_set *read_fds,
-                             time_t now);
+                             ares_socket_t read_fd, time_t now);
 static void process_timeouts(ares_channel channel, time_t now);
 static void process_answer(ares_channel channel, unsigned char *abuf,
                            int alen, int whichserver, int tcp, int now);
@@ -80,12 +81,30 @@ void ares_process(ares_channel channel, fd_set *read_fds, fd_set *write_fds)
   time_t now;
 
   time(&now);
-  write_tcp_data(channel, write_fds, now);
-  read_tcp_data(channel, read_fds, now);
-  read_udp_packets(channel, read_fds, now);
+  write_tcp_data(channel, write_fds, ARES_SOCKET_BAD, now);
+  read_tcp_data(channel, read_fds, ARES_SOCKET_BAD, now);
+  read_udp_packets(channel, read_fds, ARES_SOCKET_BAD, now);
   process_timeouts(channel, now);
 }
 
+/* Something interesting happened on the wire, or there was a timeout.
+ * See what's up and respond accordingly.
+ */
+void ares_process_fd(ares_channel channel,
+                     ares_socket_t read_fd, /* use ARES_SOCKET_BAD or valid
+                                               file descriptors */
+                     ares_socket_t write_fd)
+{
+  time_t now;
+
+  time(&now);
+  write_tcp_data(channel, NULL, write_fd, now);
+  read_tcp_data(channel, NULL, read_fd, now);
+  read_udp_packets(channel, NULL, read_fd, now);
+  process_timeouts(channel, now);
+}
+
+
 /* Return 1 if the specified error number describes a readiness error, or 0
  * otherwise. This is mostly for HP-UX, which could return EAGAIN or
  * EWOULDBLOCK. See this man page
@@ -114,7 +133,10 @@ static int try_again(int errnum)
 /* If any TCP sockets select true for writing, write out queued data
  * we have for them.
  */
-static void write_tcp_data(ares_channel channel, fd_set *write_fds, time_t now)
+static void write_tcp_data(ares_channel channel,
+                           fd_set *write_fds,
+                           ares_socket_t write_fd,
+                           time_t now)
 {
   struct server_state *server;
   struct send_request *sendreq;
@@ -124,14 +146,27 @@ static void write_tcp_data(ares_channel channel, fd_set *write_fds, time_t now)
   ssize_t wcount;
   size_t n;
 
+  if(!write_fds && (write_fd == ARES_SOCKET_BAD))
+    /* no possible action */
+    return;
+
   for (i = 0; i < channel->nservers; i++)
     {
-      /* Make sure server has data to send and is selected in write_fds. */
+      /* Make sure server has data to send and is selected in write_fds or
+         write_fd. */
       server = &channel->servers[i];
-      if (!server->qhead || server->tcp_socket == ARES_SOCKET_BAD
-          || !FD_ISSET(server->tcp_socket, write_fds))
+      if (!server->qhead || server->tcp_socket == ARES_SOCKET_BAD)
         continue;
 
+      if(write_fds) {
+        if(!FD_ISSET(server->tcp_socket, write_fds))
+          continue;
+      }
+      else {
+        if(server->tcp_socket != write_fd)
+          continue;
+      }
+
       /* Count the number of send queue items. */
       n = 0;
       for (sendreq = server->qhead; sendreq; sendreq = sendreq->next)
@@ -218,20 +253,33 @@ static void write_tcp_data(ares_channel channel, fd_set *write_fds, time_t now)
  * allocate a buffer if we finish reading the length word, and process
  * a packet if we finish reading one.
  */
-static void read_tcp_data(ares_channel channel, fd_set *read_fds, time_t now)
+static void read_tcp_data(ares_channel channel, fd_set *read_fds,
+                          ares_socket_t read_fd, time_t now)
 {
   struct server_state *server;
   int i;
   ssize_t count;
 
+  if(!read_fds && (read_fd == ARES_SOCKET_BAD))
+    /* no possible action */
+    return;
+
   for (i = 0; i < channel->nservers; i++)
     {
       /* Make sure the server has a socket and is selected in read_fds. */
       server = &channel->servers[i];
-      if (server->tcp_socket == ARES_SOCKET_BAD ||
-          !FD_ISSET(server->tcp_socket, read_fds))
+      if (server->tcp_socket == ARES_SOCKET_BAD)
         continue;
 
+      if(read_fds) {
+        if(!FD_ISSET(server->tcp_socket, read_fds))
+          continue;
+      }
+      else {
+        if(server->tcp_socket != read_fd)
+          continue;
+      }
+
       if (server->tcp_lenbuf_pos != 2)
         {
           /* We haven't yet read a length word, so read that (or
@@ -294,22 +342,34 @@ static void read_tcp_data(ares_channel channel, fd_set *read_fds, time_t now)
 
 /* If any UDP sockets select true for reading, process them. */
 static void read_udp_packets(ares_channel channel, fd_set *read_fds,
-                             time_t now)
+                             ares_socket_t read_fd, time_t now)
 {
   struct server_state *server;
   int i;
   ssize_t count;
   unsigned char buf[PACKETSZ + 1];
 
+  if(!read_fds && (read_fd == ARES_SOCKET_BAD))
+    /* no possible action */
+    return;
+
   for (i = 0; i < channel->nservers; i++)
     {
       /* Make sure the server has a socket and is selected in read_fds. */
       server = &channel->servers[i];
 
-      if (server->udp_socket == ARES_SOCKET_BAD ||
-          !FD_ISSET(server->udp_socket, read_fds))
+      if (server->udp_socket == ARES_SOCKET_BAD)
         continue;
 
+      if(read_fds) {
+        if(!FD_ISSET(server->udp_socket, read_fds))
+          continue;
+      }
+      else {
+        if(server->udp_socket != read_fd)
+          continue;
+      }
+
       count = sread(server->udp_socket, buf, sizeof(buf));
       if (count == -1 && try_again(SOCKERRNO))
         continue;
diff --git a/setup.h b/setup.h
index 465e012..2106df7 100644 (file)
--- a/setup.h
+++ b/setup.h
@@ -3,7 +3,7 @@
 
 /* $Id$ */
 
-/* Copyright (C) 2004 - 2005 by Daniel Stenberg et al
+/* Copyright (C) 2004 - 2007 by Daniel Stenberg et al
  *
  * Permission to use, copy, modify, and distribute this software and its
  * documentation for any purpose and without fee is hereby granted, provided
 #undef PACKAGE
 
 /*
- * Typedef our socket type
- */
-
-#ifdef USE_WINSOCK
-typedef SOCKET ares_socket_t;
-#define ARES_SOCKET_BAD INVALID_SOCKET
-#else
-typedef int ares_socket_t;
-#define ARES_SOCKET_BAD -1
-#endif
-
-/*
  * Assume a few thing unless they're set by configure
  */