technology: return already enabled when tethering is enabled
[framework/connectivity/connman.git] / gweb / gresolv.c
index 938aa69..e93bf4f 100644 (file)
@@ -2,7 +2,7 @@
  *
  *  Resolver library with GLib integration
  *
- *  Copyright (C) 2009-2010  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2009-2012  Intel Corporation. All rights reserved.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2 as
@@ -34,6 +34,7 @@
 #include <netdb.h>
 #include <arpa/inet.h>
 #include <arpa/nameser.h>
+#include <net/if.h>
 
 #include "gresolv.h"
 
@@ -97,7 +98,9 @@ struct resolv_nameserver {
 };
 
 struct _GResolv {
-       gint ref_count;
+       int ref_count;
+
+       int result_family;
 
        guint next_lookup_id;
        GQueue *lookup_queue;
@@ -159,7 +162,8 @@ static void find_srcaddr(struct sort_result *res)
        socklen_t sl = sizeof(res->src);
        int fd;
 
-       fd = socket(res->dst.sa.sa_family, SOCK_DGRAM, IPPROTO_IP);
+       fd = socket(res->dst.sa.sa_family, SOCK_DGRAM | SOCK_CLOEXEC,
+                       IPPROTO_IP);
        if (fd < 0)
                return;
 
@@ -451,7 +455,7 @@ static void rfc3484_sort_results(struct resolv_lookup *lookup)
 
 static void sort_and_return_results(struct resolv_lookup *lookup)
 {
-       char buf[100];
+       char buf[INET6_ADDRSTRLEN + 1];
        GResolvResultStatus status;
        char **results = g_try_new0(char *, lookup->nr_results + 1);
        int i, n = 0;
@@ -459,18 +463,20 @@ static void sort_and_return_results(struct resolv_lookup *lookup)
        if (!results)
                return;
 
+       memset(buf, 0, INET6_ADDRSTRLEN + 1);
+
        rfc3484_sort_results(lookup);
 
        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)) == NULL)
+                                       buf, sizeof(buf) - 1) == NULL)
                                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)) == NULL)
+                                       buf, sizeof(buf) - 1) == NULL)
                                continue;
                } else
                        continue;
@@ -562,6 +568,8 @@ static int send_query(GResolv *resolv, const unsigned char *buf, int len)
                sk = g_io_channel_unix_get_fd(nameserver->udp_channel);
 
                sent = send(sk, buf, len, 0);
+               if (sent < 0)
+                       continue;
        }
 
        return 0;
