wispr: Proxy lookup and web context setup
[platform/upstream/connman.git] / src / wispr.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 #include <stdlib.h>
28
29 #include <gweb/gweb.h>
30
31 #include "connman.h"
32
33 #define STATUS_URL  "http://www.connman.net/online/status.html"
34
35 struct connman_wispr_portal_context {
36         struct connman_service *service;
37         enum connman_ipconfig_type type;
38
39         /* Portal/WISPr common */
40         GWeb *web;
41         unsigned int token;
42 };
43
44 struct connman_wispr_portal {
45         struct connman_wispr_portal_context *ipv4_context;
46         struct connman_wispr_portal_context *ipv6_context;
47 };
48
49 static GHashTable *wispr_portal_list = NULL;
50
51 static void free_connman_wispr_portal_context(struct connman_wispr_portal_context *wp_context)
52 {
53         DBG("");
54
55         if (wp_context == NULL)
56                 return;
57
58         if (wp_context->token > 0)
59                 connman_proxy_lookup_cancel(wp_context->token);
60
61         g_web_unref(wp_context->web);
62
63         g_free(wp_context);
64 }
65
66 static void free_connman_wispr_portal(gpointer data)
67 {
68         struct connman_wispr_portal *wispr_portal = data;
69
70         DBG("");
71
72         if (wispr_portal == NULL)
73                 return;
74
75         free_connman_wispr_portal_context(wispr_portal->ipv4_context);
76         free_connman_wispr_portal_context(wispr_portal->ipv6_context);
77
78         g_free(wispr_portal);
79 }
80
81 static void web_debug(const char *str, void *data)
82 {
83         connman_info("%s: %s\n", (const char *) data, str);
84 }
85
86 static void proxy_callback(const char *proxy, void *user_data)
87 {
88         struct connman_wispr_portal_context *wp_context = user_data;
89
90         DBG("proxy %s", proxy);
91
92         wp_context->token = 0;
93
94         if (proxy == NULL)
95                 proxy = getenv("http_proxy");
96
97         if (getenv("CONNMAN_WEB_DEBUG"))
98                 g_web_set_debug(wp_context->web, web_debug, "WEB");
99
100         if (proxy != NULL && g_strcmp0(proxy, "DIRECT") != 0)
101                 g_web_set_proxy(wp_context->web, proxy);
102
103         g_web_set_accept(wp_context->web, NULL);
104         g_web_set_user_agent(wp_context->web, "ConnMan/%s", VERSION);
105         g_web_set_close_connection(wp_context->web, TRUE);
106 }
107
108 static int wispr_portal_detect(struct connman_wispr_portal_context *wp_context)
109 {
110         enum connman_service_type service_type;
111         char *interface = NULL;
112         int err = 0;
113
114         DBG("wispr/portal context %p", wp_context);
115         DBG("service %p", wp_context->service);
116
117         service_type = connman_service_get_type(wp_context->service);
118
119         switch (service_type) {
120         case CONNMAN_SERVICE_TYPE_ETHERNET:
121         case CONNMAN_SERVICE_TYPE_WIFI:
122         case CONNMAN_SERVICE_TYPE_WIMAX:
123         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
124         case CONNMAN_SERVICE_TYPE_CELLULAR:
125                 break;
126         case CONNMAN_SERVICE_TYPE_UNKNOWN:
127         case CONNMAN_SERVICE_TYPE_SYSTEM:
128         case CONNMAN_SERVICE_TYPE_GPS:
129         case CONNMAN_SERVICE_TYPE_VPN:
130         case CONNMAN_SERVICE_TYPE_GADGET:
131                 return -EOPNOTSUPP;
132         }
133
134         interface = connman_service_get_interface(wp_context->service);
135         if (interface == NULL)
136                 return -EINVAL;
137
138         DBG("interface %s", interface);
139
140         wp_context->web = g_web_new(0);
141         if (wp_context->web == NULL) {
142                 err = -ENOMEM;
143                 goto done;
144         }
145
146         if (wp_context->type == CONNMAN_IPCONFIG_TYPE_IPV4)
147                 g_web_set_address_family(wp_context->web, AF_INET);
148         else
149                 g_web_set_address_family(wp_context->web, AF_INET6);
150
151         wp_context->token = connman_proxy_lookup(interface,
152                                         STATUS_URL, wp_context->service,
153                                         proxy_callback, wp_context);
154         if (wp_context->token == 0)
155                 err = -EINVAL;
156
157 done:
158         g_free(interface);
159         return err;
160 }
161
162 int __connman_wispr_start(struct connman_service *service,
163                                         enum connman_ipconfig_type type)
164 {
165         struct connman_wispr_portal_context *wp_context = NULL;
166         struct connman_wispr_portal *wispr_portal = NULL;
167         int index;
168
169         DBG("service %p", service);
170
171         if (wispr_portal_list == NULL)
172                 return -EINVAL;
173
174         index = __connman_service_get_index(service);
175         if (index < 0)
176                 return -EINVAL;
177
178         wispr_portal = g_hash_table_lookup(wispr_portal_list,
179                                         GINT_TO_POINTER(index));
180         if (wispr_portal == NULL) {
181                 wispr_portal = g_try_new0(struct connman_wispr_portal, 1);
182                 if (wispr_portal == NULL)
183                         return -ENOMEM;
184
185                 g_hash_table_replace(wispr_portal_list,
186                                         GINT_TO_POINTER(index), wispr_portal);
187         }
188
189         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
190                 wp_context = wispr_portal->ipv4_context;
191         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
192                 wp_context = wispr_portal->ipv6_context;
193         else
194                 return -EINVAL;
195
196         if (wp_context == NULL) {
197                 wp_context = g_try_new0(struct connman_wispr_portal_context, 1);
198                 if (wp_context == NULL)
199                         return -ENOMEM;
200
201                 wp_context->service = service;
202                 wp_context->type = type;
203
204                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
205                         wispr_portal->ipv4_context = wp_context;
206                 else
207                         wispr_portal->ipv6_context = wp_context;
208
209                 return wispr_portal_detect(wp_context);
210         }
211
212         return 0;
213 }
214
215 void __connman_wispr_stop(struct connman_service *service)
216 {
217         int index;
218
219         DBG("service %p", service);
220
221         if (wispr_portal_list == NULL)
222                 return;
223
224         index = __connman_service_get_index(service);
225         if (index < 0)
226                 return;
227
228         g_hash_table_remove(wispr_portal_list, GINT_TO_POINTER(index));
229 }
230
231 int __connman_wispr_init(void)
232 {
233         DBG("");
234
235         wispr_portal_list = g_hash_table_new_full(g_direct_hash,
236                                                 g_direct_equal, NULL,
237                                                 free_connman_wispr_portal);
238
239         return 0;
240 }
241
242 void __connman_wispr_cleanup(void)
243 {
244         DBG("");
245
246         g_hash_table_destroy(wispr_portal_list);
247         wispr_portal_list = NULL;
248 }