Nick Mathewson added the ARES_OPT_SOCK_STATE_CB option that when set makes
authorDaniel Stenberg <daniel@haxx.se>
Wed, 3 May 2006 06:11:44 +0000 (06:11 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Wed, 3 May 2006 06:11:44 +0000 (06:11 +0000)
c-ares call a callback on socket state changes. A better way than the
ares_getsock() to get full control over the socket state.

CHANGES
ares.h
ares__close_sockets.c
ares_cancel.c
ares_destroy.c
ares_init.3
ares_init.c
ares_private.h
ares_process.c

diff --git a/CHANGES b/CHANGES
index 11c2955..3c91e27 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,11 @@
   Changelog for the c-ares project
 
+* May 3, 2006
+
+- Nick Mathewson added the ARES_OPT_SOCK_STATE_CB option that when set makes
+  c-ares call a callback on socket state changes. A better way than the
+  ares_getsock() to get full control over the socket state.
+
 * January 9, 2006
 
 - Alexander Lazic improved the getservbyport_r() configure check.
@@ -28,8 +34,8 @@
 
 - Added constants that will be used by ares_getaddrinfo
 
-- Made ares_getnameinfo use the reentrant getservbyport (getservbyport_r) if it is
-  available to ensure it works properly in a threaded environment.
+- Made ares_getnameinfo use the reentrant getservbyport (getservbyport_r) if it
+  is available to ensure it works properly in a threaded environment.
 
 * September 10
 
diff --git a/ares.h b/ares.h
index 8e8da28..9414f9b 100644 (file)
--- a/ares.h
+++ b/ares.h
@@ -93,6 +93,7 @@ extern "C" {
 #define ARES_OPT_SERVERS        (1 << 6)
 #define ARES_OPT_DOMAINS        (1 << 7)
 #define ARES_OPT_LOOKUPS        (1 << 8)
+#define ARES_OPT_SOCK_STATE_CB  (1 << 9)
 
 /* Nameinfo flag values */
 #define ARES_NI_NOFQDN                  (1 << 0)
@@ -135,6 +136,18 @@ extern "C" {
 #define ARES_GETSOCK_WRITABLE(bits,num) (bits & (1 << ((num) + \
                                          ARES_GETSOCK_MAXNUM)))
 
