void hclib_end_finish() { hclib_worker_state *ws = CURRENT_WS_INTERNAL; finish_t *current_finish = ws->current_finish; hclib_task_t *current_task = ws->curr_task; #ifdef VERBOSE fprintf(stderr, "hclib_end_finish: ending finish %p on worker %p\n", current_finish, CURRENT_WS_INTERNAL); #endif #ifdef HCLIB_STATS worker_stats[CURRENT_WS_INTERNAL->id].count_end_finishes++; #endif HASSERT(current_finish); HASSERT(current_finish->counter > 0); help_finish(current_finish); check_out_finish(current_finish->parent); // NULL check in check_out_finish #ifdef VERBOSE fprintf(stderr, "hclib_end_finish: out of finish, setting current finish " "of %p to %p from %p\n", CURRENT_WS_INTERNAL, current_finish->parent, current_finish); #endif // Don't reuse worker-state! (we might not be on the same worker anymore) ws = CURRENT_WS_INTERNAL; ws->current_finish = current_finish->parent; ws->curr_task = current_task; free(current_finish); }
/* 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; } }