Imported Upstream version 1.24
[platform/upstream/connman.git] / plugins / pacrunner.c
index cf0fc39..850139f 100644 (file)
@@ -2,7 +2,7 @@
  *
  *  Connection Manager
  *
- *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2007-2013  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
@@ -24,6 +24,7 @@
 #endif
 
 #include <errno.h>
+#include <string.h>
 
 #include <gdbus.h>
 
 #include <connman/notifier.h>
 #include <connman/dbus.h>
 #include <connman/log.h>
+#include <connman/proxy.h>
 
 #define PACRUNNER_SERVICE      "org.pacrunner"
 #define PACRUNNER_INTERFACE    "org.pacrunner.Manager"
 #define PACRUNNER_PATH         "/org/pacrunner/manager"
 
+#define PACRUNNER_CLIENT_INTERFACE     "org.pacrunner.Client"
+#define PACRUNNER_CLIENT_PATH          "/org/pacrunner/client"
+
 #define DBUS_TIMEOUT   5000
 
+struct proxy_data {
+       struct connman_service *service;
+       char *url;
+};
+
 static DBusConnection *connection;
+static dbus_bool_t daemon_running = FALSE;
 
 static struct connman_service *default_service = NULL;
 static char *current_config = NULL;
@@ -56,8 +67,8 @@ static void create_config_reply(DBusPendingCall *call, void *user_data)
                goto done;
        }
 
-       if (dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, &path,
-                                               DBUS_TYPE_INVALID) == FALSE)
+       if (!dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH,
+                                       &path, DBUS_TYPE_INVALID))
                goto done;
 
        g_free(current_config);
@@ -67,66 +78,132 @@ done:
        dbus_message_unref(reply);
 }
 
-static void add_string_entry(DBusMessageIter *iter,
-                                       const char *key, const char *str)
+static void append_string(DBusMessageIter *iter, void *user_data)
 {
-       DBusMessageIter value;
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, user_data);
+}
 
-       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &key);
+static void append_string_list(DBusMessageIter *iter, void *user_data)
+{
+       char **list = user_data;
+       int i;
 
-       dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
-                                       DBUS_TYPE_STRING_AS_STRING, &value);
-       dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &str);
-       dbus_message_iter_close_container(iter, &value);
+       for (i = 0; list[i]; i++)
+               dbus_message_iter_append_basic(iter,
+                                       DBUS_TYPE_STRING, &list[i]);
 }
 
-static void create_proxy_configuration(const char *interface, const char *url)
+static void create_proxy_configuration(void)
 {
        DBusMessage *msg;
-       DBusMessageIter iter, dict, entry;
+       DBusMessageIter iter, dict;
        DBusPendingCall *call;
        dbus_bool_t result;
+       char *interface;
+       const char *method;
+       const char *str;
+       char **str_list;
 
-       if (url == NULL)
+       if (!default_service)
                return;
 
-       DBG("interface %s url %s", interface, url);
+       DBG("");
 
        msg = dbus_message_new_method_call(PACRUNNER_SERVICE, PACRUNNER_PATH,
                        PACRUNNER_INTERFACE, "CreateProxyConfiguration");
-       if (msg == NULL)
+       if (!msg)
                return;
 
        dbus_message_set_auto_start(msg, FALSE);
 
        dbus_message_iter_init_append(msg, &iter);
+       connman_dbus_dict_open(&iter, &dict);
 
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
-                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
-        dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
-                                                               NULL, &entry);
+       switch(connman_service_get_proxy_method(default_service)) {
+       case CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN:
+               connman_dbus_dict_close(&iter, &dict);
+               goto done;
+       case CONNMAN_SERVICE_PROXY_METHOD_DIRECT:
+               method= "direct";
+               break;
+       case CONNMAN_SERVICE_PROXY_METHOD_MANUAL:
+               method = "manual";
+
+               str_list = connman_service_get_proxy_servers(default_service);
+               if (!str_list) {
+                       connman_dbus_dict_close(&iter, &dict);
+                       goto done;
+               }
+
+               connman_dbus_dict_append_array(&dict, "Servers",
+                                       DBUS_TYPE_STRING, append_string_list,
+                                       str_list);
+               g_strfreev(str_list);
+
+               str_list = connman_service_get_proxy_excludes(default_service);
+               if (!str_list)
+                       break;
+
+               connman_dbus_dict_append_array(&dict, "Excludes",
+                                       DBUS_TYPE_STRING, append_string_list,
+                                       str_list);
+               g_strfreev(str_list);
+
+               break;
+       case CONNMAN_SERVICE_PROXY_METHOD_AUTO:
+               method = "auto";
+
+               str = connman_service_get_proxy_url(default_service);
+               if (!str) {
+                       str = connman_service_get_proxy_autoconfig(
+                                                       default_service);
+                       if (!str) {
+                               connman_dbus_dict_close(&iter, &dict);
+                               goto done;
+                       }
+               }
+
+               connman_dbus_dict_append_basic(&dict, "URL",
+                                       DBUS_TYPE_STRING, &str);
+               break;
+       }
+
+       connman_dbus_dict_append_basic(&dict, "Method",
+                               DBUS_TYPE_STRING, &method);
+
+       interface = connman_service_get_interface(default_service);
+       if (interface) {
+               connman_dbus_dict_append_basic(&dict, "Interface",
+                                               DBUS_TYPE_STRING, &interface);
+               g_free(interface);
+       }
 
