/* ares__gc * * __gc metamethod for the ares userdata. * cancels request if * * Arguments: * L Lua State * * Lua Stack: * 1 aResolver userdata */ static int ares__gc(lua_State *L) { aResolver *ares = (aResolver*) lua_touserdata(L, 1); void *dummy; gai_cancel(ares->rq); gai_finalize(ares->rq, (struct addrinfo **) &dummy); ares->rq = NULL; return 0; }
/* ares_cancel * * cancels an asynchronous getaddrinfo request * * Arguments: * L Lua State * * Lua Stack: * 1 the aResolver userdata * * Lua Returns: * +1 true, if the cancel request was sent, nil + error message if an * error occurred. */ static int ares_cancel(lua_State *L) { aResolver *ares = ares_checkaResolver(L, 1); if (!ares->rq) return ares_error(L, "invalid request object, has already been finalized."); int res = gai_cancel(ares->rq); if (res == 0) lua_pushboolean(L, 1); else return ares_error(L, strerror(errno)); return 1; }
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; }
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 }