@@ -599,8 +607,10 @@ static void add_result(struct resolv_lookup *lookup, int family,
                                                        const void *data)
 {
        int n = lookup->nr_results++;
-       lookup->results = g_realloc(lookup->results,
+       lookup->results = g_try_realloc(lookup->results,
                                        sizeof(struct sort_result) * (n + 1));
+       if (lookup->results == NULL)
+               return;
 
        memset(&lookup->results[n], 0, sizeof(struct sort_result));
 
@@ -623,7 +633,7 @@ static void parse_response(struct resolv_nameserver *nameserver,
        GList *list;
        ns_msg msg;
        ns_rr rr;
-       int i, n, rcode, count;
+       int i, rcode, count;
 
        debug(resolv, "response from %s", nameserver->address);
 
@@ -675,7 +685,7 @@ static void parse_response(struct resolv_nameserver *nameserver,
                lookup->ipv4_query = NULL;
        }
 
-       for (i = 0, n = 0; i < count; i++) {
+       for (i = 0; i < count; i++) {
                ns_parserr(&msg, ns_s_an, i, &rr);
 
                if (ns_rr_class(rr) != ns_c_in)
@@ -753,6 +763,26 @@ static int connect_udp_channel(struct resolv_nameserver *nameserver)
                return -EIO;
        }
 
+       /*
+        * If nameserver points to localhost ip, their is no need to
+        * bind the socket on any interface.
+        */
+       if (nameserver->resolv->index > 0 &&
+                       strncmp(nameserver->address, "127.0.0.1", 9) != 0) {
+               char interface[IF_NAMESIZE];
+
+               memset(interface, 0, IF_NAMESIZE);
+               if (if_indextoname(nameserver->resolv->index,
+                                               interface) != NULL) {
+                       if (setsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE,
+                                               interface, IF_NAMESIZE) < 0) {
+                               close(sk);
+                               freeaddrinfo(rp);
+                               return -EIO;
+                       }
+               }
+       }
+
        if (connect(sk, rp->ai_addr, rp->ai_addrlen) < 0) {
                close(sk);
                freeaddrinfo(rp);
@@ -789,6 +819,8 @@ GResolv *g_resolv_new(int index)
 
        resolv->ref_count = 1;
 
+       resolv->result_family = AF_UNSPEC;
+
        resolv->next_lookup_id = 1;
 
        resolv->query_queue = g_queue_new();
@@ -817,7 +849,7 @@ GResolv *g_resolv_ref(GResolv *resolv)
        if (resolv == NULL)
                return NULL;
 
-       g_atomic_int_inc(&resolv->ref_count);
+       __sync_fetch_and_add(&resolv->ref_count, 1);
 
        return resolv;
 }
@@ -829,7 +861,7 @@ void g_resolv_unref(GResolv *resolv)
        if (resolv == NULL)
                return;
 
-       if (g_atomic_int_dec_and_test(&resolv->ref_count) == FALSE)
+       if (__sync_fetch_and_sub(&resolv->ref_count, 1) != 1)
                return;
 
        while ((query = g_queue_pop_head(resolv->query_queue)))
@@ -870,14 +902,13 @@ gboolean g_resolv_add_nameserver(GResolv *resolv, const char *address,
        nameserver->address = g_strdup(address);
        nameserver->port = port;
        nameserver->flags = flags;
+       nameserver->resolv = resolv;
 
        if (connect_udp_channel(nameserver) < 0) {
                free_nameserver(nameserver);
                return FALSE;
        }
 
-       nameserver->resolv = resolv;
-
        resolv->nameserver_list = g_list_append(resolv->nameserver_list,
                                                                nameserver);
 
@@ -908,8 +939,10 @@ static gint add_query(struct resolv_lookup *lookup, const char *hostname, int ty
 
        query->msgid = buf[0] << 8 | buf[1];
 
-       if (send_query(lookup->resolv, buf, len) < 0)
+       if (send_query(lookup->resolv, buf, len) < 0) {
+               g_free(query);
                return -EIO;
+       }
 
        query->resolv = lookup->resolv;
        query->lookup = lookup;
@@ -970,16 +1003,24 @@ guint g_resolv_lookup_hostname(GResolv *resolv, const char *hostname,
        lookup->result_data = user_data;
        lookup->id = resolv->next_lookup_id++;
 
-       if (add_query(lookup, hostname, ns_t_a)) {
-               g_free(lookup);
-               return -EIO;
+       if (resolv->result_family != AF_INET6) {
+               if (add_query(lookup, hostname, ns_t_a)) {
+                       g_free(lookup);
+                       return -EIO;
+               }
        }
 
-       if (add_query(lookup, hostname, ns_t_aaaa)) {
-               destroy_query(lookup->ipv4_query);
-               g_queue_remove(resolv->query_queue, lookup->ipv4_query);
-               g_free(lookup);
-               return -EIO;
+       if (resolv->result_family != AF_INET) {
+               if (add_query(lookup, hostname, ns_t_aaaa)) {
+                       if (resolv->result_family != AF_INET6) {
+                               destroy_query(lookup->ipv4_query);
+                               g_queue_remove(resolv->query_queue,
+                                               lookup->ipv4_query);
+                       }
+
+                       g_free(lookup);
+                       return -EIO;
+               }
        }
 
        g_queue_push_tail(resolv->lookup_queue, lookup);
@@ -1001,3 +1042,16 @@ gboolean g_resolv_cancel_lookup(GResolv *resolv, guint id)
 
        return TRUE;
 }
+
+gboolean g_resolv_set_address_family(GResolv *resolv, int family)
+{
+       if (resolv == NULL)
+               return FALSE;
+
+       if (family != AF_UNSPEC && family != AF_INET && family != AF_INET6)
+               return FALSE;
+
+       resolv->result_family = family;
+
+       return TRUE;
+}