3 static void autosys(adns_state ads
, struct timeval now
) {
4 if (ads
->iflags
& adns_if_noautosys
) return;
5 adns_callback(ads
,-1,0,0,0);
8 static int callb_checkfd(int maxfd
, const fd_set
*fds
, int fd
) {
9 return maxfd
<0 || !fds ?
1 :
10 fd
<maxfd
&& FD_ISSET(fd
,fds
);
13 int adns_callback(adns_state ads
, int maxfd
,
14 const fd_set
*readfds
, const fd_set
*writefds
,
15 const fd_set
*exceptfds
) {
16 int skip
, dgramlen
, count
;
17 enum adns__tcpstate oldtcpstate
;
20 oldtcpstate
= ads
->tcpstate
;
22 if (ads
->tcpstate
== server_connecting
) {
23 if (callb_checkfd(maxfd
,writefds
,ads
->tcpsocket
)) {
25 assert(ads
->tcprecv
.used
==0);
26 vbuf_ensure(&ads
->tcprecv
,1);
27 if (ads
->tcprecv
.buf
) {
28 r
= read(ads
->tcpsocket
,&ads
->tcprecv
.buf
,1);
29 if (r
==0 || (r
<0 && (errno
==EAGAIN
|| errno
==EWOULDBLOCK
))) {
30 diag("nameserver %s TCP connection made",
31 inet_ntoa(ads
->servers
[ads
->tcpserver
].addr
));
32 ads
->tcpstate
= server_connected
;
34 tcpserver_broken(ads
,"connect/read","sent data before first request");
35 } else if (errno
!=EINTR
) {
36 tcpserver_broken(ads
,"connect",strerror(errno
));
41 if (ads
->tcpstate
== server_connected
) {
42 if (oldtcpstate
== server_connected
)
43 count
+= callb_checkfd(maxfd
,readfds
,ads
->tcpsocket
) +
44 callb_checkfd(maxfd
,exceptfds
,ads
->tcpsocket
) +
45 (ads
->tcpsend
.used
&& callb_checkfd(maxfd
,writefds
,ads
->tcpsocket
));
46 if (oldtcpstate
!= server_connected
|| callb_checkfd(maxfd
,readfds
,ads
->tcpsocket
)) {
49 if (ads
->tcprecv
.used
<skip
+2) {
52 dgramlen
= (ads
->tcprecv
.buf
[skip
]<<8) | ads
->tcprecv
.buf
[skip
+1];
53 if (ads
->tcprecv
.used
<skip
+2+dgramlen
) {
56 procdgram(ads
,ads
->tcprecv
.buf
+skip
+2,dgramlen
,-1);
57 skip
+= 2+dgramlen
; continue;
60 Ads
->tcprecv
.used
-= skip
;
61 memmove(ads
->tcprecv
.buf
,ads
->tcprecv
.buf
+skip
,ads
->tcprecv
.used
);
62 vbuf_ensure(&ads
->tcprecv
,want
);
63 if (ads
->tcprecv
.used
>= ads
->tcprecv
.avail
) break;
64 r
= read(ads
->tcpsocket
,
65 ads
->tcprecv
.buf
+ads
->tcprecv
.used
,
66 ads
->tcprecv
.avail
-ads
->tcprecv
.used
);
68 ads
->tcprecv
.used
+= r
;
71 if (errno
==EAGAIN
|| errno
==EWOULDBLOCK
|| errno
==ENOMEM
) break;
72 if (errno
==EINTR
) continue;
74 tcpserver_broken(ads
->tcpserver
,"read",r?
strerror(errno
):"closed");
78 } else if (callb_checkfd(maxfd
,exceptfds
,ads
->tcpsocket
)) {
79 tcpserver_broken(ads
->tcpserver
,"select","exceptional condition detected");
80 } else if (ads
->tcpsend
.used
&& callb_checkfd(maxfd
,writefds
,ads
->tcpsocket
)) {
81 r
= write(ads
->tcpsocket
,ads
->tcpsend
.buf
,ads
->tcpsend
.used
);
83 if (errno
!=EAGAIN
&& errno
!=EWOULDBLOCK
&& errno
!=ENOMEM
&& errno
!=EINTR
) {
84 tcpserver_broken(ads
->tcpserver
,"write",strerror(errno
));
87 ads
->tcpsend
.used
-= r
;
88 memmove(ads
->tcpsend
.buf
,ads
->tcpsend
.buf
+r
,ads
->tcpsend
.used
);
104 vbuf_ensure(&ads
->tcprecv
,2);
105 vbuf_ensure(&ads
->tcprecv
,
106 if (ads
->tcprecv
.avail
<2) break;
107 if (ads
->tcprecv
.used
109 if (ads
->tcprecv
.used
<2 && ads
->tcprecv
.avail
110 if (ads
->tcprecv
.used
<2 && ads
->tcprecv
.avail
111 r
= read(ads
->tcpsocket
,
112 if (adns
->tcprecv
.used
<2) {
115 if (ads
->tcpstate
!= server_disc
) {
119 if (maxfd
<0 || !readfds
|| (FD_ISSET
124 diag("nameserver #%d (%s) TCP connection died: %s",
125 inet_ntoa(ads
->servers
[tcpserver
].addr
),
127 static void inter_maxto(struct timeval
**tv_io
, struct timeval
*tvbuf
,
128 struct timeval maxto
) {
132 if (!rbuf
) { *tvbuf
= maxto
; *tv_io
= tvbuf
; return; }
133 if (timercmp(rbuf
,&maxto
,>)) *rbuf
= maxto
;
136 static void inter_maxtoabs(struct timeval
**tv_io
, struct timeval
*tvbuf
,
137 struct timeval now
, struct timeval maxtime
) {
140 maxtime
.tv_sec
-= (now
.tv_sec
-1);
141 maxtime
.tv_usec
+= (1000-now
.tv_usec
);
142 dr
= ldiv(maxtime
.tv_usec
,1000);
143 maxtime
.tv_sec
+= dr
.quot
;
144 maxtime
.tv_usec
-= dr
.rem
;
145 inter_maxto(tv_io
,tvbuf
,maxtime
);
148 static void localresourcerr(struct timeval
**tv_io
, struct timeval
*tvbuf
,
149 const char *syscall
) {
150 struct timeval tvto_lr
;
152 diag(ads
,"local system resources scarce (during %s): %s",syscall
,strerror(errno
));
153 timerclear(&tvto_lr
); timevaladd(&tvto_lr
,LOCALRESOURCEMS
);
154 inter_maxto(tv_io
, tvbuf
, tvto_lr
);
158 static void inter_addfd(int *maxfd
, fd_set
*fds
, int fd
) {
159 if (fd
>=*maxfd
) *maxfd
= fd
+1;
163 void adns_interest(adns_state ads
, int *maxfd
,
164 fd_set
*readfds
, fd_set
*writefds
, fd_set
*exceptfds
,
165 struct timeval
**tv_io
, struct timeval
*tvbuf
) {
170 r
= gettimeofday(&now
,0);
171 if (r
) { localresourcerr(tv_io
,tvbuf
,"gettimeofday"); return; }
173 for (qu
= ads
->timew
; qu
; qu
= nqu
) {
175 if (timercmp(&now
,qu
->timeout
,>)) {
176 DLIST_UNLINK(ads
->timew
,qu
);
177 if (qu
->nextudpserver
== -1) {
178 query_fail(ads
,qu
,adns_s_notresponding
);
180 DLIST_LINKTAIL(ads
->tosend
,qu
);
183 inter_maxtoabs(tv_io
,tvbuf
,now
,qu
->timeout
);
187 for (qu
= ads
->tosend
; qu
; qu
= nqu
) {
189 quproc_tosend(ads
,qu
,now
);
192 inter_addfd(maxfd
,readfds
,ads
->udpsocket
);
193 switch (ads
->tcpstate
) {
196 case server_connecting
:
197 inter_addfd(maxfd
,writefds
,ads
->tcpsocket
);
199 case server_connected
:
200 inter_addfd(maxfd
,readfds
,ads
->tcpsocket
);
201 inter_addfd(maxfd
,exceptfds
,ads
->tcpsocket
);
202 if (ads
->opbufused
) inter_addfd(maxfd
,writefds
,ads
->tcpsocket
);
209 static int internal_check(adns_state ads
,
210 adns_query
*query_io
,
211 adns_answer
**answer
,
217 if (!ads
->output
.head
) return EWOULDBLOCK
;
218 qu
= ads
->output
.head
;
220 if (qu
->id
>=0) return EWOULDBLOCK
;
222 LIST_UNLINK(ads
->output
,qu
);
224 if (context_r
) *context_r
= qu
->context
;
229 int adns_wait(adns_state ads
,
230 adns_query
*query_io
,
231 adns_answer
**answer_r
,
233 int r
, maxfd
, rsel
, rcb
;
234 fd_set readfds
, writefds
, exceptfds
;
235 struct timeval tvbuf
, *tvp
;
238 r
= internal_check(ads
,query_io
,answer_r
,context_r
);
239 if (r
&& r
!= EWOULDBLOCK
) return r
;
240 FD_ZERO(&readfds
); FD_ZERO(&writefds
); FD_ZERO(&exceptfds
);
242 adns_interest(ads
,&maxfd
,&readfds
,&writefds
,&exceptfds
,&tvp
,&tvbuf
);
243 rsel
= select(maxfd
,&readfds
,&writefds
,&exceptfds
,tvp
);
244 if (rsel
==-1) return r
;
245 rcb
= adns_callback(ads
,maxfd
,&readfds
,&writefds
,&exceptfds
);
250 int adns_check(adns_state ads
,
251 adns_query
*query_io
,
252 adns_answer
**answer_r
,
255 return internal_check(ads
,query_io
,answer_r
,context_r
);