summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2007-05-30 12:58:47 +0000
committerDaniel Stenberg <daniel@haxx.se>2007-05-30 12:58:47 +0000
commit670273968ce2a8e648c61829d3304de23d91349d (patch)
tree9c30f3b95d44058e9a67fde10bf55f9943b76cc8
parentb6820b26745c819386be03d4150d5006ec33080c (diff)
downloadgnurl-670273968ce2a8e648c61829d3304de23d91349d.tar.gz
gnurl-670273968ce2a8e648c61829d3304de23d91349d.tar.bz2
gnurl-670273968ce2a8e648c61829d3304de23d91349d.zip
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.
-rw-r--r--ares/CHANGES10
-rw-r--r--ares/ares.h18
-rw-r--r--ares/ares_process.321
-rw-r--r--ares/ares_process.c92
-rw-r--r--ares/setup.h14
5 files changed, 118 insertions, 37 deletions
diff --git a/ares/CHANGES b/ares/CHANGES
index b4580c773..3f607b880 100644
--- a/ares/CHANGES
+++ b/ares/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/ares.h b/ares/ares.h
index 83a1c8e46..73fc3e6c3 100644
--- a/ares/ares.h
+++ b/ares/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);
diff --git a/ares/ares_process.3 b/ares/ares_process.3
index 50216e144..c9cd5477f 100644
--- a/ares/ares_process.3
+++ b/ares/ares_process.3
@@ -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:
diff --git a/ares/ares_process.c b/ares/ares_process.c
index 8cb51c3b2..efc462a40 100644
--- a/ares/ares_process.c
+++ b/ares/ares_process.c
@@ -56,10 +56,11 @@
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/ares/setup.h b/ares/setup.h
index 465e012fe..2106df770 100644
--- a/ares/setup.h
+++ b/ares/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
@@ -118,18 +118,6 @@
#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
*/