summaryrefslogtreecommitdiff
path: root/ares_gethostbyname.c
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2009-01-31 20:17:41 (GMT)
committerDaniel Stenberg <daniel@haxx.se>2009-01-31 20:17:41 (GMT)
commit1ce8e6583ebcdc448c3187d186a9ef219218bfdb (patch)
tree544bf377dbb9d8320556ec5ad0ba72f25fa77640 /ares_gethostbyname.c
parent054aa0e11e3e71109bcb994146f2e641916ef115 (diff)
downloadc-ares-1ce8e6583ebcdc448c3187d186a9ef219218bfdb.zip
c-ares-1ce8e6583ebcdc448c3187d186a9ef219218bfdb.tar.gz
c-ares-1ce8e6583ebcdc448c3187d186a9ef219218bfdb.tar.bz2
- ares_gethostbyname() now accepts 'AF_UNSPEC' as a family for resolving
either AF_INET6 or AF_INET. It works by accepting any of the looksups in the hosts file, and it resolves the AAAA field with a fallback to A.
Diffstat (limited to 'ares_gethostbyname.c')
-rw-r--r--ares_gethostbyname.c95
1 files changed, 54 insertions, 41 deletions
diff --git a/ares_gethostbyname.c b/ares_gethostbyname.c
index 55bfb30..e6b9f7f 100644
--- a/ares_gethostbyname.c
+++ b/ares_gethostbyname.c
@@ -61,7 +61,8 @@ struct host_query {
char *name;
ares_host_callback callback;
void *arg;
- int family;
+ int sent_family; /* this family is what was is being used */
+ int want_family; /* this family is what is asked for in the API */
const char *remaining_lookups;
int timeouts;
};
@@ -71,29 +72,34 @@ static void host_callback(void *arg, int status, int timeouts,
unsigned char *abuf, int alen);
static void end_hquery(struct host_query *hquery, int status,
struct hostent *host);
-static int fake_hostent(const char *name, int family, ares_host_callback callback,
- void *arg);
+static int fake_hostent(const char *name, int family,
+ ares_host_callback callback, void *arg);
static int file_lookup(const char *name, int family, struct hostent **host);
-static void sort_addresses(struct hostent *host, const struct apattern *sortlist,
- int nsort);
-static void sort6_addresses(struct hostent *host, const struct apattern *sortlist,
- int nsort);
-static int get_address_index(const struct in_addr *addr, const struct apattern *sortlist,
- int nsort);
-static int get6_address_index(const struct in6_addr *addr, const struct apattern *sortlist,
- int nsort);
+static void sort_addresses(struct hostent *host,
+ const struct apattern *sortlist, int nsort);
+static void sort6_addresses(struct hostent *host,
+ const struct apattern *sortlist, int nsort);
+static int get_address_index(const struct in_addr *addr,
+ const struct apattern *sortlist, int nsort);
+static int get6_address_index(const struct in6_addr *addr,
+ const struct apattern *sortlist, int nsort);
void ares_gethostbyname(ares_channel channel, const char *name, int family,
ares_host_callback callback, void *arg)
{
struct host_query *hquery;
- /* Right now we only know how to look up Internet addresses. */
- if (family != AF_INET && family != AF_INET6)
- {
- callback(arg, ARES_ENOTIMP, 0, NULL);
- return;
- }
+ /* Right now we only know how to look up Internet addresses - and unspec
+ means try both basically. */
+ switch (family) {
+ case AF_INET:
+ case AF_INET6:
+ case AF_UNSPEC:
+ break;
+ default:
+ callback(arg, ARES_ENOTIMP, 0, NULL);
+ return;
+ }
if (fake_hostent(name, family, callback, arg))
return;
@@ -107,13 +113,13 @@ void ares_gethostbyname(ares_channel channel, const char *name, int family,
}
hquery->channel = channel;
hquery->name = strdup(name);
- hquery->family = family;
- if (!hquery->name)
- {
- free(hquery);
- callback(arg, ARES_ENOMEM, 0, NULL);
- return;
- }
+ hquery->want_family = family;
+ hquery->sent_family = -1; /* nothing is sent yet */
+ if (!hquery->name) {
+ free(hquery);
+ callback(arg, ARES_ENOMEM, 0, NULL);
+ return;
+ }
hquery->callback = callback;
hquery->arg = arg;
hquery->remaining_lookups = channel->lookups;
@@ -136,17 +142,23 @@ static void next_lookup(struct host_query *hquery, int status_code)
case 'b':
/* DNS lookup */
hquery->remaining_lookups = p + 1;
- if (hquery->family == AF_INET6)
+ if ((hquery->want_family == AF_INET6) ||
+ (hquery->want_family == AF_UNSPEC)) {
+ /* if inet6 or unspec, start out with AAAA */
+ hquery->sent_family = AF_INET6;
ares_search(hquery->channel, hquery->name, C_IN, T_AAAA,
host_callback, hquery);
- else
+ }
+ else {
+ hquery->sent_family = AF_INET;
ares_search(hquery->channel, hquery->name, C_IN, T_A, host_callback,
hquery);
+ }
return;
case 'f':
/* Host file lookup */
- status = file_lookup(hquery->name, hquery->family, &host);
+ status = file_lookup(hquery->name, hquery->want_family, &host);
/* this status check below previously checked for !ARES_ENOTFOUND,
but we should not assume that this single error code is the one
@@ -173,33 +185,34 @@ static void host_callback(void *arg, int status, int timeouts,
hquery->timeouts += timeouts;
if (status == ARES_SUCCESS)
{
- if (hquery->family == AF_INET)
+ if (hquery->sent_family == AF_INET)
{
status = ares_parse_a_reply(abuf, alen, &host, NULL, NULL);
if (host && channel->nsort)
sort_addresses(host, channel->sortlist, channel->nsort);
}
- else if (hquery->family == AF_INET6)
+ else if (hquery->sent_family == AF_INET6)
{
status = ares_parse_aaaa_reply(abuf, alen, &host, NULL, NULL);
- if (status == ARES_ENODATA)
- {
- /* The query returned something (e.g. CNAME) but there were no
- AAAA records. Try looking up A instead. */
- hquery->family = AF_INET;
- ares_search(hquery->channel, hquery->name, C_IN, T_A, host_callback,
- hquery);
- return;
- }
+ if (status == ARES_ENODATA) {
+ /* The query returned something (e.g. CNAME) but there were no
+ AAAA records. Try looking up A instead. We should possibly
+ limit this attempt-next logic to AF_UNSPEC lookups only. */
+ hquery->sent_family = AF_INET;
+ ares_search(hquery->channel, hquery->name, C_IN, T_A,
+ host_callback, hquery);
+ return;
+ }
if (host && channel->nsort)
sort6_addresses(host, channel->sortlist, channel->nsort);
}
end_hquery(hquery, status, host);
}
- else if (status == ARES_ENODATA && hquery->family == AF_INET6)
+ else if (status == ARES_ENODATA && hquery->sent_family == AF_INET6)
{
- /* There was no AAAA. Now lookup an A */
- hquery->family = AF_INET;
+ /* There was no AAAA. Now lookup an A. We should possibly limit this
+ attempt-next logic to AF_UNSPEC lookups only. */
+ hquery->sent_family = AF_INET;
ares_search(hquery->channel, hquery->name, C_IN, T_A, host_callback,
hquery);
}