aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2006-05-03 06:11:44 +0000
committerDaniel Stenberg <daniel@haxx.se>2006-05-03 06:11:44 +0000
commitdd06c60ada039faafd937a136e3dc7ff9c41159a (patch)
tree5e5337faa1571a343b4c643da651ca817afc7802
parent6ca627ae742816cfca67d7e2ad3b59c269e5651d (diff)
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.
-rw-r--r--ares/CHANGES10
-rw-r--r--ares/ares.h15
-rw-r--r--ares/ares__close_sockets.c4
-rw-r--r--ares/ares_cancel.c2
-rw-r--r--ares/ares_destroy.c2
-rw-r--r--ares/ares_init.318
-rw-r--r--ares/ares_init.c6
-rw-r--r--ares/ares_private.h11
-rw-r--r--ares/ares_process.c22
9 files changed, 79 insertions, 11 deletions
diff --git a/ares/CHANGES b/ares/CHANGES
index 11c2955c5..3c91e27d0 100644
--- a/ares/CHANGES
+++ b/ares/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/ares.h b/ares/ares.h
index 8e8da2847..9414f9b78 100644
--- a/ares/ares.h
+++ b/ares/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;
diff --git a/ares/ares__close_sockets.c b/ares/ares__close_sockets.c
index fb883f9a9..7475a4b44 100644
--- a/ares/ares__close_sockets.c
+++ b/ares/ares__close_sockets.c
@@ -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;
}
diff --git a/ares/ares_cancel.c b/ares/ares_cancel.c
index 04642848d..4df1e9f5b 100644
--- a/ares/ares_cancel.c
+++ b/ares/ares_cancel.c
@@ -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]);
}
}
diff --git a/ares/ares_destroy.c b/ares/ares_destroy.c
index efe2b5383..d3860da13 100644
--- a/ares/ares_destroy.c
+++ b/ares/ares_destroy.c
@@ -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]);
diff --git a/ares/ares_init.3 b/ares/ares_init.3
index 1f252f22b..026d8da0e 100644
--- a/ares/ares_init.3
+++ b/ares/ares_init.3
@@ -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
diff --git a/ares/ares_init.c b/ares/ares_init.c
index a6a672343..2f320a2fa 100644
--- a/ares/ares_init.c
+++ b/ares/ares_init.c
@@ -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)
diff --git a/ares/ares_private.h b/ares/ares_private.h
index df51266dc..8d5af0817 100644
--- a/ares/ares_private.h
+++ b/ares/ares_private.h
@@ -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
diff --git a/ares/ares_process.c b/ares/ares_process.c
index 456d95218..f38e591f2 100644
--- a/ares/ares_process.c
+++ b/ares/ares_process.c
@@ -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);
}