/* called to check if the name is resolved now */ CURLcode Curl_is_resolved(struct connectdata *conn, struct Curl_dns_entry **dns) { fd_set read_fds, write_fds; static const struct timeval tv={0,0}; int count; struct SessionHandle *data = conn->data; int nfds; FD_ZERO(&read_fds); FD_ZERO(&write_fds); nfds = ares_fds(data->state.areschannel, &read_fds, &write_fds); count = select(nfds, &read_fds, &write_fds, NULL, (struct timeval *)&tv); if(count) ares_process(data->state.areschannel, &read_fds, &write_fds); *dns = NULL; if(conn->async.done) { /* we're done, kill the ares handle */ if(!conn->async.dns) return CURLE_COULDNT_RESOLVE_HOST; *dns = conn->async.dns; } return CURLE_OK; }
static void ares_worker_thread(char *ptr) { struct timeval tv, max_tv = { 30, 0 }; fd_set readset, writeset; int nfds, ret; while (1) { FD_ZERO(&readset); FD_ZERO(&writeset); nfds = ares_fds(achannel, &readset, &writeset); if (nfds == 0) { tv = max_tv; IOMGR_Sleep(max_tv.tv_sec); } else { struct timeval *tvp; tvp = ares_timeout(achannel, &max_tv, &tv); ret = IOMGR_Select(nfds, &readset, &writeset, NULL, tvp); if (ret < 0) /* XXX some error, lets ignore that for now */; else if (ret == 0) /* timeout */; else ares_process(achannel, &readset, &writeset); } } }
static void wait_ares(ares_channel channel) { for(;;){ struct timeval *tvp, tv; fd_set read_fds, write_fds, err_fds; int nfds; FD_ZERO(&read_fds); FD_ZERO(&write_fds); FD_ZERO(&err_fds); nfds = ares_fds(channel, &read_fds, &write_fds); if (nfds == 0){ return; } memcpy(&err_fds, &read_fds, sizeof(read_fds)); tvp = ares_timeout(channel, NULL, &tv); select(nfds, &read_fds, &write_fds, &err_fds, tvp); for (int i = 0; i < nfds; i++) { if (FD_ISSET(i, &err_fds)) { return; } } ares_process(channel, &read_fds, &write_fds); } }
/* * Curl_is_resolved() is called repeatedly to check if a previous name resolve * request has completed. It should also make sure to time-out if the * operation seems to take too long. * * Returns normal CURLcode errors. */ CURLcode Curl_is_resolved(struct connectdata *conn, struct Curl_dns_entry **dns) { fd_set read_fds, write_fds; struct timeval tv={0,0}; struct SessionHandle *data = conn->data; int nfds; FD_ZERO(&read_fds); FD_ZERO(&write_fds); nfds = ares_fds(data->state.areschannel, &read_fds, &write_fds); (void)select(nfds, &read_fds, &write_fds, NULL, (struct timeval *)&tv); /* Call ares_process() unconditonally here, even if we simply timed out above, as otherwise the ares name resolve won't timeout! */ ares_process(data->state.areschannel, &read_fds, &write_fds); *dns = NULL; if(conn->async.done) { /* we're done, kill the ares handle */ if(!conn->async.dns) { failf(data, "Could not resolve host: %s (%s)", conn->host.dispname, ares_strerror(conn->async.status)); return CURLE_COULDNT_RESOLVE_HOST; } *dns = conn->async.dns; } return CURLE_OK; }
inline unsigned long srv_ares(char *host, int *port, char *srv) { int nfds, count, srvh_len; char *srvh; fd_set read_fds, write_fds; struct timeval *tvp, tv; caport = 0; caadr = 0; ca_tmpname = NULL; #ifdef DEBUG printf("!!! ARES query !!!\n"); #endif srvh_len = strlen(host) + strlen(srv) + 2; srvh = malloc(srvh_len); if (srvh == NULL) { printf("error: failed to allocate memory (%i) for ares query\n", srvh_len); exit_code(2); } memset(srvh, 0, srvh_len); strncpy(srvh, srv, strlen(srv)); memcpy(srvh + strlen(srv), ".", 1); strcpy(srvh + strlen(srv) + 1, host); #ifdef DEBUG printf("hostname: '%s', len: %i\n", srvh, srvh_len); #endif ares_query(channel, srvh, CARES_CLASS_C_IN, CARES_TYPE_SRV, cares_callback, (char *) NULL); #ifdef DEBUG printf("after ares_query\n"); #endif /* wait for query to complete */ while (1) { FD_ZERO(&read_fds); FD_ZERO(&write_fds); nfds = ares_fds(channel, &read_fds, &write_fds); if (nfds == 0) break; tvp = ares_timeout(channel, NULL, &tv); count = select(nfds, &read_fds, &write_fds, NULL, tvp); if (count < 0 && errno != EINVAL) { perror("ares select"); exit_code(2); } ares_process(channel, &read_fds, &write_fds); } #ifdef DEBUG printf("end of while\n"); #endif *port = caport; if (caadr == 0 && ca_tmpname != NULL) { caadr = getaddress(ca_tmpname); } if (ca_tmpname != NULL) free(ca_tmpname); free(srvh); return caadr; }
void dns_process_active(listhead_t *activelist, fd_set *fdread, fd_set *fdwrite) { listitem_t *walk; // dbgprintf("DNS - process active fds\n"); for (walk = activelist->head; (walk); walk = walk->next) { myconn_t *rec = (myconn_t *)walk->data; // dbgprintf("\t%s - proto %s, dnsstatus %s\n", rec->testspec, prototxt[rec->talkprotocol], dnsstatustxt[rec->dnsstatus]); if (rec->talkprotocol != TALK_PROTO_DNSQUERY) continue; if (rec->dnsstatus != DNS_QUERY_ACTIVE) continue; // dbgprintf("DNS query %s processing\n", rec->testspec); ares_process(*((ares_channel *)rec->dnschannel), fdread, fdwrite); } /* ... and the lookup channel ... */ ares_process(dns_lookupchannel, fdread, fdwrite); }
tt_s64_t tt_dns_run_ntv(IN ares_channel ch) { fd_set rfds, wfds; int nfds, i; int ep = tt_current_task()->iop.sys_iop.ep; struct timeval tv; FD_ZERO(&rfds); FD_ZERO(&wfds); nfds = ares_fds(ch, &rfds, &wfds); for (i = 0; i < nfds; ++i) { __dskt_t *dskt = __DSKT(ch, i); tt_bool_t r = TT_BOOL(FD_ISSET(i, &rfds)); tt_bool_t w = TT_BOOL(FD_ISSET(i, &wfds)); dskt = __DSKT(ch, i); if (r && w) { if (dskt->status != __DNS_READ_WRITE) { dskt->ev.ev = __DNS_READ_WRITE; tt_ep_read_write(ep, dskt->s, &dskt->ev); dskt->status = __DNS_READ_WRITE; } } else if (r) { if (dskt->status != __DNS_READ) { dskt->ev.ev = __DNS_READ; tt_ep_read(ep, dskt->s, &dskt->ev); dskt->status = __DNS_READ; } } else if (w) { if (dskt->status != __DNS_WRITE) { dskt->ev.ev = __DNS_WRITE; tt_ep_write(ep, dskt->s, &dskt->ev); dskt->status = __DNS_WRITE; } } else { if ((dskt->s != -1) && (dskt->status != __DNS_NULL)) { dskt->ev.ev = __DNS_NULL; tt_ep_unread(ep, dskt->s, &__s_null_io_ev); dskt->status = __DNS_NULL; } } } // to process timer ares_process(ch, NULL, NULL); if (ares_timeout(ch, NULL, &tv) != NULL) { return (tt_s64_t)tv.tv_sec * 1000 + (tt_s64_t)tv.tv_usec / 1000; } else { return TT_TIME_INFINITE; } }
void *auth_mgr_adns_handler(void *arg) { UNUSED_ARGUMENT(arg); int count=0; struct timeval *tvp, tv; fd_set read_fds, write_fds; int nfds; 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) { FD_ZERO(&read_fds); FD_ZERO(&write_fds); pthread_mutex_lock(&cares_mutex); nfds = ares_fds(channel, &read_fds, &write_fds); if(nfds==0) { pthread_cond_wait(&cares_cond, &cares_mutex); pthread_mutex_unlock(&cares_mutex); continue; } tvp = ares_timeout(channel, NULL, &tv); pthread_mutex_unlock(&cares_mutex); /********************************************************* 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. ******************************************************/ count = select(nfds, &read_fds, &write_fds, NULL, tvp); if (count < 0) // && errno != EINVAL) { //Something is wrong here, lets sleep over it DBG_LOG(SEVERE, MOD_AUTHMGR, "select failed in adns for nfds=%d error:%s", nfds, strerror(errno)); usleep(1000); continue; } pthread_mutex_lock(&cares_mutex); ares_process(channel, &read_fds, &write_fds); pthread_mutex_unlock(&cares_mutex); } }
static inline unsigned long srv_ares(char *host, int *port, char *srv) { int nfds, count, srvh_len; char *srvh; fd_set read_fds, write_fds; struct timeval *tvp, tv; caport = 0; caadr = 0; ca_tmpname = NULL; dbg("starting ARES query\n"); srvh_len = strlen(host) + strlen(srv) + 2; srvh = malloc(srvh_len); if (srvh == NULL) { printf("error: failed to allocate memory (%i) for ares query\n", srvh_len); exit_code(2, __PRETTY_FUNCTION__, "memory allocation failure"); } memset(srvh, 0, srvh_len); strncpy(srvh, srv, strlen(srv)); memcpy(srvh + strlen(srv), ".", 1); strcpy(srvh + strlen(srv) + 1, host); dbg("hostname: '%s', len: %i\n", srvh, srvh_len); ares_query(channel, srvh, CARES_CLASS_C_IN, CARES_TYPE_SRV, cares_callback, (char *) NULL); dbg("ares_query finished, waiting for result...\n"); /* wait for query to complete */ while (1) { FD_ZERO(&read_fds); FD_ZERO(&write_fds); nfds = ares_fds(channel, &read_fds, &write_fds); if (nfds == 0) break; tvp = ares_timeout(channel, NULL, &tv); count = select(nfds, &read_fds, &write_fds, NULL, tvp); if (count < 0 && errno != EINVAL) { perror("ares select"); exit_code(2, __PRETTY_FUNCTION__, "ares DNS resolution failure"); } ares_process(channel, &read_fds, &write_fds); } dbg("ARES answer processed\n"); *port = caport; if (caadr == 0 && ca_tmpname != NULL) { caadr = getaddress(ca_tmpname); } if (ca_tmpname != NULL) free(ca_tmpname); free(srvh); return caadr; }
void step() { if( state == kResolving ) { if( ares ) { if( canceling ) { ares_cancel(ares); } int nfds, count; fd_set readers, writers; struct timeval tv, maxtv, *tvp; FD_ZERO(&readers); FD_ZERO(&writers); nfds = ares_fds(ares, &readers, &writers); maxtv.tv_sec = 0; maxtv.tv_usec = 1000; if (nfds == 0) { ares_process(ares, NULL, NULL); } else { tvp = ares_timeout(ares, &maxtv, &tv); count = select(nfds, &readers, &writers, NULL, tvp); ares_process(ares, &readers, &writers); } } } if( state == kStartDownload ) { if( ares ) ares_destroy( ares ); ares = 0; start_curl(); } if( state == kFinishingOK ) { got_done(); } if( state == kFinishingError ) { got_error(); } // Nothing to do with other states }
void wait_ares(ares_channel channel) { for(;;){ struct timeval *tvp, tv; fd_set read_fds, write_fds; int nfds; FD_ZERO(&read_fds); FD_ZERO(&write_fds); nfds = ares_fds(channel, &read_fds, &write_fds); if(nfds == 0){ break; } tvp = ares_timeout(channel, NULL, &tv); select(nfds, &read_fds, &write_fds, NULL, tvp); ares_process(channel, &read_fds, &write_fds); } }
void tehloop(void) { fd_set read, write; int nfds, count; struct timeval tv, *tvp; fprintf(stderr, "Starting...\n"); tv.tv_usec = 100000; while(1) { FD_ZERO(&read); FD_ZERO(&write); nfds = ares_fds(ares_chan, &read, &write); if(nfds) { tvp = ares_timeout(ares_chan, NULL, &tv); count = select(nfds, &read, &write, NULL, tvp); ares_process(ares_chan, &read, &write); fprintf(stderr, "\rResolved %i of %i", global_counter, global_total); } else break; } fprintf(stderr, "\nFinished...\n"); }
static void wait_ares (ares_channel channel) { struct ptimer *timer = NULL; if (opt.dns_timeout) timer = ptimer_new (); for (;;) { struct timeval *tvp, tv; fd_set read_fds, write_fds; int nfds, rc; FD_ZERO (&read_fds); FD_ZERO (&write_fds); nfds = ares_fds (channel, &read_fds, &write_fds); if (nfds == 0) break; if (timer) { double max = opt.dns_timeout - ptimer_measure (timer); tv.tv_sec = (long) max; tv.tv_usec = 1000000 * (max - (long) max); tvp = ares_timeout (channel, &tv, &tv); } else tvp = ares_timeout (channel, NULL, &tv); rc = select (nfds, &read_fds, &write_fds, NULL, tvp); if (rc == 0 && timer && ptimer_measure (timer) >= opt.dns_timeout) ares_cancel (channel); else ares_process (channel, &read_fds, &write_fds); } if (timer) ptimer_destroy (timer); }
int mosquitto_loop(struct mosquitto *mosq, int timeout, int max_packets) { #ifdef HAVE_PSELECT struct timespec local_timeout; #else struct timeval local_timeout; #endif fd_set readfds, writefds; int fdcount; int rc; char pairbuf; int maxfd = 0; if(!mosq || max_packets < 1) return MOSQ_ERR_INVAL; #ifndef WIN32 if(mosq->sock >= FD_SETSIZE || mosq->sockpairR >= FD_SETSIZE){ return MOSQ_ERR_INVAL; } #endif FD_ZERO(&readfds); FD_ZERO(&writefds); if(mosq->sock != INVALID_SOCKET){ maxfd = mosq->sock; FD_SET(mosq->sock, &readfds); pthread_mutex_lock(&mosq->current_out_packet_mutex); pthread_mutex_lock(&mosq->out_packet_mutex); if(mosq->out_packet || mosq->current_out_packet){ FD_SET(mosq->sock, &writefds); } #ifdef WITH_TLS if(mosq->ssl){ if(mosq->want_write){ FD_SET(mosq->sock, &writefds); mosq->want_write = false; }else if(mosq->want_connect){ /* Remove possible FD_SET from above, we don't want to check * for writing if we are still connecting, unless want_write is * definitely set. The presence of outgoing packets does not * matter yet. */ FD_CLR(mosq->sock, &writefds); } } #endif pthread_mutex_unlock(&mosq->out_packet_mutex); pthread_mutex_unlock(&mosq->current_out_packet_mutex); }else{ #ifdef WITH_SRV if(mosq->achan){ pthread_mutex_lock(&mosq->state_mutex); if(mosq->state == mosq_cs_connect_srv){ rc = ares_fds(mosq->achan, &readfds, &writefds); if(rc > maxfd){ maxfd = rc; } }else{ pthread_mutex_unlock(&mosq->state_mutex); return MOSQ_ERR_NO_CONN; } pthread_mutex_unlock(&mosq->state_mutex); } #else return MOSQ_ERR_NO_CONN; #endif } if(mosq->sockpairR != INVALID_SOCKET){ /* sockpairR is used to break out of select() before the timeout, on a * call to publish() etc. */ FD_SET(mosq->sockpairR, &readfds); if(mosq->sockpairR > maxfd){ maxfd = mosq->sockpairR; } } if(timeout >= 0){ local_timeout.tv_sec = timeout/1000; #ifdef HAVE_PSELECT local_timeout.tv_nsec = (timeout-local_timeout.tv_sec*1000)*1e6; #else local_timeout.tv_usec = (timeout-local_timeout.tv_sec*1000)*1000; #endif }else{ local_timeout.tv_sec = 1; #ifdef HAVE_PSELECT local_timeout.tv_nsec = 0; #else local_timeout.tv_usec = 0; #endif } #ifdef HAVE_PSELECT fdcount = pselect(maxfd+1, &readfds, &writefds, NULL, &local_timeout, NULL); #else fdcount = select(maxfd+1, &readfds, &writefds, NULL, &local_timeout); #endif if(fdcount == -1){ #ifdef WIN32 errno = WSAGetLastError(); #endif if(errno == EINTR){ return MOSQ_ERR_SUCCESS; }else{ return MOSQ_ERR_ERRNO; } }else{ if(mosq->sock != INVALID_SOCKET){ if(FD_ISSET(mosq->sock, &readfds)){ #ifdef WITH_TLS if(mosq->want_connect){ rc = mosquitto__socket_connect_tls(mosq); if(rc) return rc; }else #endif { do{ rc = mosquitto_loop_read(mosq, max_packets); if(rc || mosq->sock == INVALID_SOCKET){ return rc; } }while(SSL_DATA_PENDING(mosq)); } } if(mosq->sockpairR != INVALID_SOCKET && FD_ISSET(mosq->sockpairR, &readfds)){ #ifndef WIN32 if(read(mosq->sockpairR, &pairbuf, 1) == 0){ } #else recv(mosq->sockpairR, &pairbuf, 1, 0); #endif /* Fake write possible, to stimulate output write even though * we didn't ask for it, because at that point the publish or * other command wasn't present. */ FD_SET(mosq->sock, &writefds); } if(FD_ISSET(mosq->sock, &writefds)){ #ifdef WITH_TLS if(mosq->want_connect){ rc = mosquitto__socket_connect_tls(mosq); if(rc) return rc; }else #endif { rc = mosquitto_loop_write(mosq, max_packets); if(rc || mosq->sock == INVALID_SOCKET){ return rc; } } } } #ifdef WITH_SRV if(mosq->achan){ ares_process(mosq->achan, &readfds, &writefds); } #endif } return mosquitto_loop_misc(mosq); }
int gethostbyaddr_with_ares(const void *addr, int addrlen, int af, struct hostent *ret_h, char *buf, size_t &buflen, struct hostent **result, int *h_errnop) { int err = 0; if (!h_errnop) h_errnop = &err; cares_async_context ctx; ctx.called = false; ctx.errnop = h_errnop; ctx.ret = 0; ctx.result = result; ctx.buf = buf; ctx.buflen = &buflen; ares_channel c; ares_init(&c); ares_gethostbyaddr(c, addr, addrlen, af, [](void * arg, int status, int timeouts, struct hostent *hostent) { cares_async_context *ctx = (cares_async_context *)arg; ctx->called = true; if (status != ARES_SUCCESS) { *ctx->result = nullptr; switch (status) { case ARES_ENODATA: *ctx->errnop = NO_DATA; break; case ARES_EBADNAME: *ctx->errnop = NO_RECOVERY; break; case ARES_ENOTFOUND: default: *ctx->errnop = HOST_NOT_FOUND; break; } ctx->ret = -1; return ; } if (!hostent_dup(hostent, *ctx->result, ctx->buf, *ctx->buflen)) { *ctx->result = nullptr; *ctx->errnop = ENOEXEC; // 奇怪的错误码. ctx->ret = -1; return ; } *ctx->errnop = 0; ctx->ret = 0; }, &ctx); fd_set readers, writers; FD_ZERO(&readers); FD_ZERO(&writers); int nfds = ares_fds(c, &readers, &writers); if (nfds) { struct timeval tv, *tvp; tvp = ares_timeout(c, NULL, &tv); int count = select(nfds, &readers, &writers, NULL, tvp); if (count > 0) { ares_process(c, &readers, &writers); } } if (ctx.called) return ctx.ret; // No yet invoke callback. *result = nullptr; *h_errnop = HOST_NOT_FOUND; // TODO return -1; }
/* This is a function that locks and waits until the name resolve operation has completed. If 'entry' is non-NULL, make it point to the resolved dns entry Return CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, and CURLE_OPERATION_TIMEDOUT if a time-out occurred. */ CURLcode Curl_wait_for_resolv(struct connectdata *conn, struct Curl_dns_entry **entry) { CURLcode rc=CURLE_OK; struct SessionHandle *data = conn->data; struct timeval now = Curl_tvnow(); bool timedout = FALSE; long timeout = 300; /* default name resolve timeout in seconds */ long elapsed = 0; /* time taken so far */ /* now, see if there's a connect timeout or a regular timeout to use instead of the default one */ if(conn->data->set.connecttimeout) timeout = conn->data->set.connecttimeout; else if(conn->data->set.timeout) timeout = conn->data->set.timeout; /* Wait for the name resolve query to complete. */ while (1) { int nfds=0; fd_set read_fds, write_fds; struct timeval *tvp, tv, store; int count; store.tv_sec = (int)(timeout - elapsed); store.tv_usec = 0; FD_ZERO(&read_fds); FD_ZERO(&write_fds); nfds = ares_fds(data->state.areschannel, &read_fds, &write_fds); if (nfds == 0) break; tvp = ares_timeout(data->state.areschannel, &store, &tv); count = select(nfds, &read_fds, &write_fds, NULL, tvp); if (count < 0 && errno != EINVAL) break; else if(!count) { /* timeout */ timedout = TRUE; break; } ares_process(data->state.areschannel, &read_fds, &write_fds); elapsed = Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */ } /* Operation complete, if the lookup was successful we now have the entry in the cache. */ if(entry) *entry = conn->async.dns; if(!conn->async.dns) { /* a name was not resolved */ if(timedout || (conn->async.status == ARES_ETIMEOUT)) { failf(data, "Resolving host timed out: %s", conn->name); rc = CURLE_OPERATION_TIMEDOUT; } else if(conn->async.done) { failf(data, "Could not resolve host: %s (%s)", conn->name, ares_strerror(conn->async.status)); rc = CURLE_COULDNT_RESOLVE_HOST; } else rc = CURLE_OPERATION_TIMEDOUT; /* close the connection, since we can't return failure here without cleaning up this connection properly */ Curl_disconnect(conn); } return rc; }
int main(int argc, char **argv) { ares_channel channel; int c, i, optmask = ARES_OPT_FLAGS, dnsclass = C_IN, type = T_A; int status, nfds, count; struct ares_options options; struct hostent *hostent; fd_set read_fds, write_fds; struct timeval *tvp, tv; #ifdef USE_WINSOCK WORD wVersionRequested = MAKEWORD(USE_WINSOCK,USE_WINSOCK); WSADATA wsaData; WSAStartup(wVersionRequested, &wsaData); #endif options.flags = ARES_FLAG_NOCHECKRESP; options.servers = NULL; options.nservers = 0; while ((c = ares_getopt(argc, argv, "df:s:c:t:T:U:")) != -1) { switch (c) { case 'd': #ifdef WATT32 dbug_init(); #endif break; case 'f': /* Add a flag. */ for (i = 0; i < nflags; i++) { if (strcmp(flags[i].name, optarg) == 0) break; } if (i == nflags) usage(); options.flags |= flags[i].value; break; case 's': /* Add a server, and specify servers in the option mask. */ if (ares_inet_pton(AF_INET, optarg, &inaddr) <= 0) { hostent = gethostbyname(optarg); if (!hostent || hostent->h_addrtype != AF_INET) { fprintf(stderr, "adig: server %s not found.\n", optarg); return 1; } memcpy(&inaddr, hostent->h_addr, sizeof(struct in_addr)); } options.servers = realloc(options.servers, (options.nservers + 1) * sizeof(struct in_addr)); if (!options.servers) { fprintf(stderr, "Out of memory!\n"); return 1; } memcpy(&options.servers[options.nservers], &inaddr, sizeof(struct in_addr)); options.nservers++; optmask |= ARES_OPT_SERVERS; break; case 'c': /* Set the query class. */ for (i = 0; i < nclasses; i++) { if (strcasecmp(classes[i].name, optarg) == 0) break; } if (i == nclasses) usage(); dnsclass = classes[i].value; break; case 't': /* Set the query type. */ for (i = 0; i < ntypes; i++) { if (strcasecmp(types[i].name, optarg) == 0) break; } if (i == ntypes) usage(); type = types[i].value; break; case 'T': /* Set the TCP port number. */ if (!ISDIGIT(*optarg)) usage(); options.tcp_port = (unsigned short)strtol(optarg, NULL, 0); optmask |= ARES_OPT_TCP_PORT; break; case 'U': /* Set the UDP port number. */ if (!ISDIGIT(*optarg)) usage(); options.udp_port = (unsigned short)strtol(optarg, NULL, 0); optmask |= ARES_OPT_UDP_PORT; break; } } argc -= optind; argv += optind; if (argc == 0) usage(); status = ares_init_options(&channel, &options, optmask); if (status != ARES_SUCCESS) { fprintf(stderr, "ares_init_options: %s\n", ares_strerror(status)); return 1; } /* Initiate the queries, one per command-line argument. If there is * only one query to do, supply NULL as the callback argument; * otherwise, supply the query name as an argument so we can * distinguish responses for the user when printing them out. */ if (argc == 1) ares_query(channel, *argv, dnsclass, type, callback, (char *) NULL); else { for (; *argv; argv++) ares_query(channel, *argv, dnsclass, type, callback, *argv); } /* Wait for all queries to complete. */ while (1) { FD_ZERO(&read_fds); FD_ZERO(&write_fds); nfds = ares_fds(channel, &read_fds, &write_fds); if (nfds == 0) break; tvp = ares_timeout(channel, NULL, &tv); count = select(nfds, &read_fds, &write_fds, NULL, tvp); if (count < 0 && SOCKERRNO != EINVAL) { perror("select"); return 1; } ares_process(channel, &read_fds, &write_fds); } ares_destroy(channel); #ifdef USE_WINSOCK WSACleanup(); #endif return 0; }
int main(int argc, char **argv) { ares_channel channel; int c, i, optmask = ARES_OPT_FLAGS, dnsclass = C_IN, type = T_A; int status, nfds, count; struct ares_options options; struct hostent *hostent; fd_set read_fds, write_fds; struct timeval *tvp, tv; struct ares_addr_node *srvr, *servers = NULL; #ifdef USE_WINSOCK WORD wVersionRequested = MAKEWORD(USE_WINSOCK,USE_WINSOCK); WSADATA wsaData; WSAStartup(wVersionRequested, &wsaData); #endif status = ares_library_init(ARES_LIB_INIT_ALL); if (status != ARES_SUCCESS) { fprintf(stderr, "ares_library_init: %s\n", ares_strerror(status)); return 1; } options.flags = ARES_FLAG_NOCHECKRESP; options.servers = NULL; options.nservers = 0; while ((c = ares_getopt(argc, argv, "df:s:c:t:T:U:")) != -1) { switch (c) { case 'd': #ifdef WATT32 dbug_init(); #endif break; case 'f': /* Add a flag. */ for (i = 0; i < nflags; i++) { if (strcmp(flags[i].name, optarg) == 0) break; } if (i < nflags) options.flags |= flags[i].value; else usage(); break; case 's': /* User-specified name servers override default ones. */ srvr = malloc(sizeof(struct ares_addr_node)); if (!srvr) { fprintf(stderr, "Out of memory!\n"); destroy_addr_list(servers); return 1; } append_addr_list(&servers, srvr); if (ares_inet_pton(AF_INET, optarg, &srvr->addr.addr4) > 0) srvr->family = AF_INET; else if (ares_inet_pton(AF_INET6, optarg, &srvr->addr.addr6) > 0) srvr->family = AF_INET6; else { hostent = gethostbyname(optarg); if (!hostent) { fprintf(stderr, "adig: server %s not found.\n", optarg); destroy_addr_list(servers); return 1; } switch (hostent->h_addrtype) { case AF_INET: srvr->family = AF_INET; memcpy(&srvr->addr.addr4, hostent->h_addr, sizeof(srvr->addr.addr4)); break; case AF_INET6: srvr->family = AF_INET6; memcpy(&srvr->addr.addr6, hostent->h_addr, sizeof(srvr->addr.addr6)); break; default: fprintf(stderr, "adig: server %s unsupported address family.\n", optarg); destroy_addr_list(servers); return 1; } } /* Notice that calling ares_init_options() without servers in the * options struct and with ARES_OPT_SERVERS set simultaneously in * the options mask, results in an initialization with no servers. * When alternative name servers have been specified these are set * later calling ares_set_servers() overriding any existing server * configuration. To prevent initial configuration with default * servers that will be discarded later, ARES_OPT_SERVERS is set. * If this flag is not set here the result shall be the same but * ares_init_options() will do needless work. */ optmask |= ARES_OPT_SERVERS; break; case 'c': /* Set the query class. */ for (i = 0; i < nclasses; i++) { if (strcasecmp(classes[i].name, optarg) == 0) break; } if (i < nclasses) dnsclass = classes[i].value; else usage(); break; case 't': /* Set the query type. */ for (i = 0; i < ntypes; i++) { if (strcasecmp(types[i].name, optarg) == 0) break; } if (i < ntypes) type = types[i].value; else usage(); break; case 'T': /* Set the TCP port number. */ if (!ISDIGIT(*optarg)) usage(); options.tcp_port = (unsigned short)strtol(optarg, NULL, 0); optmask |= ARES_OPT_TCP_PORT; break; case 'U': /* Set the UDP port number. */ if (!ISDIGIT(*optarg)) usage(); options.udp_port = (unsigned short)strtol(optarg, NULL, 0); optmask |= ARES_OPT_UDP_PORT; break; } } argc -= optind; argv += optind; if (argc == 0) usage(); status = ares_init_options(&channel, &options, optmask); if (status != ARES_SUCCESS) { fprintf(stderr, "ares_init_options: %s\n", ares_strerror(status)); return 1; } if(servers) { status = ares_set_servers(channel, servers); destroy_addr_list(servers); if (status != ARES_SUCCESS) { fprintf(stderr, "ares_init_options: %s\n", ares_strerror(status)); return 1; } } /* Initiate the queries, one per command-line argument. If there is * only one query to do, supply NULL as the callback argument; * otherwise, supply the query name as an argument so we can * distinguish responses for the user when printing them out. */ if (argc == 1) ares_query(channel, *argv, dnsclass, type, callback, (char *) NULL); else { for (; *argv; argv++) ares_query(channel, *argv, dnsclass, type, callback, *argv); } /* Wait for all queries to complete. */ for (;;) { FD_ZERO(&read_fds); FD_ZERO(&write_fds); nfds = ares_fds(channel, &read_fds, &write_fds); if (nfds == 0) break; tvp = ares_timeout(channel, NULL, &tv); count = select(nfds, &read_fds, &write_fds, NULL, tvp); if (count < 0 && SOCKERRNO != EINVAL) { perror("select"); return 1; } ares_process(channel, &read_fds, &write_fds); } ares_destroy(channel); ares_library_cleanup(); #ifdef USE_WINSOCK WSACleanup(); #endif return 0; }
int main(int argc, char **argv) { struct ares_options options; int optmask = 0; ares_channel channel; int status, nfds, c, addr_family = AF_INET; fd_set read_fds, write_fds; struct timeval *tvp, tv; struct in_addr addr4; struct ares_in6_addr addr6; #ifdef USE_WINSOCK WORD wVersionRequested = MAKEWORD(USE_WINSOCK,USE_WINSOCK); WSADATA wsaData; WSAStartup(wVersionRequested, &wsaData); #endif memset(&options, 0, sizeof(options)); status = ares_library_init(ARES_LIB_INIT_ALL); if (status != ARES_SUCCESS) { fprintf(stderr, "ares_library_init: %s\n", ares_strerror(status)); return 1; } while ((c = ares_getopt(argc,argv,"dt:hs:")) != -1) { switch (c) { case 'd': #ifdef WATT32 dbug_init(); #endif break; case 's': optmask |= ARES_OPT_DOMAINS; options.ndomains++; options.domains = realloc(options.domains, options.ndomains * sizeof(char *)); options.domains[options.ndomains - 1] = strdup(optarg); break; case 't': if (!strcasecmp(optarg,"a")) addr_family = AF_INET; else if (!strcasecmp(optarg,"aaaa")) addr_family = AF_INET6; else if (!strcasecmp(optarg,"u")) addr_family = AF_UNSPEC; else usage(); break; case 'h': default: usage(); break; } } argc -= optind; argv += optind; if (argc < 1) usage(); status = ares_init_options(&channel, &options, optmask); if (status != ARES_SUCCESS) { fprintf(stderr, "ares_init: %s\n", ares_strerror(status)); return 1; } /* Initiate the queries, one per command-line argument. */ for ( ; *argv; argv++) { if (ares_inet_pton(AF_INET, *argv, &addr4) == 1) { ares_gethostbyaddr(channel, &addr4, sizeof(addr4), AF_INET, callback, *argv); } else if (ares_inet_pton(AF_INET6, *argv, &addr6) == 1) { ares_gethostbyaddr(channel, &addr6, sizeof(addr6), AF_INET6, callback, *argv); } else { ares_gethostbyname(channel, *argv, addr_family, callback, *argv); } } /* Wait for all queries to complete. */ for (;;) { int res; FD_ZERO(&read_fds); FD_ZERO(&write_fds); nfds = ares_fds(channel, &read_fds, &write_fds); if (nfds == 0) break; tvp = ares_timeout(channel, NULL, &tv); res = select(nfds, &read_fds, &write_fds, NULL, tvp); if (-1 == res) break; ares_process(channel, &read_fds, &write_fds); } ares_destroy(channel); ares_library_cleanup(); #ifdef USE_WINSOCK WSACleanup(); #endif return 0; }
/* * Curl_wait_for_resolv() waits for a resolve to finish. This function should * be avoided since using this risk getting the multi interface to "hang". * * If 'entry' is non-NULL, make it point to the resolved dns entry * * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, and * CURLE_OPERATION_TIMEDOUT if a time-out occurred. */ CURLcode Curl_wait_for_resolv(struct connectdata *conn, struct Curl_dns_entry **entry) { CURLcode rc=CURLE_OK; struct SessionHandle *data = conn->data; long timeout = CURL_TIMEOUT_RESOLVE; /* default name resolve timeout */ /* now, see if there's a connect timeout or a regular timeout to use instead of the default one */ if(conn->data->set.connecttimeout) timeout = conn->data->set.connecttimeout; else if(conn->data->set.timeout) timeout = conn->data->set.timeout; /* We convert the number of seconds into number of milliseconds here: */ if(timeout < 2147483) /* maximum amount of seconds that can be multiplied with 1000 and still fit within 31 bits */ timeout *= 1000; else timeout = 0x7fffffff; /* ridiculous amount of time anyway */ /* Wait for the name resolve query to complete. */ while (1) { int nfds=0; fd_set read_fds, write_fds; struct timeval *tvp, tv, store; int count; struct timeval now = Curl_tvnow(); long timediff; store.tv_sec = (int)timeout/1000; store.tv_usec = (timeout%1000)*1000; FD_ZERO(&read_fds); FD_ZERO(&write_fds); nfds = ares_fds(data->state.areschannel, &read_fds, &write_fds); if (nfds == 0) /* no file descriptors means we're done waiting */ break; tvp = ares_timeout(data->state.areschannel, &store, &tv); count = select(nfds, &read_fds, &write_fds, NULL, tvp); if (count < 0 && errno != EINVAL) break; ares_process(data->state.areschannel, &read_fds, &write_fds); timediff = Curl_tvdiff(Curl_tvnow(), now); /* spent time */ timeout -= timediff?timediff:1; /* always deduct at least 1 */ if (timeout < 0) { /* our timeout, so we cancel the ares operation */ ares_cancel(data->state.areschannel); break; } } /* Operation complete, if the lookup was successful we now have the entry in the cache. */ if(entry) *entry = conn->async.dns; if(!conn->async.dns) { /* a name was not resolved */ if((timeout < 0) || (conn->async.status == ARES_ETIMEOUT)) { failf(data, "Resolving host timed out: %s", conn->host.dispname); rc = CURLE_OPERATION_TIMEDOUT; } else if(conn->async.done) { failf(data, "Could not resolve host: %s (%s)", conn->host.dispname, ares_strerror(conn->async.status)); rc = CURLE_COULDNT_RESOLVE_HOST; } else rc = CURLE_OPERATION_TIMEDOUT; /* close the connection, since we can't return failure here without cleaning up this connection properly */ conn->bits.close = TRUE; } return rc; }
void mux_loop(void) { int i, nfds; fd_set inputs, outputs; struct timeval tv, *tvp; mux_end_loop_p = 0; for (;;) { /* * Exit if mux_end_loop_p has been set to true by a handler: */ if (mux_end_loop_p) break; tvp = NULL; tv.tv_sec = 0; if (have_tty) { #ifdef CMU_ZWGCPLUS tv.tv_sec = plus_timequeue_events(); if (tv.tv_sec > 10) tv.tv_sec = 10; #else tv.tv_sec = 10; #endif tv.tv_usec = 0; #ifdef CMU_ZWGCPLUS } else { tv.tv_sec = plus_timequeue_events(); tv.tv_usec = 0; #endif } if (tv.tv_sec) tvp = &tv; /* * Do a select on all the file descriptors we care about to * wait until at least one of them has input available: */ inputs = input_sources; FD_ZERO(&outputs); #ifdef HAVE_ARES nfds = ares_fds(achannel, &inputs, &outputs); if (nfds < max_source + 1) nfds = max_source + 1; tvp = ares_timeout(achannel, tvp, &tv); #else nfds = max_source + 1; #endif i = select(nfds, &inputs, &outputs, NULL, tvp); if (i == -1) { if (errno == EINTR) continue; /* on a signal restart checking mux_loop_end_p */ else FATAL_TRAP( errno, "while selecting" ); } else if (i == 0) { if (have_tty && !check_tty()) { mux_end_loop_p = 1; continue; } } #ifdef HAVE_ARES ares_process(achannel, &inputs, &outputs); #endif /* * Call all input handlers whose corresponding file descriptors have * input: */ for(i=0; i<=max_source; i++) if (FD_ISSET(i, &inputs) && input_handler[i]) { #ifdef DEBUG if (zwgc_debug) fprintf(stderr, "mux_loop...activity on fd %d, calling %lx(%lx)\n", i, (unsigned long)input_handler[i], (unsigned long)input_handler_arg[i]); #endif input_handler[i](input_handler_arg[i]); } } }
/** * Tell the DNS resolver that the select() has finished and it can check if any of its sockets had any data * on it. * * This function should be called after calling p_dns_fds() and select(). It ignores any file descriptors that * do not belong to it (e.g. IRC connections). */ void p_dns_process(fd_set *read_fds, fd_set *write_fds) { pcontext; ares_process(resolver, read_fds, write_fds); }
void DNSHandler::worker () { // FD sets used for selecting fd_set readable; fd_set writeable; // Maximum file descriptor to pass // to select int nfds; // The timeout for select struct timeval tv; // Loop until shutdown for (;;) { // Zero FDs FD_ZERO(&readable); FD_ZERO(&writeable); if (lock.Execute([&] () mutable { // Wait for there to be something actionable, // either pending queries, or a shutdown command while (!stop && (queries.size()==0)) wait.Sleep(lock); // If the command to shutdown has been given, // do that at once if (stop) return true; // Get the file descriptors from libcares nfds=ares_fds( channel, &readable, &writeable ); // Get the timeout from libcares ares_timeout( channel, nullptr, &tv ); return false; })) break; // If there's a message pending on // the worker end of the socket pair, // we want to be woken up, so // If there's a message pending // on the worker end of the socket // pair, we want to be woken up, // so we're checking for readability nfds=control.Add(readable,nfds); // Wait for something to happen if (select( nfds, &readable, &writeable, nullptr, &tv )== #ifdef ENVIRONMENT_WINDOWS SOCKET_ERROR #else -1 #endif ) raise_os(); // Did something happen with the // control socket? if (control.Is(readable)) { // Check to see if a shutdown command // is coming through the control socket, // if so end at once if (should_stop()) break; // Remove it in case it matters to // libcares what's in the fd_set control.Clear(readable); } // Call libcares lock.Execute([&] () mutable { ares_process( channel, &readable, &writeable ); }); } }