/* * 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; }
void runSuccess() { char buf[] = "hi"; //@ assert \valid((char*)buf); struct addrinfo ai; struct gaicb g1 = { .ar_name = buf, .ar_service = buf, .ar_request = &ai, }; struct gaicb *list[] = {NULL, &g1}; if (!getaddrinfo_a(anyint(), list, 2, NULL)) { gai_cancel(&g1); } }
void testValues() { f = 2; char buf[] = "hi"; //@ assert \valid((char*)buf); struct addrinfo ai; struct gaicb g1 = { .ar_name = buf, .ar_service = buf, .ar_request = &ai, }; struct gaicb *list[] = {NULL, &g1}; if (!getaddrinfo_a(anyint(), list, 2, NULL)) { gai_cancel(&g1); } //@ assert f == 2; //@ assert vacuous: \false; }
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 ResolverRequest::addRequest(const char *hostName) { int i, emptyIndex = -1; DWORD oldestTime = 0x7fffffff; int oldestIndex = -1; // find usable slot for(i=0; i<RESOLV_COUNT; i++) { if(requests[i].startTime == 0) { // start time 0 means it's empty (not running) emptyIndex = i; break; } // if it's running and it's older than the currently found oldest, mark it if(oldestTime > requests[i].startTime) { oldestTime = requests[i].startTime; oldestIndex = i; } } // get pointer to that slot Tresolv *r; int usedIndex; if(emptyIndex != -1) { // if found empty slot, use it r = &requests[emptyIndex]; usedIndex = emptyIndex; } else { // if not found empty slot, cancel existing and use it gai_cancel(&requests[oldestIndex].req); // try to cancel r = &requests[oldestIndex]; usedIndex = oldestIndex; } r->startTime = Utils::getCurrentMs(); // store start time r->getaddrinfoHasFinished = 0; // mark that we did not finish yet r->count = 0; // no IPs stored yet r->processed = 0; // not processed yet memset(r->canonName, 0, 256); // no canon name yet memset (r->hostName, 0, 256); strncpy(r->hostName, hostName, 255); // copy host name to our array r->req.ar_name = r->hostName; // store pointer to that array //------------------- // check and possibly resolve dotted IP int a,b,c,d; int iRes = sscanf(hostName, "%d.%d.%d.%d", &a, &b, &c, &d); if(iRes == 4) { // succeeded to get IP parts if(IS_VALID_IP_NUMBER(a) && IS_VALID_IP_NUMBER(b) && IS_VALID_IP_NUMBER(c) && IS_VALID_IP_NUMBER(d)) { BYTE *pIps = (BYTE *) r->data; pIps[0] = a; // store that IP pIps[1] = b; pIps[2] = c; pIps[3] = d; r->count = 1; // store count strcpy(r->canonName, r->hostName); // pretend that the string is canonical name r->getaddrinfoHasFinished = 1; // resolve finished r->processed = 1; return usedIndex; } } //------------------- r->hints.ai_flags = AI_CANONNAME; // get the official name of the host r->req.ar_request = &r->hints; gaicb *pReq = &r->req; int ret = getaddrinfo_a(GAI_NOWAIT, &pReq, 1, NULL); if (ret) { Debug::out(LOG_DEBUG, "addRequest() failed"); return -1; } Debug::out(LOG_DEBUG, "addRequest() - resolving %s under index %d", hostName, usedIndex); return usedIndex; // return index under which this request runs }
int iio_cmdsrv_connect(const char *addr, const char *port, const char protocol, struct iio_cmdsrv *handle) { struct addrinfo hints, *servinfo, *p; int rv; char s[INET6_ADDRSTRLEN]; struct timeval timeout; struct gaicb *in[1]; if (addr && port) { strcpy(handle->addr, (char *)addr); strcpy(handle->port, (char *)port); handle->sockfd = -1; } else { close(handle->sockfd); } memset(&hints, 0, sizeof (struct addrinfo)); hints.ai_family = AF_INET; if(protocol == TCP) { hints.ai_socktype = SOCK_STREAM; } else if(protocol == UDP) { hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; } in[0] =(gaicb*)malloc(sizeof(*in[0])); memset(in[0], 0, sizeof (*in[0])); in[0]->ar_name = handle->addr; in[0]->ar_service = handle->port; in[0]->ar_request = &hints; /* Get ready to make this time out */ rv = getaddrinfo_a(GAI_WAIT, in, 1, NULL); if (rv != 0) { syslog(LOG_ERR, "%s: getaddrinfo_a failed\n", __func__); return 1; } servinfo = in[0]->ar_result; // loop through all the results and connect to the first we can for(p = servinfo; p != NULL; p = p->ai_next) { handle->sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol); if (handle->sockfd == -1) { syslog(LOG_ERR, "%s: socket failed\n", __func__); continue; } timeout.tv_sec = 1; timeout.tv_usec = 0; setsockopt(handle->sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)); setsockopt(handle->sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)); if (connect(handle->sockfd, p->ai_addr, p->ai_addrlen) == -1) { close(handle->sockfd); handle->sockfd = -1; syslog(LOG_ERR, "%s: connection failed\n", __func__); continue; } break; } if (p == NULL) { syslog(LOG_ERR, "%s: connection failed\n", __func__); return 2; } inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), s, sizeof s); freeaddrinfo(servinfo); free(in[0]); return 0; }