Merge "Modified logic to process each VSIE of all vendors." into tizen
[platform/upstream/connman.git] / plugins / pacrunner.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2013  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 #include <string.h>
28
29 #include <gdbus.h>
30
31 #define CONNMAN_API_SUBJECT_TO_CHANGE
32 #include <connman/plugin.h>
33 #include <connman/notifier.h>
34 #include <connman/dbus.h>
35 #include <connman/log.h>
36 #include <connman/proxy.h>
37
38 #define PACRUNNER_SERVICE       "org.pacrunner"
39 #define PACRUNNER_INTERFACE     "org.pacrunner.Manager"
40 #define PACRUNNER_PATH          "/org/pacrunner/manager"
41
42 #define PACRUNNER_CLIENT_INTERFACE      "org.pacrunner.Client"
43 #define PACRUNNER_CLIENT_PATH           "/org/pacrunner/client"
44
45 #define DBUS_TIMEOUT    5000
46
47 struct proxy_data {
48         struct connman_service *service;
49         char *url;
50 };
51
52 static DBusConnection *connection;
53 static dbus_bool_t daemon_running = FALSE;
54
55 static struct connman_service *default_service = NULL;
56 static char *current_config = NULL;
57
58 static void create_config_reply(DBusPendingCall *call, void *user_data)
59 {
60         DBusMessage *reply = dbus_pending_call_steal_reply(call);
61         const char *path;
62
63         DBG("");
64
65         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
66                 connman_error("Failed to create proxy configuration");
67                 goto done;
68         }
69
70         if (!dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH,
71                                         &path, DBUS_TYPE_INVALID))
72                 goto done;
73
74         g_free(current_config);
75         current_config = g_strdup(path);
76
77 done:
78         dbus_message_unref(reply);
79 }
80
81 static void append_string(DBusMessageIter *iter, void *user_data)
82 {
83         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, user_data);
84 }
85
86 static void append_string_list(DBusMessageIter *iter, void *user_data)
87 {
88         char **list = user_data;
89         int i;
90
91         for (i = 0; list[i]; i++)
92                 dbus_message_iter_append_basic(iter,
93                                         DBUS_TYPE_STRING, &list[i]);
94 }
95
96 static void create_proxy_configuration(void)
97 {
98         DBusMessage *msg;
99         DBusMessageIter iter, dict;
100         DBusPendingCall *call;
101         dbus_bool_t result;
102         char *interface;
103         const char *method;
104         const char *str;
105         char **str_list;
106
107         if (!default_service)
108                 return;
109
110         DBG("");
111
112         msg = dbus_message_new_method_call(PACRUNNER_SERVICE, PACRUNNER_PATH,
113                         PACRUNNER_INTERFACE, "CreateProxyConfiguration");
114         if (!msg)
115                 return;
116
117         dbus_message_set_auto_start(msg, FALSE);
118
119         dbus_message_iter_init_append(msg, &iter);
120         connman_dbus_dict_open(&iter, &dict);
121
122         switch(connman_service_get_proxy_method(default_service)) {
123         case CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN:
124                 connman_dbus_dict_close(&iter, &dict);
125                 goto done;
126         case CONNMAN_SERVICE_PROXY_METHOD_DIRECT:
127                 method= "direct";
128                 break;
129         case CONNMAN_SERVICE_PROXY_METHOD_MANUAL:
130                 method = "manual";
131
132                 str_list = connman_service_get_proxy_servers(default_service);
133                 if (!str_list) {
134                         connman_dbus_dict_close(&iter, &dict);
135                         goto done;
136                 }
137
138                 connman_dbus_dict_append_array(&dict, "Servers",
139                                         DBUS_TYPE_STRING, append_string_list,
140                                         str_list);
141                 g_strfreev(str_list);
142
143                 str_list = connman_service_get_proxy_excludes(default_service);
144                 if (!str_list)
145                         break;
146
147                 connman_dbus_dict_append_array(&dict, "Excludes",
148                                         DBUS_TYPE_STRING, append_string_list,
149                                         str_list);
150                 g_strfreev(str_list);
151
152                 break;
153         case CONNMAN_SERVICE_PROXY_METHOD_AUTO:
154                 method = "auto";
155
156                 str = connman_service_get_proxy_url(default_service);
157                 if (!str) {
158                         str = connman_service_get_proxy_autoconfig(
159                                                         default_service);
160                         if (!str) {
161                                 connman_dbus_dict_close(&iter, &dict);
162                                 goto done;
163                         }
164                 }
165
166                 connman_dbus_dict_append_basic(&dict, "URL",
167                                         DBUS_TYPE_STRING, &str);
168                 break;
169         }
170
171         connman_dbus_dict_append_basic(&dict, "Method",
172                                 DBUS_TYPE_STRING, &method);
173
174         interface = connman_service_get_interface(default_service);
175         if (interface) {
176                 connman_dbus_dict_append_basic(&dict, "Interface",
177                                                 DBUS_TYPE_STRING, &interface);
178                 g_free(interface);
179         }
180
181         str = connman_service_get_domainname(default_service);
182         if (str)
183                 connman_dbus_dict_append_array(&dict, "Domains",
184                                         DBUS_TYPE_STRING, append_string, &str);
185
186         str_list = connman_service_get_nameservers(default_service);
187         if (str_list)
188                 connman_dbus_dict_append_array(&dict, "Nameservers",
189                                         DBUS_TYPE_STRING, append_string_list,
190                                         str_list);
191         g_strfreev(str_list);
192
193         connman_dbus_dict_close(&iter, &dict);
194
195         result = dbus_connection_send_with_reply(connection, msg,
196                                                         &call, DBUS_TIMEOUT);
197
198         if (!result || !call)
199                 goto done;
200
201         dbus_pending_call_set_notify(call, create_config_reply, NULL, NULL);
202
203         dbus_pending_call_unref(call);
204
205 done:
206         dbus_message_unref(msg);
207 }
208
209 static void destroy_config_reply(DBusPendingCall *call, void *user_data)
210 {
211         DBusMessage *reply = dbus_pending_call_steal_reply(call);
212
213         DBG("");
214
215         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
216                 connman_error("Failed to destoy proxy configuration");
217
218         dbus_message_unref(reply);
219 }
220
221 static void destroy_proxy_configuration(void)
222 {
223         DBusMessage *msg;
224         DBusPendingCall *call;
225         dbus_bool_t result;
226
227         if (!current_config)
228                 return;
229
230         DBG("");
231
232         msg = dbus_message_new_method_call(PACRUNNER_SERVICE, PACRUNNER_PATH,
233                         PACRUNNER_INTERFACE, "DestroyProxyConfiguration");
234         if (!msg)
235                 return;
236
237         dbus_message_set_auto_start(msg, FALSE);
238
239         dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &current_config,
240                                                         DBUS_TYPE_INVALID);
241
242         result = dbus_connection_send_with_reply(connection, msg,
243                                                         &call, DBUS_TIMEOUT);
244
245         dbus_message_unref(msg);
246
247         if (!result || !call)
248                 return;
249
250         dbus_pending_call_set_notify(call, destroy_config_reply, NULL, NULL);
251
252         dbus_pending_call_unref(call);
253
254         g_free(current_config);
255         current_config = NULL;
256 }
257
258 static void default_service_changed(struct connman_service *service)
259 {
260         DBG("service %p", service);
261
262         if (service == default_service)
263                 return;
264
265         default_service = service;
266
267         if (!daemon_running)
268                 return;
269
270         destroy_proxy_configuration();
271
272         create_proxy_configuration();
273 }
274
275 static void proxy_changed(struct connman_service *service)
276 {
277         DBG("service %p", service);
278
279         if (service != default_service)
280                 return;
281
282         if (!daemon_running)
283                 return;
284
285         destroy_proxy_configuration();
286
287         create_proxy_configuration();
288 }
289
290 static struct connman_notifier pacrunner_notifier = {
291         .name                   = "pacrunner",
292         .default_changed        = default_service_changed,
293         .proxy_changed          = proxy_changed,
294 };
295
296 static void pacrunner_connect(DBusConnection *conn, void *user_data)
297 {
298         DBG("");
299
300         daemon_running = TRUE;
301
302         create_proxy_configuration();
303 }
304
305 static void pacrunner_disconnect(DBusConnection *conn, void *user_data)
306 {
307         DBG("");
308
309         daemon_running = FALSE;
310
311         g_free(current_config);
312         current_config = NULL;
313 }
314
315 static char * parse_url(const char *url)
316 {
317         char *scheme, *host, *path, *host_ret;
318
319         scheme = g_strdup(url);
320         if (!scheme)
321                 return NULL;
322
323         host = strstr(scheme, "://");
324         if (host) {
325                 *host = '\0';
326                 host += 3;
327         } else
328                 host = scheme;
329
330         path = strchr(host, '/');
331         if (path)
332                 *(path++) = '\0';
333
334         host_ret = g_strdup(host);
335
336         g_free(scheme);
337
338         return host_ret;
339 }
340
341 static void request_lookup_reply(DBusPendingCall *call, void *user_data)
342 {
343         DBusMessage *reply = dbus_pending_call_steal_reply(call);
344         struct proxy_data *data = user_data;
345         const char *proxy;
346
347         DBG("");
348
349         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
350                 connman_error("Failed to find URL:%s", data->url);
351                 proxy = NULL;
352                 goto done;
353         }
354
355         if (!dbus_message_get_args(reply, NULL, DBUS_TYPE_STRING,
356                                         &proxy, DBUS_TYPE_INVALID))
357                 proxy = NULL;
358
359 done:
360         connman_proxy_driver_lookup_notify(data->service, data->url, proxy);
361
362         connman_service_unref(data->service);
363
364         g_free(data->url);
365         g_free(data);
366
367         dbus_message_unref(reply);
368 }
369
370 static int request_lookup(struct connman_service *service, const char *url)
371 {
372         DBusMessage *msg;
373         DBusPendingCall *call;
374         dbus_bool_t result;
375         char *host;
376         struct proxy_data *data;
377
378         DBG("");
379
380         msg = dbus_message_new_method_call(PACRUNNER_SERVICE,
381                                                 PACRUNNER_CLIENT_PATH,
382                                                 PACRUNNER_CLIENT_INTERFACE,
383                                                 "FindProxyForURL");
384         if (!msg)
385                 return -1;
386
387         host = parse_url(url);
388         if (!host) {
389                 dbus_message_unref(msg);
390                 return -EINVAL;
391         }
392
393         data = g_try_new0(struct proxy_data, 1);
394         if (!data) {
395                 dbus_message_unref(msg);
396                 g_free(host);
397                 return -ENOMEM;
398         }
399
400         data->url = g_strdup(url);
401         data->service = connman_service_ref(service);
402
403         dbus_message_append_args(msg, DBUS_TYPE_STRING, &url,
404                                         DBUS_TYPE_STRING, &host,
405                                         DBUS_TYPE_INVALID);
406
407         result = dbus_connection_send_with_reply(connection, msg,
408                                                         &call, DBUS_TIMEOUT);
409
410         dbus_message_unref(msg);
411
412         if (!result || !call) {
413                 g_free(host);
414                 g_free(data->url);
415                 g_free(data);
416                 return -EINVAL;
417         }
418
419         dbus_pending_call_set_notify(call, request_lookup_reply,
420                                                         data, NULL);
421
422         dbus_pending_call_unref(call);
423         g_free(host);
424
425         return 0;
426 }
427
428 static void cancel_lookup(struct connman_service *service, const char *url)
429 {
430         DBG("");
431 }
432
433 static struct connman_proxy_driver pacrunner_proxy = {
434         .name           = "pacrunnerproxy",
435         .priority       = CONNMAN_PROXY_PRIORITY_HIGH,
436         .request_lookup = request_lookup,
437         .cancel_lookup  = cancel_lookup,
438 };
439
440 static guint pacrunner_watch;
441
442 static int pacrunner_init(void)
443 {
444         connection = connman_dbus_get_connection();
445         if (!connection)
446                 return -EIO;
447
448         pacrunner_watch = g_dbus_add_service_watch(connection,
449                                         PACRUNNER_SERVICE, pacrunner_connect,
450                                         pacrunner_disconnect, NULL, NULL);
451         if (pacrunner_watch == 0) {
452                 dbus_connection_unref(connection);
453                 return -EIO;
454         }
455
456         connman_notifier_register(&pacrunner_notifier);
457
458         connman_proxy_driver_register(&pacrunner_proxy);
459
460         return 0;
461 }
462
463 static void pacrunner_exit(void)
464 {
465         connman_proxy_driver_unregister(&pacrunner_proxy);
466
467         connman_notifier_unregister(&pacrunner_notifier);
468
469         g_dbus_remove_watch(connection, pacrunner_watch);
470
471         destroy_proxy_configuration();
472
473         dbus_connection_unref(connection);
474 }
475
476 CONNMAN_PLUGIN_DEFINE(pacrunner, "PAC runner proxy plugin", VERSION,
477                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, pacrunner_init, pacrunner_exit)