Add support for PAC runner configuration updates
[framework/connectivity/connman.git] / plugins / pacrunner.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27
28 #include <gdbus.h>
29
30 #define CONNMAN_API_SUBJECT_TO_CHANGE
31 #include <connman/plugin.h>
32 #include <connman/notifier.h>
33 #include <connman/dbus.h>
34 #include <connman/log.h>
35
36 #define PACRUNNER_SERVICE       "org.pacrunner"
37 #define PACRUNNER_INTERFACE     "org.pacrunner.Manager"
38 #define PACRUNNER_PATH          "/org/pacrunner/manager"
39
40 #define DBUS_TIMEOUT    5000
41
42 static DBusConnection *connection;
43
44 static struct connman_service *default_service = NULL;
45 static char *current_config = NULL;
46
47 static void create_config_reply(DBusPendingCall *call, void *user_data)
48 {
49         DBusMessage *reply = dbus_pending_call_steal_reply(call);
50         const char *path;
51
52         DBG("");
53
54         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
55                 connman_error("Failed to create proxy configuration");
56                 goto done;
57         }
58
59         if (dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, &path,
60                                                 DBUS_TYPE_INVALID) == FALSE)
61                 goto done;
62
63         g_free(current_config);
64         current_config = g_strdup(path);
65
66 done:
67         dbus_message_unref(reply);
68 }
69
70 static void add_dict_with_string_value(DBusMessageIter *iter,
71                                         const char *key, const char *str)
72 {
73         DBusMessageIter dict, entry, value;
74
75         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
76                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
77                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
78                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
79         dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
80                                                                 NULL, &entry);
81
82         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
83
84         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
85                                         DBUS_TYPE_STRING_AS_STRING, &value);
86         dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &str);
87         dbus_message_iter_close_container(&entry, &value);
88
89         dbus_message_iter_close_container(&dict, &entry);
90         dbus_message_iter_close_container(iter, &dict);
91 }
92
93 static void create_proxy_configuration(const char *url)
94 {
95         DBusMessage *msg;
96         DBusMessageIter iter;
97         DBusPendingCall *call;
98         dbus_bool_t result;
99
100         if (url == NULL)
101                 return;
102
103         DBG("url %s", url);
104
105         msg = dbus_message_new_method_call(PACRUNNER_SERVICE, PACRUNNER_PATH,
106                         PACRUNNER_INTERFACE, "CreateProxyConfiguration");
107         if (msg == NULL)
108                 return;
109
110         dbus_message_set_auto_start(msg, FALSE);
111
112         dbus_message_iter_init_append(msg, &iter);
113         add_dict_with_string_value(&iter, "URL", url);
114
115         result = dbus_connection_send_with_reply(connection, msg,
116                                                         &call, DBUS_TIMEOUT);
117
118         dbus_message_unref(msg);
119
120         if (result == FALSE || call == NULL)
121                 return;
122
123         dbus_pending_call_set_notify(call, create_config_reply, NULL, NULL);
124
125         dbus_pending_call_unref(call);
126 }
127
128 static void destroy_config_reply(DBusPendingCall *call, void *user_data)
129 {
130         DBusMessage *reply = dbus_pending_call_steal_reply(call);
131
132         DBG("");
133
134         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
135                 connman_error("Failed to destoy proxy configuration");
136
137         dbus_message_unref(reply);
138 }
139
140 static void destroy_proxy_configuration(void)
141 {
142         DBusMessage *msg;
143         DBusPendingCall *call;
144         dbus_bool_t result;
145
146         if (current_config == NULL)
147                 return;
148
149         DBG("");
150
151         msg = dbus_message_new_method_call(PACRUNNER_SERVICE, PACRUNNER_PATH,
152                         PACRUNNER_INTERFACE, "DestroyProxyConfiguration");
153         if (msg == NULL)
154                 return;
155
156         dbus_message_set_auto_start(msg, FALSE);
157
158         dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &current_config,
159                                                         DBUS_TYPE_INVALID);
160
161         result = dbus_connection_send_with_reply(connection, msg,
162                                                         &call, DBUS_TIMEOUT);
163
164         dbus_message_unref(msg);
165
166         if (result == FALSE || call == NULL)
167                 return;
168
169         dbus_pending_call_set_notify(call, destroy_config_reply, NULL, NULL);
170
171         dbus_pending_call_unref(call);
172
173         g_free(current_config);
174         current_config = NULL;
175 }
176
177 static void default_service_changed(struct connman_service *service)
178 {
179         const char *url;
180
181         DBG("service %p", service);
182
183         if (service == default_service)
184                 return;
185
186         default_service = service;
187
188         destroy_proxy_configuration();
189
190         url = connman_service_get_proxy_autoconfig(service);
191         create_proxy_configuration(url);
192 }
193
194 static struct connman_notifier pacrunner_notifier = {
195         .name                   = "pacrunner",
196         .default_changed        = default_service_changed,
197 };
198
199 static void pacrunner_connect(DBusConnection *conn, void *user_data)
200 {
201         const char *url;
202
203         DBG("");
204
205         url = connman_service_get_proxy_autoconfig(default_service);
206         create_proxy_configuration(url);
207 }
208
209 static void pacrunner_disconnect(DBusConnection *conn, void *user_data)
210 {
211         DBG("");
212
213         g_free(current_config);
214         current_config = NULL;
215 }
216
217 static guint pacrunner_watch;
218
219 static int pacrunner_init(void)
220 {
221         connection = connman_dbus_get_connection();
222         if (connection == NULL)
223                 return -EIO;
224
225         pacrunner_watch = g_dbus_add_service_watch(connection,
226                                         PACRUNNER_SERVICE, pacrunner_connect,
227                                         pacrunner_disconnect, NULL, NULL);
228         if (pacrunner_watch == 0) {
229                 dbus_connection_unref(connection);
230                 return -EIO;
231         }
232
233         connman_notifier_register(&pacrunner_notifier);
234
235         return 0;
236 }
237
238 static void pacrunner_exit(void)
239 {
240         connman_notifier_unregister(&pacrunner_notifier);
241
242         g_dbus_remove_watch(connection, pacrunner_watch);
243
244         destroy_proxy_configuration();
245
246         dbus_connection_unref(connection);
247 }
248
249 CONNMAN_PLUGIN_DEFINE(pacrunner, "PAC runner proxy plugin", VERSION,
250                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, pacrunner_init, pacrunner_exit)