+/* `Interest' functions - find out which fd's we might be interested in,
+ * and when we want to be called back for a timeout.
+ */
+
+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) {
+ 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 inter_addfd(int *maxfd, fd_set *fds, int fd) {
+ if (!maxfd || !fds) return;
+ if (fd>=*maxfd) *maxfd= fd+1;
+ FD_SET(fd,fds);
+}
+
+static void checktimeouts(adns_state ads, struct timeval now,
+ struct timeval **tv_io, struct timeval *tvbuf) {
+ adns_query qu, nqu;
+
+ for (qu= ads->timew.head; qu; qu= nqu) {
+ nqu= qu->next;
+ if (timercmp(&now,&qu->timeout,>)) {
+ LIST_UNLINK(ads->timew,qu);
+ if (qu->state != query_udp) {
+ adns__query_fail(qu,adns_s_timeout);
+ } else {
+ adns__query_udp(qu,now);
+ }
+ } else {
+ inter_maxtoabs(tv_io,tvbuf,now,qu->timeout);
+ }
+ }
+}
+
+void adns_interest(adns_state ads, int *maxfd,
+ fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+ struct timeval **tv_io, struct timeval *tvbuf) {
+ struct timeval now;
+ struct timeval tvto_lr;
+ int r;
+
+/*fprintf(stderr,"adns_interest\n");*/
+
+ r= gettimeofday(&now,0);
+ if (r) {
+ adns__warn(ads,-1,0,"gettimeofday failed - will sleep for a bit: %s",
+ strerror(errno));
+ timerclear(&tvto_lr); timevaladd(&tvto_lr,LOCALRESOURCEMS);
+ inter_maxto(tv_io, tvbuf, tvto_lr);
+ } else {
+ checktimeouts(ads,now,tv_io,tvbuf);
+ }
+
+ inter_addfd(maxfd,readfds,ads->udpsocket);
+
+ switch (ads->tcpstate) {
+ case server_disconnected:
+ break;
+ case server_connecting:
+ inter_addfd(maxfd,writefds,ads->tcpsocket);
+ break;
+ case server_ok:
+ inter_addfd(maxfd,readfds,ads->tcpsocket);
+ inter_addfd(maxfd,exceptfds,ads->tcpsocket);
+ if (ads->tcpsend.used) inter_addfd(maxfd,writefds,ads->tcpsocket);
+ break;
+ default:
+ abort();
+ }
+}
+
+/* Callback procedures - these do the real work of reception and timeout, etc. */
+
+static int callb_checkfd(int maxfd, const fd_set *fds, int fd) {
+ return maxfd<0 || !fds ? 1 :
+ fd<maxfd && FD_ISSET(fd,fds);
+}
+
+static int internal_callback(adns_state ads, int maxfd,
+ const fd_set *readfds, const fd_set *writefds,
+ const fd_set *exceptfds,
+ struct timeval now) {
+ int skip, want, dgramlen, count, udpaddrlen, r, serv;
+ byte udpbuf[DNS_MAXUDP];