static int ares_waitperform(struct connectdata *conn, int timeout_ms) { struct SessionHandle *data = conn->data; int nfds; int bitmask; int socks[ARES_GETSOCK_MAXNUM]; struct pollfd pfd[ARES_GETSOCK_MAXNUM]; int m; int i; int num; bitmask = ares_getsock(data->state.areschannel, socks, ARES_GETSOCK_MAXNUM); for(i=0; i < ARES_GETSOCK_MAXNUM; i++) { pfd[i].events = 0; m=0; if(ARES_GETSOCK_READABLE(bitmask, i)) { pfd[i].fd = socks[i]; pfd[i].events |= POLLRDNORM|POLLIN; m=1; } if(ARES_GETSOCK_WRITABLE(bitmask, i)) { pfd[i].fd = socks[i]; pfd[i].events |= POLLWRNORM|POLLOUT; m=1; } pfd[i].revents=0; if(!m) break; } num = i; if(num) nfds = Curl_poll(pfd, num, timeout_ms); else nfds = 0; if(!nfds) /* Call ares_process() unconditonally here, even if we simply timed out above, as otherwise the ares name resolve won't timeout! */ ares_process_fd(data->state.areschannel, ARES_SOCKET_BAD, ARES_SOCKET_BAD); else { /* move through the descriptors and ask for processing on them */ for(i=0; i < num; i++) ares_process_fd(data->state.areschannel, pfd[i].revents & (POLLRDNORM|POLLIN)? pfd[i].fd:ARES_SOCKET_BAD, pfd[i].revents & (POLLWRNORM|POLLOUT)? pfd[i].fd:ARES_SOCKET_BAD); } return nfds; }
tt_bool_t __do_read_write(IN tt_io_ev_t *io_ev) { __dskt_t *dskt = TT_CONTAINER(io_ev, __dskt_t, ev); uint32_t events = io_ev->epev->events; ares_socket_t rs, ws; TT_ASSERT(dskt->status = __DNS_READ_WRITE); dskt->status = __DNS_NULL; if (events & ~EPOLLOUT) { // read if it sees any ev other than EPOLLOUT(EPOLLIN, error, etc.) rs = __DSKT_IDX(dskt); } else { rs = ARES_SOCKET_BAD; } if (events & EPOLLOUT) { ws = __DSKT_IDX(dskt); } else { ws = ARES_SOCKET_BAD; } ares_process_fd(dskt->ch, rs, ws); return TT_TRUE; }
// Called when an ARES socket is ready static void process_ares(ph_job_t *job, ph_iomask_t why, void *data) { ph_dns_channel_t *chan = data; ares_socket_t fd; ares_socket_t rfd = ARES_SOCKET_BAD; ares_socket_t wfd = ARES_SOCKET_BAD; fd = job->fd; if (why & PH_IOMASK_READ) { rfd = job->fd; } if (why & PH_IOMASK_WRITE) { wfd = job->fd; } pthread_mutex_lock(&chan->chanlock); ares_process_fd(chan->chan, rfd, wfd); if (ph_ht_lookup(&chan->sock_map, &fd, &job, false) == PH_OK && ph_job_get_kmask(job) == 0) { // Didn't delete it, but didn't reschedule it, so do that now apply_mask(chan, job, job->mask ? job->mask : PH_IOMASK_READ); } pthread_mutex_unlock(&chan->chanlock); }
/* called via uv_poll when ares completion port signaled */ void uv_process_ares_event_req(uv_loop_t* loop, uv_ares_action_t* handle, uv_req_t* req) { ares_process_fd(loop->ares_chan, handle->read ? handle->sock : INVALID_SOCKET, handle->write ? handle->sock : INVALID_SOCKET); /* release handle for select here */ free(handle); }
static void uv__ares_io(EV_P_ struct ev_io* watcher, int revents) { /* Reset the idle timer */ ev_timer_again(EV_A_ &ares_data.timer); /* Process DNS responses */ ares_process_fd(ares_data.channel, revents & EV_READ ? watcher->fd : ARES_SOCKET_BAD, revents & EV_WRITE ? watcher->fd : ARES_SOCKET_BAD); }
/* * DNS timeout callback */ static void resolv_timeout_cb(struct ev_loop *loop, struct ev_timer *w, int revents) { struct resolv_ctx *ctx = cork_container_of(w, struct resolv_ctx, tw); ares_process_fd(ctx->channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD); reset_timer(); }
void Resolver::on_timer(tornado::IOLoop::TimerID tid, int64_t expiration) { TORNADO_LOG_DEBUG_STR("timeout"); assert(tid == timer_); if(timer_ != 0)//have clear { timer_ = 0; ares_process_fd(channel_, ARES_SOCKET_BAD, ARES_SOCKET_BAD); } }
tt_bool_t __do_write(IN tt_io_ev_t *io_ev) { __dskt_t *dskt = TT_CONTAINER(io_ev, __dskt_t, ev); TT_ASSERT(dskt->status = __DNS_WRITE); dskt->status = __DNS_NULL; ares_process_fd(dskt->ch, ARES_SOCKET_BAD, __DSKT_IDX(dskt)); return TT_TRUE; }
void Resolver::process_fd(int32_t fd, uint32_t events) { TORNADO_LOG_DEBUG("fd=%d, events=%u", fd, events); assert(channel_ != nullptr); int read_fd = fd; int write_fd = read_fd; if(!(events & tornado::IOLoop::READ)) read_fd = ARES_SOCKET_BAD; if(!(events & tornado::IOLoop::WRITE)) write_fd = ARES_SOCKET_BAD; ares_process_fd(channel_, read_fd, write_fd); }
static PyObject * Channel_func_process_fd(Channel *self, PyObject *args) { long read_fd, write_fd; CHECK_CHANNEL(self); if (!PyArg_ParseTuple(args, "ll:process_fd", &read_fd, &write_fd)) { return NULL; } ares_process_fd(self->channel, (ares_socket_t)read_fd, (ares_socket_t)write_fd); Py_RETURN_NONE; }
static void uv__ares_io(struct ev_loop* ev, struct ev_io* watcher, int revents) { uv_loop_t* loop = ev_userdata(ev); assert(ev == loop->ev); /* Reset the idle timer */ uv_timer_again(&loop->timer); /* Process DNS responses */ ares_process_fd(loop->channel, revents & EV_READ ? watcher->fd : ARES_SOCKET_BAD, revents & EV_WRITE ? watcher->fd : ARES_SOCKET_BAD); }
void OnEventDNSTask(int fd, short event, void *arg) { struct DNSTask *dnstask = (struct DNSTask *) arg; debug("event:%s, LobjId:%d, Hostname %s", getActionText(event), dnstask->task->LObjId, dnstask->task->Record.HostName); if (event & EV_READ) { ares_process_fd(dnstask->channel, fd, ARES_SOCKET_BAD); } else if (event & EV_TIMEOUT) { dnstask->task->code = STATE_TIMEOUT; dnstask->task->callback(dnstask->task); } if (!dnstask->isNeed) { ares_destroy(dnstask->channel); event_del(&dnstask->ev); } }
/* * DNS UDP socket activity callback */ static void resolv_sock_cb(EV_P_ ev_io *w, int revents) { struct resolv_ctx *ctx = (struct resolv_ctx *)w; ares_socket_t rfd = ARES_SOCKET_BAD, wfd = ARES_SOCKET_BAD; if (revents & EV_READ) rfd = w->fd; if (revents & EV_WRITE) wfd = w->fd; ares_process_fd(ctx->channel, rfd, wfd); reset_timer(); }
/* * This is called once per second by loop->timer. It is used to * constantly callback into c-ares for possibly processing timeouts. */ static void uv__ares_timeout(uv_timer_t* handle, int status) { assert(!uv_ares_handles_empty(handle->loop)); ares_process_fd(handle->loop->channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD); }
int CDnsSocket::Write(void) { ares_process_fd(CDnsQuery::GetDnsChannel(), ARES_SOCKET_BAD, m_Socket); return 0; }
int CDnsSocket::Read(bool DontProcess) { ares_process_fd(CDnsQuery::GetDnsChannel(), m_Socket, ARES_SOCKET_BAD); return 0; }
bool LLAres::process(U64 timeout) { if (!gAPRPoolp) { ll_init_apr(); } ares_socket_t socks[ARES_GETSOCK_MAXNUM]; apr_pollfd_t aprFds[ARES_GETSOCK_MAXNUM]; apr_int32_t nsds = 0; int nactive = 0; int bitmask; bitmask = ares_getsock(chan_, socks, ARES_GETSOCK_MAXNUM); if (bitmask == 0) { return nsds > 0; } apr_status_t status; LLAPRPool pool; status = pool.getStatus() ; ll_apr_assert_status(status); for (int i = 0; i < ARES_GETSOCK_MAXNUM; i++) { if (ARES_GETSOCK_READABLE(bitmask, i)) { aprFds[nactive].reqevents = APR_POLLIN | APR_POLLERR; } else if (ARES_GETSOCK_WRITABLE(bitmask, i)) { aprFds[nactive].reqevents = APR_POLLOUT | APR_POLLERR; } else { continue; } apr_socket_t *aprSock = NULL; status = apr_os_sock_put(&aprSock, (apr_os_sock_t *) &socks[i], pool.getAPRPool()); if (status != APR_SUCCESS) { ll_apr_warn_status(status); return nsds > 0; } aprFds[nactive].desc.s = aprSock; aprFds[nactive].desc_type = APR_POLL_SOCKET; aprFds[nactive].p = pool.getAPRPool(); aprFds[nactive].rtnevents = 0; aprFds[nactive].client_data = &socks[i]; nactive++; } if (nactive > 0) { status = apr_poll(aprFds, nactive, &nsds, timeout); if (status != APR_SUCCESS && status != APR_TIMEUP) { ll_apr_warn_status(status); } for (int i = 0; i < nactive; i++) { int evts = aprFds[i].rtnevents; int ifd = (evts & (APR_POLLIN | APR_POLLERR)) ? *((int *) aprFds[i].client_data) : ARES_SOCKET_BAD; int ofd = (evts & (APR_POLLOUT | APR_POLLERR)) ? *((int *) aprFds[i].client_data) : ARES_SOCKET_BAD; ares_process_fd(chan_, ifd, ofd); } } return nsds > 0; }
void *auth_mgr_adns_handler_epoll(void *arg) { //struct timeval *tvp, tv, tv_copy; ares_socket_t dns_client_fds[16] = {0}; struct epoll_event ev, events[DNS_MAX_EVENTS]; int i,bitmask,nfds, epollfd, timeout, fd_count, ret; UNUSED_ARGUMENT(arg); memset(dns_client_fds, 0, sizeof(dns_client_fds)); memset((char *)&ev, 0, sizeof(struct epoll_event)); memset((char *)&events[0], 0, sizeof(events)); epollfd = epoll_create(DNS_MAX_SERVERS); if (epollfd < 0) { DBG_LOG(SEVERE, MOD_AUTHMGR, "epoll_create() error"); assert(0); } prctl(PR_SET_NAME, "nvsd-adns", 0, 0, 0); /*Infinite loop, to process all the dns responses. Each channel can handle 16 name servers in RR fashion. Inside each channel there is one socket dedicated for one nameserver. So if there are 2 nameservers in /etc/resol.conf , then c-ares will assign 2 fds to the channel*/ while(1) { nfds=0; bitmask=0; for (i =0; i < DNS_MAX_SERVERS ; i++) { if (dns_client_fds[i] > 0) { if (epoll_ctl(epollfd, EPOLL_CTL_DEL, dns_client_fds[i], NULL) < 0) { //not a serious problem, strange that we should hit this case continue; } } } memset(dns_client_fds, 0, sizeof(dns_client_fds)); pthread_mutex_lock(&cares_mutex); bitmask = ares_getsock(channel, dns_client_fds, DNS_MAX_SERVERS); for (i =0; i < DNS_MAX_SERVERS ; i++) { if (dns_client_fds[i] > 0) { ev.events = 0; if (ARES_GETSOCK_READABLE(bitmask, i)) { ev.events |= EPOLLIN; } if (ARES_GETSOCK_WRITABLE(bitmask, i)) { ev.events |= EPOLLOUT; } ev.data.fd = dns_client_fds[i]; if (epoll_ctl(epollfd, EPOLL_CTL_ADD, dns_client_fds[i], &ev) < 0) { if(errno == EEXIST) { nfds++; continue; } DBG_LOG(SEVERE, MOD_AUTHMGR, "%d fd has trouble when adding to epoll:%s\n", dns_client_fds[i], strerror(errno)); continue; } nfds++; } } if(nfds==0) { pthread_cond_wait(&cares_cond, &cares_mutex); pthread_mutex_unlock(&cares_mutex); continue; } //tvp = ares_timeout(channel, NULL, &tv); //memcpy(&tv_copy, tvp, sizeof(struct timeval)); pthread_mutex_unlock(&cares_mutex); //timeout = (tv_copy.tv_sec)*1000;//millisecs timeout = 1000;//millisecs /********************************************************* The default timeout was 5 seconds with default retries as 4. The timeout algorith that c-ares adopts, has timeout increasing linearly for every retry, and can go upto 75secs(~5+~10+~20+~40). To avoid such a big block in our select, reduced the timeout to 3secs and retries to 2, so max blocking limited to 9 secs Changes in ares_init. ******************************************************/ fd_count = epoll_wait(epollfd, events, DNS_MAX_EVENTS, timeout); if (fd_count < 0) { DBG_LOG(SEVERE, MOD_AUTHMGR, "epoll_wait failed:%s", strerror(errno)); continue; } pthread_mutex_lock(&cares_mutex); if (fd_count > 0) { for (i = 0; i < fd_count; ++i) { ares_process_fd(channel, ((events[i].events) & (EPOLLIN) ? events[i].data.fd:ARES_SOCKET_BAD), ((events[i].events) & (EPOLLOUT)? events[i].data.fd:ARES_SOCKET_BAD)); } } else { ares_process_fd(channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD); } if (channel_ready == 0 ) { ares_destroy(channel); //re-init the channel to get a new port ret = ares_init_options(&channel, &options, optmask); if (ret != ARES_SUCCESS) { DBG_LOG(SEVERE, MOD_AUTHMGR,"ares_init: %d %s", ret, ares_strerror(ret)); assert(0); } channel_ready = 1; AO_fetch_and_add1(&glob_dns_channel_reinit); } pthread_mutex_unlock(&cares_mutex); } }
/* * This is called once per second by ares_data.timer. It is used to * constantly callback into c-ares for possibly processing timeouts. */ static void uv__ares_timeout(EV_P_ struct ev_timer* watcher, int revents) { assert(watcher == &ares_data.timer); assert(revents == EV_TIMER); assert(!uv_ares_handles_empty()); ares_process_fd(ares_data.channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD); }
/// Waits for replies to outstanding DNS queries on the specified channel. void DnsCachedResolver::wait_for_replies(DnsChannel* channel) { // Wait until the expected number of results has been returned. while (channel->pending_queries > 0) { // Call into ares to get details of the sockets it's using. ares_socket_t scks[ARES_GETSOCK_MAXNUM]; int rw_bits = ares_getsock(channel->channel, scks, ARES_GETSOCK_MAXNUM); // Translate these sockets into pollfd structures. int num_fds = 0; struct pollfd fds[ARES_GETSOCK_MAXNUM]; for (int fd_idx = 0; fd_idx < ARES_GETSOCK_MAXNUM; fd_idx++) { struct pollfd* fd = &fds[fd_idx]; fd->fd = scks[fd_idx]; fd->events = 0; fd->revents = 0; if (ARES_GETSOCK_READABLE(rw_bits, fd_idx)) { fd->events |= POLLRDNORM | POLLIN; } if (ARES_GETSOCK_WRITABLE(rw_bits, fd_idx)) { fd->events |= POLLWRNORM | POLLOUT; } if (fd->events != 0) { num_fds++; } } // Calculate the timeout. struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 0; (void)ares_timeout(channel->channel, NULL, &tv); // Wait for events on these file descriptors. if (poll(fds, num_fds, tv.tv_sec * 1000 + tv.tv_usec / 1000) != 0) { // We got at least one event, so find which file descriptor(s) this was on. for (int fd_idx = 0; fd_idx < num_fds; fd_idx++) { struct pollfd* fd = &fds[fd_idx]; if (fd->revents != 0) { // Call into ares to notify it of the event. The interface requires // that we pass separate file descriptors for read and write events // or ARES_SOCKET_BAD if no event has occurred. ares_process_fd(channel->channel, fd->revents & (POLLRDNORM | POLLIN) ? fd->fd : ARES_SOCKET_BAD, fd->revents & (POLLWRNORM | POLLOUT) ? fd->fd : ARES_SOCKET_BAD); } } } else { // No events, so just call into ares with no file descriptor to let it handle timeouts. ares_process_fd(channel->channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD); } } }
static void ares_io(int fd, int ev, void *data, ape_global *ape) { ares_process_fd(ape->dns.channel, (ev & EVENT_READ ? fd : ARES_SOCKET_BAD), (ev & EVENT_WRITE ? fd : ARES_SOCKET_BAD)); }
/* periodically call ares to check for timeouts */ static void uv_ares_poll(uv_timer_t* handle, int status) { uv_loop_t* loop = handle->loop; if (loop->ares_chan != NULL && loop->ares_active_sockets > 0) { ares_process_fd(loop->ares_chan, ARES_SOCKET_BAD, ARES_SOCKET_BAD); } }