void _wake_up(register struct wait_queue *q, unsigned short int it) { register struct task_struct *p; // FIXME: task list not protected against interruption for_each_task(p) { if ((p->waitpt == q) || ((p->waitpt == &select_queue) && select_poll (p, q)) ) if (p->state == TASK_INTERRUPTIBLE || (it && p->state == TASK_UNINTERRUPTIBLE)) { wake_up_process(p); } } }
int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, struct timeval *timeout) { int rv = -1, old, tmo; // This is a fairly quick operation for us, and we don't want the // results to change out from under us. So unlike the BSD design, // we'll actually disable ints temporarily here. old = irq_disable(); // Figure out the timeout in milliseconds if (!timeout) tmo = -1; else { tmo = timeout->tv_sec*1000 + timeout->tv_usec/1000; } // Until we have something... do { // Poll everything rv = select_poll(maxfdp1, readset, writeset, exceptset); if (rv == 0) { // Zero timeout -- report immediately if (tmo == 0) break; else if (!timeout) genwait_wait(&select_wait, "lwip_select", 0, NULL); else genwait_wait(&select_wait, "lwip_select", tmo, NULL); } } while (rv == 0); // In case of a timeout, zero the sets. if (!rv) { if (readset) FD_ZERO(readset); if (writeset) FD_ZERO(writeset); } // Restore stuff irq_restore(old); return rv; }
/* Just poll without blocking */ static int select_poll(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds) { int i, n = 0; #ifdef HAVE_LWIP int sock_n = 0, sock_nfds = 0; fd_set sock_readfds, sock_writefds, sock_exceptfds; struct timeval timeout = { .tv_sec = 0, .tv_usec = 0}; #endif #ifdef LIBC_VERBOSE static int nb; static int nbread[NOFILE], nbwrite[NOFILE], nbexcept[NOFILE]; static s_time_t lastshown; nb++; #endif #ifdef HAVE_LWIP /* first poll network */ FD_ZERO(&sock_readfds); FD_ZERO(&sock_writefds); FD_ZERO(&sock_exceptfds); for (i = 0; i < nfds; i++) { if (files[i].type == FTYPE_SOCKET) { if (FD_ISSET(i, readfds)) { FD_SET(files[i].socket.fd, &sock_readfds); sock_nfds = i+1; } if (FD_ISSET(i, writefds)) { FD_SET(files[i].socket.fd, &sock_writefds); sock_nfds = i+1; } if (FD_ISSET(i, exceptfds)) { FD_SET(files[i].socket.fd, &sock_exceptfds); sock_nfds = i+1; } } } if (sock_nfds > 0) { DEBUG("lwip_select("); dump_set(nfds, &sock_readfds, &sock_writefds, &sock_exceptfds, &timeout); DEBUG("); -> "); sock_n = lwip_select(sock_nfds, &sock_readfds, &sock_writefds, &sock_exceptfds, &timeout); dump_set(nfds, &sock_readfds, &sock_writefds, &sock_exceptfds, &timeout); DEBUG("\n"); } #endif /* Then see others as well. */ for (i = 0; i < nfds; i++) { switch(files[i].type) { default: if (FD_ISSET(i, readfds) || FD_ISSET(i, writefds) || FD_ISSET(i, exceptfds)) printk("bogus fd %d in select\n", i); /* Fallthrough. */ case FTYPE_CONSOLE: if (FD_ISSET(i, readfds)) { if (xencons_ring_avail(files[i].cons.dev)) n++; else FD_CLR(i, readfds); } if (FD_ISSET(i, writefds)) n++; FD_CLR(i, exceptfds); break; #ifdef CONFIG_XENBUS case FTYPE_XENBUS: if (FD_ISSET(i, readfds)) { if (files[i].xenbus.events) n++; else FD_CLR(i, readfds); } FD_CLR(i, writefds); FD_CLR(i, exceptfds); break; #endif case FTYPE_EVTCHN: case FTYPE_TAP: case FTYPE_BLK: case FTYPE_KBD: case FTYPE_FB: if (FD_ISSET(i, readfds)) { if (files[i].read) n++; else FD_CLR(i, readfds); } FD_CLR(i, writefds); FD_CLR(i, exceptfds); break; #ifdef HAVE_LWIP case FTYPE_SOCKET: if (FD_ISSET(i, readfds)) { /* Optimize no-network-packet case. */ if (sock_n && FD_ISSET(files[i].socket.fd, &sock_readfds)) n++; else FD_CLR(i, readfds); } if (FD_ISSET(i, writefds)) { if (sock_n && FD_ISSET(files[i].socket.fd, &sock_writefds)) n++; else FD_CLR(i, writefds); } if (FD_ISSET(i, exceptfds)) { if (sock_n && FD_ISSET(files[i].socket.fd, &sock_exceptfds)) n++; else FD_CLR(i, exceptfds); } break; #endif } #ifdef LIBC_VERBOSE if (FD_ISSET(i, readfds)) nbread[i]++; if (FD_ISSET(i, writefds)) nbwrite[i]++; if (FD_ISSET(i, exceptfds)) nbexcept[i]++; #endif } #ifdef LIBC_VERBOSE if (NOW() > lastshown + 1000000000ull) { lastshown = NOW(); printk("%lu MB free, ", num_free_pages() / ((1 << 20) / PAGE_SIZE)); printk("%d(%d): ", nb, sock_n); for (i = 0; i < nfds; i++) { if (nbread[i] || nbwrite[i] || nbexcept[i]) printk(" %d(%c):", i, file_types[files[i].type]); if (nbread[i]) printk(" %dR", nbread[i]); if (nbwrite[i]) printk(" %dW", nbwrite[i]); if (nbexcept[i]) printk(" %dE", nbexcept[i]); } printk("\n"); memset(nbread, 0, sizeof(nbread)); memset(nbwrite, 0, sizeof(nbwrite)); memset(nbexcept, 0, sizeof(nbexcept)); nb = 0; } #endif return n; } /* The strategy is to * - announce that we will maybe sleep * - poll a bit ; if successful, return * - if timeout, return * - really sleep (except if somebody woke us in the meanwhile) */ int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) { int n, ret; fd_set myread, mywrite, myexcept; struct thread *thread = get_current(); s_time_t start = NOW(), stop; #ifdef CONFIG_NETFRONT DEFINE_WAIT(netfront_w); #endif DEFINE_WAIT(event_w); #ifdef CONFIG_BLKFRONT DEFINE_WAIT(blkfront_w); #endif #ifdef CONFIG_XENBUS DEFINE_WAIT(xenbus_watch_w); #endif #ifdef CONFIG_KBDFRONT DEFINE_WAIT(kbdfront_w); #endif DEFINE_WAIT(console_w); assert(thread == main_thread); DEBUG("select(%d, ", nfds); dump_set(nfds, readfds, writefds, exceptfds, timeout); DEBUG(");\n"); if (timeout) stop = start + SECONDS(timeout->tv_sec) + timeout->tv_usec * 1000; else /* just make gcc happy */ stop = start; /* Tell people we're going to sleep before looking at what they are * saying, hence letting them wake us if events happen between here and * schedule() */ #ifdef CONFIG_NETFRONT add_waiter(netfront_w, netfront_queue); #endif add_waiter(event_w, event_queue); #ifdef CONFIG_BLKFRONT add_waiter(blkfront_w, blkfront_queue); #endif #ifdef CONFIG_XENBUS add_waiter(xenbus_watch_w, xenbus_watch_queue); #endif #ifdef CONFIG_KBDFRONT add_waiter(kbdfront_w, kbdfront_queue); #endif add_waiter(console_w, console_queue); if (readfds) myread = *readfds; else FD_ZERO(&myread); if (writefds) mywrite = *writefds; else FD_ZERO(&mywrite); if (exceptfds) myexcept = *exceptfds; else FD_ZERO(&myexcept); DEBUG("polling "); dump_set(nfds, &myread, &mywrite, &myexcept, timeout); DEBUG("\n"); n = select_poll(nfds, &myread, &mywrite, &myexcept); if (n) { dump_set(nfds, readfds, writefds, exceptfds, timeout); if (readfds) *readfds = myread; if (writefds) *writefds = mywrite; if (exceptfds) *exceptfds = myexcept; DEBUG(" -> "); dump_set(nfds, readfds, writefds, exceptfds, timeout); DEBUG("\n"); wake(thread); ret = n; goto out; } if (timeout && NOW() >= stop) { if (readfds) FD_ZERO(readfds); if (writefds) FD_ZERO(writefds); if (exceptfds) FD_ZERO(exceptfds); timeout->tv_sec = 0; timeout->tv_usec = 0; wake(thread); ret = 0; goto out; } if (timeout) thread->wakeup_time = stop; schedule(); if (readfds) myread = *readfds; else FD_ZERO(&myread); if (writefds) mywrite = *writefds; else FD_ZERO(&mywrite); if (exceptfds) myexcept = *exceptfds; else FD_ZERO(&myexcept); n = select_poll(nfds, &myread, &mywrite, &myexcept); if (n) { if (readfds) *readfds = myread; if (writefds) *writefds = mywrite; if (exceptfds) *exceptfds = myexcept; ret = n; goto out; } errno = EINTR; ret = -1; out: #ifdef CONFIG_NETFRONT remove_waiter(netfront_w, netfront_queue); #endif remove_waiter(event_w, event_queue); #ifdef CONFIG_BLKFRONT remove_waiter(blkfront_w, blkfront_queue); #endif #ifdef CONFIG_XENBUS remove_waiter(xenbus_watch_w, xenbus_watch_queue); #endif #ifdef CONFIG_KBDFRONT remove_waiter(kbdfront_w, kbdfront_queue); #endif remove_waiter(console_w, console_queue); return ret; }
/* The strategy is to * - announce that we will maybe sleep * - poll a bit ; if successful, return * - if timeout, return * - really sleep (except if somebody woke us in the meanwhile) */ int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) { int n, ret; fd_set myread, mywrite, myexcept; struct thread *thread = get_current(); s_time_t start = NOW(), stop; DEFINE_WAIT(w1); DEFINE_WAIT(w2); DEFINE_WAIT(w3); DEFINE_WAIT(w4); DEFINE_WAIT(w5); DEFINE_WAIT(w6); int n_sockets; int n_non_sockets; assert(thread == main_thread); n_sockets = 0; n_non_sockets = 0; for (n = 0; n <= nfds; n++) { if ((readfds && FD_ISSET(n, readfds)) || (writefds && FD_ISSET(n, writefds)) || (exceptfds && FD_ISSET(n, exceptfds))) { if (files[n].type == FTYPE_SOCKET) n_sockets++; else n_non_sockets++; } } if (n_sockets != 0 && n_non_sockets != 0) { static int cntr; if (cntr < 1000) { printk("WARNING: select combining socket and non-socket FDs (n = %d vs %d); warning %d/1000\n", n_sockets, n_non_sockets, cntr); cntr++; } } if (n_non_sockets == 0) return do_lwip_select(nfds, readfds, writefds, exceptfds, timeout); if (timeout) stop = start + SECONDS(timeout->tv_sec) + timeout->tv_usec * 1000; else /* just make gcc happy */ stop = start; /* Tell people we're going to sleep before looking at what they are * saying, hence letting them wake us if events happen between here and * schedule() */ add_waiter(w1, netfront_queue); add_waiter(w2, event_queue); add_waiter(w3, blkfront_queue); add_waiter(w4, xenbus_watch_queue); add_waiter(w5, kbdfront_queue); add_waiter(w6, console_queue); if (readfds) myread = *readfds; else FD_ZERO(&myread); if (writefds) mywrite = *writefds; else FD_ZERO(&mywrite); if (exceptfds) myexcept = *exceptfds; else FD_ZERO(&myexcept); DEBUG("polling "); dump_set(nfds, &myread, &mywrite, &myexcept, timeout); DEBUG("\n"); n = select_poll(nfds, &myread, &mywrite, &myexcept); if (n) { dump_set(nfds, readfds, writefds, exceptfds, timeout); if (readfds) *readfds = myread; if (writefds) *writefds = mywrite; if (exceptfds) *exceptfds = myexcept; DEBUG(" -> "); dump_set(nfds, readfds, writefds, exceptfds, timeout); DEBUG("\n"); wake(thread); ret = n; goto out; } if (timeout && NOW() >= stop) { if (readfds) FD_ZERO(readfds); if (writefds) FD_ZERO(writefds); if (exceptfds) FD_ZERO(exceptfds); timeout->tv_sec = 0; timeout->tv_usec = 0; wake(thread); ret = 0; goto out; } if (timeout) thread->wakeup_time = stop; schedule(); if (readfds) myread = *readfds; else FD_ZERO(&myread); if (writefds) mywrite = *writefds; else FD_ZERO(&mywrite); if (exceptfds) myexcept = *exceptfds; else FD_ZERO(&myexcept); n = select_poll(nfds, &myread, &mywrite, &myexcept); if (n) { if (readfds) *readfds = myread; if (writefds) *writefds = mywrite; if (exceptfds) *exceptfds = myexcept; ret = n; goto out; } errno = EINTR; ret = -1; out: remove_waiter(w1); remove_waiter(w2); remove_waiter(w3); remove_waiter(w4); remove_waiter(w5); remove_waiter(w6); return ret; }
/* ask a helper process to do some filtering */ u_char /* 1=got an answer */ ask_helper(DCC_CLNT_CTXT *ctxt, void *logp, time_t avail_us, /* spend at most this much time */ HELPER_REQ_HDR *req, /* request sent to helper */ int req_len, HELPER_RESP_HDR *resp, /* put answer here */ int resp_len) { DCC_EMSG emsg; DCC_SOCKU send_su; socklen_t su_len; DCC_SOCKU recv_su; char sustr[DCC_SU2STR_SIZE]; char sustr2[DCC_SU2STR_SIZE]; u_char counted; u_int gen; struct timeval now; time_t us; DCC_POLLFD pollfd; int i; emsg[0] = '\0'; /* We will use the client context socket to talk to the helper, * so ensure that it is open */ if (!helper_soc_open(emsg, ctxt)) { thr_trace_msg(logp, "DNSBL reopen %s", emsg); return 0; } /* keep the lock until we have sent our request and wake-up call * to ensure that some other thread does not shut down all of * the helpers. */ helper_lock(); gettimeofday(&now, 0); /* If it has been a long time since we used a helper, then the last * of them might be about to die of boredom. Fix that race by * restarting all of them. * Most dying helpers should be reaped by the totals timer thread. */ if (helper.idle_helpers > 0 && DCC_IS_TIME(now.tv_sec, helper.idle_restart, HELPER_IDLE_RESTART)) { reap_helpers(1); if (helper.idle_helpers > 0) terminate_helpers(); gettimeofday(&now, 0); } /* Restart all helpers if the current helper socket is the wrong * family. This should happen only when the DCC client library * has chosen a new server */ if (helper.soc != INVALID_SOCKET && ctxt->soc[0].loc.sa.sa_family != AF_UNSPEC && helper.su.sa.sa_family != ctxt->soc[0].loc.sa.sa_family) { terminate_helpers(); gettimeofday(&now, 0); } helper.idle_restart = now.tv_sec + HELPER_IDLE_RESTART; if (helper.idle_helpers - helper.slow_helpers > 0) { /* avoid taking the last idle helper because there are * usually fewer truly idle helpers than we think because * we don't always wait for them to finish */ if (helper.idle_helpers > 2 || helper.total_helpers >= helper.max_helpers || !new_helper(ctxt, logp, req->id)) --helper.idle_helpers; counted = 1; } else if (helper.total_helpers >= helper.max_helpers) { if (helper.debug > 0) thr_trace_msg(logp, "%s DNSBL %d idle, %d slow, and" " %d total DNSBL helpers", req->id, helper.idle_helpers, helper.slow_helpers, helper.total_helpers); counted = 0; } else { if (!new_helper(ctxt, logp, req->id)) { helper_unlock(); return 0; } counted = 1; } /* The resolution of the BIND timeout limits is seconds, so even on * systems where the timeout limits work, the helper might delay * a second or two. To keep the count of idle helpers as accurate * as possible, always wait at least 1 second for an answer * and 2 seconds for an answer to reach the parent. */ req->avail_us = avail_us; avail_us += DCC_US; req->start = now; req->magic = HELPER_MAGIC_REQ; req->version = HELPER_VERSION; req->sn = ++helper.sn; gen = helper.gen; /* snapshot the address in case another thread restarts the helpers */ send_su = helper.su; /* If the client context socket is connected but not to the helper * socket, * then either disconnect it or connect to the helper's socket */ if (ctxt->soc[0].rem.sa.sa_family != AF_UNSPEC && !DCC_SU_EQ(&ctxt->soc[0].rem, &send_su) && !helper_soc_connect(emsg, ctxt, &send_su)) { thr_trace_msg(logp, "DNSBL soc_connect(): %s", emsg); help_finish(gen, 0, counted, 1); helper_unlock(); return 0; } if (ctxt->soc[0].rem.sa.sa_family == AF_UNSPEC) { i = sendto(ctxt->soc[0].s, req, req_len, 0, &send_su.sa, DCC_SU_LEN(&send_su)); } else { i = send(ctxt->soc[0].s, req, req_len, 0); } if (i != req_len) { if (i < 0) thr_trace_msg(logp, "%s DNSBL sendto(%s): %s", req->id, dcc_su2str(sustr, sizeof(sustr), &send_su), ERROR_STR()); else thr_trace_msg(logp, "%s DNSBL sendto(%s)=%d", req->id, dcc_su2str(sustr, sizeof(sustr), &send_su), i); help_finish(gen, 0, counted, 1); helper_unlock(); return 0; } /* awaken a helper */ i = write(helper.pipe_write, "x", 1); if (i != 1) { if (i < 0) thr_trace_msg(logp, "%s DNSBL write(pipe_write=%d): %s", req->id, helper.pipe_write, ERROR_STR()); else thr_trace_msg(logp, "%s DNSBL write(pipe_write)=%d", req->id, i); help_finish(gen, 0, counted, 1); helper_unlock(); return 0; } helper_unlock(); for (;;) { us = avail_us - tv_diff2us(&now, &req->start); if (us < 0) us = 0; pollfd.fd = ctxt->soc[0].s; i = select_poll(emsg, &pollfd, 1, 1, us); if (i < 0) { thr_error_msg(logp, "%s DNSBL %s", req->id, emsg); help_finish(gen, 0, counted, 0); return 0; } gettimeofday(&now, 0); if (i == 0) { if (helper.debug) thr_trace_msg(logp, "%s DNSBL no helper answer after" " %1.f sec", req->id, tv_diff2us(&now, &req->start) / (DCC_US*1.0)); helper_lock(); if (helper.slow_helpers<=helper.total_helpers/MAX_SLOW) ++helper.slow_helpers; help_finish(gen, 0, counted, 1); helper_unlock(); return 0; } su_len = sizeof(recv_su); i = recvfrom(ctxt->soc[0].s, resp, resp_len, 0, &recv_su.sa, &su_len); /* because we are using UDP, we might get stray packets */ if (i != resp_len) { if (i < 0) { thr_trace_msg(logp, "%s DNSBL recvfrom(): %s", req->id, ERROR_STR()); if (DCC_BLOCK_ERROR()) continue; help_finish(gen, 0, counted, 0); return 0; } if (helper.debug > 1) thr_trace_msg(logp, "%s DNSBL recvfrom(%s)=%d", req->id, dcc_su2str(sustr, sizeof(sustr), &recv_su), i); continue; } if (!DCC_SUnP_EQ(&send_su, &recv_su)) { if (helper.debug != 0) thr_trace_msg(logp, "%s DNSBL recvfrom(%s)" " instead of %s", req->id, dcc_su2str(sustr, sizeof(sustr), &recv_su), dcc_su2str(sustr2, sizeof(sustr2), &send_su)); continue; } if (resp->magic != HELPER_MAGIC_RESP || resp->version != HELPER_VERSION || resp->sn != req->sn) { if (helper.debug >1 ) thr_trace_msg(logp, "%s DNSBL recvfrom(%s)" " magic=%#08x sn=%d", req->id, dcc_su2str(sustr, sizeof(sustr), &recv_su), resp->magic, resp->sn); continue; } if (helper.debug > 4) thr_trace_msg(logp,"%s DNSBL answer from %s", req->id, dcc_su2str(sustr, sizeof(sustr), &recv_su)); help_finish(gen, 1, counted, 0); return 1; } }
/* helper processes start here via fork()/exec() in the parent */ void DCC_NORET helper_child(DCC_SOCKET s, int fd, int total_helpers) { sigset_t sigs; socklen_t soc_len; DNSBL_REQ req; int req_len; DNSBL_RESP resp; DCC_SOCKU req_su; socklen_t su_len; struct timeval now; u_char wake_buf; int secs, i; /* this process inherits via exec() by dccm or dccifd odd signal * blocking from some pthreads implementations including FreeBSD 5.* */ signal(SIGHUP, SIG_IGN); signal(SIGINT, SIG_IGN); signal(SIGTERM, SIG_IGN); sigemptyset(&sigs); sigaddset(&sigs, SIGALRM); sigprocmask(SIG_UNBLOCK, &sigs, 0); helper_init(0); if (have_helpers) dcc_logbad(EX_SOFTWARE, "no threads for DNSBL helpers"); helper.total_helpers = total_helpers; helper.pipe_read = fd; helper.soc = s; soc_len = sizeof(helper.su); if (0 > getsockname(helper.soc, &helper.su.sa, &soc_len)) dcc_logbad(EX_IOERR, "DNSBL helper getsockname(%d): %s", helper.soc, ERROR_STR()); if (helper.debug > 1) dcc_trace_msg("DNSBL helper process starting on %s", dcc_su2str_err(&helper.su)); for (;;) { /* Use read() and SIGALRM to watch for a wake-up byte * from the parent, the parent ending and closing the pipe, * or enough idle time to require our retirement. This * tactic awakens a single child for each wake-up call * from the parent. Using select() or poll() on the main * socket awakens a thundering herd of children */ secs = HELPER_IDLE_STOP_SECS+1; if (helper.total_helpers > 0) secs /= helper.total_helpers+1; if (secs < 5) secs = 5; signal(SIGALRM, helper_alarm); #ifdef HAVE_SIGINTERRUPT siginterrupt(SIGALRM, 1); #endif helper_alarm_hit = 0; alarm(secs); for (;;) { su_len = sizeof(req_su); req_len = recvfrom(helper.soc, &req, ISZ(req), 0, &req_su.sa, &su_len); /* sleep until awakened if no work is ready */ if (req_len <= 0) { if (req_len == 0) dcc_logbad(EX_IOERR, "DNSBL helper recvfrom()=0"); if (!DCC_BLOCK_ERROR()) dcc_logbad(EX_IOERR, "DNSBL helper recvfrom():" " %s", ERROR_STR()); if (helper_alarm_hit) helper_exit("idle helper exit"); i = read(helper.pipe_read, &wake_buf, 1); /* The other end of the pipe can be marked * non-blocking by some pthreads * implementations. That makes read() on this * end fail with EAGAIN. When that happens, * fall back on select() or poll(). * Even on such pthread implementations, * it rarely happens. */ if (i < 0 && DCC_BLOCK_ERROR()) { DCC_POLLFD pollfd; DCC_EMSG emsg; pollfd.fd = helper.pipe_read; i = select_poll(emsg, &pollfd, 1, 0, -1); if (i < 0) dcc_logbad(EX_IOERR, "dnsbl HELPER %s", emsg); } /* loof for work after a wake-up call */ if (i > 0) continue; if (helper_alarm_hit) continue; if (i == 0) helper_exit("shutdown"); if (i < 0) { dcc_logbad(EX_OSERR, "DNSBL read(terminate): %s", ERROR_STR()); } } if (req_len != helper.req_len) { if (helper.debug) dcc_trace_msg("DNSBL helper" " recvfrom(parent %s)=%d" " instead of %d", dcc_su2str_err(&req_su), req_len, helper.req_len); continue; } /* we might get stray packets because we cannot * connect to a single port */ if (!DCC_SUnP_EQ(&helper.su, &req_su)) { if (helper.debug) dcc_trace_msg("DNSBL helper" " request from" " %s instead of %s", dcc_su2str_err(&req_su), dcc_su2str_err(&helper.su)); continue; } if (req.hdr.magic != HELPER_MAGIC_REQ || req.hdr.version != HELPER_VERSION) { if (helper.debug) dcc_trace_msg("DNSBL helper" " recvfrom(parent %s)" " magic=%#08x", dcc_su2str_err(&req_su), req.hdr.magic); continue; } break; } gettimeofday(&now, 0); alarm(0); /* do not bother working if it is already too late to answer, * perhaps because a previous helper died */ i = tv_diff2us(&now, &req.hdr.start); if (i >= req.hdr.avail_us) { if (helper.debug > 1) dcc_trace_msg("%s DNSBL helper" " already too late to start;" " used %.1f of %.1f seconds", req.hdr.id, i / (DCC_US*1.0), req.hdr.avail_us / (DCC_US*1.0)); continue; } memset(&resp, 0, sizeof(resp)); resp.hdr.magic = HELPER_MAGIC_RESP; resp.hdr.version = HELPER_VERSION; resp.hdr.sn = req.hdr.sn; /* do the work and send an answer if we have one */ if (!dnsbl_work(&req, &resp)) continue; /* do not answer if it is too late */ gettimeofday(&now, 0); i = tv_diff2us(&now, &req.hdr.start); if (i > (req.hdr.avail_us + DCC_US/2)) { if (helper.debug > 1) dcc_trace_msg("%s DNSBL helper" " too late to answer;" " used %.1f of %.1f seconds", req.hdr.id, i / (DCC_US*1.0), req.hdr.avail_us / (DCC_US*1.0)); continue; } i = sendto(helper.soc, &resp, sizeof(resp), 0, &req_su.sa, DCC_SU_LEN(&req_su)); if (i != sizeof(resp)) { if (i < 0) dcc_error_msg("%s helper sendto(%s): %s", req.hdr.id, dcc_su2str_err(&req_su), ERROR_STR()); else dcc_error_msg("%s helper sendto(%s)=%d", req.hdr.id, dcc_su2str_err(&req_su), i); } } }