//--------------------------------- bool ResolverRequest::getaddrinfoHasFinished(int index) // returns true if request has finished { if(!slotIndexValid(index)) { // out of bounds? false return false; } if(requests[index].startTime == 0) { // not used? false return false; } Tresolv *r = &requests[index]; if(r->getaddrinfoHasFinished) { // if the request already finished, good return true; } // if we don't know if it finished yet, let's check it out r->error = gai_error(&r->req); if(r->error == EAI_INPROGRESS) { // if still in progress, false return false; } r->getaddrinfoHasFinished = 1; // ok, we're done return true; }
/* $begin getaddrinfo */ void Getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) { int rc; if ((rc = getaddrinfo(node, service, hints, res)) != 0) gai_error(rc, "Getaddrinfo error"); }
void Getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) { int rc; if ((rc = getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)) != 0) gai_error(rc, "Getnameinfo error"); }
/* * Test and see if the Internet is reachable; we do this by attempting * to resolve a DNS entry. The GLIBC getaddrinfo_a() function is used * so we can timeout if the query takes too long. We simply assume the * Internet access works if we're able to successfully resolve the entry. */ boolean checkInetAccess() { struct gaicb **requests = NULL; struct timespec timeout = {0}; int ret_val = 0, loop_cnt = 0; boolean has_inet = FALSE; /* Setup our request */ requests = realloc(requests, (1 * sizeof requests[0])); requests[0] = calloc(1, sizeof *requests[0]); requests[0]->ar_name = INET_TEST_HOST; /* Queue the request */ ret_val = getaddrinfo_a(GAI_NOWAIT, &requests[0], 1, NULL); if (ret_val != 0) { DEBUG_LOG("getaddrinfo_a(): %s", gai_strerror(ret_val)); return FALSE; } /* Wait for the request to complete, or hit the timeout */ timeout.tv_nsec = 250000000; loop_cnt = 1; while (1) { /* Don't wait too long */ if (loop_cnt >= 10) { DEBUG_LOG("Timeout value reached, returning..."); has_inet = FALSE; break; } ++loop_cnt; /* Check the request */ ret_val = gai_error(requests[0]); if (ret_val == EAI_INPROGRESS) { ; } else if (ret_val == 0) { has_inet = TRUE; break; } else { DEBUG_LOG("gai_error(): %s", gai_strerror(ret_val)); has_inet = FALSE; break; } /* Sleep for a bit */ if (nanosleep(&timeout, NULL) != 0) { DEBUG_LOG("nanosleep(): %s", strerror(errno)); has_inet = FALSE; break; } } /* Done */ freeaddrinfo(requests[0]->ar_request); freeaddrinfo(requests[0]->ar_result); free(requests); return has_inet; }
int _ribified_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **results) { struct gaicb cb = { .ar_name = node, .ar_service = service, .ar_request = hints, .ar_result = NULL }; struct gaicb *cb_p[1] = { &cb }; struct sigevent sevp; sevp.sigev_notify = SIGEV_SIGNAL; sevp.sigev_signo = SIGRTMIN; /* special support in epoll_worker.c */ sevp.sigev_value.sival_ptr = current_ctx; sevp.sigev_notify_attributes = NULL; int res = getaddrinfo_a(GAI_NOWAIT, cb_p, 1, &sevp); if (!res) { yield(); res = gai_error(cb_p[0]); *results = cb.ar_result; } return res; }
bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup) { vIP.clear(); { CNetAddr addr; if (addr.SetSpecial(std::string(pszName))) { vIP.push_back(addr); return true; } } #ifdef HAVE_GETADDRINFO_A struct in_addr ipv4_addr; #ifdef HAVE_INET_PTON if (inet_pton(AF_INET, pszName, &ipv4_addr) > 0) { vIP.push_back(CNetAddr(ipv4_addr)); return true; } struct in6_addr ipv6_addr; if (inet_pton(AF_INET6, pszName, &ipv6_addr) > 0) { vIP.push_back(CNetAddr(ipv6_addr)); return true; } #else ipv4_addr.s_addr = inet_addr(pszName); if (ipv4_addr.s_addr != INADDR_NONE) { vIP.push_back(CNetAddr(ipv4_addr)); return true; } #endif #endif struct addrinfo aiHint; memset(&aiHint, 0, sizeof(struct addrinfo)); aiHint.ai_socktype = SOCK_STREAM; aiHint.ai_protocol = IPPROTO_TCP; aiHint.ai_family = AF_UNSPEC; #ifdef WIN32 aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST; #else aiHint.ai_flags = fAllowLookup ? AI_ADDRCONFIG : AI_NUMERICHOST; #endif struct addrinfo *aiRes = NULL; #ifdef HAVE_GETADDRINFO_A struct gaicb gcb, *query = &gcb; memset(query, 0, sizeof(struct gaicb)); gcb.ar_name = pszName; gcb.ar_request = &aiHint; int nErr = getaddrinfo_a(GAI_NOWAIT, &query, 1, NULL); if (nErr) return false; do { // Should set the timeout limit to a resonable value to avoid // generating unnecessary checking call during the polling loop, // while it can still response to stop request quick enough. // 2 seconds looks fine in our situation. struct timespec ts = { 2, 0 }; gai_suspend(&query, 1, &ts); boost::this_thread::interruption_point(); nErr = gai_error(query); if (0 == nErr) aiRes = query->ar_result; } while (nErr == EAI_INPROGRESS); #else int nErr = getaddrinfo(pszName, NULL, &aiHint, &aiRes); #endif if (nErr) return false; struct addrinfo *aiTrav = aiRes; while (aiTrav != NULL && (nMaxSolutions == 0 || vIP.size() < nMaxSolutions)) { if (aiTrav->ai_family == AF_INET) { assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in)); vIP.push_back(CNetAddr(((struct sockaddr_in*)(aiTrav->ai_addr))->sin_addr)); } if (aiTrav->ai_family == AF_INET6) { assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in6)); vIP.push_back(CNetAddr(((struct sockaddr_in6*)(aiTrav->ai_addr))->sin6_addr)); } aiTrav = aiTrav->ai_next; } freeaddrinfo(aiRes); return (vIP.size() > 0); }
ipaddr ipremote(const char *name, int port, int mode, int64_t deadline) { ipaddr addr = mill_ipliteral(name, port, mode); #if !defined __linux__ return addr; #else if(errno == 0) return addr; /* Let's do asynchronous DNS query here. */ int efd = eventfd(0, 0); if(mill_slow(efd < 0)) return addr; struct addrinfo request; memset(&request, 0, sizeof(request)); request.ai_family = AF_UNSPEC; request.ai_socktype = SOCK_STREAM; struct gaicb gcb; memset(&gcb, 0, sizeof(gcb)); gcb.ar_name = name; gcb.ar_service = NULL; gcb.ar_request = &request; gcb.ar_result = NULL; struct sigevent sev; memset(&sev, 0, sizeof(sev)); /* The event will be delivered using a new thread rather than by a signal running of one of the coroutines' stack and possibly breaking it. */ sev.sigev_notify = SIGEV_THREAD; sev.sigev_notify_function = mill_getaddrinfo_a_done; sev.sigev_value.sival_int = efd; struct gaicb *pgcb = &gcb; int rc = getaddrinfo_a(GAI_NOWAIT, &pgcb, 1, &sev); if(mill_slow(rc != 0)) { if(rc == EAI_AGAIN || rc == EAI_MEMORY) { close(efd); errno = ENOMEM; return addr; } mill_assert(0); } rc = fdwait(efd, FDW_IN, deadline); if(rc == 0) { gai_cancel(&gcb); rc = fdwait(efd, FDW_IN, -1); } mill_assert(rc == FDW_IN); close(efd); rc = gai_error(&gcb); if(rc != 0) { errno = EINVAL; return addr; } struct addrinfo *ipv4 = NULL; struct addrinfo *ipv6 = NULL; struct addrinfo *it = gcb.ar_result; while(it) { if(!ipv4 && it->ai_family == AF_INET) ipv4 = it; if(!ipv6 && it->ai_family == AF_INET6) ipv6 = it; if(ipv4 && ipv6) break; it = it->ai_next; } switch(mode) { case IPADDR_IPV4: ipv6 = NULL; break; case IPADDR_IPV6: ipv4 = NULL; break; case 0: case IPADDR_PREF_IPV4: if(ipv4) ipv6 = NULL; break; case IPADDR_PREF_IPV6: if(ipv6) ipv4 = NULL; break; default: mill_assert(0); } if(ipv4) { struct sockaddr_in *inaddr = (struct sockaddr_in*)&addr; memcpy(inaddr, ipv4->ai_addr, sizeof (struct sockaddr_in)); inaddr->sin_port = htons(port); } if(ipv6) { struct sockaddr_in6 *inaddr = (struct sockaddr_in6*)&addr; memcpy(inaddr, ipv6->ai_addr, sizeof (struct sockaddr_in6)); inaddr->sin6_port = htons(port); } freeaddrinfo(gcb.ar_result); errno = 0; return addr; #endif }
int irc_conn_found(nl_list **list, fd_set *master, int *fdmax) { int serverhandle=0; struct addrinfo *servinfo; while(*list) { if(gai_error((*list)->nl_details)) *list=(*list)->next; else break; } if(!*list) return(0); // 0 indicates failure as rv is new serverhandle value servinfo=(*list)->nl_details->ar_result; #else /* ASYNCH_NL */ int irc_connect(char *server, const char *portno, fd_set *master, int *fdmax) { int serverhandle=0; struct addrinfo hints, *servinfo; // Look up server memset(&hints, 0, sizeof(hints)); hints.ai_family=AF_INET; hints.ai_socktype = SOCK_STREAM; // TCP stream sockets int rv; if((rv=getaddrinfo(server, portno, &hints, &servinfo))!=0) { add_to_buffer(0, ERR, NORMAL, 0, false, (char *)gai_strerror(rv), "getaddrinfo: "); return(0); // 0 indicates failure as rv is new serverhandle value } #endif /* ASYNCH_NL */ char sip[INET_ADDRSTRLEN]; struct addrinfo *p; // loop through all the results and connect to the first we can for(p=servinfo;p;p=p->ai_next) { inet_ntop(p->ai_family, &(((struct sockaddr_in*)p->ai_addr)->sin_addr), sip, sizeof(sip)); if((serverhandle=socket(p->ai_family, p->ai_socktype, p->ai_protocol))==-1) { add_to_buffer(0, ERR, NORMAL, 0, false, strerror(errno), "socket: "); continue; } if(fcntl(serverhandle, F_SETFD, O_NONBLOCK)==-1) { close(serverhandle); add_to_buffer(0, ERR, NORMAL, 0, false, strerror(errno), "fcntl: "); continue; } connect_loop: if(connect(serverhandle, p->ai_addr, p->ai_addrlen)==-1) { if(errno!=EINPROGRESS) { if(errno==EINTR) { goto connect_loop; } else { close(serverhandle); add_to_buffer(0, ERR, NORMAL, 0, false, strerror(errno), "connect: "); continue; } } } break; } char cmsg[16+strlen(sip)]; sprintf(cmsg, "fd=%d, ip=%s", serverhandle, sip); add_to_buffer(0, STA, DEBUG, 0, false, cmsg, "DBG connect: "); if(!p) { add_to_buffer(0, ERR, NORMAL, 0, false, "failed to connect to server", "/connect: "); return(0); // 0 indicates failure as rv is new serverhandle value } freeaddrinfo(servinfo); servinfo=NULL; FD_SET(serverhandle, master); *fdmax=max(*fdmax, serverhandle); return(serverhandle); }