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