Hi! I'm glad to see that c-ares is being decoupled from select().
Unfortunately, the new ares_getsock interface is not particularly
well-suited for high-performance async io implementations such as
epoll (Linux), kqueue (BSD) and /dev/poll (SunOS, I think). Rather
than repeatedly building a list of sockets, for these interfaces, it
is most convenient to know when a socket's state has changed.
This patch introduces a callback mechanism that gets invoked when a
socket becomes (or stops being) interested in reads or writes; it
would make c-ares way easier to use for my application
(http://tor.eff.org/).
Thanks for your time!
Index: ares.h
===================================================================
RCS file: /cvsroot/curl/curl/ares/ares.h,v
retrieving revision 1.22
diff -u -r1.22 ares.h
--- ares.h 22 Dec 2005 15:27:41 -0000 1.22
+++ ares.h 14 Apr 2006 07:45:46 -0000
@@ -93,6 +93,7 @@
#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 @@
#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 @@
char **domains;
int ndomains;
char *lookups;
+ ares_sock_state_cb sock_state_cb;
+ void *sock_state_cb_data;
};
struct hostent;
Index: ares__close_sockets.c
===================================================================
RCS file: /cvsroot/curl/curl/ares/ares__close_sockets.c,v
retrieving revision 1.4
diff -u -r1.4 ares__close_sockets.c
--- ares__close_sockets.c 20 Aug 2004 13:45:26 -0000 1.4
+++ ares__close_sockets.c 14 Apr 2006 07:45:46 -0000
@@ -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 @@
/* 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: ares_cancel.c
===================================================================
RCS file: /cvsroot/curl/curl/ares/ares_cancel.c,v
retrieving revision 1.2
diff -u -r1.2 ares_cancel.c
--- ares_cancel.c 22 Jul 2004 22:18:45 -0000 1.2
+++ ares_cancel.c 14 Apr 2006 07:45:46 -0000
@@ -38,6 +38,6 @@
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: ares_destroy.c
===================================================================
RCS file: /cvsroot/curl/curl/ares/ares_destroy.c,v
retrieving revision 1.4
diff -u -r1.4 ares_destroy.c
--- ares_destroy.c 22 Jul 2004 22:18:45 -0000 1.4
+++ ares_destroy.c 14 Apr 2006 07:45:46 -0000
@@ -24,7 +24,7 @@
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: ares_init.3
===================================================================
RCS file: /cvsroot/curl/curl/ares/ares_init.3,v
retrieving revision 1.2
diff -u -r1.2 ares_init.3
--- ares_init.3 7 Dec 2004 10:43:21 -0000 1.2
+++ ares_init.3 14 Apr 2006 07:45:46 -0000
@@ -98,6 +98,24 @@
.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: ares_init.c
===================================================================
RCS file: /cvsroot/curl/curl/ares/ares_init.c,v
retrieving revision 1.35
diff -u -r1.35 ares_init.c
--- ares_init.c 5 Jan 2006 07:57:32 -0000 1.35
+++ ares_init.c 14 Apr 2006 07:45:46 -0000
@@ -113,6 +113,7 @@
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 @@
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: ares_private.h
===================================================================
RCS file: /cvsroot/curl/curl/ares/ares_private.h,v
retrieving revision 1.20
diff -u -r1.20 ares_private.h
--- ares_private.h 5 Jan 2006 07:57:32 -0000 1.20
+++ ares_private.h 14 Apr 2006 07:45:46 -0000
@@ -176,13 +176,22 @@
/* 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: ares_process.c
===================================================================
RCS file: /cvsroot/curl/curl/ares/ares_process.c,v
retrieving revision 1.24
diff -u -r1.24 ares_process.c
--- ares_process.c 20 Dec 2005 20:48:38 -0000 1.24
+++ ares_process.c 14 Apr 2006 07:45:46 -0000
@@ -149,7 +149,10 @@
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 @@
{
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 @@
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 @@
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 @@
}
}
+ SOCK_STATE_CALLBACK(channel, s, 1, 0);
server->tcp_buffer_pos = 0;
server->tcp_socket = s;
return 0;
@@ -604,6 +614,8 @@
return -1;
}
+ SOCK_STATE_CALLBACK(channel, s, 1, 0);
+
server->udp_socket = s;
return 0;
}
@@ -714,7 +726,7 @@
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);
}