iptables-test: Support for user defined chain jumps
[framework/connectivity/connman.git] / tools / portal-test.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 <stdio.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <netdb.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34
35 #include <glib.h>
36 #include <glib/gprintf.h>
37
38 #define PORT 80
39 #define PROXY_PORT 911
40 #define PAGE "/"
41 #define HOST "connman.net"
42 #define USER_APP "connman"
43
44 #define CONNECT_TIMEOUT 120
45 #define MAX_COUNTER     80
46
47 enum get_page_status {
48         GET_PAGE_SUCCESS        = 0,
49         GET_PAGE_TIMEOUT        = 1,
50         GET_PAGE_FAILED         = 2,
51         GET_PAGE_REDIRECTED     = 3,
52 };
53
54 struct server_data {
55         char host[MAX_COUNTER];
56         char page[MAX_COUNTER];
57         char proxy[MAX_COUNTER];
58         GIOChannel *channel;
59         guint watch;
60         guint timeout;
61         int connection_ready;
62         int sock;
63         int proxy_port;
64         int (*get_page) (struct server_data *data, char *page, int len,
65                                                 enum get_page_status status);
66 };
67
68 static GMainLoop *main_loop = NULL;
69
70 static int create_socket()
71 {
72         int sk;
73
74         sk = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
75         if (sk < 0) {
76                 perror("Error: Can not create TCP socket");
77                 exit(1);
78         }
79
80         return sk;
81 }
82
83 static char *get_ip_from_host(char *host)
84 {
85         int ip_len = 15;
86         char *ip;
87         struct hostent *host_ent;
88
89         ip = g_try_malloc0(ip_len + 1);
90         if ((host_ent = gethostbyname(host)) == NULL) {
91                 perror("Error: Can not get IP");
92                 exit(1);
93         }
94
95         if (inet_ntop(AF_INET, (void *) host_ent->h_addr_list[0],
96                                                         ip, ip_len) == NULL) {
97                 perror("Error: Can not resolve host");
98                 exit(1);
99         }
100
101         return ip;
102 }
103
104 static char *build_get_query(char *host, char *page)
105 {
106         char *query;
107         char *host_page = page;
108         char *tpl = "GET /%s HTTP/1.0\r\nHost: %s\r\nUser-Agent: %s\r\n\r\n";
109
110         if(host_page[0] == '/')
111                 host_page = host_page + 1;
112
113         query = g_try_malloc0(strlen(host) + strlen(host_page) +
114                                         strlen(USER_APP) + strlen(tpl) - 5);
115         sprintf(query, tpl, host_page, host, USER_APP);
116
117         return query;
118 }
119
120 static gboolean connect_timeout(gpointer user_data)
121 {
122         struct server_data *data = user_data;
123
124         data->timeout = 0;
125
126         if (data->get_page)
127                 data->get_page(data, NULL, 0, GET_PAGE_TIMEOUT);
128
129         return FALSE;
130 }
131
132 static void remove_timeout(struct server_data *data)
133 {
134         if (data->timeout > 0) {
135                 g_source_remove(data->timeout);
136                 data->timeout = 0;
137         }
138 }
139
140 static gboolean tcp_event(GIOChannel *channel, GIOCondition condition,
141                                                         gpointer user_data)
142 {
143         char buf[BUFSIZ+1];
144         int len;
145         int sk;
146         struct server_data *data = user_data;
147
148         if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
149                 remove_timeout(data);
150                 data->watch = 0;
151                 if (data->get_page)
152                         data->get_page(data, NULL, 0, GET_PAGE_FAILED);
153
154                 return FALSE;
155         }
156
157         sk = g_io_channel_unix_get_fd(channel);
158         len = recv(sk, buf, BUFSIZ, 0);
159
160         if (len > 0) {
161                 remove_timeout(data);
162                 if (data->get_page)
163                         data->get_page(data, buf, len, GET_PAGE_SUCCESS);
164         }
165
166         return TRUE;
167 }
168
169 static gboolean socket_event(GIOChannel *channel, GIOCondition condition,
170                                 gpointer user_data)
171 {
172         struct server_data *data = user_data;
173         char *query;
174         int sk;
175         unsigned int send_counter = 0;
176         int ret;
177
178         if (condition & G_IO_OUT && data->connection_ready == 0) {
179                 data->connection_ready = 1;
180                 sk = g_io_channel_unix_get_fd(channel);
181
182                 query = build_get_query(data->host, data->page);
183                 fprintf(stderr, "query is:\n%s\n", query);
184
185                 while (send_counter < strlen(query)) {
186                         ret = send(sk, query+send_counter,
187                                         strlen(query) - send_counter, 0);
188                         if(ret == -1) {
189                                 perror("Error sending query");
190                                 remove_timeout(data);
191                                 if (data->get_page)
192                                         data->get_page(data, NULL, 0,
193                                                         GET_PAGE_FAILED);
194                                 g_free(query);
195                                 return FALSE;
196                         }
197                         send_counter += ret;
198                 }
199                 g_free(query);
200         } else if (condition & G_IO_IN)
201                 tcp_event(channel, condition, user_data);
202
203         return TRUE;
204 }
205
206 static void remove_connection(struct server_data *data)
207 {
208         remove_timeout(data);
209         g_source_remove(data->watch);
210         g_io_channel_shutdown(data->channel, TRUE, NULL);
211         
212         if (data->sock >= 0)
213                 close(data->sock);
214
215         g_free(data);
216 }
217
218 static int get_html(struct server_data *data, int ms_time)
219 {
220         struct sockaddr_in *remote_host;
221         int ret;
222         char *ip;
223
224         data->connection_ready = 0;
225         data->sock = create_socket();
226         if (strlen(data->proxy) > 0)
227                 ip = get_ip_from_host(data->proxy);
228         else
229                 ip = get_ip_from_host(data->host);
230
231         fprintf(stderr, "IP from host %s is %s\n", data->host, ip); 
232
233         remote_host = g_try_new0(struct sockaddr_in, 1);
234         remote_host->sin_family = AF_INET;
235         ret = inet_pton(AF_INET, ip, (void *) (&(remote_host->sin_addr.s_addr)));
236         if (ret < 0) {
237                 perror("Error Calling inet_pton");
238                 goto error;
239         } else if (ret == 0) {
240                 fprintf(stderr, "Error: wrong IP address:%s\n", ip);
241                 goto error;
242         }
243         if (strlen(data->proxy) > 0)
244                 remote_host->sin_port = htons(data->proxy_port);
245         else
246                 remote_host->sin_port = htons(PORT);
247
248         data->channel = g_io_channel_unix_new(data->sock);
249         g_io_channel_set_flags(data->channel, G_IO_FLAG_NONBLOCK, NULL);
250         g_io_channel_set_close_on_unref(data->channel, TRUE);
251         data->watch = g_io_add_watch(data->channel, G_IO_OUT | G_IO_IN,
252                                                         socket_event, data);
253         data->timeout = g_timeout_add_seconds(ms_time, connect_timeout, data);
254
255         ret = connect(data->sock, (struct sockaddr *)remote_host,
256                                                 sizeof(struct sockaddr));
257         if (ret < 0 && errno != EINPROGRESS) {
258                 perror("Could not connect");
259                 remove_timeout(data);
260                 goto error;
261         }
262
263         g_free(remote_host);
264         g_free(ip);
265         return 0;
266
267 error:
268         g_free(remote_host);
269         g_free(ip);
270
271         if (data->get_page)
272                 data->get_page(data, NULL, 0, GET_PAGE_FAILED);
273
274         return ret;
275 }
276
277 static int get_status(struct server_data *data, char *page, int len)
278 {
279         gchar **lines;
280         gchar *str;
281         int i;
282         int ret = GET_PAGE_REDIRECTED;
283
284         lines = g_strsplit(page, "\n", 13);
285
286         str = g_strrstr(lines[0], "200 OK");
287         if (str != NULL) {
288                 for (i = 0; lines[i] != NULL && i < 12; i++) {
289                         str = g_strstr_len(lines[i], 12, "Set-Cookie");
290                         if (str != NULL)
291                                 ret = GET_PAGE_SUCCESS;
292                 }
293         }
294         g_strfreev(lines);
295
296         return ret;
297 }
298
299 static int get_page_cb(struct server_data *data, char *page, int len,
300                 enum get_page_status status)
301 {
302         int ret = status;
303
304         if (page)
305                 ret = get_status(data, page, len);
306
307         switch (ret) {
308         case GET_PAGE_SUCCESS:
309                 fprintf(stderr, "%s\n", "Page was fetched");
310                 break;
311         case GET_PAGE_REDIRECTED:
312                 fprintf(stderr, "%s\n", "Page was redirected");
313                 break;
314         case GET_PAGE_FAILED:
315                 fprintf(stderr, "%s\n", "error can not get the page");
316                 break;
317         case GET_PAGE_TIMEOUT:
318                 fprintf(stderr, "%s\n", "Page was timeout");
319                 break;
320         }
321         g_main_loop_quit(main_loop);
322
323         return ret;
324 }
325
326 int main(int argc, char **argv)
327 {
328         char *host = HOST;
329         char *page = PAGE;
330         char *proxy;
331         struct server_data *data;
332
333         if (argc > 1)
334                 host = argv[1];
335
336         if (argc > 2)
337                 page = argv[2];
338
339         data = g_try_new0(struct server_data, 1);
340         if (data == NULL)
341                 exit(1);
342
343         memset(data, 0, sizeof(struct server_data));
344         strcpy(data->host, host);
345         strcpy(data->page, page);
346         data->get_page = get_page_cb;
347         data->timeout = 0;
348
349         main_loop = g_main_loop_new(NULL, FALSE);
350
351         proxy = getenv("http_proxy");
352         if (proxy) {
353                 char *delim;
354
355                 if (strncmp(proxy, "http://", 7) == 0)
356                         strcpy(data->proxy, proxy + 7);
357                 else
358                         strcpy(data->proxy, proxy);
359
360                 delim = strchr(data->proxy, ':');
361                 if (delim) {
362                         int len;
363
364                         len = delim - data->proxy;
365                         data->proxy[len] = '\0';
366
367                         data->proxy_port = atoi(delim + 1);
368                 } else
369                         data->proxy_port = PROXY_PORT;
370         }
371         get_html(data, CONNECT_TIMEOUT);
372
373         g_main_loop_run(main_loop);
374
375         remove_connection(data);
376
377         return 0;
378 }