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