adns_if_debug= 0x0008, /* enable all output to stderr plus debug msgs */
adns_if_noautosys= 0x0010, /* do not make syscalls at every opportunity */
adns_if_eintr= 0x0020, /* allow _wait and _synchronous to return EINTR */
+ adns_if_nosigpipe= 0x0040, /* applic has SIGPIPE set to SIG_IGN, do not protect */
} adns_initflags;
typedef enum {
} else if (callb_checkfd(maxfd,exceptfds,ads->tcpsocket)) {
adns__tcp_broken(ads,"select","exceptional condition detected");
} else if (ads->tcpsend.used && callb_checkfd(maxfd,writefds,ads->tcpsocket)) {
+ adns__sigpipe_protect(ads);
r= write(ads->tcpsocket,ads->tcpsend.buf,ads->tcpsend.used);
+ adns__sigpipe_unprotect(ads);
if (r<0) {
if (errno!=EAGAIN && errno!=EWOULDBLOCK && errno!=ENOMEM && errno!=EINTR) {
adns__tcp_broken(ads,"write",strerror(errno));
}
}
}
+
+/* SIGPIPE protection. */
+
+void adns__sigpipe_protect(adns_state ads) {
+ sigset_t toblock;
+ struct sigaction sa;
+ int r;
+
+ if (ads->iflags & adns_if_nosigpipe) return;
+
+ sigfillset(&toblock);
+ sigdelset(&toblock,SIGPIPE);
+
+ sa.sa_handler= SIG_IGN;
+ sigfillset(&sa.sa_mask);
+ sa.sa_flags= 0;
+
+ r= sigprocmask(SIG_SETMASK,&toblock,&ads->stdsigmask); assert(!r);
+ r= sigaction(SIGPIPE,&sa,&ads->stdsigpipe); assert(!r);
+}
+
+void adns__sigpipe_unprotect(adns_state ads) {
+ int r;
+
+ if (ads->iflags & adns_if_nosigpipe) return;
+
+ r= sigaction(SIGPIPE,&ads->stdsigpipe,0); assert(!r);
+ r= sigprocmask(SIG_SETMASK,&ads->stdsigmask,0); assert(!r);
+}
#include <stdarg.h>
#include <assert.h>
#include <unistd.h>
+#include <signal.h>
#include <sys/time.h>
int nservers, nsortlist, tcpserver;
enum adns__tcpstate { server_disconnected, server_connecting, server_ok } tcpstate;
struct timeval tcptimeout;
+ struct sigaction stdsigpipe;
+ sigset_t stdsigmask;
struct server {
struct in_addr addr;
} servers[MAXSERVERS];
* sz bytes long. needswap should return !0 if a>b (strictly, ie
* wrong order) 0 if a<=b (ie, order is fine).
*/
-
+
+void adns__sigpipe_protect(adns_state);
+void adns__sigpipe_unprotect(adns_state);
+/* If SIGPIPE protection is not disabled, will block all signals except
+ * SIGPIPE, and set SIGPIPE's disposition to SIG_IGN. (And then restore.)
+ * Each call to _protect must be followed by a call to _unprotect before
+ * any significant amount of code gets to run.
+ */
+
/* From transmit.c: */
adns_status adns__mkquery(adns_state ads, vbuf *vb, int *id_r,
iov[0].iov_len= 2;
iov[1].iov_base= qu->query_dgram;
iov[1].iov_len= qu->query_dglen;
+ adns__sigpipe_protect(qu->ads);
wr= writev(qu->ads->tcpsocket,iov,2);
+ adns__sigpipe_unprotect(qu->ads);
if (wr < 0) {
if (!(errno == EAGAIN || errno == EINTR || errno == ENOSPC ||
errno == ENOBUFS || errno == ENOMEM)) {