*
* Connection Manager
*
- * Copyright (C) 2007-2010 Intel Corporation. All rights reserved.
+ * Copyright (C) 2007-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
#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;
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] != NULL; 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 == NULL)
return;
- DBG("interface %s url %s", interface, url);
+ DBG("");
msg = dbus_message_new_method_call(PACRUNNER_SERVICE, PACRUNNER_PATH,
PACRUNNER_INTERFACE, "CreateProxyConfiguration");
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 == NULL) {
+ 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 == NULL)
+ 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 == NULL) {
+ str = connman_service_get_proxy_autoconfig(
+ default_service);
+ if (str == NULL) {
+ 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 != NULL) {
+ 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 != NULL)
+ 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 != NULL)
+ 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;
+ 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)
static void default_service_changed(struct connman_service *service)
{
- char *interface;
- const char *url;
-
DBG("service %p", service);
if (service == default_service)
default_service = service;
+ if (daemon_running == FALSE)
+ return;
+
destroy_proxy_configuration();
- interface = connman_service_get_interface(service);
+ create_proxy_configuration();
+}
+
+static void proxy_changed(struct connman_service *service)
+{
+ DBG("service %p", service);
+
+ if (service != default_service)
+ return;
- url = connman_service_get_proxy_autoconfig(service);
- create_proxy_configuration(interface, url);
+ if (daemon_running == FALSE)
+ return;
+
+ destroy_proxy_configuration();
- g_free(interface);
+ 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 == NULL)
+ return NULL;
+
+ host = strstr(scheme, "://");
+ if (host != NULL) {
+ *host = '\0';
+ host += 3;
+ } else
+ host = scheme;
+
+ path = strchr(host, '/');
+ if (path != NULL)
+ *(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) == FALSE)
+ 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("");
+
+ if (daemon_running == FALSE)
+ return -EINVAL;
+
+ msg = dbus_message_new_method_call(PACRUNNER_SERVICE,
+ PACRUNNER_CLIENT_PATH,
+ PACRUNNER_CLIENT_INTERFACE,
+ "FindProxyForURL");
+ if (msg == NULL)
+ return -1;
+
+ host = parse_url(url);
+ if (host == NULL) {
+ dbus_message_unref(msg);
+ return -EINVAL;
+ }
+
+ data = g_try_new0(struct proxy_data, 1);
+ if (data == NULL) {
+ dbus_message_unref(msg);
+ g_free(host);
+ return -ENOMEM;
+ }
+
+ data->url = g_strdup(url);
+ data->service = connman_service_ref(service);
+
+ dbus_message_set_auto_start(msg, FALSE);
+
+ 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 == FALSE || call == NULL) {
+ 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)
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);