static void _ecore_con_dns_free(Ecore_Con_DNS *dns) { if (dns->svr->infos) dns->svr->infos = eina_list_remove(dns->svr->infos, dns); if (dns->timer) ecore_timer_del(dns->timer); if (dns->fdh) ecore_main_fd_handler_del(dns->fdh); dns_res_close(dns_res_mortal(dns->resolv)); free(dns); }
EAPI int ecore_con_info_get(Ecore_Con_Server *svr, Ecore_Con_Info_Cb done_cb, void *data, struct addrinfo *hints) { Ecore_Con_DNS *dns; int error = 0; dns = calloc(1, sizeof(Ecore_Con_DNS)); if (!dns) return 0; dns->svr = svr; dns->done_cb = done_cb; dns->data = data; if (hints) memcpy(&dns->hints, hints, sizeof(struct addrinfo)); if (!(dns->resolv = dns_res_open(resconf, hosts, dns_hints_mortal(dns_hints_local(resconf, &error)), NULL, dns_opts(), &error))) { ERR("res_open: %s", dns_strerror(error)); goto reserr; } error = _dns_addrinfo_get(dns, svr->ecs ? svr->ecs->ip : svr->name, dns->svr->ecs ? dns->svr->ecs->port : dns->svr->port); if (error && (error != EAGAIN)) { ERR("resolver: %s", dns_strerror(error)); goto seterr; } switch (_ecore_con_dns_check(dns)) { case 0: break; case 1: dns->fdh = ecore_main_fd_handler_add(dns_ai_pollfd(dns->ai), dns_ai_events(dns->ai), (Ecore_Fd_Cb)_dns_fd_cb, dns, NULL, NULL); svr->infos = eina_list_append(svr->infos, dns); dns->timer = ecore_timer_add(5.0, (Ecore_Task_Cb)_dns_timer_cb, dns); break; default: return 0; } return 1; seterr: if (dns->resolv) dns_res_close(dns_res_mortal(dns->resolv)); reserr: free(dns); return 0; }
ipaddr mill_ipremote_(const char *name, int port, int mode, int64_t deadline) { int rc; ipaddr addr = mill_ipliteral(name, port, mode); if(errno == 0) return addr; /* Load DNS config files, unless they are already chached. */ if(mill_slow(!mill_dns_conf)) { /* TODO: Maybe re-read the configuration once in a while? */ mill_dns_conf = dns_resconf_local(&rc); mill_assert(mill_dns_conf); mill_dns_hosts = dns_hosts_local(&rc); mill_assert(mill_dns_hosts); mill_dns_hints = dns_hints_local(mill_dns_conf, &rc); mill_assert(mill_dns_hints); } /* Let's do asynchronous DNS query here. */ struct dns_resolver *resolver = dns_res_open(mill_dns_conf, mill_dns_hosts, mill_dns_hints, NULL, dns_opts(), &rc); mill_assert(resolver); mill_assert(port >= 0 && port <= 0xffff); char portstr[8]; snprintf(portstr, sizeof(portstr), "%d", port); struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; struct dns_addrinfo *ai = dns_ai_open(name, portstr, DNS_T_A, &hints, resolver, &rc); mill_assert(ai); dns_res_close(resolver); struct addrinfo *ipv4 = NULL; struct addrinfo *ipv6 = NULL; struct addrinfo *it = NULL; while(1) { rc = dns_ai_nextent(&it, ai); if(rc == EAGAIN) { int fd = dns_ai_pollfd(ai); mill_assert(fd >= 0); int events = fdwait(fd, FDW_IN, deadline); /* There's no guarantee that the file descriptor will be reused in next iteration. We have to clean the fdwait cache here to be on the safe side. */ fdclean(fd); if(mill_slow(!events)) { errno = ETIMEDOUT; return addr; } mill_assert(events == FDW_IN); continue; } if(rc == ENOENT) break; if(!ipv4 && it && it->ai_family == AF_INET) { ipv4 = it; } else if(!ipv6 && it && it->ai_family == AF_INET6) { ipv6 = it; } else { free(it); } if(ipv4 && ipv6) break; } switch(mode) { case IPADDR_IPV4: if(ipv6) { free(ipv6); ipv6 = NULL; } break; case IPADDR_IPV6: if(ipv4) { free(ipv4); ipv4 = NULL; } break; case 0: case IPADDR_PREF_IPV4: if(ipv4 && ipv6) { free(ipv6); ipv6 = NULL; } break; case IPADDR_PREF_IPV6: if(ipv6 && ipv4) { free(ipv4); 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); dns_ai_close(ai); free(ipv4); errno = 0; return addr; } if(ipv6) { struct sockaddr_in6 *inaddr = (struct sockaddr_in6*)&addr; memcpy(inaddr, ipv6->ai_addr, sizeof (struct sockaddr_in6)); inaddr->sin6_port = htons(port); dns_ai_close(ai); free(ipv6); errno = 0; return addr; } dns_ai_close(ai); ((struct sockaddr*)&addr)->sa_family = AF_UNSPEC; errno = EADDRNOTAVAIL; return addr; }