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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 665 void adns__autosys(adns_state ads, struct timeval now) { 666 if (ads->iflags & adns_if_noautosys) return; 667 adns_processany(ads); 668 } 669 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 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 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