int ecore_con_info_init(void) { int err; if (_ecore_con_dns_init) return ++_ecore_con_dns_init; resconf = dns_resconf_local(&err); if (!resconf) { ERR("resconf_open: %s", dns_strerror(err)); return 0; } hosts = dns_hosts_local(&err); if (!hosts) { ERR("hosts_open: %s", dns_strerror(err)); dns_resconf_close(resconf); resconf = NULL; return 0; } /* this is super slow don't do it */ //resconf->options.recurse = 1; return ++_ecore_con_dns_init; }
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; }