-       if (interface != NULL)
-               add_string_entry(&entry, "Interface", interface);
+       str = connman_service_get_domainname(default_service);
+       if (str)
+               connman_dbus_dict_append_array(&dict, "Domains",
+                                       DBUS_TYPE_STRING, append_string, &str);
 
-       add_string_entry(&entry, "URL", url);
+       str_list = connman_service_get_nameservers(default_service);
+       if (str_list)
+               connman_dbus_dict_append_array(&dict, "Nameservers",
+                                       DBUS_TYPE_STRING, append_string_list,
+                                       str_list);
+       g_strfreev(str_list);
 
-       dbus_message_iter_close_container(&dict, &entry);
-       dbus_message_iter_close_container(&iter, &dict);
+       connman_dbus_dict_close(&iter, &dict);
 
        result = dbus_connection_send_with_reply(connection, msg,
                                                        &call, DBUS_TIMEOUT);
 
-       dbus_message_unref(msg);
-
-       if (result == FALSE || call == NULL)
-               return;
+       if (!result || !call)
+               goto done;
 
        dbus_pending_call_set_notify(call, create_config_reply, NULL, NULL);
 
        dbus_pending_call_unref(call);
+
+done:
+       dbus_message_unref(msg);
 }
 
 static void destroy_config_reply(DBusPendingCall *call, void *user_data)
@@ -147,14 +224,14 @@ static void destroy_proxy_configuration(void)
        DBusPendingCall *call;
        dbus_bool_t result;
 
-       if (current_config == NULL)
+       if (!current_config)
                return;
 
        DBG("");
 
        msg = dbus_message_new_method_call(PACRUNNER_SERVICE, PACRUNNER_PATH,
                        PACRUNNER_INTERFACE, "DestroyProxyConfiguration");
-       if (msg == NULL)
+       if (!msg)
                return;
 
        dbus_message_set_auto_start(msg, FALSE);
@@ -167,7 +244,7 @@ static void destroy_proxy_configuration(void)
 
        dbus_message_unref(msg);
 
-       if (result == FALSE || call == NULL)
+       if (!result || !call)
                return;
 
        dbus_pending_call_set_notify(call, destroy_config_reply, NULL, NULL);
@@ -180,9 +257,6 @@ static void destroy_proxy_configuration(void)
 
 static void default_service_changed(struct connman_service *service)
 {
-       char *interface;
-       const char *url;
-
        DBG("service %p", service);
 
        if (service == default_service)
@@ -190,50 +264,185 @@ static void default_service_changed(struct connman_service *service)
 
        default_service = service;
 
+       if (!daemon_running)
+               return;
+
        destroy_proxy_configuration();
 
-       interface = connman_service_get_interface(service);
+       create_proxy_configuration();
+}
 
-       url = connman_service_get_proxy_autoconfig(service);
-       create_proxy_configuration(interface, url);
+static void proxy_changed(struct connman_service *service)
+{
+       DBG("service %p", service);
+
+       if (service != default_service)
+               return;
+
+       if (!daemon_running)
+               return;
 
-       g_free(interface);
+       destroy_proxy_configuration();
+
+       create_proxy_configuration();
 }
 
 static struct connman_notifier pacrunner_notifier = {
        .name                   = "pacrunner",
        .default_changed        = default_service_changed,
+       .proxy_changed          = proxy_changed,
 };
 
 static void pacrunner_connect(DBusConnection *conn, void *user_data)
 {
-       char *interface;
-       const char *url;
-
        DBG("");
 
-       interface = connman_service_get_interface(default_service);
-
-       url = connman_service_get_proxy_autoconfig(default_service);
-       create_proxy_configuration(interface, url);
+       daemon_running = TRUE;
 
-       g_free(interface);
+       create_proxy_configuration();
 }
 
 static void pacrunner_disconnect(DBusConnection *conn, void *user_data)
 {
        DBG("");
 
+       daemon_running = FALSE;
+
        g_free(current_config);
        current_config = NULL;
 }
 
