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