+ rbuf= *tv_io;
+ if (!rbuf) { *tv_io= rbuf= tvbuf; }
+
+ timerclear(rbuf);
+}
+
+static void inter_maxto(struct timeval **tv_io, struct timeval *tvbuf,
+ struct timeval maxto) {
+ struct timeval *rbuf;
+
+ if (!tv_io) return;
+ rbuf= *tv_io;
+ if (!rbuf) {
+ *tvbuf= maxto; *tv_io= tvbuf;
+ } else {
+ if (timercmp(rbuf,&maxto,>)) *rbuf= maxto;
+ }
+/*fprintf(stderr,"inter_maxto maxto=%ld.%06ld result=%ld.%06ld\n",
+ maxto.tv_sec,maxto.tv_usec,(**tv_io).tv_sec,(**tv_io).tv_usec);*/
+}
+
+static void inter_maxtoabs(struct timeval **tv_io, struct timeval *tvbuf,
+ struct timeval now, struct timeval maxtime) {
+ /* tv_io may be 0 */
+ ldiv_t dr;
+
+/*fprintf(stderr,"inter_maxtoabs now=%ld.%06ld maxtime=%ld.%06ld\n",
+ now.tv_sec,now.tv_usec,maxtime.tv_sec,maxtime.tv_usec);*/
+ if (!tv_io) return;
+ maxtime.tv_sec -= (now.tv_sec+2);
+ maxtime.tv_usec -= (now.tv_usec-2000000);
+ dr= ldiv(maxtime.tv_usec,1000000);
+ maxtime.tv_sec += dr.quot;
+ maxtime.tv_usec -= dr.quot*1000000;
+ if (maxtime.tv_sec<0) timerclear(&maxtime);
+ inter_maxto(tv_io,tvbuf,maxtime);
+}
+
+static void timeouts_queue(adns_state ads, int act,
+ struct timeval **tv_io, struct timeval *tvbuf,
+ struct timeval now, struct query_queue *queue) {
+ adns_query qu, nqu;
+
+ for (qu= queue->head; qu; qu= nqu) {
+ nqu= qu->next;
+ if (!timercmp(&now,&qu->timeout,>)) {
+ inter_maxtoabs(tv_io,tvbuf,now,qu->timeout);
+ } else {
+ if (!act) { inter_immed(tv_io,tvbuf); return; }
+ LIST_UNLINK(*queue,qu);
+ if (qu->state != query_tosend) {
+ adns__query_fail(qu,adns_s_timeout);
+ } else {
+ adns__query_send(qu,now);
+ }
+ nqu= queue->head;
+ }
+ }
+}
+
+static void tcp_events(adns_state ads, int act,
+ struct timeval **tv_io, struct timeval *tvbuf,
+ struct timeval now) {
+ for (;;) {
+ switch (ads->tcpstate) {
+ case server_broken:
+ if (!act) { inter_immed(tv_io,tvbuf); return; }
+ tcp_broken_events(ads);
+ case server_disconnected: /* fall through */
+ if (!ads->tcpw.head) return;
+ if (!act) { inter_immed(tv_io,tvbuf); return; }
+ adns__tcp_tryconnect(ads,now);
+ break;
+ case server_ok:
+ if (ads->tcpw.head) return;
+ if (!ads->tcptimeout.tv_sec) {
+ assert(!ads->tcptimeout.tv_usec);
+ ads->tcptimeout= now;
+ timevaladd(&ads->tcptimeout,TCPIDLEMS);
+ }
+ case server_connecting: /* fall through */
+ if (!act || !timercmp(&now,&ads->tcptimeout,>)) {
+ inter_maxtoabs(tv_io,tvbuf,now,ads->tcptimeout);
+ return;
+ } {
+ /* TCP timeout has happened */
+ switch (ads->tcpstate) {
+ case server_connecting: /* failed to connect */
+ adns__tcp_broken(ads,"unable to make connection","timed out");
+ break;
+ case server_ok: /* idle timeout */
+ tcp_close(ads);
+ ads->tcpstate= server_disconnected;
+ return;
+ default:
+ abort();
+ }
+ }
+ break;
+ default:
+ abort();
+ }
+ }
+ return;
+}
+
+void adns__timeouts(adns_state ads, int act,
+ struct timeval **tv_io, struct timeval *tvbuf,
+ struct timeval now) {
+ timeouts_queue(ads,act,tv_io,tvbuf,now, &ads->udpw);
+ timeouts_queue(ads,act,tv_io,tvbuf,now, &ads->tcpw);
+ tcp_events(ads,act,tv_io,tvbuf,now);
+}
+
+void adns_firsttimeout(adns_state ads,
+ struct timeval **tv_io, struct timeval *tvbuf,
+ struct timeval now) {
+ adns__consistency(ads,0,cc_entex);
+ adns__timeouts(ads, 0, tv_io,tvbuf, now);
+ adns__returning(ads,0);
+}
+
+void adns_processtimeouts(adns_state ads, const struct timeval *now) {
+ struct timeval tv_buf;
+
+ adns__consistency(ads,0,cc_entex);
+ adns__must_gettimeofday(ads,&now,&tv_buf);
+ if (now) adns__timeouts(ads, 1, 0,0, *now);
+ adns__returning(ads,0);
+}
+
+/* fd handling functions. These are the top-level of the real work of
+ * reception and often transmission.
+ */
+
+int adns__pollfds(adns_state ads, struct pollfd pollfds_buf[MAX_POLLFDS]) {
+ /* Returns the number of entries filled in. Always zeroes revents. */
+ int nwanted=0;
+#define ADD_POLLFD(wantfd, wantevents) do{ \
+ pollfds_buf[nwanted].fd= (wantfd); \
+ pollfds_buf[nwanted].events= (wantevents); \
+ pollfds_buf[nwanted].revents= 0; \
+ nwanted++; \
+ }while(0)
+
+ int i;
+
+ assert(MAX_POLLFDS == MAXUDP + 1);
+
+ for (i=0; i<ads->nudpsockets; i++)
+ ADD_POLLFD(ads->udpsockets[i].fd, POLLIN);