+static char * parse_url(const char *url)
+{
+       char *scheme, *host, *path, *host_ret;
+
+       scheme = g_strdup(url);
+       if (!scheme)
+               return NULL;
+
+       host = strstr(scheme, "://");
+       if (host) {
+               *host = '\0';
+               host += 3;
+       } else
+               host = scheme;
+
+       path = strchr(host, '/');
+       if (path)
+               *(path++) = '\0';
+
+       host_ret = g_strdup(host);
+
+       g_free(scheme);
+
+       return host_ret;
+}
+
+static void request_lookup_reply(DBusPendingCall *call, void *user_data)
+{
+       DBusMessage *reply = dbus_pending_call_steal_reply(call);
+       struct proxy_data *data = user_data;
+       const char *proxy;
+
+       DBG("");
+
+       if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
+               connman_error("Failed to find URL:%s", data->url);
+               proxy = NULL;
+               goto done;
+       }
+
+       if (!dbus_message_get_args(reply, NULL, DBUS_TYPE_STRING,
+                                       &proxy, DBUS_TYPE_INVALID))
+               proxy = NULL;
+
+done:
+       connman_proxy_driver_lookup_notify(data->service, data->url, proxy);
+
+       connman_service_unref(data->service);
+
+       g_free(data->url);
+       g_free(data);
+
+       dbus_message_unref(reply);
+}
+
+static int request_lookup(struct connman_service *service, const char *url)
+{
+       DBusMessage *msg;
+       DBusPendingCall *call;
+       dbus_bool_t result;
+       char *host;
+       struct proxy_data *data;
+
+       DBG("");
+
+       msg = dbus_message_new_method_call(PACRUNNER_SERVICE,
+                                               PACRUNNER_CLIENT_PATH,
+                                               PACRUNNER_CLIENT_INTERFACE,
+                                               "FindProxyForURL");
+       if (!msg)
+               return -1;
+
+       host = parse_url(url);
+       if (!host) {
+               dbus_message_unref(msg);
+               return -EINVAL;
+       }
+
+       data = g_try_new0(struct proxy_data, 1);
+       if (!data) {
+               dbus_message_unref(msg);
+               g_free(host);
+               return -ENOMEM;
+       }
+
+       data->url = g_strdup(url);
+       data->service = connman_service_ref(service);
+
+       dbus_message_append_args(msg, DBUS_TYPE_STRING, &url,
+                                       DBUS_TYPE_STRING, &host,
+                                       DBUS_TYPE_INVALID);
+
+       result = dbus_connection_send_with_reply(connection, msg,
+                                                       &call, DBUS_TIMEOUT);
+
+       dbus_message_unref(msg);
+
+       if (!result || !call) {
+               g_free(host);
+               g_free(data->url);
+               g_free(data);
+               return -EINVAL;
+       }
+
+       dbus_pending_call_set_notify(call, request_lookup_reply,
+                                                       data, NULL);
+
+       dbus_pending_call_unref(call);
+       g_free(host);
+
+       return 0;
+}
+
+static void cancel_lookup(struct connman_service *service, const char *url)
+{
+       DBG("");
+}
+
+static struct connman_proxy_driver pacrunner_proxy = {
+       .name           = "pacrunnerproxy",
+       .priority       = CONNMAN_PROXY_PRIORITY_HIGH,
+       .request_lookup = request_lookup,
+       .cancel_lookup  = cancel_lookup,
+};
+
 static guint pacrunner_watch;
 
 static int pacrunner_init(void)
 {
        connection = connman_dbus_get_connection();
-       if (connection == NULL)
+       if (!connection)
                return -EIO;
 
        pacrunner_watch = g_dbus_add_service_watch(connection,
@@ -246,11 +455,15 @@ static int pacrunner_init(void)
 
        connman_notifier_register(&pacrunner_notifier);
 
+       connman_proxy_driver_register(&pacrunner_proxy);
+
        return 0;
 }
 
 static void pacrunner_exit(void)
 {
+       connman_proxy_driver_unregister(&pacrunner_proxy);
+
        connman_notifier_unregister(&pacrunner_notifier);
 
        g_dbus_remove_watch(connection, pacrunner_watch);