xref: /reactos/sdk/lib/3rdparty/adns/src/event.c (revision c2c66aff)
1*c2c66affSColin Finck /*
2*c2c66affSColin Finck  * event.c
3*c2c66affSColin Finck  * - event loop core
4*c2c66affSColin Finck  * - TCP connection management
5*c2c66affSColin Finck  * - user-visible check/wait and event-loop-related functions
6*c2c66affSColin Finck  */
7*c2c66affSColin Finck /*
8*c2c66affSColin Finck  *  This file is
9*c2c66affSColin Finck  *    Copyright (C) 1997-2000 Ian Jackson <ian@davenant.greenend.org.uk>
10*c2c66affSColin Finck  *
11*c2c66affSColin Finck  *  It is part of adns, which is
12*c2c66affSColin Finck  *    Copyright (C) 1997-2000 Ian Jackson <ian@davenant.greenend.org.uk>
13*c2c66affSColin Finck  *    Copyright (C) 1999-2000 Tony Finch <dot@dotat.at>
14*c2c66affSColin Finck  *
15*c2c66affSColin Finck  *  This program is free software; you can redistribute it and/or modify
16*c2c66affSColin Finck  *  it under the terms of the GNU General Public License as published by
17*c2c66affSColin Finck  *  the Free Software Foundation; either version 2, or (at your option)
18*c2c66affSColin Finck  *  any later version.
19*c2c66affSColin Finck  *
20*c2c66affSColin Finck  *  This program is distributed in the hope that it will be useful,
21*c2c66affSColin Finck  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
22*c2c66affSColin Finck  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23*c2c66affSColin Finck  *  GNU General Public License for more details.
24*c2c66affSColin Finck  *
25*c2c66affSColin Finck  *  You should have received a copy of the GNU General Public License
26*c2c66affSColin Finck  *  along with this program; if not, adns_socket_write to the Free Software Foundation,
27*c2c66affSColin Finck  *  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28*c2c66affSColin Finck  */
29*c2c66affSColin Finck 
30*c2c66affSColin Finck #include <errno.h>
31*c2c66affSColin Finck #include <stdlib.h>
32*c2c66affSColin Finck 
33*c2c66affSColin Finck #ifdef ADNS_JGAA_WIN32
34*c2c66affSColin Finck # include "adns_win32.h"
35*c2c66affSColin Finck #else
36*c2c66affSColin Finck # include <unistd.h>
37*c2c66affSColin Finck # include <sys/types.h>
38*c2c66affSColin Finck # include <sys/time.h>
39*c2c66affSColin Finck # include <netdb.h>
40*c2c66affSColin Finck # include <sys/socket.h>
41*c2c66affSColin Finck # include <netinet/in.h>
42*c2c66affSColin Finck # include <arpa/inet.h>
43*c2c66affSColin Finck #endif
44*c2c66affSColin Finck 
45*c2c66affSColin Finck #include "internal.h"
46*c2c66affSColin Finck #include "tvarith.h"
47*c2c66affSColin Finck 
48*c2c66affSColin Finck /* TCP connection management. */
49*c2c66affSColin Finck 
tcp_close(adns_state ads)50*c2c66affSColin Finck static void tcp_close(adns_state ads) {
51*c2c66affSColin Finck   int serv;
52*c2c66affSColin Finck 
53*c2c66affSColin Finck   serv= ads->tcpserver;
54*c2c66affSColin Finck   adns_socket_close(ads->tcpsocket);
55*c2c66affSColin Finck   ads->tcpsocket= -1;
56*c2c66affSColin Finck   ads->tcprecv.used= ads->tcprecv_skip= ads->tcpsend.used= 0;
57*c2c66affSColin Finck }
58*c2c66affSColin Finck 
adns__tcp_broken(adns_state ads,const char * what,const char * why)59*c2c66affSColin Finck void adns__tcp_broken(adns_state ads, const char *what, const char *why) {
60*c2c66affSColin Finck   int serv;
61*c2c66affSColin Finck   adns_query qu;
62*c2c66affSColin Finck 
63*c2c66affSColin Finck   assert(ads->tcpstate == server_connecting || ads->tcpstate == server_ok);
64*c2c66affSColin Finck   serv= ads->tcpserver;
65*c2c66affSColin Finck   if (what) adns__warn(ads,serv,0,"TCP connection failed: %s: %s",what,why);
66*c2c66affSColin Finck 
67*c2c66affSColin Finck   if (ads->tcpstate == server_connecting) {
68*c2c66affSColin Finck     /* Counts as a retry for all the queries waiting for TCP. */
69*c2c66affSColin Finck     for (qu= ads->tcpw.head; qu; qu= qu->next)
70*c2c66affSColin Finck       qu->retries++;
71*c2c66affSColin Finck   }
72*c2c66affSColin Finck 
73*c2c66affSColin Finck   tcp_close(ads);
74*c2c66affSColin Finck   ads->tcpstate= server_broken;
75*c2c66affSColin Finck   ads->tcpserver= (serv+1)%ads->nservers;
76*c2c66affSColin Finck }
77*c2c66affSColin Finck 
tcp_connected(adns_state ads,struct timeval now)78*c2c66affSColin Finck static void tcp_connected(adns_state ads, struct timeval now) {
79*c2c66affSColin Finck   adns_query qu, nqu;
80*c2c66affSColin Finck 
81*c2c66affSColin Finck   adns__debug(ads,ads->tcpserver,0,"TCP connected");
82*c2c66affSColin Finck   ads->tcpstate= server_ok;
83*c2c66affSColin Finck   for (qu= ads->tcpw.head; qu && ads->tcpstate == server_ok; qu= nqu) {
84*c2c66affSColin Finck     nqu= qu->next;
85*c2c66affSColin Finck     assert(qu->state == query_tcpw);
86*c2c66affSColin Finck     adns__querysend_tcp(qu,now);
87*c2c66affSColin Finck   }
88*c2c66affSColin Finck }
89*c2c66affSColin Finck 
adns__tcp_tryconnect(adns_state ads,struct timeval now)90*c2c66affSColin Finck void adns__tcp_tryconnect(adns_state ads, struct timeval now) {
91*c2c66affSColin Finck   int r, tries;
92*c2c66affSColin Finck   ADNS_SOCKET fd;
93*c2c66affSColin Finck   struct sockaddr_in addr;
94*c2c66affSColin Finck   struct protoent *proto;
95*c2c66affSColin Finck 
96*c2c66affSColin Finck   for (tries=0; tries<ads->nservers; tries++) {
97*c2c66affSColin Finck     switch (ads->tcpstate) {
98*c2c66affSColin Finck     case server_connecting:
99*c2c66affSColin Finck     case server_ok:
100*c2c66affSColin Finck     case server_broken:
101*c2c66affSColin Finck       return;
102*c2c66affSColin Finck     case server_disconnected:
103*c2c66affSColin Finck       break;
104*c2c66affSColin Finck     default:
105*c2c66affSColin Finck       abort();
106*c2c66affSColin Finck     }
107*c2c66affSColin Finck 
108*c2c66affSColin Finck     assert(!ads->tcpsend.used);
109*c2c66affSColin Finck     assert(!ads->tcprecv.used);
110*c2c66affSColin Finck     assert(!ads->tcprecv_skip);
111*c2c66affSColin Finck 
112*c2c66affSColin Finck     proto= getprotobyname("tcp");
113*c2c66affSColin Finck     if (!proto) { adns__diag(ads,-1,0,"unable to find protocol no. for TCP !"); return; }
114*c2c66affSColin Finck 	ADNS_CLEAR_ERRNO
115*c2c66affSColin Finck     fd= socket(AF_INET,SOCK_STREAM,proto->p_proto);
116*c2c66affSColin Finck 	ADNS_CAPTURE_ERRNO;
117*c2c66affSColin Finck     if (fd<0) {
118*c2c66affSColin Finck       adns__diag(ads,-1,0,"cannot create TCP socket: %s",strerror(errno));
119*c2c66affSColin Finck       return;
120*c2c66affSColin Finck     }
121*c2c66affSColin Finck     r= adns__setnonblock(ads,fd);
122*c2c66affSColin Finck     if (r) {
123*c2c66affSColin Finck       adns__diag(ads,-1,0,"cannot make TCP socket nonblocking: %s",strerror(r));
124*c2c66affSColin Finck       adns_socket_close(fd);
125*c2c66affSColin Finck       return;
126*c2c66affSColin Finck     }
127*c2c66affSColin Finck     memset(&addr,0,sizeof(addr));
128*c2c66affSColin Finck     addr.sin_family= AF_INET;
129*c2c66affSColin Finck     addr.sin_port= htons(DNS_PORT);
130*c2c66affSColin Finck     addr.sin_addr= ads->servers[ads->tcpserver].addr;
131*c2c66affSColin Finck     ADNS_CLEAR_ERRNO;
132*c2c66affSColin Finck     r= connect(fd,(const struct sockaddr*)&addr,sizeof(addr));
133*c2c66affSColin Finck     ADNS_CAPTURE_ERRNO;
134*c2c66affSColin Finck     ads->tcpsocket= fd;
135*c2c66affSColin Finck     ads->tcpstate= server_connecting;
136*c2c66affSColin Finck     if (r==0) { tcp_connected(ads,now); return; }
137*c2c66affSColin Finck     if (errno == EWOULDBLOCK || errno == EINPROGRESS) {
138*c2c66affSColin Finck       ads->tcptimeout= now;
139*c2c66affSColin Finck       timevaladd(&ads->tcptimeout,TCPCONNMS);
140*c2c66affSColin Finck       return;
141*c2c66affSColin Finck     }
142*c2c66affSColin Finck     adns__tcp_broken(ads,"connect",strerror(errno));
143*c2c66affSColin Finck     ads->tcpstate= server_disconnected;
144*c2c66affSColin Finck   }
145*c2c66affSColin Finck }
146*c2c66affSColin Finck 
147*c2c66affSColin Finck /* Timeout handling functions. */
148*c2c66affSColin Finck 
adns__must_gettimeofday(adns_state ads,const struct timeval ** now_io,struct timeval * tv_buf)149*c2c66affSColin Finck void adns__must_gettimeofday(adns_state ads, const struct timeval **now_io,
150*c2c66affSColin Finck 			     struct timeval *tv_buf) {
151*c2c66affSColin Finck   const struct timeval *now;
152*c2c66affSColin Finck   int r;
153*c2c66affSColin Finck 
154*c2c66affSColin Finck   now= *now_io;
155*c2c66affSColin Finck   if (now) return;
156*c2c66affSColin Finck   r= gettimeofday(tv_buf,0); if (!r) { *now_io= tv_buf; return; }
157*c2c66affSColin Finck   adns__diag(ads,-1,0,"gettimeofday failed: %s",strerror(errno));
158*c2c66affSColin Finck   adns_globalsystemfailure(ads);
159*c2c66affSColin Finck   return;
160*c2c66affSColin Finck }
161*c2c66affSColin Finck 
inter_immed(struct timeval ** tv_io,struct timeval * tvbuf)162*c2c66affSColin Finck static void inter_immed(struct timeval **tv_io, struct timeval *tvbuf) {
163*c2c66affSColin Finck   struct timeval *rbuf;
164*c2c66affSColin Finck 
165*c2c66affSColin Finck   if (!tv_io) return;
166*c2c66affSColin Finck 
167*c2c66affSColin Finck   rbuf= *tv_io;
168*c2c66affSColin Finck   if (!rbuf) { *tv_io= rbuf= tvbuf; }
169*c2c66affSColin Finck 
170*c2c66affSColin Finck   timerclear(rbuf);
171*c2c66affSColin Finck }
172*c2c66affSColin Finck 
inter_maxto(struct timeval ** tv_io,struct timeval * tvbuf,struct timeval maxto)173*c2c66affSColin Finck static void inter_maxto(struct timeval **tv_io, struct timeval *tvbuf,
174*c2c66affSColin Finck 			struct timeval maxto) {
175*c2c66affSColin Finck   struct timeval *rbuf;
176*c2c66affSColin Finck 
177*c2c66affSColin Finck   if (!tv_io) return;
178*c2c66affSColin Finck   rbuf= *tv_io;
179*c2c66affSColin Finck   if (!rbuf) {
180*c2c66affSColin Finck     *tvbuf= maxto; *tv_io= tvbuf;
181*c2c66affSColin Finck   } else {
182*c2c66affSColin Finck     if (timercmp(rbuf,&maxto,>)) *rbuf= maxto;
183*c2c66affSColin Finck   }
184*c2c66affSColin Finck /*fprintf(stderr,"inter_maxto maxto=%ld.%06ld result=%ld.%06ld\n",
185*c2c66affSColin Finck 	maxto.tv_sec,maxto.tv_usec,(**tv_io).tv_sec,(**tv_io).tv_usec);*/
186*c2c66affSColin Finck }
187*c2c66affSColin Finck 
inter_maxtoabs(struct timeval ** tv_io,struct timeval * tvbuf,struct timeval now,struct timeval maxtime)188*c2c66affSColin Finck static void inter_maxtoabs(struct timeval **tv_io, struct timeval *tvbuf,
189*c2c66affSColin Finck 			   struct timeval now, struct timeval maxtime) {
190*c2c66affSColin Finck   /* tv_io may be 0 */
191*c2c66affSColin Finck   ldiv_t dr;
192*c2c66affSColin Finck 
193*c2c66affSColin Finck /*fprintf(stderr,"inter_maxtoabs now=%ld.%06ld maxtime=%ld.%06ld\n",
194*c2c66affSColin Finck 	now.tv_sec,now.tv_usec,maxtime.tv_sec,maxtime.tv_usec);*/
195*c2c66affSColin Finck   if (!tv_io) return;
196*c2c66affSColin Finck   maxtime.tv_sec -= (now.tv_sec+2);
197*c2c66affSColin Finck   maxtime.tv_usec -= (now.tv_usec-2000000);
198*c2c66affSColin Finck   dr= ldiv(maxtime.tv_usec,1000000);
199*c2c66affSColin Finck   maxtime.tv_sec += dr.quot;
200*c2c66affSColin Finck   maxtime.tv_usec -= dr.quot*1000000;
201*c2c66affSColin Finck   if (maxtime.tv_sec<0) timerclear(&maxtime);
202*c2c66affSColin Finck   inter_maxto(tv_io,tvbuf,maxtime);
203*c2c66affSColin Finck }
204*c2c66affSColin Finck 
timeouts_queue(adns_state ads,int act,struct timeval ** tv_io,struct timeval * tvbuf,struct timeval now,struct query_queue * queue)205*c2c66affSColin Finck static void timeouts_queue(adns_state ads, int act,
206*c2c66affSColin Finck 			   struct timeval **tv_io, struct timeval *tvbuf,
207*c2c66affSColin Finck 			   struct timeval now, struct query_queue *queue) {
208*c2c66affSColin Finck   adns_query qu, nqu;
209*c2c66affSColin Finck 
210*c2c66affSColin Finck   for (qu= queue->head; qu; qu= nqu) {
211*c2c66affSColin Finck     nqu= qu->next;
212*c2c66affSColin Finck     if (!timercmp(&now,&qu->timeout,>)) {
213*c2c66affSColin Finck       inter_maxtoabs(tv_io,tvbuf,now,qu->timeout);
214*c2c66affSColin Finck     } else {
215*c2c66affSColin Finck       if (!act) { inter_immed(tv_io,tvbuf); return; }
216*c2c66affSColin Finck       LIST_UNLINK(*queue,qu);
217*c2c66affSColin Finck       if (qu->state != query_tosend) {
218*c2c66affSColin Finck 	adns__query_fail(qu,adns_s_timeout);
219*c2c66affSColin Finck       } else {
220*c2c66affSColin Finck 	adns__query_send(qu,now);
221*c2c66affSColin Finck       }
222*c2c66affSColin Finck       nqu= queue->head;
223*c2c66affSColin Finck     }
224*c2c66affSColin Finck   }
225*c2c66affSColin Finck }
226*c2c66affSColin Finck 
tcp_events(adns_state ads,int act,struct timeval ** tv_io,struct timeval * tvbuf,struct timeval now)227*c2c66affSColin Finck static void tcp_events(adns_state ads, int act,
228*c2c66affSColin Finck 		       struct timeval **tv_io, struct timeval *tvbuf,
229*c2c66affSColin Finck 		       struct timeval now) {
230*c2c66affSColin Finck   adns_query qu, nqu;
231*c2c66affSColin Finck 
232*c2c66affSColin Finck   for (;;) {
233*c2c66affSColin Finck     switch (ads->tcpstate) {
234*c2c66affSColin Finck     case server_broken:
235*c2c66affSColin Finck       if (!act) { inter_immed(tv_io,tvbuf); return; }
236*c2c66affSColin Finck       for (qu= ads->tcpw.head; qu; qu= nqu) {
237*c2c66affSColin Finck 	nqu= qu->next;
238*c2c66affSColin Finck 	assert(qu->state == query_tcpw);
239*c2c66affSColin Finck 	if (qu->retries > ads->nservers) {
240*c2c66affSColin Finck 	  LIST_UNLINK(ads->tcpw,qu);
241*c2c66affSColin Finck 	  adns__query_fail(qu,adns_s_allservfail);
242*c2c66affSColin Finck 	}
243*c2c66affSColin Finck       }
244*c2c66affSColin Finck       ads->tcpstate= server_disconnected;
245*c2c66affSColin Finck     case server_disconnected: /* fall through */
246*c2c66affSColin Finck       if (!ads->tcpw.head) return;
247*c2c66affSColin Finck       if (!act) { inter_immed(tv_io,tvbuf); return; }
248*c2c66affSColin Finck       adns__tcp_tryconnect(ads,now);
249*c2c66affSColin Finck       break;
250*c2c66affSColin Finck     case server_ok:
251*c2c66affSColin Finck       if (ads->tcpw.head) return;
252*c2c66affSColin Finck       if (!ads->tcptimeout.tv_sec) {
253*c2c66affSColin Finck 	assert(!ads->tcptimeout.tv_usec);
254*c2c66affSColin Finck 	ads->tcptimeout= now;
255*c2c66affSColin Finck 	timevaladd(&ads->tcptimeout,TCPIDLEMS);
256*c2c66affSColin Finck       }
257*c2c66affSColin Finck     case server_connecting: /* fall through */
258*c2c66affSColin Finck       if (!act || !timercmp(&now,&ads->tcptimeout,>)) {
259*c2c66affSColin Finck 	inter_maxtoabs(tv_io,tvbuf,now,ads->tcptimeout);
260*c2c66affSColin Finck 	return;
261*c2c66affSColin Finck       } {
262*c2c66affSColin Finck 	/* TCP timeout has happened */
263*c2c66affSColin Finck 	switch (ads->tcpstate) {
264*c2c66affSColin Finck 	case server_connecting: /* failed to connect */
265*c2c66affSColin Finck 	  adns__tcp_broken(ads,"unable to make connection","timed out");
266*c2c66affSColin Finck 	  break;
267*c2c66affSColin Finck 	case server_ok: /* idle timeout */
268*c2c66affSColin Finck 	  tcp_close(ads);
269*c2c66affSColin Finck 	  ads->tcpstate= server_disconnected;
270*c2c66affSColin Finck 	  return;
271*c2c66affSColin Finck 	default:
272*c2c66affSColin Finck 	  abort();
273*c2c66affSColin Finck 	}
274*c2c66affSColin Finck       }
275*c2c66affSColin Finck       break;
276*c2c66affSColin Finck     default:
277*c2c66affSColin Finck       abort();
278*c2c66affSColin Finck     }
279*c2c66affSColin Finck   }
280*c2c66affSColin Finck   return;
281*c2c66affSColin Finck }
282*c2c66affSColin Finck 
adns__timeouts(adns_state ads,int act,struct timeval ** tv_io,struct timeval * tvbuf,struct timeval now)283*c2c66affSColin Finck void adns__timeouts(adns_state ads, int act,
284*c2c66affSColin Finck 		    struct timeval **tv_io, struct timeval *tvbuf,
285*c2c66affSColin Finck 		    struct timeval now) {
286*c2c66affSColin Finck   timeouts_queue(ads,act,tv_io,tvbuf,now, &ads->udpw);
287*c2c66affSColin Finck   timeouts_queue(ads,act,tv_io,tvbuf,now, &ads->tcpw);
288*c2c66affSColin Finck   tcp_events(ads,act,tv_io,tvbuf,now);
289*c2c66affSColin Finck }
290*c2c66affSColin Finck 
adns_firsttimeout(adns_state ads,struct timeval ** tv_io,struct timeval * tvbuf,struct timeval now)291*c2c66affSColin Finck void adns_firsttimeout(adns_state ads,
292*c2c66affSColin Finck 		       struct timeval **tv_io, struct timeval *tvbuf,
293*c2c66affSColin Finck 		       struct timeval now) {
294*c2c66affSColin Finck   adns__consistency(ads,0,cc_entex);
295*c2c66affSColin Finck   adns__timeouts(ads, 0, tv_io,tvbuf, now);
296*c2c66affSColin Finck   adns__consistency(ads,0,cc_entex);
297*c2c66affSColin Finck }
298*c2c66affSColin Finck 
adns_processtimeouts(adns_state ads,const struct timeval * now)299*c2c66affSColin Finck void adns_processtimeouts(adns_state ads, const struct timeval *now) {
300*c2c66affSColin Finck   struct timeval tv_buf;
301*c2c66affSColin Finck 
302*c2c66affSColin Finck   adns__consistency(ads,0,cc_entex);
303*c2c66affSColin Finck   adns__must_gettimeofday(ads,&now,&tv_buf);
304*c2c66affSColin Finck   if (now) adns__timeouts(ads, 1, 0,0, *now);
305*c2c66affSColin Finck   adns__consistency(ads,0,cc_entex);
306*c2c66affSColin Finck }
307*c2c66affSColin Finck 
308*c2c66affSColin Finck /* fd handling functions.  These are the top-level of the real work of
309*c2c66affSColin Finck  * reception and often transmission.
310*c2c66affSColin Finck  */
311*c2c66affSColin Finck 
adns__pollfds(adns_state ads,struct pollfd pollfds_buf[MAX_POLLFDS])312*c2c66affSColin Finck int adns__pollfds(adns_state ads, struct pollfd pollfds_buf[MAX_POLLFDS]) {
313*c2c66affSColin Finck   /* Returns the number of entries filled in.  Always zeroes revents. */
314*c2c66affSColin Finck 
315*c2c66affSColin Finck   assert(MAX_POLLFDS==2);
316*c2c66affSColin Finck 
317*c2c66affSColin Finck   pollfds_buf[0].fd= ads->udpsocket;
318*c2c66affSColin Finck   pollfds_buf[0].events= POLLIN;
319*c2c66affSColin Finck   pollfds_buf[0].revents= 0;
320*c2c66affSColin Finck 
321*c2c66affSColin Finck   switch (ads->tcpstate) {
322*c2c66affSColin Finck   case server_disconnected:
323*c2c66affSColin Finck   case server_broken:
324*c2c66affSColin Finck     return 1;
325*c2c66affSColin Finck   case server_connecting:
326*c2c66affSColin Finck     pollfds_buf[1].events= POLLOUT;
327*c2c66affSColin Finck     break;
328*c2c66affSColin Finck   case server_ok:
329*c2c66affSColin Finck     pollfds_buf[1].events= ads->tcpsend.used ? POLLIN|POLLOUT|POLLPRI : POLLIN|POLLPRI;
330*c2c66affSColin Finck     break;
331*c2c66affSColin Finck   default:
332*c2c66affSColin Finck     abort();
333*c2c66affSColin Finck   }
334*c2c66affSColin Finck   pollfds_buf[1].fd= ads->tcpsocket;
335*c2c66affSColin Finck   return 2;
336*c2c66affSColin Finck }
337*c2c66affSColin Finck 
adns_processreadable(adns_state ads,ADNS_SOCKET fd,const struct timeval * now)338*c2c66affSColin Finck int adns_processreadable(adns_state ads, ADNS_SOCKET fd, const struct timeval *now) {
339*c2c66affSColin Finck   int want, dgramlen, r, udpaddrlen, serv, old_skip;
340*c2c66affSColin Finck   byte udpbuf[DNS_MAXUDP];
341*c2c66affSColin Finck   struct sockaddr_in udpaddr;
342*c2c66affSColin Finck 
343*c2c66affSColin Finck   adns__consistency(ads,0,cc_entex);
344*c2c66affSColin Finck 
345*c2c66affSColin Finck   switch (ads->tcpstate) {
346*c2c66affSColin Finck   case server_disconnected:
347*c2c66affSColin Finck   case server_broken:
348*c2c66affSColin Finck   case server_connecting:
349*c2c66affSColin Finck     break;
350*c2c66affSColin Finck   case server_ok:
351*c2c66affSColin Finck     if (fd != ads->tcpsocket) break;
352*c2c66affSColin Finck     assert(!ads->tcprecv_skip);
353*c2c66affSColin Finck     do {
354*c2c66affSColin Finck       if (ads->tcprecv.used >= ads->tcprecv_skip+2) {
355*c2c66affSColin Finck 	dgramlen= ((ads->tcprecv.buf[ads->tcprecv_skip]<<8) |
356*c2c66affSColin Finck 	           ads->tcprecv.buf[ads->tcprecv_skip+1]);
357*c2c66affSColin Finck 	if (ads->tcprecv.used >= ads->tcprecv_skip+2+dgramlen) {
358*c2c66affSColin Finck 	  old_skip= ads->tcprecv_skip;
359*c2c66affSColin Finck 	  ads->tcprecv_skip += 2+dgramlen;
360*c2c66affSColin Finck 	  adns__procdgram(ads, ads->tcprecv.buf+old_skip+2,
361*c2c66affSColin Finck 			  dgramlen, ads->tcpserver, 1,*now);
362*c2c66affSColin Finck 	  continue;
363*c2c66affSColin Finck 	} else {
364*c2c66affSColin Finck 	  want= 2+dgramlen;
365*c2c66affSColin Finck 	}
366*c2c66affSColin Finck       } else {
367*c2c66affSColin Finck 	want= 2;
368*c2c66affSColin Finck       }
369*c2c66affSColin Finck       ads->tcprecv.used -= ads->tcprecv_skip;
370*c2c66affSColin Finck       memmove(ads->tcprecv.buf,ads->tcprecv.buf+ads->tcprecv_skip, (size_t) ads->tcprecv.used);
371*c2c66affSColin Finck       ads->tcprecv_skip= 0;
372*c2c66affSColin Finck       if (!adns__vbuf_ensure(&ads->tcprecv,want)) { r= ENOMEM; goto xit; }
373*c2c66affSColin Finck       assert(ads->tcprecv.used <= ads->tcprecv.avail);
374*c2c66affSColin Finck       if (ads->tcprecv.used == ads->tcprecv.avail) continue;
375*c2c66affSColin Finck 	  ADNS_CLEAR_ERRNO;
376*c2c66affSColin Finck       r= adns_socket_read(ads->tcpsocket,
377*c2c66affSColin Finck 	      ads->tcprecv.buf+ads->tcprecv.used,
378*c2c66affSColin Finck 	      ads->tcprecv.avail-ads->tcprecv.used);
379*c2c66affSColin Finck 	  ADNS_CAPTURE_ERRNO;
380*c2c66affSColin Finck       if (r>0) {
381*c2c66affSColin Finck 	ads->tcprecv.used+= r;
382*c2c66affSColin Finck       } else {
383*c2c66affSColin Finck 	if (r) {
384*c2c66affSColin Finck 	  if (errno==EAGAIN || errno==EWOULDBLOCK) { r= 0; goto xit; }
385*c2c66affSColin Finck 	  if (errno==EINTR) continue;
386*c2c66affSColin Finck 	  if (errno_resources(errno)) { r= errno; goto xit; }
387*c2c66affSColin Finck 	}
388*c2c66affSColin Finck 	adns__tcp_broken(ads,"adns_socket_read",r?strerror(errno):"closed");
389*c2c66affSColin Finck       }
390*c2c66affSColin Finck     } while (ads->tcpstate == server_ok);
391*c2c66affSColin Finck     r= 0; goto xit;
392*c2c66affSColin Finck   default:
393*c2c66affSColin Finck     abort();
394*c2c66affSColin Finck   }
395*c2c66affSColin Finck   if (fd == ads->udpsocket) {
396*c2c66affSColin Finck     for (;;) {
397*c2c66affSColin Finck       udpaddrlen= sizeof(udpaddr);
398*c2c66affSColin Finck 	  ADNS_CLEAR_ERRNO;
399*c2c66affSColin Finck       r= recvfrom(ads->udpsocket,(char*)udpbuf,sizeof(udpbuf),0,
400*c2c66affSColin Finck 		  (struct sockaddr*)&udpaddr,&udpaddrlen);
401*c2c66affSColin Finck 	  ADNS_CAPTURE_ERRNO;
402*c2c66affSColin Finck       if (r<0) {
403*c2c66affSColin Finck 	if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ECONNRESET) { r= 0; goto xit; }
404*c2c66affSColin Finck 	if (errno == EINTR) continue;
405*c2c66affSColin Finck 	if (errno_resources(errno)) { r= errno; goto xit; }
406*c2c66affSColin Finck 	adns__warn(ads,-1,0,"datagram receive error: %s (%d)",strerror(errno), errno);
407*c2c66affSColin Finck 	r= 0; goto xit;
408*c2c66affSColin Finck       }
409*c2c66affSColin Finck       if (udpaddrlen != sizeof(udpaddr)) {
410*c2c66affSColin Finck 	adns__diag(ads,-1,0,"datagram received with wrong address length %d"
411*c2c66affSColin Finck 		   " (expected %lu)", udpaddrlen,
412*c2c66affSColin Finck 		   (unsigned long)sizeof(udpaddr));
413*c2c66affSColin Finck 	continue;
414*c2c66affSColin Finck       }
415*c2c66affSColin Finck       if (udpaddr.sin_family != AF_INET) {
416*c2c66affSColin Finck 	adns__diag(ads,-1,0,"datagram received with wrong protocol family"
417*c2c66affSColin Finck 		   " %u (expected %u)",udpaddr.sin_family,AF_INET);
418*c2c66affSColin Finck 	continue;
419*c2c66affSColin Finck       }
420*c2c66affSColin Finck       if (ntohs(udpaddr.sin_port) != DNS_PORT) {
421*c2c66affSColin Finck 	adns__diag(ads,-1,0,"datagram received from wrong port %u (expected %u)",
422*c2c66affSColin Finck 		   ntohs(udpaddr.sin_port),DNS_PORT);
423*c2c66affSColin Finck 	continue;
424*c2c66affSColin Finck       }
425*c2c66affSColin Finck       for (serv= 0;
426*c2c66affSColin Finck 	   serv < ads->nservers &&
427*c2c66affSColin Finck 	     ads->servers[serv].addr.s_addr != udpaddr.sin_addr.s_addr;
428*c2c66affSColin Finck 	   serv++);
429*c2c66affSColin Finck       if (serv >= ads->nservers) {
430*c2c66affSColin Finck 	adns__warn(ads,-1,0,"datagram received from unknown nameserver %s",
431*c2c66affSColin Finck 		   inet_ntoa(udpaddr.sin_addr));
432*c2c66affSColin Finck 	continue;
433*c2c66affSColin Finck       }
434*c2c66affSColin Finck       adns__procdgram(ads,udpbuf,r,serv,0,*now);
435*c2c66affSColin Finck     }
436*c2c66affSColin Finck   }
437*c2c66affSColin Finck   r= 0;
438*c2c66affSColin Finck xit:
439*c2c66affSColin Finck   adns__consistency(ads,0,cc_entex);
440*c2c66affSColin Finck   return r;
441*c2c66affSColin Finck }
442*c2c66affSColin Finck 
adns_processwriteable(adns_state ads,ADNS_SOCKET fd,const struct timeval * now)443*c2c66affSColin Finck int adns_processwriteable(adns_state ads, ADNS_SOCKET fd, const struct timeval *now) {
444*c2c66affSColin Finck   int r;
445*c2c66affSColin Finck 
446*c2c66affSColin Finck   adns__consistency(ads,0,cc_entex);
447*c2c66affSColin Finck 
448*c2c66affSColin Finck   switch (ads->tcpstate) {
449*c2c66affSColin Finck   case server_disconnected:
450*c2c66affSColin Finck   case server_broken:
451*c2c66affSColin Finck     break;
452*c2c66affSColin Finck   case server_connecting:
453*c2c66affSColin Finck     if (fd != ads->tcpsocket) break;
454*c2c66affSColin Finck     assert(ads->tcprecv.used==0);
455*c2c66affSColin Finck     assert(ads->tcprecv_skip==0);
456*c2c66affSColin Finck     for (;;) {
457*c2c66affSColin Finck       if (!adns__vbuf_ensure(&ads->tcprecv,1)) { r= ENOMEM; goto xit; }
458*c2c66affSColin Finck 	  ADNS_CLEAR_ERRNO;
459*c2c66affSColin Finck       r= adns_socket_read(ads->tcpsocket,&ads->tcprecv.buf,1);
460*c2c66affSColin Finck 	  ADNS_CAPTURE_ERRNO;
461*c2c66affSColin Finck       if (r==0 || (r<0 && (errno==EAGAIN || errno==EWOULDBLOCK))) {
462*c2c66affSColin Finck 	tcp_connected(ads,*now);
463*c2c66affSColin Finck 	r= 0; goto xit;
464*c2c66affSColin Finck       }
465*c2c66affSColin Finck       if (r>0) {
466*c2c66affSColin Finck 	adns__tcp_broken(ads,"connect/adns_socket_read","sent data before first request");
467*c2c66affSColin Finck 	r= 0; goto xit;
468*c2c66affSColin Finck       }
469*c2c66affSColin Finck       if (errno==EINTR) continue;
470*c2c66affSColin Finck       if (errno_resources(errno)) { r= errno; goto xit; }
471*c2c66affSColin Finck       adns__tcp_broken(ads,"connect/adns_socket_read",strerror(errno));
472*c2c66affSColin Finck       r= 0; goto xit;
473*c2c66affSColin Finck     } /* not reached */
474*c2c66affSColin Finck   case server_ok:
475*c2c66affSColin Finck     if (fd != ads->tcpsocket) break;
476*c2c66affSColin Finck     while (ads->tcpsend.used) {
477*c2c66affSColin Finck       adns__sigpipe_protect(ads);
478*c2c66affSColin Finck 	  ADNS_CLEAR_ERRNO;
479*c2c66affSColin Finck       r= adns_socket_write(ads->tcpsocket,ads->tcpsend.buf,ads->tcpsend.used);
480*c2c66affSColin Finck 	  ADNS_CAPTURE_ERRNO;
481*c2c66affSColin Finck       adns__sigpipe_unprotect(ads);
482*c2c66affSColin Finck       if (r<0) {
483*c2c66affSColin Finck 	if (errno==EINTR) continue;
484*c2c66affSColin Finck 	if (errno==EAGAIN || errno==EWOULDBLOCK) { r= 0; goto xit; }
485*c2c66affSColin Finck 	if (errno_resources(errno)) { r= errno; goto xit; }
486*c2c66affSColin Finck 	adns__tcp_broken(ads,"adns_socket_write",strerror(errno));
487*c2c66affSColin Finck 	r= 0; goto xit;
488*c2c66affSColin Finck       } else if (r>0) {
489*c2c66affSColin Finck 	ads->tcpsend.used -= r;
490*c2c66affSColin Finck 	memmove(ads->tcpsend.buf,ads->tcpsend.buf+r, (size_t) ads->tcpsend.used);
491*c2c66affSColin Finck       }
492*c2c66affSColin Finck     }
493*c2c66affSColin Finck     r= 0;
494*c2c66affSColin Finck     goto xit;
495*c2c66affSColin Finck   default:
496*c2c66affSColin Finck     abort();
497*c2c66affSColin Finck   }
498*c2c66affSColin Finck   r= 0;
499*c2c66affSColin Finck xit:
500*c2c66affSColin Finck   adns__consistency(ads,0,cc_entex);
501*c2c66affSColin Finck   return r;
502*c2c66affSColin Finck }
503*c2c66affSColin Finck 
adns_processexceptional(adns_state ads,ADNS_SOCKET fd,const struct timeval * now)504*c2c66affSColin Finck int adns_processexceptional(adns_state ads, ADNS_SOCKET fd, const struct timeval *now) {
505*c2c66affSColin Finck   adns__consistency(ads,0,cc_entex);
506*c2c66affSColin Finck   switch (ads->tcpstate) {
507*c2c66affSColin Finck   case server_disconnected:
508*c2c66affSColin Finck   case server_broken:
509*c2c66affSColin Finck     break;
510*c2c66affSColin Finck   case server_connecting:
511*c2c66affSColin Finck   case server_ok:
512*c2c66affSColin Finck     if (fd != ads->tcpsocket) break;
513*c2c66affSColin Finck     adns__tcp_broken(ads,"poll/select","exceptional condition detected");
514*c2c66affSColin Finck     break;
515*c2c66affSColin Finck   default:
516*c2c66affSColin Finck     abort();
517*c2c66affSColin Finck   }
518*c2c66affSColin Finck   adns__consistency(ads,0,cc_entex);
519*c2c66affSColin Finck   return 0;
520*c2c66affSColin Finck }
521*c2c66affSColin Finck 
fd_event(adns_state ads,ADNS_SOCKET fd,int revent,int pollflag,int maxfd,const fd_set * fds,int (* func)(adns_state,ADNS_SOCKET fd,const struct timeval * now),struct timeval now,int * r_r)522*c2c66affSColin Finck static void fd_event(adns_state ads, ADNS_SOCKET fd,
523*c2c66affSColin Finck 		     int revent, int pollflag,
524*c2c66affSColin Finck 		     int maxfd, const fd_set *fds,
525*c2c66affSColin Finck 		     int (*func)(adns_state, ADNS_SOCKET fd, const struct timeval *now),
526*c2c66affSColin Finck 		     struct timeval now, int *r_r) {
527*c2c66affSColin Finck   int r;
528*c2c66affSColin Finck 
529*c2c66affSColin Finck   if (!(revent & pollflag)) return;
530*c2c66affSColin Finck   if (fds && !((int)fd<maxfd && FD_ISSET(fd,fds))) return;
531*c2c66affSColin Finck   r= func(ads,fd,&now);
532*c2c66affSColin Finck   if (r) {
533*c2c66affSColin Finck     if (r_r) {
534*c2c66affSColin Finck       *r_r= r;
535*c2c66affSColin Finck     } else {
536*c2c66affSColin Finck       adns__diag(ads,-1,0,"process fd failed after select: %s",strerror(errno));
537*c2c66affSColin Finck       adns_globalsystemfailure(ads);
538*c2c66affSColin Finck     }
539*c2c66affSColin Finck   }
540*c2c66affSColin Finck }
541*c2c66affSColin Finck 
adns__fdevents(adns_state ads,const struct pollfd * pollfds,int npollfds,int maxfd,const fd_set * readfds,const fd_set * writefds,const fd_set * exceptfds,struct timeval now,int * r_r)542*c2c66affSColin Finck void adns__fdevents(adns_state ads,
543*c2c66affSColin Finck 		    const struct pollfd *pollfds, int npollfds,
544*c2c66affSColin Finck 		    int maxfd, const fd_set *readfds,
545*c2c66affSColin Finck 		    const fd_set *writefds, const fd_set *exceptfds,
546*c2c66affSColin Finck 		    struct timeval now, int *r_r) {
547*c2c66affSColin Finck   int i, revents;
548*c2c66affSColin Finck   ADNS_SOCKET fd;
549*c2c66affSColin Finck 
550*c2c66affSColin Finck   for (i=0; i<npollfds; i++) {
551*c2c66affSColin Finck     fd= pollfds[i].fd;
552*c2c66affSColin Finck     if ((int)fd >= maxfd) maxfd= fd+1;
553*c2c66affSColin Finck     revents= pollfds[i].revents;
554*c2c66affSColin Finck     fd_event(ads,fd, revents,POLLIN, maxfd,readfds, adns_processreadable,now,r_r);
555*c2c66affSColin Finck     fd_event(ads,fd, revents,POLLOUT, maxfd,writefds, adns_processwriteable,now,r_r);
556*c2c66affSColin Finck     fd_event(ads,fd, revents,POLLPRI, maxfd,exceptfds, adns_processexceptional,now,r_r);
557*c2c66affSColin Finck   }
558*c2c66affSColin Finck }
559*c2c66affSColin Finck 
560*c2c66affSColin Finck /* Wrappers for select(2). */
561*c2c66affSColin Finck 
adns_beforeselect(adns_state ads,int * maxfd_io,fd_set * readfds_io,fd_set * writefds_io,fd_set * exceptfds_io,struct timeval ** tv_mod,struct timeval * tv_tobuf,const struct timeval * now)562*c2c66affSColin Finck void adns_beforeselect(adns_state ads, int *maxfd_io, fd_set *readfds_io,
563*c2c66affSColin Finck 		       fd_set *writefds_io, fd_set *exceptfds_io,
564*c2c66affSColin Finck 		       struct timeval **tv_mod, struct timeval *tv_tobuf,
565*c2c66affSColin Finck 		       const struct timeval *now) {
566*c2c66affSColin Finck   struct timeval tv_nowbuf;
567*c2c66affSColin Finck   struct pollfd pollfds[MAX_POLLFDS];
568*c2c66affSColin Finck   int i, maxfd, npollfds;
569*c2c66affSColin Finck   ADNS_SOCKET fd;
570*c2c66affSColin Finck 
571*c2c66affSColin Finck   adns__consistency(ads,0,cc_entex);
572*c2c66affSColin Finck 
573*c2c66affSColin Finck   if (tv_mod && (!*tv_mod || (*tv_mod)->tv_sec || (*tv_mod)->tv_usec)) {
574*c2c66affSColin Finck     /* The caller is planning to sleep. */
575*c2c66affSColin Finck     adns__must_gettimeofday(ads,&now,&tv_nowbuf);
576*c2c66affSColin Finck     if (!now) { inter_immed(tv_mod,tv_tobuf); goto xit; }
577*c2c66affSColin Finck     adns__timeouts(ads, 0, tv_mod,tv_tobuf, *now);
578*c2c66affSColin Finck   }
579*c2c66affSColin Finck 
580*c2c66affSColin Finck   npollfds= adns__pollfds(ads,pollfds);
581*c2c66affSColin Finck   maxfd= *maxfd_io;
582*c2c66affSColin Finck   for (i=0; i<npollfds; i++) {
583*c2c66affSColin Finck     fd= pollfds[i].fd;
584*c2c66affSColin Finck     if ((int)fd >= maxfd) maxfd= fd+1;
585*c2c66affSColin Finck     if (pollfds[i].events & POLLIN) FD_SET(fd,readfds_io);
586*c2c66affSColin Finck     if (pollfds[i].events & POLLOUT) FD_SET(fd,writefds_io);
587*c2c66affSColin Finck     if (pollfds[i].events & POLLPRI) FD_SET(fd,exceptfds_io);
588*c2c66affSColin Finck   }
589*c2c66affSColin Finck   *maxfd_io= maxfd;
590*c2c66affSColin Finck 
591*c2c66affSColin Finck xit:
592*c2c66affSColin Finck   adns__consistency(ads,0,cc_entex);
593*c2c66affSColin Finck }
594*c2c66affSColin Finck 
adns_afterselect(adns_state ads,int maxfd,const fd_set * readfds,const fd_set * writefds,const fd_set * exceptfds,const struct timeval * now)595*c2c66affSColin Finck void adns_afterselect(adns_state ads, int maxfd, const fd_set *readfds,
596*c2c66affSColin Finck 		      const fd_set *writefds, const fd_set *exceptfds,
597*c2c66affSColin Finck 		      const struct timeval *now) {
598*c2c66affSColin Finck   struct timeval tv_buf;
599*c2c66affSColin Finck   struct pollfd pollfds[MAX_POLLFDS];
600*c2c66affSColin Finck   int npollfds, i;
601*c2c66affSColin Finck 
602*c2c66affSColin Finck   adns__consistency(ads,0,cc_entex);
603*c2c66affSColin Finck   adns__must_gettimeofday(ads,&now,&tv_buf);
604*c2c66affSColin Finck   if (!now) goto xit;
605*c2c66affSColin Finck   adns_processtimeouts(ads,now);
606*c2c66affSColin Finck 
607*c2c66affSColin Finck   npollfds= adns__pollfds(ads,pollfds);
608*c2c66affSColin Finck   for (i=0; i<npollfds; i++) pollfds[i].revents= POLLIN|POLLOUT|POLLPRI;
609*c2c66affSColin Finck   adns__fdevents(ads,
610*c2c66affSColin Finck 		 pollfds,npollfds,
611*c2c66affSColin Finck 		 maxfd,readfds,writefds,exceptfds,
612*c2c66affSColin Finck 		 *now, 0);
613*c2c66affSColin Finck xit:
614*c2c66affSColin Finck   adns__consistency(ads,0,cc_entex);
615*c2c66affSColin Finck }
616*c2c66affSColin Finck 
617*c2c66affSColin Finck /* General helpful functions. */
618*c2c66affSColin Finck 
adns_globalsystemfailure(adns_state ads)619*c2c66affSColin Finck void adns_globalsystemfailure(adns_state ads) {
620*c2c66affSColin Finck   adns__consistency(ads,0,cc_entex);
621*c2c66affSColin Finck 
622*c2c66affSColin Finck   while (ads->udpw.head) adns__query_fail(ads->udpw.head, adns_s_systemfail);
623*c2c66affSColin Finck   while (ads->tcpw.head) adns__query_fail(ads->tcpw.head, adns_s_systemfail);
624*c2c66affSColin Finck 
625*c2c66affSColin Finck   switch (ads->tcpstate) {
626*c2c66affSColin Finck   case server_connecting:
627*c2c66affSColin Finck   case server_ok:
628*c2c66affSColin Finck     adns__tcp_broken(ads,0,0);
629*c2c66affSColin Finck     break;
630*c2c66affSColin Finck   case server_disconnected:
631*c2c66affSColin Finck   case server_broken:
632*c2c66affSColin Finck     break;
633*c2c66affSColin Finck   default:
634*c2c66affSColin Finck     abort();
635*c2c66affSColin Finck   }
636*c2c66affSColin Finck   adns__consistency(ads,0,cc_entex);
637*c2c66affSColin Finck }
638*c2c66affSColin Finck 
adns_processany(adns_state ads)639*c2c66affSColin Finck int adns_processany(adns_state ads) {
640*c2c66affSColin Finck   int r, i;
641*c2c66affSColin Finck   struct timeval now;
642*c2c66affSColin Finck   struct pollfd pollfds[MAX_POLLFDS];
643*c2c66affSColin Finck   int npollfds;
644*c2c66affSColin Finck 
645*c2c66affSColin Finck   adns__consistency(ads,0,cc_entex);
646*c2c66affSColin Finck 
647*c2c66affSColin Finck   r= gettimeofday(&now,0);
648*c2c66affSColin Finck   if (!r) adns_processtimeouts(ads,&now);
649*c2c66affSColin Finck 
650*c2c66affSColin Finck   /* We just use adns__fdevents to loop over the fd's trying them.
651*c2c66affSColin Finck    * This seems more sensible than calling select, since we're most
652*c2c66affSColin Finck    * likely just to want to do a adns_socket_read on one or two fds anyway.
653*c2c66affSColin Finck    */
654*c2c66affSColin Finck   npollfds= adns__pollfds(ads,pollfds);
655*c2c66affSColin Finck   for (i=0; i<npollfds; i++) pollfds[i].revents= pollfds[i].events & ~POLLPRI;
656*c2c66affSColin Finck   adns__fdevents(ads,
657*c2c66affSColin Finck 		 pollfds,npollfds,
658*c2c66affSColin Finck 		 0,0,0,0,
659*c2c66affSColin Finck 		 now,&r);
660*c2c66affSColin Finck 
661*c2c66affSColin Finck   adns__consistency(ads,0,cc_entex);
662*c2c66affSColin Finck   return 0;
663*c2c66affSColin Finck }
664*c2c66affSColin Finck 
adns__autosys(adns_state ads,struct timeval now)665*c2c66affSColin Finck void adns__autosys(adns_state ads, struct timeval now) {
666*c2c66affSColin Finck   if (ads->iflags & adns_if_noautosys) return;
667*c2c66affSColin Finck   adns_processany(ads);
668*c2c66affSColin Finck }
669*c2c66affSColin Finck 
adns__internal_check(adns_state ads,adns_query * query_io,adns_answer ** answer,void ** context_r)670*c2c66affSColin Finck int adns__internal_check(adns_state ads,
671*c2c66affSColin Finck 			 adns_query *query_io,
672*c2c66affSColin Finck 			 adns_answer **answer,
673*c2c66affSColin Finck 			 void **context_r) {
674*c2c66affSColin Finck   adns_query qu;
675*c2c66affSColin Finck 
676*c2c66affSColin Finck   qu= *query_io;
677*c2c66affSColin Finck   if (!qu) {
678*c2c66affSColin Finck     if (ads->output.head) {
679*c2c66affSColin Finck       qu= ads->output.head;
680*c2c66affSColin Finck     } else if (ads->udpw.head || ads->tcpw.head) {
681*c2c66affSColin Finck       return EAGAIN;
682*c2c66affSColin Finck     } else {
683*c2c66affSColin Finck       return ESRCH;
684*c2c66affSColin Finck     }
685*c2c66affSColin Finck   } else {
686*c2c66affSColin Finck     if (qu->id>=0) return EAGAIN;
687*c2c66affSColin Finck   }
688*c2c66affSColin Finck   LIST_UNLINK(ads->output,qu);
689*c2c66affSColin Finck   *answer= qu->answer;
690*c2c66affSColin Finck   if (context_r) *context_r= qu->ctx.ext;
691*c2c66affSColin Finck   *query_io= qu;
692*c2c66affSColin Finck   free(qu);
693*c2c66affSColin Finck   return 0;
694*c2c66affSColin Finck }
695*c2c66affSColin Finck 
adns_wait(adns_state ads,adns_query * query_io,adns_answer ** answer_r,void ** context_r)696*c2c66affSColin Finck int adns_wait(adns_state ads,
697*c2c66affSColin Finck 	      adns_query *query_io,
698*c2c66affSColin Finck 	      adns_answer **answer_r,
699*c2c66affSColin Finck 	      void **context_r) {
700*c2c66affSColin Finck   int r, maxfd, rsel;
701*c2c66affSColin Finck   fd_set readfds, writefds, exceptfds;
702*c2c66affSColin Finck   struct timeval tvbuf, *tvp;
703*c2c66affSColin Finck 
704*c2c66affSColin Finck   adns__consistency(ads,*query_io,cc_entex);
705*c2c66affSColin Finck   for (;;) {
706*c2c66affSColin Finck     r= adns__internal_check(ads,query_io,answer_r,context_r);
707*c2c66affSColin Finck     if (r != EAGAIN) break;
708*c2c66affSColin Finck     maxfd= 0; tvp= 0;
709*c2c66affSColin Finck     FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds);
710*c2c66affSColin Finck     adns_beforeselect(ads,&maxfd,&readfds,&writefds,&exceptfds,&tvp,&tvbuf,0);
711*c2c66affSColin Finck     assert(tvp);
712*c2c66affSColin Finck 	ADNS_CLEAR_ERRNO;
713*c2c66affSColin Finck     rsel= select(maxfd,&readfds,&writefds,&exceptfds,tvp);
714*c2c66affSColin Finck 	ADNS_CAPTURE_ERRNO;
715*c2c66affSColin Finck     if (rsel==-1) {
716*c2c66affSColin Finck       if (errno == EINTR) {
717*c2c66affSColin Finck 	if (ads->iflags & adns_if_eintr) { r= EINTR; break; }
718*c2c66affSColin Finck       } else {
719*c2c66affSColin Finck 	adns__diag(ads,-1,0,"select failed in wait: %s",strerror(errno));
720*c2c66affSColin Finck 	adns_globalsystemfailure(ads);
721*c2c66affSColin Finck       }
722*c2c66affSColin Finck     } else {
723*c2c66affSColin Finck       assert(rsel >= 0);
724*c2c66affSColin Finck       adns_afterselect(ads,maxfd,&readfds,&writefds,&exceptfds,0);
725*c2c66affSColin Finck     }
726*c2c66affSColin Finck   }
727*c2c66affSColin Finck   adns__consistency(ads,0,cc_entex);
728*c2c66affSColin Finck   return r;
729*c2c66affSColin Finck }
730*c2c66affSColin Finck 
adns_check(adns_state ads,adns_query * query_io,adns_answer ** answer_r,void ** context_r)731*c2c66affSColin Finck int adns_check(adns_state ads,
732*c2c66affSColin Finck 	       adns_query *query_io,
733*c2c66affSColin Finck 	       adns_answer **answer_r,
734*c2c66affSColin Finck 	       void **context_r) {
735*c2c66affSColin Finck   struct timeval now;
736*c2c66affSColin Finck   int r;
737*c2c66affSColin Finck 
738*c2c66affSColin Finck   adns__consistency(ads,*query_io,cc_entex);
739*c2c66affSColin Finck   r= gettimeofday(&now,0);
740*c2c66affSColin Finck   if (!r) adns__autosys(ads,now);
741*c2c66affSColin Finck 
742*c2c66affSColin Finck   r= adns__internal_check(ads,query_io,answer_r,context_r);
743*c2c66affSColin Finck   adns__consistency(ads,0,cc_entex);
744*c2c66affSColin Finck   return r;
745*c2c66affSColin Finck }
746