mirror of
https://github.com/cuberite/libevent.git
synced 2025-09-09 20:41:27 -04:00
evdns_getaddrinfo() now supports the /etc/hosts file.
The regular blocking evutil_getaddrinfo() already supported /etc/hosts by falling back to getaddrinfo() or gethostbyname(). But evdns_getaddrinfo() had no such facility. Now it does. The data structure here isn't very clever. I guess people with huge /etc/hosts files will either need to get out of the 1980s, or submit a patch to this code so that it uses a hashtable instead of a linked list. Includes basic unit tests.
This commit is contained in:
parent
0f7144fd8b
commit
72dd666777
280
evdns.c
280
evdns.c
@ -363,11 +363,24 @@ struct evdns_base {
|
|||||||
|
|
||||||
struct search_state *global_search_state;
|
struct search_state *global_search_state;
|
||||||
|
|
||||||
|
TAILQ_HEAD(hosts_list, hosts_entry) hostsdb;
|
||||||
|
|
||||||
#ifndef _EVENT_DISABLE_THREAD_SUPPORT
|
#ifndef _EVENT_DISABLE_THREAD_SUPPORT
|
||||||
void *lock;
|
void *lock;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct hosts_entry {
|
||||||
|
TAILQ_ENTRY(hosts_entry) next;
|
||||||
|
union {
|
||||||
|
struct sockaddr sa;
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
struct sockaddr_in6 sin6;
|
||||||
|
} addr;
|
||||||
|
int addrlen;
|
||||||
|
char hostname[1];
|
||||||
|
};
|
||||||
|
|
||||||
static struct evdns_base *current_base = NULL;
|
static struct evdns_base *current_base = NULL;
|
||||||
|
|
||||||
struct evdns_base *
|
struct evdns_base *
|
||||||
@ -2502,6 +2515,28 @@ evdns_nameserver_add(unsigned long int address) {
|
|||||||
return evdns_base_nameserver_add(current_base, address);
|
return evdns_base_nameserver_add(current_base, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sockaddr_setport(struct sockaddr *sa, ev_uint16_t port)
|
||||||
|
{
|
||||||
|
if (sa->sa_family == AF_INET) {
|
||||||
|
((struct sockaddr_in *)sa)->sin_port = htons(port);
|
||||||
|
} else if (sa->sa_family == AF_INET6) {
|
||||||
|
((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ev_uint16_t
|
||||||
|
sockaddr_getport(struct sockaddr *sa)
|
||||||
|
{
|
||||||
|
if (sa->sa_family == AF_INET) {
|
||||||
|
return ntohs(((struct sockaddr_in *)sa)->sin_port);
|
||||||
|
} else if (sa->sa_family == AF_INET6) {
|
||||||
|
return ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* exported function */
|
/* exported function */
|
||||||
int
|
int
|
||||||
evdns_base_nameserver_ip_add(struct evdns_base *base, const char *ip_as_string) {
|
evdns_base_nameserver_ip_add(struct evdns_base *base, const char *ip_as_string) {
|
||||||
@ -2516,20 +2551,8 @@ evdns_base_nameserver_ip_add(struct evdns_base *base, const char *ip_as_string)
|
|||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
sa = (struct sockaddr *) &ss;
|
sa = (struct sockaddr *) &ss;
|
||||||
if (sa->sa_family == AF_INET) {
|
if (sockaddr_getport(sa) == 0)
|
||||||
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
|
sockaddr_setport(sa, 53);
|
||||||
if (sin->sin_port == 0)
|
|
||||||
sin->sin_port = htons(53);
|
|
||||||
}
|
|
||||||
#ifdef AF_INET6
|
|
||||||
else if (sa->sa_family == AF_INET6) {
|
|
||||||
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
|
|
||||||
if (sin6->sin6_port == 0)
|
|
||||||
sin6->sin6_port = htons(53);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
else
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
EVDNS_LOCK(base);
|
EVDNS_LOCK(base);
|
||||||
res = _evdns_nameserver_add_impl(base, sa, len);
|
res = _evdns_nameserver_add_impl(base, sa, len);
|
||||||
@ -3370,42 +3393,32 @@ evdns_base_resolv_conf_parse(struct evdns_base *base, int flags, const char *con
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
evdns_base_resolv_conf_parse_impl(struct evdns_base *base, int flags, const char *const filename) {
|
evdns_base_resolv_conf_parse_impl(struct evdns_base *base, int flags, const char *const filename) {
|
||||||
struct stat st;
|
size_t n;
|
||||||
int fd, n, r;
|
char *resolv;
|
||||||
u8 *resolv;
|
|
||||||
char *start;
|
char *start;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
log(EVDNS_LOG_DEBUG, "Parsing resolv.conf file %s", filename);
|
log(EVDNS_LOG_DEBUG, "Parsing resolv.conf file %s", filename);
|
||||||
|
|
||||||
fd = open(filename, O_RDONLY);
|
if (flags & DNS_OPTION_HOSTSFILE) {
|
||||||
if (fd < 0) {
|
#ifdef WIN32
|
||||||
evdns_resolv_set_defaults(base, flags);
|
evdns_base_load_hosts(base, NULL);
|
||||||
return 1;
|
#else
|
||||||
|
evdns_base_load_hosts(base, "/etc/hosts");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fstat(fd, &st)) { err = 2; goto out1; }
|
if ((err = evutil_read_file(filename, &resolv, &n, 0)) < 0) {
|
||||||
if (!st.st_size) {
|
if (err == -1) {
|
||||||
evdns_resolv_set_defaults(base, flags);
|
/* No file. */
|
||||||
err = (flags & DNS_OPTION_NAMESERVERS) ? 6 : 0;
|
evdns_resolv_set_defaults(base, flags);
|
||||||
goto out1;
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (st.st_size > 65535) { err = 3; goto out1; } /* no resolv.conf should be any bigger */
|
|
||||||
|
|
||||||
resolv = (u8 *) mm_malloc((size_t)st.st_size + 1);
|
start = resolv;
|
||||||
if (!resolv) { err = 4; goto out1; }
|
|
||||||
|
|
||||||
n = 0;
|
|
||||||
while ((r = read(fd, resolv+n, (size_t)st.st_size-n)) > 0) {
|
|
||||||
n += r;
|
|
||||||
if (n == st.st_size)
|
|
||||||
break;
|
|
||||||
EVUTIL_ASSERT(n < st.st_size);
|
|
||||||
}
|
|
||||||
if (r < 0) { err = 5; goto out2; }
|
|
||||||
resolv[n] = 0; /* we malloced an extra byte; this should be fine. */
|
|
||||||
|
|
||||||
start = (char *) resolv;
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
char *const newline = strchr(start, '\n');
|
char *const newline = strchr(start, '\n');
|
||||||
if (!newline) {
|
if (!newline) {
|
||||||
@ -3427,10 +3440,7 @@ evdns_base_resolv_conf_parse_impl(struct evdns_base *base, int flags, const char
|
|||||||
search_set_from_hostname(base);
|
search_set_from_hostname(base);
|
||||||
}
|
}
|
||||||
|
|
||||||
out2:
|
|
||||||
mm_free(resolv);
|
mm_free(resolv);
|
||||||
out1:
|
|
||||||
close(fd);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3441,6 +3451,8 @@ evdns_resolv_conf_parse(int flags, const char *const filename) {
|
|||||||
return evdns_base_resolv_conf_parse(current_base, flags, filename);
|
return evdns_base_resolv_conf_parse(current_base, flags, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
/* Add multiple nameservers from a space-or-comma-separated list. */
|
/* Add multiple nameservers from a space-or-comma-separated list. */
|
||||||
static int
|
static int
|
||||||
@ -3703,6 +3715,8 @@ evdns_base_new(struct event_base *event_base, int initialize_nameservers)
|
|||||||
base->global_nameserver_probe_initial_timeout.tv_sec = 10;
|
base->global_nameserver_probe_initial_timeout.tv_sec = 10;
|
||||||
base->global_nameserver_probe_initial_timeout.tv_usec = 0;
|
base->global_nameserver_probe_initial_timeout.tv_usec = 0;
|
||||||
|
|
||||||
|
TAILQ_INIT(&base->hostsdb);
|
||||||
|
|
||||||
if (initialize_nameservers) {
|
if (initialize_nameservers) {
|
||||||
int r;
|
int r;
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
@ -3798,6 +3812,15 @@ evdns_base_free_and_unlock(struct evdns_base *base, int fail_requests)
|
|||||||
mm_free(base->global_search_state);
|
mm_free(base->global_search_state);
|
||||||
base->global_search_state = NULL;
|
base->global_search_state = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
struct hosts_entry *victim;
|
||||||
|
while ((victim = TAILQ_FIRST(&base->hostsdb))) {
|
||||||
|
TAILQ_REMOVE(&base->hostsdb, victim, next);
|
||||||
|
mm_free(victim);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
EVDNS_UNLOCK(base);
|
EVDNS_UNLOCK(base);
|
||||||
EVTHREAD_FREE_LOCK(base->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
|
EVTHREAD_FREE_LOCK(base->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
|
||||||
|
|
||||||
@ -3822,6 +3845,111 @@ evdns_shutdown(int fail_requests)
|
|||||||
evdns_log_fn = NULL;
|
evdns_log_fn = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
evdns_base_parse_hosts_line(struct evdns_base *base, char *line)
|
||||||
|
{
|
||||||
|
char *strtok_state;
|
||||||
|
static const char *const delims = " \t";
|
||||||
|
char *const addr = strtok_r(line, delims, &strtok_state);
|
||||||
|
char *hostname, *hash;
|
||||||
|
struct sockaddr_storage ss;
|
||||||
|
int socklen = sizeof(ss);
|
||||||
|
ASSERT_LOCKED(base);
|
||||||
|
|
||||||
|
#define NEXT_TOKEN strtok_r(NULL, delims, &strtok_state)
|
||||||
|
|
||||||
|
if (!addr || *addr == '#')
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
memset(&ss, 0, sizeof(ss));
|
||||||
|
if (evutil_parse_sockaddr_port(addr, (struct sockaddr*)&ss, &socklen)<0)
|
||||||
|
return -1;
|
||||||
|
if (socklen > sizeof(struct sockaddr_in6))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (sockaddr_getport((struct sockaddr*)&ss))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
while ((hostname = NEXT_TOKEN)) {
|
||||||
|
struct hosts_entry *he;
|
||||||
|
size_t namelen;
|
||||||
|
if ((hash = strchr(hostname, '#'))) {
|
||||||
|
if (hash == hostname)
|
||||||
|
return 0;
|
||||||
|
*hash = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
namelen = strlen(hostname);
|
||||||
|
|
||||||
|
he = mm_calloc(1, sizeof(struct hosts_entry)+namelen);
|
||||||
|
if (!he)
|
||||||
|
return -1;
|
||||||
|
EVUTIL_ASSERT(socklen <= sizeof(he->addr));
|
||||||
|
memcpy(&he->addr, &ss, socklen);
|
||||||
|
memcpy(he->hostname, hostname, namelen+1);
|
||||||
|
he->addrlen = socklen;
|
||||||
|
|
||||||
|
TAILQ_INSERT_TAIL(&base->hostsdb, he, next);
|
||||||
|
|
||||||
|
if (hash)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
#undef NEXT_TOKEN
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
evdns_base_load_hosts_impl(struct evdns_base *base, const char *hosts_fname)
|
||||||
|
{
|
||||||
|
char *str=NULL, *cp, *eol;
|
||||||
|
size_t len;
|
||||||
|
int err=0;
|
||||||
|
|
||||||
|
ASSERT_LOCKED(base);
|
||||||
|
|
||||||
|
if (hosts_fname == NULL ||
|
||||||
|
(err = evutil_read_file(hosts_fname, &str, &len, 0)) < 0) {
|
||||||
|
char tmp[64];
|
||||||
|
strlcpy(tmp, "127.0.0.1 localhost", sizeof(tmp));
|
||||||
|
evdns_base_parse_hosts_line(base, tmp);
|
||||||
|
strlcpy(tmp, "::1 localhost", sizeof(tmp));
|
||||||
|
evdns_base_parse_hosts_line(base, tmp);
|
||||||
|
return err ? -1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This will break early if there is a NUL in the hosts file.
|
||||||
|
* Probably not a problem.*/
|
||||||
|
cp = str;
|
||||||
|
for (;;) {
|
||||||
|
eol = strchr(cp, '\n');
|
||||||
|
|
||||||
|
if (eol) {
|
||||||
|
*eol = '\0';
|
||||||
|
evdns_base_parse_hosts_line(base, cp);
|
||||||
|
cp = eol+1;
|
||||||
|
} else {
|
||||||
|
evdns_base_parse_hosts_line(base, cp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mm_free(str);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
evdns_base_load_hosts(struct evdns_base *base, const char *hosts_fname)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
if (!base)
|
||||||
|
base = current_base;
|
||||||
|
EVDNS_LOCK(base);
|
||||||
|
res = evdns_base_load_hosts_impl(base, hosts_fname);
|
||||||
|
EVDNS_UNLOCK(base);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/* A single request for a getaddrinfo, either v4 or v6. */
|
/* A single request for a getaddrinfo, either v4 or v6. */
|
||||||
struct getaddrinfo_subrequest {
|
struct getaddrinfo_subrequest {
|
||||||
struct evdns_request *r;
|
struct evdns_request *r;
|
||||||
@ -4106,6 +4234,64 @@ evdns_getaddrinfo_gotresolve(int result, char type, int count,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct hosts_entry *
|
||||||
|
find_hosts_entry(struct evdns_base *base, const char *hostname,
|
||||||
|
struct hosts_entry *find_after)
|
||||||
|
{
|
||||||
|
struct hosts_entry *e;
|
||||||
|
|
||||||
|
if (find_after)
|
||||||
|
e = TAILQ_NEXT(find_after, next);
|
||||||
|
else
|
||||||
|
e = TAILQ_FIRST(&base->hostsdb);
|
||||||
|
|
||||||
|
for (; e; e = TAILQ_NEXT(e, next)) {
|
||||||
|
if (!evutil_ascii_strcasecmp(e->hostname, hostname))
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
evdns_getaddrinfo_fromhosts(struct evdns_base *base,
|
||||||
|
const char *nodename, struct evutil_addrinfo *hints, ev_uint16_t port,
|
||||||
|
struct evutil_addrinfo **res)
|
||||||
|
{
|
||||||
|
int n_found = 0;
|
||||||
|
struct hosts_entry *e;
|
||||||
|
struct evutil_addrinfo *ai=NULL;
|
||||||
|
int f = hints->ai_family;
|
||||||
|
|
||||||
|
EVDNS_LOCK(base);
|
||||||
|
for (e = find_hosts_entry(base, nodename, NULL); e;
|
||||||
|
e = find_hosts_entry(base, nodename, e)) {
|
||||||
|
struct evutil_addrinfo *ai_new;
|
||||||
|
++n_found;
|
||||||
|
if ((e->addr.sa.sa_family == AF_INET && f == PF_INET6) ||
|
||||||
|
(e->addr.sa.sa_family == AF_INET6 && f == PF_INET))
|
||||||
|
continue;
|
||||||
|
ai_new = evutil_new_addrinfo(&e->addr.sa, e->addrlen, hints);
|
||||||
|
if (!ai_new) {
|
||||||
|
n_found = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
sockaddr_setport(ai_new->ai_addr, port);
|
||||||
|
ai = evutil_addrinfo_append(ai, ai_new);
|
||||||
|
}
|
||||||
|
EVDNS_UNLOCK(base);
|
||||||
|
out:
|
||||||
|
if (n_found) {
|
||||||
|
/* Note that we return an empty answer if we found entries for
|
||||||
|
* this hostname but none were of the right address type. */
|
||||||
|
*res = ai;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
if (ai)
|
||||||
|
evutil_freeaddrinfo(ai);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct evdns_getaddrinfo_request *
|
struct evdns_getaddrinfo_request *
|
||||||
evdns_getaddrinfo(struct evdns_base *dns_base,
|
evdns_getaddrinfo(struct evdns_base *dns_base,
|
||||||
const char *nodename, const char *servname,
|
const char *nodename, const char *servname,
|
||||||
@ -4158,6 +4344,12 @@ evdns_getaddrinfo(struct evdns_base *dns_base,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If there is an entry in the hosts file, we should give it now. */
|
||||||
|
if (!evdns_getaddrinfo_fromhosts(dns_base, nodename, &hints, port, &res)) {
|
||||||
|
cb(0, res, arg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Okay, things are serious now. We're going to need to actually
|
/* Okay, things are serious now. We're going to need to actually
|
||||||
* launch a request.
|
* launch a request.
|
||||||
*/
|
*/
|
||||||
|
@ -201,7 +201,8 @@ extern "C" {
|
|||||||
#define DNS_OPTION_SEARCH 1
|
#define DNS_OPTION_SEARCH 1
|
||||||
#define DNS_OPTION_NAMESERVERS 2
|
#define DNS_OPTION_NAMESERVERS 2
|
||||||
#define DNS_OPTION_MISC 4
|
#define DNS_OPTION_MISC 4
|
||||||
#define DNS_OPTIONS_ALL 7
|
#define DNS_OPTION_HOSTSFILE 8
|
||||||
|
#define DNS_OPTIONS_ALL 15
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The callback that contains the results from a lookup.
|
* The callback that contains the results from a lookup.
|
||||||
@ -431,7 +432,7 @@ int evdns_base_set_option(struct evdns_base *base, const char *option, const cha
|
|||||||
|
|
||||||
@param base the evdns_base to which to apply this operation
|
@param base the evdns_base to which to apply this operation
|
||||||
@param flags any of DNS_OPTION_NAMESERVERS|DNS_OPTION_SEARCH|DNS_OPTION_MISC|
|
@param flags any of DNS_OPTION_NAMESERVERS|DNS_OPTION_SEARCH|DNS_OPTION_MISC|
|
||||||
DNS_OPTIONS_ALL
|
DNS_OPTIONS_HOSTSFILE|DNS_OPTIONS_ALL
|
||||||
@param filename the path to the resolv.conf file
|
@param filename the path to the resolv.conf file
|
||||||
@return 0 if successful, or various positive error codes if an error
|
@return 0 if successful, or various positive error codes if an error
|
||||||
occurred (see above)
|
occurred (see above)
|
||||||
@ -439,6 +440,17 @@ int evdns_base_set_option(struct evdns_base *base, const char *option, const cha
|
|||||||
*/
|
*/
|
||||||
int evdns_base_resolv_conf_parse(struct evdns_base *base, int flags, const char *const filename);
|
int evdns_base_resolv_conf_parse(struct evdns_base *base, int flags, const char *const filename);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Load an /etc/hosts-style file from 'hosts_fname' into 'base'.
|
||||||
|
|
||||||
|
If hosts_fname is NULL, add minimal entries for localhost, and nothing
|
||||||
|
else.
|
||||||
|
|
||||||
|
Note that only evdns_getaddrinfo uses the /etc/hosts entries.
|
||||||
|
|
||||||
|
Return 0 on success, negative on failure.
|
||||||
|
*/
|
||||||
|
int evdns_base_load_hosts(struct evdns_base *base, const char *hosts_fname);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Obtain nameserver information using the Windows API.
|
Obtain nameserver information using the Windows API.
|
||||||
@ -616,7 +628,6 @@ struct evdns_getaddrinfo_request;
|
|||||||
* Limitations:
|
* Limitations:
|
||||||
*
|
*
|
||||||
* - The AI_V4MAPPED and AI_ALL flags are not currently implemented.
|
* - The AI_V4MAPPED and AI_ALL flags are not currently implemented.
|
||||||
* - We don't look at the /etc/hosts file.
|
|
||||||
* - For ai_socktype, we only handle SOCKTYPE_STREAM, SOCKTYPE_UDP, and 0.
|
* - For ai_socktype, we only handle SOCKTYPE_STREAM, SOCKTYPE_UDP, and 0.
|
||||||
* - For ai_protocol, we only handle IPPROTO_TCP, IPPROTO_UDP, and 0.
|
* - For ai_protocol, we only handle IPPROTO_TCP, IPPROTO_UDP, and 0.
|
||||||
*/
|
*/
|
||||||
|
@ -1151,6 +1151,9 @@ test_getaddrinfo_async(void *arg)
|
|||||||
|
|
||||||
struct evdns_base *dns_base = evdns_base_new(data->base, 0);
|
struct evdns_base *dns_base = evdns_base_new(data->base, 0);
|
||||||
|
|
||||||
|
/* for localhost */
|
||||||
|
evdns_base_load_hosts(dns_base, NULL);
|
||||||
|
|
||||||
memset(a_out, 0, sizeof(a_out));
|
memset(a_out, 0, sizeof(a_out));
|
||||||
|
|
||||||
n_gai_results_pending = 10000; /* don't think about exiting yet. */
|
n_gai_results_pending = 10000; /* don't think about exiting yet. */
|
||||||
@ -1260,6 +1263,43 @@ test_getaddrinfo_async(void *arg)
|
|||||||
evutil_freeaddrinfo(local_outcome.ai);
|
evutil_freeaddrinfo(local_outcome.ai);
|
||||||
local_outcome.ai = NULL;
|
local_outcome.ai = NULL;
|
||||||
|
|
||||||
|
/* 1g. We find localhost immediately. (pf_unspec) */
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
memset(&local_outcome, 0, sizeof(local_outcome));
|
||||||
|
hints.ai_family = PF_UNSPEC;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
r = evdns_getaddrinfo(dns_base, "LOCALHOST", "80",
|
||||||
|
&hints, gai_cb, &local_outcome);
|
||||||
|
tt_int_op(r,==,0);
|
||||||
|
tt_int_op(local_outcome.err,==,0);
|
||||||
|
tt_assert(local_outcome.ai);
|
||||||
|
/* we should get a v4 address of 127.0.0.1 .... */
|
||||||
|
a = ai_find_by_family(local_outcome.ai, PF_INET);
|
||||||
|
tt_assert(a);
|
||||||
|
test_ai_eq(a, "127.0.0.1:80", SOCK_STREAM, IPPROTO_TCP);
|
||||||
|
/* ... and a v6 address of ::1 */
|
||||||
|
a = ai_find_by_family(local_outcome.ai, PF_INET6);
|
||||||
|
tt_assert(a);
|
||||||
|
test_ai_eq(a, "[::1]:80", SOCK_STREAM, IPPROTO_TCP);
|
||||||
|
evutil_freeaddrinfo(local_outcome.ai);
|
||||||
|
local_outcome.ai = NULL;
|
||||||
|
|
||||||
|
/* 1g. We find localhost immediately. (pf_inet6) */
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
memset(&local_outcome, 0, sizeof(local_outcome));
|
||||||
|
hints.ai_family = PF_INET6;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
r = evdns_getaddrinfo(dns_base, "LOCALHOST", "9999",
|
||||||
|
&hints, gai_cb, &local_outcome);
|
||||||
|
tt_int_op(r,==,0);
|
||||||
|
tt_int_op(local_outcome.err,==,0);
|
||||||
|
tt_assert(local_outcome.ai);
|
||||||
|
a = local_outcome.ai;
|
||||||
|
test_ai_eq(a, "[::1]:9999", SOCK_STREAM, IPPROTO_TCP);
|
||||||
|
tt_ptr_op(a->ai_next, ==, NULL);
|
||||||
|
evutil_freeaddrinfo(local_outcome.ai);
|
||||||
|
local_outcome.ai = NULL;
|
||||||
|
|
||||||
/* 2. Okay, now we can actually test the asynchronous resolver. */
|
/* 2. Okay, now we can actually test the asynchronous resolver. */
|
||||||
/* Start a dummy local dns server... */
|
/* Start a dummy local dns server... */
|
||||||
port = get_generic_server(data->base, &dns_port,
|
port = get_generic_server(data->base, &dns_port,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user