summaryrefslogtreecommitdiff
path: root/gweb
diff options
context:
space:
mode:
authorDavid Woodhouse <David.Woodhouse@intel.com>2010-12-02 00:25:30 +0000
committerDavid Woodhouse <David.Woodhouse@intel.com>2010-12-02 00:28:34 +0000
commit96ab387102b4a9db92772f02aadeca9a93514af9 (patch)
tree94df5225eb6154423a4e23ebab8c9bbf7e721fe5 /gweb
parent658282bdf62e165c44a5e97e22ba5cce13839044 (diff)
downloadconnman-96ab387102b4a9db92772f02aadeca9a93514af9.tar.gz
connman-96ab387102b4a9db92772f02aadeca9a93514af9.tar.bz2
connman-96ab387102b4a9db92772f02aadeca9a93514af9.zip
gresolv: Don't convert results to strings so early
We're going to want results in sockaddr form for sorting, so let's put them directly into the array we'll want for the sort process, even though we haven't actually implemented sorting yet. We can ditch the support for arbitrary callbacks from the individual queries, too; there's no need for that. The callback to user code comes from the *lookup*, having combined the A and AAAA query results.
Diffstat (limited to 'gweb')
-rw-r--r--gweb/gresolv.c194
1 files changed, 100 insertions, 94 deletions
diff --git a/gweb/gresolv.c b/gweb/gresolv.c
index 09509da1..2b686a02 100644
--- a/gweb/gresolv.c
+++ b/gweb/gresolv.c
@@ -36,11 +36,30 @@
#include "gresolv.h"
+struct sort_result {
+ int precedence;
+ int scope;
+ gboolean reachable;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ } src;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ } dst;
+};
+
+struct resolv_query;
+
struct resolv_lookup {
GResolv *resolv;
guint id;
- char **results;
+ int nr_results;
+ struct sort_result *results;
struct resolv_query *ipv4_query;
struct resolv_query *ipv6_query;
@@ -59,8 +78,7 @@ struct resolv_query {
uint16_t msgid;
- GResolvResultFunc result_func;
- gpointer result_data;
+ struct resolv_lookup *lookup;
};
struct resolv_nameserver {
@@ -90,6 +108,8 @@ struct _GResolv {
gpointer debug_data;
};
+static void sort_and_return_results(struct resolv_lookup *lookup);
+
static inline void debug(GResolv *resolv, const char *format, ...)
{
char str[256];
@@ -124,20 +144,27 @@ static void destroy_lookup(struct resolv_lookup *lookup)
destroy_query(lookup->ipv6_query);
g_queue_remove(lookup->resolv->query_queue, lookup->ipv4_query);
}
- g_strfreev(lookup->results);
+ g_free(lookup->results);
g_free(lookup);
}
static gboolean query_timeout(gpointer user_data)
{
struct resolv_query *query = user_data;
+ struct resolv_lookup *lookup = query->lookup;
GResolv *resolv = query->resolv;
query->timeout = 0;
- if (query->result_func != NULL)
- query->result_func(G_RESOLV_RESULT_STATUS_NO_RESPONSE,
- NULL, query->result_data);
+ if (query == lookup->ipv4_query) {
+ lookup->ipv4_status = G_RESOLV_RESULT_STATUS_NO_RESPONSE;
+ lookup->ipv4_query = NULL;
+ } else if (query == lookup->ipv6_query) {
+ lookup->ipv6_status = G_RESOLV_RESULT_STATUS_NO_RESPONSE;
+ lookup->ipv6_query = NULL;
+ }
+ if (!lookup->ipv4_query && !lookup->ipv4_query)
+ sort_and_return_results(lookup);
destroy_query(query);
g_queue_remove(resolv->query_queue, query);
@@ -223,13 +250,29 @@ static gint compare_query_msgid(gconstpointer a, gconstpointer b)
return 0;
}
+static void add_result(struct resolv_lookup *lookup, int family, const void *data)
+{
+ int n = lookup->nr_results++;
+ lookup->results = g_realloc(lookup->results,
+ sizeof(struct sort_result) * (n+1));
+
+ memset(&lookup->results[n], 0, sizeof(struct sort_result));
+
+ lookup->results[n].dst.sa.sa_family = family;
+ if (family == AF_INET)
+ memcpy(&lookup->results[n].dst.sin.sin_addr, data, NS_INADDRSZ);
+ else
+ memcpy(&lookup->results[n].dst.sin6.sin6_addr, data, NS_IN6ADDRSZ);
+}
+
static void parse_response(struct resolv_nameserver *nameserver,
const unsigned char *buf, int len)
{
GResolv *resolv = nameserver->resolv;
GResolvResultStatus status;
+ struct resolv_query *query;
+ struct resolv_lookup *lookup;
GList *list;
- char **results;
ns_msg msg;
ns_rr rr;
int i, n, rcode, count;
@@ -268,50 +311,45 @@ static void parse_response(struct resolv_nameserver *nameserver,
break;
}
- results = g_try_new(char *, count + 1);
- if (results == NULL)
+ list = g_queue_find_custom(resolv->query_queue,
+ GUINT_TO_POINTER(ns_msg_id(msg)), compare_query_msgid);
+ if (!list)
return;
- for (i = 0, n = 0; i < count; i++) {
- char result[100];
+ query = list->data;
+ lookup = query->lookup;
+
+ if (query == lookup->ipv6_query) {
+ lookup->ipv6_status = status;
+ lookup->ipv6_query = NULL;
+ } else if (query == lookup->ipv4_query) {
+ lookup->ipv4_status = status;
+ lookup->ipv4_query = NULL;
+ }
+ for (i = 0, n = 0; i < count; i++) {
ns_parserr(&msg, ns_s_an, i, &rr);
if (ns_rr_class(rr) != ns_c_in)
continue;
+ g_assert(offsetof(struct sockaddr_in, sin_addr) ==
+ offsetof(struct sockaddr_in6, sin6_flowinfo));
+
if (ns_rr_type(rr) == ns_t_a &&
ns_rr_rdlen(rr) == NS_INADDRSZ) {
- inet_ntop(AF_INET, ns_rr_rdata(rr), result, sizeof(result));
+ add_result(lookup, AF_INET, ns_rr_rdata(rr));
} else if (ns_rr_type(rr) == ns_t_aaaa &&
ns_rr_rdlen(rr) == NS_IN6ADDRSZ) {
- inet_ntop(AF_INET6, ns_rr_rdata(rr), result, sizeof(result));
- } else
- continue;
-
- results[n++] = g_strdup(result);
+ add_result(lookup, AF_INET6, ns_rr_rdata(rr));
+ }
}
- results[n] = NULL;
-
- list = g_queue_find_custom(resolv->query_queue,
- GUINT_TO_POINTER(ns_msg_id(msg)), compare_query_msgid);
-
- if (list != NULL) {
- struct resolv_query *query = list->data;
-
- /* FIXME: This set of results is *only* for a single A or AAAA
- query; we need to merge both results together and then sort
- them according to RFC3484. While honouring /etc/gai.conf */
- if (query->result_func != NULL)
- query->result_func(status, results,
- query->result_data);
-
- destroy_query(query);
- g_queue_remove(resolv->query_queue, query);
- }
+ if (!lookup->ipv4_query && !lookup->ipv6_query)
+ sort_and_return_results(lookup);
- g_strfreev(results);
+ destroy_query(query);
+ g_queue_remove(resolv->query_queue, query);
}
static gboolean received_udp_data(GIOChannel *channel, GIOCondition cond,
@@ -506,73 +544,45 @@ void g_resolv_flush_nameservers(GResolv *resolv)
flush_nameservers(resolv);
}
-static int count_results(char **results)
+static void sort_and_return_results(struct resolv_lookup *lookup)
{
- int i;
+ char buf[100];
+ GResolvResultStatus status;
+ char **results = g_try_new0(char *, lookup->nr_results + 1);
+ int i, n = 0;
if (!results)
- return 0;
-
- for (i = 0; results[i]; i++)
- ;
-
- return i;
-}
+ return;
-static void add_result(struct resolv_lookup *lookup, char **results)
-{
- int nr_new_results = count_results(results);
- int nr_old_results = count_results(lookup->results);
- GResolvResultStatus status;
+ /* FIXME: Now sort them properly according to RFC3484 and /etc/gai.conf */
- if (nr_new_results) {
- lookup->results = g_realloc(lookup->results, sizeof(char *) *
- (nr_new_results + nr_old_results + 1));
+ for (i = 0; i < lookup->nr_results; i++) {
+ if (lookup->results[i].dst.sa.sa_family == AF_INET) {
+ if (!inet_ntop(AF_INET, &lookup->results[i].dst.sin.sin_addr,
+ buf, sizeof(buf)))
+ continue;
+ } else if (lookup->results[i].dst.sa.sa_family == AF_INET6) {
+ if (!inet_ntop(AF_INET6, &lookup->results[i].dst.sin6.sin6_addr,
+ buf, sizeof(buf)))
+ continue;
+ } else
+ continue;
- while (nr_new_results) {
- lookup->results[nr_old_results++] = results[0];
- results[0] = NULL;
- results++;
- nr_new_results--;
- }
- lookup->results[nr_old_results] = NULL;
+ results[n++] = strdup(buf);
}
- if (lookup->ipv4_query || lookup->ipv6_query)
- return;
-
- /* FIXME: Sort results according to RFC3484 and /etc/gai.conf */
+ results[n++] = NULL;
status = lookup->ipv4_status;
if (status == G_RESOLV_RESULT_STATUS_SUCCESS)
status = lookup->ipv6_status;
- lookup->result_func(status, lookup->results, lookup->result_data);
+ lookup->result_func(status, results, lookup->result_data);
+ g_strfreev(results);
g_queue_remove(lookup->resolv->lookup_queue, lookup);
destroy_lookup(lookup);
}
-static void ipv4_result(GResolvResultStatus status, char **results, gpointer data)
-{
- struct resolv_lookup *lookup = data;
-
- lookup->ipv4_status = status;
- lookup->ipv4_query = NULL;
-
- add_result(lookup, results);
-}
-
-static void ipv6_result(GResolvResultStatus status, char **results, gpointer data)
-{
- struct resolv_lookup *lookup = data;
-
- lookup->ipv6_status = status;
- lookup->ipv6_query = NULL;
-
- add_result(lookup, results);
-}
-
-
static gint add_query(struct resolv_lookup *lookup, const char *hostname, int type)
{
struct resolv_query *query = g_try_new0(struct resolv_query, 1);
@@ -587,24 +597,20 @@ static gint add_query(struct resolv_lookup *lookup, const char *hostname, int ty
query->msgid = buf[0] << 8 | buf[1];
- query->result_data = lookup;
-
if (send_query(lookup->resolv, buf, len) < 0)
return -EIO;
query->resolv = lookup->resolv;
+ query->lookup = lookup;
g_queue_push_tail(lookup->resolv->query_queue, query);
query->timeout = g_timeout_add_seconds(5, query_timeout, query);
- if (type == ns_t_aaaa) {
- query->result_func = ipv6_result;
+ if (type == ns_t_aaaa)
lookup->ipv6_query = query;
- } else {
- query->result_func = ipv4_result;
+ else
lookup->ipv4_query = query;
- }
return 0;
}