X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=adns.git;a=blobdiff_plain;f=src%2Fevent.c;h=29d50a0cf6e8817476d4a300f400e1a99e85e1b0;hp=a1641c630a1d0307d62fffc6f6e6c61e39a3844d;hb=d00d4b99046ceb395e4ca22c97cd8aa0942f115a;hpb=2953d358511ac5d196362f6b339c010d4e9cae3e diff --git a/src/event.c b/src/event.c index a1641c6..29d50a0 100644 --- a/src/event.c +++ b/src/event.c @@ -6,10 +6,10 @@ */ /* * This file is - * Copyright (C) 1997-1999 Ian Jackson + * Copyright (C) 1997-2000 Ian Jackson * * It is part of adns, which is - * Copyright (C) 1997-1999 Ian Jackson + * Copyright (C) 1997-2000 Ian Jackson * Copyright (C) 1999 Tony Finch * * This program is free software; you can redistribute it and/or modify @@ -54,11 +54,18 @@ static void tcp_close(adns_state ads) { void adns__tcp_broken(adns_state ads, const char *what, const char *why) { int serv; + adns_query qu; assert(ads->tcpstate == server_connecting || ads->tcpstate == server_ok); serv= ads->tcpserver; if (what) adns__warn(ads,serv,0,"TCP connection failed: %s: %s",what,why); + if (ads->tcpstate == server_connecting) { + /* Counts as a retry for all the queries waiting for TCP. */ + for (qu= ads->tcpw.head; qu; qu= qu->next) + qu->retries++; + } + tcp_close(ads); ads->tcpstate= server_broken; ads->tcpserver= (serv+1)%ads->nservers; @@ -143,6 +150,17 @@ void adns__must_gettimeofday(adns_state ads, const struct timeval **now_io, return; } +static void inter_immed(struct timeval **tv_io, struct timeval *tvbuf) { + struct timeval *rbuf; + + if (!tv_io) return; + + rbuf= *tv_io; + if (!rbuf) { *tv_io= rbuf= tvbuf; } + + timerclear(rbuf); +} + static void inter_maxto(struct timeval **tv_io, struct timeval *tvbuf, struct timeval maxto) { struct timeval *rbuf; @@ -185,12 +203,7 @@ static void timeouts_queue(adns_state ads, int act, if (!timercmp(&now,&qu->timeout,>)) { inter_maxtoabs(tv_io,tvbuf,now,qu->timeout); } else { - if (!act) { - tvbuf->tv_sec= 0; - tvbuf->tv_usec= 0; - *tv_io= tvbuf; - return; - } + if (!act) { inter_immed(tv_io,tvbuf); return; } LIST_UNLINK(*queue,qu); if (qu->state != query_tosend) { adns__query_fail(qu,adns_s_timeout); @@ -210,6 +223,7 @@ static void tcp_events(adns_state ads, int act, for (;;) { switch (ads->tcpstate) { case server_broken: + if (!act) { inter_immed(tv_io,tvbuf); return; } for (qu= ads->tcpw.head; qu; qu= nqu) { nqu= qu->next; assert(qu->state == query_tcpw); @@ -221,6 +235,7 @@ static void tcp_events(adns_state ads, int act, ads->tcpstate= server_disconnected; case server_disconnected: /* fall through */ if (!ads->tcpw.head) return; + if (!act) { inter_immed(tv_io,tvbuf); return; } adns__tcp_tryconnect(ads,now); break; case server_ok: @@ -231,7 +246,7 @@ static void tcp_events(adns_state ads, int act, timevaladd(&ads->tcptimeout,TCPIDLEMS); } case server_connecting: /* fall through */ - if (!timercmp(&now,&ads->tcptimeout,>)) { + if (!act || !timercmp(&now,&ads->tcptimeout,>)) { inter_maxtoabs(tv_io,tvbuf,now,ads->tcptimeout); return; } { @@ -253,6 +268,7 @@ static void tcp_events(adns_state ads, int act, abort(); } } + return; } void adns__timeouts(adns_state ads, int act, @@ -295,6 +311,7 @@ int adns__pollfds(adns_state ads, struct pollfd pollfds_buf[MAX_POLLFDS]) { switch (ads->tcpstate) { case server_disconnected: + case server_broken: return 1; case server_connecting: pollfds_buf[1].events= POLLOUT; @@ -318,12 +335,13 @@ int adns_processreadable(adns_state ads, int fd, const struct timeval *now) { switch (ads->tcpstate) { case server_disconnected: + case server_broken: case server_connecting: break; case server_ok: if (fd != ads->tcpsocket) break; assert(!ads->tcprecv_skip); - for (;;) { + do { if (ads->tcprecv.used >= ads->tcprecv_skip+2) { dgramlen= ((ads->tcprecv.buf[ads->tcprecv_skip]<<8) | ads->tcprecv.buf[ads->tcprecv_skip+1]); @@ -357,9 +375,9 @@ int adns_processreadable(adns_state ads, int fd, const struct timeval *now) { if (errno_resources(errno)) { r= errno; goto xit; } } adns__tcp_broken(ads,"read",r?strerror(errno):"closed"); - r= 0; goto xit; } - } /* never reached */ + } while (ads->tcpstate == server_ok); + r= 0; goto xit; default: abort(); } @@ -415,6 +433,7 @@ int adns_processwriteable(adns_state ads, int fd, const struct timeval *now) { switch (ads->tcpstate) { case server_disconnected: + case server_broken: break; case server_connecting: if (fd != ads->tcpsocket) break; @@ -437,8 +456,8 @@ int adns_processwriteable(adns_state ads, int fd, const struct timeval *now) { r= 0; goto xit; } /* not reached */ case server_ok: - if (!(ads->tcpsend.used && fd == ads->tcpsocket)) break; - for (;;) { + if (fd != ads->tcpsocket) break; + while (ads->tcpsend.used) { adns__sigpipe_protect(ads); r= write(ads->tcpsocket,ads->tcpsend.buf,ads->tcpsend.used); adns__sigpipe_unprotect(ads); @@ -452,7 +471,9 @@ int adns_processwriteable(adns_state ads, int fd, const struct timeval *now) { ads->tcpsend.used -= r; memmove(ads->tcpsend.buf,ads->tcpsend.buf+r,ads->tcpsend.used); } - } /* not reached */ + } + r= 0; + goto xit; default: abort(); } @@ -466,6 +487,7 @@ int adns_processexceptional(adns_state ads, int fd, const struct timeval *now) { adns__consistency(ads,0,cc_entex); switch (ads->tcpstate) { case server_disconnected: + case server_broken: break; case server_connecting: case server_ok: @@ -531,8 +553,8 @@ void adns_beforeselect(adns_state ads, int *maxfd_io, fd_set *readfds_io, if (tv_mod && (!*tv_mod || (*tv_mod)->tv_sec || (*tv_mod)->tv_usec)) { /* The caller is planning to sleep. */ adns__must_gettimeofday(ads,&now,&tv_nowbuf); - if (!now) goto xit; - adns__timeouts(ads, 1, tv_mod,tv_tobuf, *now); + if (!now) { inter_immed(tv_mod,tv_tobuf); goto xit; } + adns__timeouts(ads, 0, tv_mod,tv_tobuf, *now); } npollfds= adns__pollfds(ads,pollfds); @@ -586,6 +608,7 @@ void adns_globalsystemfailure(adns_state ads) { adns__tcp_broken(ads,0,0); break; case server_disconnected: + case server_broken: break; default: abort(); @@ -609,7 +632,7 @@ int adns_processany(adns_state ads) { * likely just to want to do a read on one or two fds anyway. */ npollfds= adns__pollfds(ads,pollfds); - for (i=0; i