Fixed memory leaks
[platform/core/connectivity/net-config.git] / src / network-state.c
index c2f5e92..bd6c95a 100755 (executable)
@@ -38,6 +38,9 @@
 #include "network-dpm.h"
 #include "network-monitor.h"
 #include "netsupplicant.h"
+#if defined TIZEN_DEBUG_ENABLE
+#include "network-dump.h"
+#endif
 
 #include "generated-code.h"
 /* Define TCP buffer sizes for various networks */
@@ -88,6 +91,9 @@ typedef struct {
 } net_profile_name_t;
 
 static Network *netconfigstate = NULL;
+#if defined TIZEN_DEBUG_ENABLE
+static Tcpdump *tcpdump_object = NULL;
+#endif
 
 struct netconfig_default_connection {
        char *profile;
@@ -508,6 +514,73 @@ done:
        return;
 }
 
+static char *__netconfig_get_preferred_ipv6_address(char *profile)
+{
+       GVariant *message = NULL, *variant = NULL, *next = NULL;
+       GVariantIter *iter = NULL, *sub_iter = NULL, *service = NULL;
+       gchar *obj_path;
+       gchar *key = NULL;
+       gchar *sub_key = NULL;
+       gchar *preferred_address6 = NULL;
+       gboolean found_profile = 0;
+
+       message = netconfig_invoke_dbus_method(CONNMAN_SERVICE,
+                                       CONNMAN_MANAGER_PATH, CONNMAN_MANAGER_INTERFACE,
+                                       "GetServices", NULL);
+       if (message == NULL) {
+               ERR("Failed to get service informations");
+               goto done;
+       }
+
+       g_variant_get(message, "(a(oa{sv}))", &service);
+       if (service == NULL) {
+               ERR("Failed to get services iter");
+               goto done;
+       }
+
+       while (g_variant_iter_loop(service, "(oa{sv})", &obj_path, &iter)) {
+               if (g_strcmp0(obj_path, profile) == 0) {
+                       g_free(obj_path);
+                       found_profile = 1;
+                       break;
+               }
+       }
+
+       if (iter == NULL || found_profile == 0) {
+               ERR("Profile %s doesn't exist", profile);
+                       goto done;
+       }
+
+       while (g_variant_iter_loop(iter, "{sv}", &key, &next)) {
+               const gchar *value = NULL;
+               if (g_strcmp0(key, "IPv6") == 0) {
+                       g_variant_get(next, "a{sv}", &sub_iter);
+                       if (sub_iter == NULL)
+                               continue;
+                       while (g_variant_iter_loop(sub_iter, "{sv}", &sub_key, &variant)) {
+                               if (g_strcmp0(sub_key, "Address") == 0) {
+                                       value = g_variant_get_string(variant, NULL);
+                                       if (!preferred_address6)
+                                               preferred_address6 = g_strdup(value);
+                               }
+                       }
+                       g_variant_iter_free(sub_iter);
+               }
+       }
+
+done:
+       if (message)
+               g_variant_unref(message);
+
+       if (iter)
+               g_variant_iter_free(iter);
+
+       if (service)
+               g_variant_iter_free(service);
+
+       return preferred_address6;
+}
+
 static void __netconfig_adjust_tcp_buffer_size(void)
 {
        int fdr = 0, fdw = 0;
@@ -644,17 +717,38 @@ static void __netconfig_update_default_connection_info(void)
        const char *ip_addr6 = netconfig_get_default_ipaddress6();
        const char *proxy_addr = netconfig_get_default_proxy();
        unsigned int freq = netconfig_get_default_frequency();
+       GVariantBuilder *builder;
+       GVariant *params;
 
        if (emulator_is_emulated() == TRUE) {
-               if (ip_addr != NULL)
+               builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+
+               if (ip_addr != NULL) {
                        netconfig_set_vconf_str(VCONFKEY_NETWORK_IP, ip_addr);
-               else
+                       g_variant_builder_add(builder, "{sv}", "IPv4Address",
+                                                                 g_variant_new_string(ip_addr));
+               } else {
                        netconfig_set_vconf_str(VCONFKEY_NETWORK_IP, "");
+                       g_variant_builder_add(builder, "{sv}", "IPv4Address",
+                                                                 g_variant_new_string(""));
+               }
 
-               if (ip_addr6 != NULL)
+               if (ip_addr6 != NULL) {
                        netconfig_set_vconf_str(VCONFKEY_NETWORK_IP6, ip_addr6);
-               else
+                       g_variant_builder_add(builder, "{sv}", "IPv6Address",
+                                                                 g_variant_new_string(ip_addr6));
+               } else {
                        netconfig_set_vconf_str(VCONFKEY_NETWORK_IP6, "");
+                       g_variant_builder_add(builder, "{sv}", "IPv6Address",
+                                                                 g_variant_new_string(""));
+               }
+
+               params = g_variant_new("(@a{sv})", g_variant_builder_end(builder));
+               g_variant_builder_unref(builder);
+
+               netconfig_dbus_emit_signal(NULL, NETCONFIG_NETWORK_PATH,
+                                                  NETCONFIG_NETWORK_INTERFACE, "NetworkConfigChanged",
+                                                  params);
 
                return;
        }
@@ -662,20 +756,40 @@ static void __netconfig_update_default_connection_info(void)
        if (profile == NULL)
                DBG("Reset network state configuration");
        else
-               DBG("profile[%s] ipv4(%s) ipv6(%s) proxy(%s)", profile, ip_addr, ip_addr6, proxy_addr);
+               DBG("profile[%s] ipv4(%s) ipv6(%s) proxy(%s)", profile, ip_addr,
+                       ip_addr6, proxy_addr);
 
        netconfig_vconf_get_int(VCONFKEY_NETWORK_STATUS, &old_network_status);
 
        if (profile == NULL && old_network_status != VCONFKEY_NETWORK_OFF) {
+               builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+
                netconfig_set_vconf_int(VCONFKEY_NETWORK_STATUS, VCONFKEY_NETWORK_OFF);
+               g_variant_builder_add(builder, "{sv}", "NetworkStatus",
+                                                         g_variant_new_int32(VCONFKEY_NETWORK_OFF));
 
                netconfig_set_vconf_str(VCONFKEY_NETWORK_IP, "");
+               g_variant_builder_add(builder, "{sv}", "IPv4Address",
+                                                         g_variant_new_string(""));
+
                netconfig_set_vconf_str(VCONFKEY_NETWORK_IP6, "");
+               g_variant_builder_add(builder, "{sv}", "IPv6Address",
+                                                         g_variant_new_string(""));
+
                netconfig_set_vconf_str(VCONFKEY_NETWORK_PROXY, "");
+               g_variant_builder_add(builder, "{sv}", "ProxyAddress",
+                                                         g_variant_new_string(""));
+
+               params = g_variant_new("(@a{sv})", g_variant_builder_end(builder));
 
                netconfig_set_vconf_int(VCONFKEY_NETWORK_CONFIGURATION_CHANGE_IND, 0);
+               netconfig_dbus_emit_signal(NULL, NETCONFIG_NETWORK_PATH,
+                                                  NETCONFIG_NETWORK_INTERFACE, "NetworkConfigChanged",
+                                                  params);
                netconfig_set_vconf_int("memory/private/wifi/frequency", 0);
 
+               g_variant_builder_unref(builder);
+
                DBG("Successfully clear IP and PROXY up");
 
        } else if (profile != NULL) {
@@ -683,8 +797,13 @@ static void __netconfig_update_default_connection_info(void)
                char *old_ip6 = vconf_get_str(VCONFKEY_NETWORK_IP6);
                char *old_proxy = vconf_get_str(VCONFKEY_NETWORK_PROXY);
 
+               builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+
                if (netconfig_is_wifi_profile(profile) == TRUE) {
-                       netconfig_set_vconf_int(VCONFKEY_NETWORK_STATUS, VCONFKEY_NETWORK_WIFI);
+                       netconfig_set_vconf_int(VCONFKEY_NETWORK_STATUS,
+                                                                       VCONFKEY_NETWORK_WIFI);
+                       g_variant_builder_add(builder, "{sv}", "NetworkStatus",
+                                                         g_variant_new_int32(VCONFKEY_NETWORK_WIFI));
                        netconfig_set_vconf_int("memory/private/wifi/frequency", freq);
 
                        netconfig_set_system_event(SYS_EVT_NETWORK_STATUS,
@@ -702,52 +821,86 @@ static void __netconfig_update_default_connection_info(void)
                                return;
                        }
 
-                       netconfig_set_vconf_int(VCONFKEY_NETWORK_STATUS, VCONFKEY_NETWORK_CELLULAR);
+                       netconfig_set_vconf_int(VCONFKEY_NETWORK_STATUS,
+                                                                       VCONFKEY_NETWORK_CELLULAR);
+                       g_variant_builder_add(builder, "{sv}", "NetworkStatus",
+                                                         g_variant_new_int32(VCONFKEY_NETWORK_CELLULAR));
 
                        netconfig_set_system_event(SYS_EVT_NETWORK_STATUS,
                                EKEY_NETWORK_STATUS, EVAL_NETWORK_CELLULAR);
                } else if (netconfig_is_ethernet_profile(profile) == TRUE) {
-                       netconfig_set_vconf_int(VCONFKEY_NETWORK_STATUS, VCONFKEY_NETWORK_ETHERNET);
+                       netconfig_set_vconf_int(VCONFKEY_NETWORK_STATUS,
+                                                                       VCONFKEY_NETWORK_ETHERNET);
+                       g_variant_builder_add(builder, "{sv}", "NetworkStatus",
+                                                         g_variant_new_int32(VCONFKEY_NETWORK_ETHERNET));
                        netconfig_set_system_event(SYS_EVT_NETWORK_STATUS,
                                EKEY_NETWORK_STATUS, EVAL_NETWORK_ETHERNET);
                } else if (netconfig_is_bluetooth_profile(profile) == TRUE) {
-                       netconfig_set_vconf_int(VCONFKEY_NETWORK_STATUS, VCONFKEY_NETWORK_BLUETOOTH);
+                       netconfig_set_vconf_int(VCONFKEY_NETWORK_STATUS,
+                                                                       VCONFKEY_NETWORK_BLUETOOTH);
+                       g_variant_builder_add(builder, "{sv}", "NetworkStatus",
+                                                         g_variant_new_int32(VCONFKEY_NETWORK_BLUETOOTH));
                        netconfig_set_system_event(SYS_EVT_NETWORK_STATUS,
                                EKEY_NETWORK_STATUS, EVAL_NETWORK_BT);
                } else{
-                       netconfig_set_vconf_int(VCONFKEY_NETWORK_STATUS, VCONFKEY_NETWORK_OFF);
+                       netconfig_set_vconf_int(VCONFKEY_NETWORK_STATUS,
+                                                                       VCONFKEY_NETWORK_OFF);
+                       g_variant_builder_add(builder, "{sv}", "NetworkStatus",
+                                                         g_variant_new_int32(VCONFKEY_NETWORK_OFF));
                        netconfig_set_system_event(SYS_EVT_NETWORK_STATUS,
                                EKEY_NETWORK_STATUS, EVAL_NETWORK_DISCONNECTED);
                }
 
                if (g_strcmp0(old_ip, ip_addr) != 0 || old_ip == NULL) {
-                       if (ip_addr != NULL)
+                       if (ip_addr != NULL) {
                                netconfig_set_vconf_str(VCONFKEY_NETWORK_IP, ip_addr);
-                       else if (old_ip != NULL && strlen(old_ip) > 0)
+                               g_variant_builder_add(builder, "{sv}", "IPv4Address",
+                                                                 g_variant_new_string(ip_addr));
+                       } else if (old_ip != NULL && strlen(old_ip) > 0) {
                                netconfig_set_vconf_str(VCONFKEY_NETWORK_IP, "");
+                               g_variant_builder_add(builder, "{sv}", "IPv4Address",
+                                                                 g_variant_new_string(""));
+                       }
                }
                if (old_ip)
                        free(old_ip);
 
                if (g_strcmp0(old_ip6, ip_addr6) != 0 || old_ip6 == NULL) {
-                       if (ip_addr6 != NULL)
+                       if (ip_addr6 != NULL) {
                                netconfig_set_vconf_str(VCONFKEY_NETWORK_IP6, ip_addr6);
-                       else if (old_ip6 != NULL && strlen(old_ip6) > 0)
+                               g_variant_builder_add(builder, "{sv}", "IPv6Address",
+                                                                 g_variant_new_string(ip_addr6));
+                       } else if (old_ip6 != NULL && strlen(old_ip6) > 0) {
                                netconfig_set_vconf_str(VCONFKEY_NETWORK_IP6, "");
+                               g_variant_builder_add(builder, "{sv}", "IPv6Address",
+                                                                 g_variant_new_string(""));
+                       }
                }
                if (old_ip6)
                        free(old_ip6);
 
                if (g_strcmp0(old_proxy, proxy_addr) != 0) {
-                       if (proxy_addr == NULL)
+                       if (proxy_addr == NULL) {
                                netconfig_set_vconf_str(VCONFKEY_NETWORK_PROXY, "");
-                       else
+                               g_variant_builder_add(builder, "{sv}", "ProxyAddress",
+                                                                 g_variant_new_string(""));
+                       } else {
                                netconfig_set_vconf_str(VCONFKEY_NETWORK_PROXY, proxy_addr);
+                               g_variant_builder_add(builder, "{sv}", "ProxyAddress",
+                                                                 g_variant_new_string(proxy_addr));
+                       }
                }
                if (old_proxy)
                        free(old_proxy);
 
+               params = g_variant_new("(@a{sv})", g_variant_builder_end(builder));
+
                netconfig_set_vconf_int(VCONFKEY_NETWORK_CONFIGURATION_CHANGE_IND, 1);
+               netconfig_dbus_emit_signal(NULL, NETCONFIG_NETWORK_PATH,
+                                                  NETCONFIG_NETWORK_INTERFACE, "NetworkConfigChanged",
+                                                  params);
+
+               g_variant_builder_unref(builder);
 
                DBG("Successfully update default network configuration");
        }
@@ -1109,7 +1262,8 @@ char *netconfig_get_ifname(const char *profile)
                        while (g_variant_iter_loop(next, "{sv}", &key1, &variant)) {
                                if (g_strcmp0(key1, "Interface") == 0) {
                                        value = g_variant_get_string(variant, NULL);
-                                       ifname = g_strdup(value);
+                                       if (!ifname)
+                                               ifname = g_strdup(value);
                                        g_free(key1);
                                        g_variant_unref(variant);
                                        break;
@@ -1140,13 +1294,12 @@ static gboolean handle_add_route(
                gchar *interface,  gchar *gateway, gint address_family)
 {
        const gchar *path = ROUTE_EXEC_PATH;
-       gchar *const args[] = { "/sbin/route", "add", "-net", ip_addr,
+       gchar gw_str[64] = {0,};
+       if (gateway != NULL && strlen(gateway) > 1)
+               g_snprintf(gw_str, 64, "gw %s", gateway);
+       gchar *const args[] = { "/sbin/route", "add", "-net", ip_addr, gw_str,
                "netmask", netmask, "dev", interface, NULL };
        gchar *const envs[] = { NULL };
-       const gchar* buf = NULL;
-       gchar* ch = NULL;
-       int prefix_len = 0;
-       int pos = 0;
 
        DBG("ip_addr(%s), netmask(%s), interface(%s), gateway(%s)", ip_addr, netmask, interface, gateway);
 
@@ -1155,13 +1308,13 @@ static gboolean handle_add_route(
                if (ip_addr == NULL || netmask == NULL || interface == NULL) {
                        ERR("Invalid parameter");
                        netconfig_error_invalid_parameter(context);
-                       return FALSE;
+                       return TRUE;
                }
 
                if (netconfig_execute_file(path, args, envs) < 0) {
                        DBG("Failed to add a new route");
                        netconfig_error_permission_denied(context);
-                       return FALSE;
+                       return TRUE;
                }
 
                break;
@@ -1169,29 +1322,19 @@ static gboolean handle_add_route(
                if (ip_addr == NULL || interface == NULL || gateway == NULL) {
                        ERR("Invalid parameter");
                        netconfig_error_invalid_parameter(context);
-                       return FALSE;
+                       return TRUE;
                }
 
-               buf = ip_addr;
-               ch = strchr(buf, '/');
-               pos = ch - buf + 1;
-               if (ch) {
-                       prefix_len = atoi(ch + 1);
-                       ip_addr[pos-1] = '\0';
-               } else {
-                       prefix_len = 128;
-               }
-
-               if (netconfig_add_route_ipv6(ip_addr, interface, gateway, prefix_len) < 0) {
+               if (netconfig_add_route_ipv6(interface, gateway) < 0) {
                        DBG("Failed to add a new route");
                        netconfig_error_permission_denied(context);
-                       return FALSE;
+                       return TRUE;
                }
                break;
        default:
                DBG("Unknown Address Family");
                netconfig_error_invalid_parameter(context);
-               return FALSE;
+               return TRUE;
        }
 
        DBG("Successfully added a new route");
@@ -1207,13 +1350,12 @@ static gboolean handle_remove_route(
                gchar *interface, gchar *gateway, gint address_family)
 {
        const char *path = ROUTE_EXEC_PATH;
-       gchar *const args[] = { "/sbin/route", "del", "-net", ip_addr,
+       gchar gw_str[64] = {0,};
+       if (gateway != NULL && strlen(gateway) > 1)
+               g_snprintf(gw_str, 64, "gw %s", gateway);
+       gchar *const args[] = { "/sbin/route", "del", "-net", ip_addr, gw_str,
                "netmask", netmask, "dev", interface, NULL };
        char *const envs[] = { NULL };
-       const char* buf = NULL;
-       char* ch = NULL;
-       int prefix_len = 0;
-       int pos = 0;
 
        DBG("ip_addr(%s), netmask(%s), interface(%s), gateway(%s)", ip_addr, netmask, interface, gateway);
 
@@ -1222,41 +1364,31 @@ static gboolean handle_remove_route(
                if (ip_addr == NULL || netmask == NULL || interface == NULL) {
                        DBG("Invalid parameter!");
                        netconfig_error_invalid_parameter(context);
-                       return FALSE;
+                       return TRUE;
                }
                if (netconfig_execute_file(path, args, envs) < 0) {
                        DBG("Failed to remove the route");
                        netconfig_error_permission_denied(context);
-                       return FALSE;
+                       return TRUE;
                }
                break;
        case AF_INET6:
                if (ip_addr == NULL || interface == NULL || gateway == NULL) {
                        DBG("Invalid parameter!");
                        netconfig_error_invalid_parameter(context);
-                       return FALSE;
-               }
-
-               buf = ip_addr;
-               ch = strchr(buf, '/');
-               pos = ch - buf + 1;
-               if (ch) {
-                       prefix_len = atoi(ch + 1);
-                       ip_addr[pos-1] = '\0';
-               } else {
-                       prefix_len = 128;
+                       return TRUE;
                }
 
-               if (netconfig_del_route_ipv6(ip_addr, interface, gateway, prefix_len) < 0) {
+               if (netconfig_del_route_ipv6(interface, gateway) < 0) {
                        DBG("Failed to remove the route");
                        netconfig_error_permission_denied(context);
-                       return FALSE;
+                       return TRUE;
                }
                break;
        default:
                DBG("Unknown Address Family");
                netconfig_error_invalid_parameter(context);
-               return FALSE;
+               return TRUE;
        }
 
        DBG("Successfully removed the route");
@@ -1296,7 +1428,7 @@ gboolean handle_ethernet_cable_state(Network *object,
        if (ret != 0) {
                DBG("Failed to get ethernet cable state");
                netconfig_error_fail_ethernet_cable_state(context);
-               return FALSE;
+               return TRUE;
        }
 
        DBG("Successfully get ethernet cable state[%d]", state);
@@ -1313,7 +1445,23 @@ gboolean handle_get_metered_info(Network *object,
 
        DBG("Default metered state [%s]", state ? "TRUE" : "FALSE");
        network_complete_get_metered_info(object, context, state);
+       return TRUE;
+}
+
+gboolean handle_preferred_ipv6_address(Network *object,
+       GDBusMethodInvocation *context, gchar *profile)
+{
+       char *address = NULL;
 
+       address = __netconfig_get_preferred_ipv6_address(profile);
+       if (address == NULL) {
+               DBG("Failed to get preferred IPv6 address");
+               netconfig_error_fail_preferred_ipv6_address(context);
+               return TRUE;
+       }
+
+       DBG("Successfully get preferred IPv6 address[%s]", address);
+       network_complete_preferred_ipv6_address(object, context, address);
        return TRUE;
 }
 
@@ -1321,6 +1469,9 @@ void state_object_create_and_init(void)
 {
        DBG("Creating network state object");
        GDBusInterfaceSkeleton *interface_network = NULL;
+#if defined TIZEN_DEBUG_ENABLE
+       GDBusInterfaceSkeleton *interface_tcpdump = NULL;
+#endif
        GDBusConnection *connection = NULL;
        GDBusObjectManagerServer *server = netdbus_get_state_manager();
        if (server == NULL)
@@ -1343,6 +1494,8 @@ void state_object_create_and_init(void)
                                G_CALLBACK(handle_check_internet_privilege), NULL);
        g_signal_connect(netconfigstate, "handle-ethernet-cable-state",
                                G_CALLBACK(handle_ethernet_cable_state), NULL);
+       g_signal_connect(netconfigstate, "handle-preferred-ipv6-address",
+                               G_CALLBACK(handle_preferred_ipv6_address), NULL);
        g_signal_connect(netconfigstate, "handle-remove-route",
                                G_CALLBACK(handle_remove_route), NULL);
        g_signal_connect(netconfigstate, "handle-launch-mdns",
@@ -1362,9 +1515,30 @@ void state_object_create_and_init(void)
                        NETCONFIG_NETWORK_STATE_PATH, NULL)) {
                ERR("Export with path failed");
        }
+
+#if defined TIZEN_DEBUG_ENABLE
+       /*Interface netconfig.tcpdump*/
+       tcpdump_object = tcpdump_skeleton_new();
+
+       interface_tcpdump = G_DBUS_INTERFACE_SKELETON(tcpdump_object);
+       g_signal_connect(tcpdump_object, "handle-start-tcpdump",
+                               G_CALLBACK(handle_start_tcpdump), NULL);
+       g_signal_connect(tcpdump_object, "handle-stop-tcpdump",
+                               G_CALLBACK(handle_stop_tcpdump), NULL);
+       g_signal_connect(tcpdump_object, "handle-get-tcpdump-state",
+                               G_CALLBACK(handle_get_tcpdump_state), NULL);
+
+       if (!g_dbus_interface_skeleton_export(interface_tcpdump, connection,
+                       NETCONFIG_NETWORK_STATE_PATH, NULL)) {
+               ERR("Export with path failed");
+       }
+#endif
 }
 
 void state_object_deinit(void)
 {
        g_object_unref(netconfigstate);
+#if defined TIZEN_DEBUG_ENABLE
+       g_object_unref(tcpdump_object);
+#endif
 }