aboutsummaryrefslogtreecommitdiff
path: root/lib/hostares.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/hostares.c')
-rw-r--r--lib/hostares.c96
1 files changed, 68 insertions, 28 deletions
diff --git a/lib/hostares.c b/lib/hostares.c
index dae1ca3b7..3aa7782bb 100644
--- a/lib/hostares.c
+++ b/lib/hostares.c
@@ -126,6 +126,69 @@ int Curl_resolv_getsock(struct connectdata *conn,
}
/*
+ * ares_waitperform()
+ *
+ * 1) Ask ares what sockets it currently plays with, then
+ * 2) wait for the timeout period to check for action on ares' sockets.
+ * 3) tell ares to act on all the sockets marked as "with action"
+ *
+ * return number of sockets it worked on
+ */
+
+static int ares_waitperform(struct connectdata *conn, int timeout_ms)
+{
+ struct SessionHandle *data = conn->data;
+ int nfds;
+ int bitmask;
+ int socks[ARES_GETSOCK_MAXNUM];
+ struct pollfd pfd[ARES_GETSOCK_MAXNUM];
+ int m;
+ int i;
+ int num;
+
+ bitmask = ares_getsock(data->state.areschannel, socks, ARES_GETSOCK_MAXNUM);
+
+ for(i=0; i < ARES_GETSOCK_MAXNUM; i++) {
+ pfd[i].events = 0;
+ m=0;
+ if(ARES_GETSOCK_READABLE(bitmask, i)) {
+ pfd[i].fd = socks[i];
+ pfd[i].events |= POLLRDNORM|POLLIN;
+ m=1;
+ }
+ if(ARES_GETSOCK_WRITABLE(bitmask, i)) {
+ pfd[i].fd = socks[i];
+ pfd[i].events |= POLLWRNORM|POLLOUT;
+ m=1;
+ }
+ pfd[i].revents=0;
+ if(!m)
+ break;
+ }
+ num = i;
+
+ if(num)
+ nfds = Curl_poll(pfd, num, timeout_ms);
+ else
+ nfds = 0;
+
+ if(!nfds)
+ /* Call ares_process() unconditonally here, even if we simply timed out
+ above, as otherwise the ares name resolve won't timeout! */
+ ares_process_fd(data->state.areschannel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
+ else {
+ /* move through the descriptors and ask for processing on them */
+ for(i=0; i < num; i++)
+ ares_process_fd(data->state.areschannel,
+ pfd[i].revents & (POLLRDNORM|POLLIN)?
+ pfd[i].fd:ARES_SOCKET_BAD,
+ pfd[i].revents & (POLLWRNORM|POLLOUT)?
+ pfd[i].fd:ARES_SOCKET_BAD);
+ }
+ return nfds;
+}
+
+/*
* Curl_is_resolved() is called repeatedly to check if a previous name resolve
* request has completed. It should also make sure to time-out if the
* operation seems to take too long.
@@ -135,25 +198,12 @@ int Curl_resolv_getsock(struct connectdata *conn,
CURLcode Curl_is_resolved(struct connectdata *conn,
struct Curl_dns_entry **dns)
{
- fd_set read_fds, write_fds;
- struct timeval tv={0,0};
struct SessionHandle *data = conn->data;
- int nfds;
-
- FD_ZERO(&read_fds);
- FD_ZERO(&write_fds);
-
- nfds = ares_fds(data->state.areschannel, &read_fds, &write_fds);
-
- (void)Curl_select(nfds, &read_fds, &write_fds, NULL,
- (struct timeval *)&tv);
-
- /* Call ares_process() unconditonally here, even if we simply timed out
- above, as otherwise the ares name resolve won't timeout! */
- ares_process(data->state.areschannel, &read_fds, &write_fds);
*dns = NULL;
+ ares_waitperform(conn, 0);
+
if(conn->async.done) {
/* we're done, kill the ares handle */
if(!conn->async.dns) {
@@ -194,28 +244,18 @@ CURLcode Curl_wait_for_resolv(struct connectdata *conn,
/* Wait for the name resolve query to complete. */
while (1) {
- int nfds=0;
- fd_set read_fds, write_fds;
struct timeval *tvp, tv, store;
- int count;
struct timeval now = Curl_tvnow();
long timediff;
store.tv_sec = (int)timeout/1000;
store.tv_usec = (timeout%1000)*1000;
- FD_ZERO(&read_fds);
- FD_ZERO(&write_fds);
- nfds = ares_fds(data->state.areschannel, &read_fds, &write_fds);
- if (nfds == 0)
- /* no file descriptors means we're done waiting */
- break;
tvp = ares_timeout(data->state.areschannel, &store, &tv);
- count = Curl_select(nfds, &read_fds, &write_fds, NULL, tvp);
- if ((count < 0) && (SOCKERRNO != EINVAL))
- break;
- ares_process(data->state.areschannel, &read_fds, &write_fds);
+ if(!ares_waitperform(conn, tv.tv_sec * 1000 + tv.tv_usec/1000))
+ /* no sockets to wait on, get out of the loop */
+ break;
timediff = Curl_tvdiff(Curl_tvnow(), now); /* spent time */
timeout -= timediff?timediff:1; /* always deduct at least 1 */