device: Include Reason in Disconnect Skip Warning
[framework/connectivity/connman.git] / plugins / portal.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 <glib.h>
30
31 #define CONNMAN_API_SUBJECT_TO_CHANGE
32 #include <connman/plugin.h>
33 #include <connman/location.h>
34 #include <connman/proxy.h>
35 #include <connman/log.h>
36
37 #include "gweb/gweb.h"
38
39 #define STATUS_URL  "http://www.connman.net/online/status.html"
40
41 struct server_data {
42         unsigned int token;
43         GWeb *web;
44         guint request_id;
45 };
46
47 static void web_debug(const char *str, void *data)
48 {
49         connman_info("%s: %s\n", (const char *) data, str);
50 }
51
52 static gboolean web_result(GWebResult *result, gpointer user_data)
53 {
54         struct connman_location *location = user_data;
55         struct server_data *data = connman_location_get_data(location);
56         const char *str;
57         guint16 status;
58
59         if (data->request_id == 0)
60                 return FALSE;
61
62         status = g_web_result_get_status(result);
63
64         /* If status header is not available, it is a portal */
65         if (g_web_result_get_header(result, "X-ConnMan-Status", &str) == FALSE)
66                 status = 302;
67
68         DBG("status %u", status);
69
70         switch (status) {
71         case 200:
72                 if (g_web_result_get_header(result, "X-ConnMan-Client-IP",
73                                                                 &str) == TRUE)
74                         connman_info("Client-IP: %s", str);
75
76                 if (g_web_result_get_header(result, "X-ConnMan-Client-Country",
77                                                                 &str) == TRUE)
78                         connman_info("Client-Country: %s", str);
79
80                 if (g_web_result_get_header(result, "X-ConnMan-Client-Region",
81                                                                 &str) == TRUE)
82                         connman_info("Client-Region: %s", str);
83
84                 connman_location_report_result(location,
85                                         CONNMAN_LOCATION_RESULT_ONLINE);
86                 break;
87         case 302:
88                 connman_location_report_result(location,
89                                         CONNMAN_LOCATION_RESULT_PORTAL);
90                 break;
91         default:
92                 connman_location_report_result(location,
93                                         CONNMAN_LOCATION_RESULT_UNKNOWN);
94                 break;
95         }
96
97         data->request_id = 0;
98
99         return FALSE;
100 }
101
102 static void proxy_callback(const char *proxy, void *user_data)
103 {
104         struct connman_location *location = user_data;
105         struct server_data *data = connman_location_get_data(location);
106
107         DBG("proxy %s", proxy);
108
109         if (proxy == NULL)
110                 proxy = getenv("http_proxy");
111
112         if (data != NULL) {
113                 if (proxy != NULL && g_strcmp0(proxy, "DIRECT") != 0)
114                         g_web_set_proxy(data->web, proxy);
115
116                 data->request_id = g_web_request_get(data->web, STATUS_URL,
117                                                         web_result, location);
118
119                 data->token = 0;
120         }
121
122         connman_location_unref(location);
123 }
124
125 static int location_detect(struct connman_location *location)
126 {
127         struct server_data *data;
128         struct connman_service *service;
129         enum connman_service_type service_type;
130         char *interface;
131         int err;
132
133         DBG("location %p", location);
134
135         service_type = connman_location_get_type(location);
136
137         switch (service_type) {
138         case CONNMAN_SERVICE_TYPE_ETHERNET:
139         case CONNMAN_SERVICE_TYPE_WIFI:
140         case CONNMAN_SERVICE_TYPE_WIMAX:
141         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
142         case CONNMAN_SERVICE_TYPE_CELLULAR:
143                 break;
144         case CONNMAN_SERVICE_TYPE_UNKNOWN:
145         case CONNMAN_SERVICE_TYPE_SYSTEM:
146         case CONNMAN_SERVICE_TYPE_GPS:
147         case CONNMAN_SERVICE_TYPE_VPN:
148         case CONNMAN_SERVICE_TYPE_GADGET:
149                 return -EOPNOTSUPP;
150         }
151
152         interface = connman_location_get_interface(location);
153         if (interface == NULL)
154                 return -EINVAL;
155
156         DBG("interface %s", interface);
157
158         data = g_try_new0(struct server_data, 1);
159         if (data == NULL) {
160                 err = -ENOMEM;
161                 goto done;
162         }
163
164         connman_location_set_data(location, data);
165
166         data->web = g_web_new(0);
167         if (data->web == NULL) {
168                 g_free(data);
169                 err = -ENOMEM;
170                 goto done;
171         }
172
173         if (getenv("CONNMAN_WEB_DEBUG"))
174                 g_web_set_debug(data->web, web_debug, "WEB");
175
176         g_web_set_accept(data->web, NULL);
177         g_web_set_user_agent(data->web, "ConnMan/%s", VERSION);
178         g_web_set_close_connection(data->web, TRUE);
179
180         connman_location_ref(location);
181
182         service = connman_location_get_service(location);
183         data->token = connman_proxy_lookup(interface, STATUS_URL,
184                                         service, proxy_callback, location);
185
186         if (data->token == 0) {
187                 connman_location_unref(location);
188                 err = -EINVAL;
189         } else
190                 err = 0;
191
192 done:
193         g_free(interface);
194         return err;
195 }
196
197 static int location_finish(struct connman_location *location)
198 {
199         struct server_data *data = connman_location_get_data(location);
200
201         DBG("location %p", location);
202
203         connman_location_set_data(location, NULL);
204
205         if (data->request_id > 0)
206                 g_web_cancel_request(data->web, data->request_id);
207
208         if (data->token > 0) {
209                 connman_proxy_lookup_cancel(data->token);
210                 connman_location_unref(location);
211         }
212
213         g_web_unref(data->web);
214
215         g_free(data);
216
217         return 0;
218 }
219
220 static struct connman_location_driver location = {
221         .name           = "portal",
222         .type           = CONNMAN_SERVICE_TYPE_WIFI,
223         .priority       = CONNMAN_LOCATION_PRIORITY_HIGH,
224         .detect         = location_detect,
225         .finish         = location_finish,
226 };
227
228 static int portal_init(void)
229 {
230         return connman_location_driver_register(&location);
231 }
232
233 static void portal_exit(void)
234 {
235         connman_location_driver_unregister(&location);
236 }
237
238 CONNMAN_PLUGIN_DEFINE(portal, "Portal detection plugin", VERSION,
239                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, portal_init, portal_exit)