Imported Upstream version 1.24
[platform/upstream/connman.git] / src / proxy.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2012  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 <glib.h>
27
28 #include "connman.h"
29
30 static unsigned int next_lookup_token = 1;
31
32 static GSList *driver_list = NULL;
33 static GSList *lookup_list = NULL;
34
35 struct proxy_lookup {
36         unsigned int token;
37         connman_proxy_lookup_cb cb;
38         void *user_data;
39         struct connman_service *service;
40         char *url;
41         guint watch;
42         struct connman_proxy_driver *proxy;
43 };
44
45 static void remove_lookup(struct proxy_lookup *lookup)
46 {
47         lookup_list = g_slist_remove(lookup_list, lookup);
48
49         connman_service_unref(lookup->service);
50         g_free(lookup->url);
51         g_free(lookup);
52 }
53
54 static void remove_lookups(GSList *lookups)
55 {
56         GSList *list;
57
58         for (list = lookups; list; list = list->next) {
59                 struct proxy_lookup *lookup = list->data;
60
61                 remove_lookup(lookup);
62         }
63
64         g_slist_free(lookups);
65 }
66
67 static gboolean lookup_callback(gpointer user_data)
68 {
69         struct proxy_lookup *lookup = user_data;
70         GSList *list;
71
72         if (!lookup)
73                 return FALSE;
74
75         lookup->watch = 0;
76
77         for (list = driver_list; list; list = list->next) {
78                 struct connman_proxy_driver *proxy = list->data;
79
80                 if (!proxy->request_lookup)
81                         continue;
82
83                 lookup->proxy = proxy;
84                 break;
85         }
86
87         if (!lookup->proxy ||
88                 lookup->proxy->request_lookup(lookup->service,
89                                                 lookup->url) < 0) {
90
91                 if (lookup->cb)
92                         lookup->cb(NULL, lookup->user_data);
93
94                 remove_lookup(lookup);
95         }
96
97         return FALSE;
98 }
99
100 unsigned int connman_proxy_lookup(const char *interface, const char *url,
101                                         struct connman_service *service,
102                                         connman_proxy_lookup_cb cb,
103                                         void *user_data)
104 {
105         struct proxy_lookup *lookup;
106
107         DBG("interface %s url %s", interface, url);
108
109         if (!interface)
110                 return 0;
111
112         lookup = g_try_new0(struct proxy_lookup, 1);
113         if (!lookup)
114                 return 0;
115
116         lookup->token = next_lookup_token++;
117
118         lookup->cb = cb;
119         lookup->user_data = user_data;
120         lookup->url = g_strdup(url);
121         lookup->service = connman_service_ref(service);
122
123         lookup->watch = g_timeout_add_seconds(0, lookup_callback, lookup);
124         if (lookup->watch == 0) {
125                 g_free(lookup->url);
126                 g_free(lookup);
127                 return 0;
128         }
129
130         DBG("token %u", lookup->token);
131         lookup_list = g_slist_prepend(lookup_list, lookup);
132
133         return lookup->token;
134 }
135
136 void connman_proxy_lookup_cancel(unsigned int token)
137 {
138         GSList *list;
139         struct proxy_lookup *lookup = NULL;
140
141         DBG("token %u", token);
142
143         for (list = lookup_list; list; list = list->next) {
144                 lookup = list->data;
145
146                 if (lookup->token == token)
147                         break;
148
149                 lookup = NULL;
150         }
151
152         if (lookup) {
153                 if (lookup->watch > 0) {
154                         g_source_remove(lookup->watch);
155                         lookup->watch = 0;
156                 }
157
158                 if (lookup->proxy &&
159                                         lookup->proxy->cancel_lookup)
160                         lookup->proxy->cancel_lookup(lookup->service,
161                                                                 lookup->url);
162
163                 remove_lookup(lookup);
164         }
165 }
166
167 void connman_proxy_driver_lookup_notify(struct connman_service *service,
168                                         const char *url, const char *result)
169 {
170         GSList *list, *matches = NULL;
171
172         DBG("service %p url %s result %s", service, url, result);
173
174         for (list = lookup_list; list; list = list->next) {
175                 struct proxy_lookup *lookup = list->data;
176
177                 if (service != lookup->service)
178                         continue;
179
180                 if (g_strcmp0(lookup->url, url) == 0) {
181                         if (lookup->cb)
182                                 lookup->cb(result, lookup->user_data);
183
184                         matches = g_slist_prepend(matches, lookup);
185                 }
186         }
187
188         if (matches)
189                 remove_lookups(matches);
190 }
191
192 static gint compare_priority(gconstpointer a, gconstpointer b)
193 {
194         const struct connman_proxy_driver *driver1 = a;
195         const struct connman_proxy_driver *driver2 = b;
196
197         return driver2->priority - driver1->priority;
198 }
199
200 /**
201  * connman_proxy_driver_register:
202  * @driver: Proxy driver definition
203  *
204  * Register a new proxy driver
205  *
206  * Returns: %0 on success
207  */
208 int connman_proxy_driver_register(struct connman_proxy_driver *driver)
209 {
210         DBG("driver %p name %s", driver, driver->name);
211
212         driver_list = g_slist_insert_sorted(driver_list, driver,
213                                                         compare_priority);
214
215         return 0;
216 }
217
218 /**
219  * connman_proxy_driver_unregister:
220  * @driver: Proxy driver definition
221  *
222  * Remove a previously registered proxy driver
223  */
224 void connman_proxy_driver_unregister(struct connman_proxy_driver *driver)
225 {
226         GSList *list;
227
228         DBG("driver %p name %s", driver, driver->name);
229
230         driver_list = g_slist_remove(driver_list, driver);
231
232         for (list = lookup_list; list; list = list->next) {
233                 struct proxy_lookup *lookup = list->data;
234
235                 if (lookup->proxy == driver)
236                         lookup->proxy = NULL;
237         }
238
239 }
240
241 int __connman_proxy_init(void)
242 {
243         DBG("");
244
245         return 0;
246 }
247
248 void __connman_proxy_cleanup(void)
249 {
250         DBG("");
251
252         remove_lookups(lookup_list);
253 }