+#ifdef WIN32
+typedef void (*ares_sock_state_cb)(void *data,
+                                   SOCKET socket,
+                                   int readable,
+                                   int writable);
+#else
+typedef void (*ares_sock_state_cb)(void *data,
+                                   int socket,
+                                   int readable,
+                                   int writable);
+#endif
+
 struct ares_options {
   int flags;
   int timeout;
@@ -147,6 +160,8 @@ struct ares_options {
   char **domains;
   int ndomains;
   char *lookups;
+  ares_sock_state_cb sock_state_cb;
+  void *sock_state_cb_data;
 };
 
 struct hostent;
index fb883f9..7475a4b 100644 (file)
@@ -23,7 +23,7 @@
 #include "ares.h"
 #include "ares_private.h"
 
-void ares__close_sockets(struct server_state *server)
+void ares__close_sockets(ares_channel channel, struct server_state *server)
 {
   struct send_request *sendreq;
 
@@ -46,11 +46,13 @@ void ares__close_sockets(struct server_state *server)
   /* Close the TCP and UDP sockets. */
   if (server->tcp_socket != ARES_SOCKET_BAD)
     {
+      SOCK_STATE_CALLBACK(channel, server->tcp_socket, 0, 0);
       closesocket(server->tcp_socket);
       server->tcp_socket = ARES_SOCKET_BAD;
     }
   if (server->udp_socket != ARES_SOCKET_BAD)
     {
+      SOCK_STATE_CALLBACK(channel, server->udp_socket, 0, 0);
       closesocket(server->udp_socket);
       server->udp_socket = ARES_SOCKET_BAD;
     }
index 0464284..4df1e9f 100644 (file)
@@ -38,6 +38,6 @@ void ares_cancel(ares_channel channel)
   if (!(channel->flags & ARES_FLAG_STAYOPEN))
   {
     for (i = 0; i < channel->nservers; i++)
-      ares__close_sockets(&channel->servers[i]);
+      ares__close_sockets(channel, &channel->servers[i]);
   }
 }
index efe2b53..d3860da 100644 (file)
@@ -24,7 +24,7 @@ void ares_destroy(ares_channel channel)
   struct query *query;
 
   for (i = 0; i < channel->nservers; i++)
-    ares__close_sockets(&channel->servers[i]);
+    ares__close_sockets(channel, &channel->servers[i]);
   free(channel->servers);
   for (i = 0; i < channel->ndomains; i++)
     free(channel->domains[i]);
index 1f252f2..026d8da 100644 (file)
@@ -98,6 +98,24 @@ The lookups to perform for host queries.
 .I lookups
 should be set to a string of the characters "b" or "f", where "b"
 indicates a DNS lookup and "f" indicates a lookup in the hosts file.
+.TP 18
+.B ARES_OPT_SOCK_STATE_CB
+.B void (*\fIsock_state_cb\fP)(void *data, int s, int read, int write);
+.br
+.B void *\fIsock_state_cb_data\fP;
+.br
+A callback function to be invoked when a socket changes state.
+.I s
+will be passed the socket whose state has changed;
+.I read
+will be set to true if the socket should listen for read events, and
+.I write
+will be set to true if the socket should listen for write events.
+The value of
+.I sock_state_cb_data
+will be passed as the
+.I data
+argument.
 .PP
 The
 .I flags
index a6a6723..2f320a2 100644 (file)
@@ -113,6 +113,7 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
   channel->queries = NULL;
   channel->domains = NULL;
   channel->sortlist = NULL;
+  channel->sock_state_cb = NULL;
 
   /* Initialize configuration by each of the four sources, from highest
    * precedence to lowest.
@@ -192,6 +193,11 @@ static int init_by_options(ares_channel channel, struct ares_options *options,
     channel->udp_port = options->udp_port;
   if ((optmask & ARES_OPT_TCP_PORT) && channel->tcp_port == -1)
     channel->tcp_port = options->tcp_port;
+  if ((optmask & ARES_OPT_SOCK_STATE_CB) && channel->sock_state_cb == NULL)
+    {
+      channel->sock_state_cb = options->sock_state_cb;
+      channel->sock_state_cb_data = options->sock_state_cb_data;
+    }
 
   /* Copy the servers, if given. */
   if ((optmask & ARES_OPT_SERVERS) && channel->nservers == -1)
index df51266..8d5af08 100644 (file)
@@ -176,13 +176,22 @@ struct ares_channeldata {
 
   /* Active queries */
   struct query *queries;
+
+  ares_sock_state_cb sock_state_cb;
+  void *sock_state_cb_data;
 };
 
 void ares__send_query(ares_channel channel, struct query *query, time_t now);
-void ares__close_sockets(struct server_state *server);
+void ares__close_sockets(ares_channel channel, struct server_state *server);
 int ares__get_hostent(FILE *fp, int family, struct hostent **host);
 int ares__read_line(FILE *fp, char **buf, int *bufsize);
 
+#define SOCK_STATE_CALLBACK(c, s, r, w)                                 \
+  do {                                                                  \
+    if ((c)->sock_state_cb)                                             \
+      (c)->sock_state_cb((c)->sock_state_cb_data, (s), (r), (w));       \
+  } while (0)
+
 #ifdef CURLDEBUG
 /* This is low-level hard-hacking memory leak tracking and similar. Using the
    libcurl lowlevel code from within library is ugly and only works when
index 456d952..f38e591 100644 (file)
@@ -149,7 +149,10 @@ static void write_tcp_data(ares_channel channel, fd_set *write_fds, time_t now)
                   wcount -= sendreq->len;
                   server->qhead = sendreq->next;
                   if (server->qhead == NULL)
-                    server->qtail = NULL;
+                    {
+                      SOCK_STATE_CALLBACK(channel, server->tcp_socket, 1, 0);
+                      server->qtail = NULL;
+                    }
                   free(sendreq);
                 }
               else
@@ -179,7 +182,10 @@ static void write_tcp_data(ares_channel channel, fd_set *write_fds, time_t now)
             {
               server->qhead = sendreq->next;
               if (server->qhead == NULL)
-                server->qtail = NULL;
+                {
+                  SOCK_STATE_CALLBACK(channel, server->tcp_socket, 1, 0);
+                  server->qtail = NULL;
+                }
               free(sendreq);
             }
           else
@@ -380,7 +386,7 @@ static void handle_error(ares_channel channel, int whichserver, time_t now)
   struct query *query, *next;
 
   /* Reset communications with this server. */
-  ares__close_sockets(&channel->servers[whichserver]);
+  ares__close_sockets(channel, &channel->servers[whichserver]);
 
   /* Tell all queries talking to this server to move on and not try
    * this server again.
@@ -452,7 +458,10 @@ void ares__send_query(ares_channel channel, struct query *query, time_t now)
       if (server->qtail)
         server->qtail->next = sendreq;
       else
-        server->qhead = sendreq;
+        {
+          SOCK_STATE_CALLBACK(channel, server->tcp_socket, 1, 1);
+          server->qhead = sendreq;
+        }
       server->qtail = sendreq;
       query->timeout = 0;
     }
@@ -575,6 +584,7 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server)
     }
   }
 
+  SOCK_STATE_CALLBACK(channel, s, 1, 0);
   server->tcp_buffer_pos = 0;
   server->tcp_socket = s;
   return 0;
@@ -604,6 +614,8 @@ static int open_udp_socket(ares_channel channel, struct server_state *server)
       return -1;
     }
 
+  SOCK_STATE_CALLBACK(channel, s, 1, 0);
+
   server->udp_socket = s;
   return 0;
 }
@@ -714,7 +726,7 @@ static struct query *end_query (ares_channel channel, struct query *query, int s
   if (!channel->queries && !(channel->flags & ARES_FLAG_STAYOPEN))
     {
       for (i = 0; i < channel->nservers; i++)
-        ares__close_sockets(&channel->servers[i]);
+        ares__close_sockets(channel, &channel->servers[i]);
     }
   return (next);
 }