fd<maxfd && FD_ISSET(fd,fds);
}
-static void tcpserver_broken(adns_state ads, const char *what, const char *why) {
- assert(ads->tcpstate == server_connecting || ads->tcpstate == server_connected);
+void adns__tcp_broken(adns_state ads, const char *what, const char *why) {
+ int serv;
+
+ assert(ads->tcpstate == server_connecting || ads->tcpstate == server_ok);
warn("nameserver %s TCP connection lost: %s: %s",
inet_ntoa(ads->servers[tcpserver].addr,what,why));
close(ads->tcpsocket);
ads->tcpstate= server_disconnected;
+ serv= ads->tcpserver;
-
+ for (qu= ads->timew; qu; qu= nqu) {
+ nqu= qu->next;
+ if (qu->senttcpserver == -1) continue;
+ assert(qu->senttcpserver == serv);
+ DLIST_UNLINK(ads->timew,qu);
+ adns__query_fail(ads,qu,adns_s_connlost); /* wishlist: send to other servers ? */
+ }
+
+ ads->tcpbuf.used= 0;
+ ads->tcpserver= (serv+1)%ads->nservers;
+}
+
+void adns__tcp_tryconnect(adns_state ads) {
+ int r, fd, tries;
+ sockaddr_in addr;
+
+ for (tries=0; tries<ads->nservers; tries++) {
+ if (ads->tcpstate == server_connecting || ads->tcpstate == server_ok) return;
+ assert(ads->tcpstate == server_disconnected);
+ assert(!ads->tcpbuf.used);
+
+ proto= getprotobyname("tcp");
+ if (!proto) { diag(ads,"unable to find protocol number for TCP !",-1); return; }
+ fd= socket(AF_INET,SOCK_STREAM,proto->p_proto);
+ if (fd<0) { diag(ads,"cannot create TCP socket: %s",-1,strerror(errno)); return; }
+ if (!adns__setnonblock(fd)) return;
+ memset(&addr,0,sizeof(addr));
+ addr.sin_family= AF_INET;
+ addr.sin_port= htons(NSPORT);
+ addr.sin_addr= ads->servers[ads->tcpserver].addr;
+ r= connect(fd,&addr,sizeof(addr));
+ ads->tcpsocket= fd;
+ ads->tcpstate= server_connecting;
+ if (r==0) { ads->tcpstate= server_ok; return; }
+ if (errno == EWOULDBLOCK || errno == EINPROGRESS) return;
+ tcpserver_broken(ads,"connect",strerror(errno));
+ }
+}
+
int adns_callback(adns_state ads, int maxfd,
const fd_set *readfds, const fd_set *writefds,
const fd_set *exceptfds) {
} else if (r>0) {
tcpserver_broken(ads,"connect/read","sent data before first request");
} else if (errno!=EINTR) {
- tcpserver_broken(ads,"connect",strerror(errno));
+ tcpserver_broken(ads,"connect/read",strerror(errno));
}
}
}
adns_answer *answer;
size_t ansalloc; ansused;
int id, flags, udpretries; /* udpretries==-1 => _f_usevc or too big for UDP */
- int nextudpserver;
- unsigned long sentudp, senttcp; /* bitmaps indexed by server */
+ int nextudpserver, senttcpserver;
+ unsigned long sentudp; /* bitmap indexed by server */
struct timeval timeout;
void *context;
unsigned char *querymsg;
int nextid, udpsocket;
adns_vbuf rqbuf, tcpsend, tcprecv;
int nservers, tcpserver;
- enum adns__tcpstate { server_disc, server_connecting, server_ok } tcpstate;
+ enum adns__tcpstate { server_disconnected, server_connecting, server_ok } tcpstate;
int tcpsocket;
struct timeval tcptimeout;
struct server {
void adns__vdiag(adns_state ads, adns_initflags prevent, const char *pfx,
int serv, const char *fmt, va_list al);
-void adns__debug(adns_state ads, int serv, const char *fmt, ...) PRINTFFORMAT(2,3);
-void adns__warn(adns_state ads, int serv, const char *fmt, ...) PRINTFFORMAT(2,3);
-void adns__diag(adns_state ads, int serv, const char *fmt, ...) PRINTFFORMAT(2,3);
+void adns__debug(adns_state ads, int serv, const char *fmt, ...) PRINTFFORMAT(3,4);
+void adns__warn(adns_state ads, int serv, const char *fmt, ...) PRINTFFORMAT(3,4);
+void adns__diag(adns_state ads, int serv, const char *fmt, ...) PRINTFFORMAT(3,4);
/* From submit.c: */
/* From query.c: */
-void adns__quproc_tosend(adns_state ads, adns_query qu, struct timeval now) {
+void adns__quproc_tosend(adns_state ads, adns_query qu, struct timeval now);
+
+/* From event.c: */
+void adns__tcp_broken(adns_state ads, const char *what, const char *why);
+void adns__tcp_tryconnect(adns_state ads);
/* Useful static inline functions: */