1*5b9c547cSRui Paulo /* 2*5b9c547cSRui Paulo * Hotspot 2.0 client - Web browser using Android browser 3*5b9c547cSRui Paulo * Copyright (c) 2013, Qualcomm Atheros, Inc. 4*5b9c547cSRui Paulo * 5*5b9c547cSRui Paulo * This software may be distributed under the terms of the BSD license. 6*5b9c547cSRui Paulo * See README for more details. 7*5b9c547cSRui Paulo */ 8*5b9c547cSRui Paulo 9*5b9c547cSRui Paulo #include "includes.h" 10*5b9c547cSRui Paulo 11*5b9c547cSRui Paulo #include "common.h" 12*5b9c547cSRui Paulo #include "utils/eloop.h" 13*5b9c547cSRui Paulo #include "wps/http_server.h" 14*5b9c547cSRui Paulo #include "browser.h" 15*5b9c547cSRui Paulo 16*5b9c547cSRui Paulo 17*5b9c547cSRui Paulo struct browser_data { 18*5b9c547cSRui Paulo int success; 19*5b9c547cSRui Paulo }; 20*5b9c547cSRui Paulo 21*5b9c547cSRui Paulo 22*5b9c547cSRui Paulo static void browser_timeout(void *eloop_data, void *user_ctx) 23*5b9c547cSRui Paulo { 24*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Timeout on waiting browser interaction to " 25*5b9c547cSRui Paulo "complete"); 26*5b9c547cSRui Paulo eloop_terminate(); 27*5b9c547cSRui Paulo } 28*5b9c547cSRui Paulo 29*5b9c547cSRui Paulo 30*5b9c547cSRui Paulo static void http_req(void *ctx, struct http_request *req) 31*5b9c547cSRui Paulo { 32*5b9c547cSRui Paulo struct browser_data *data = ctx; 33*5b9c547cSRui Paulo struct wpabuf *resp; 34*5b9c547cSRui Paulo const char *url; 35*5b9c547cSRui Paulo int done = 0; 36*5b9c547cSRui Paulo 37*5b9c547cSRui Paulo url = http_request_get_uri(req); 38*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Browser response received: %s", url); 39*5b9c547cSRui Paulo 40*5b9c547cSRui Paulo if (os_strcmp(url, "/") == 0) { 41*5b9c547cSRui Paulo data->success = 1; 42*5b9c547cSRui Paulo done = 1; 43*5b9c547cSRui Paulo } else if (os_strncmp(url, "/osu/", 5) == 0) { 44*5b9c547cSRui Paulo data->success = atoi(url + 5); 45*5b9c547cSRui Paulo done = 1; 46*5b9c547cSRui Paulo } 47*5b9c547cSRui Paulo 48*5b9c547cSRui Paulo resp = wpabuf_alloc(1); 49*5b9c547cSRui Paulo if (resp == NULL) { 50*5b9c547cSRui Paulo http_request_deinit(req); 51*5b9c547cSRui Paulo if (done) 52*5b9c547cSRui Paulo eloop_terminate(); 53*5b9c547cSRui Paulo return; 54*5b9c547cSRui Paulo } 55*5b9c547cSRui Paulo 56*5b9c547cSRui Paulo if (done) { 57*5b9c547cSRui Paulo eloop_cancel_timeout(browser_timeout, NULL, NULL); 58*5b9c547cSRui Paulo eloop_register_timeout(0, 500000, browser_timeout, &data, NULL); 59*5b9c547cSRui Paulo } 60*5b9c547cSRui Paulo 61*5b9c547cSRui Paulo http_request_send_and_deinit(req, resp); 62*5b9c547cSRui Paulo } 63*5b9c547cSRui Paulo 64*5b9c547cSRui Paulo 65*5b9c547cSRui Paulo int hs20_web_browser(const char *url) 66*5b9c547cSRui Paulo { 67*5b9c547cSRui Paulo struct http_server *http; 68*5b9c547cSRui Paulo struct in_addr addr; 69*5b9c547cSRui Paulo struct browser_data data; 70*5b9c547cSRui Paulo pid_t pid; 71*5b9c547cSRui Paulo 72*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Launching Android browser to %s", url); 73*5b9c547cSRui Paulo 74*5b9c547cSRui Paulo os_memset(&data, 0, sizeof(data)); 75*5b9c547cSRui Paulo 76*5b9c547cSRui Paulo if (eloop_init() < 0) { 77*5b9c547cSRui Paulo wpa_printf(MSG_ERROR, "eloop_init failed"); 78*5b9c547cSRui Paulo return -1; 79*5b9c547cSRui Paulo } 80*5b9c547cSRui Paulo addr.s_addr = htonl((127 << 24) | 1); 81*5b9c547cSRui Paulo http = http_server_init(&addr, 12345, http_req, &data); 82*5b9c547cSRui Paulo if (http == NULL) { 83*5b9c547cSRui Paulo wpa_printf(MSG_ERROR, "http_server_init failed"); 84*5b9c547cSRui Paulo eloop_destroy(); 85*5b9c547cSRui Paulo return -1; 86*5b9c547cSRui Paulo } 87*5b9c547cSRui Paulo 88*5b9c547cSRui Paulo pid = fork(); 89*5b9c547cSRui Paulo if (pid < 0) { 90*5b9c547cSRui Paulo wpa_printf(MSG_ERROR, "fork: %s", strerror(errno)); 91*5b9c547cSRui Paulo http_server_deinit(http); 92*5b9c547cSRui Paulo eloop_destroy(); 93*5b9c547cSRui Paulo return -1; 94*5b9c547cSRui Paulo } 95*5b9c547cSRui Paulo 96*5b9c547cSRui Paulo if (pid == 0) { 97*5b9c547cSRui Paulo /* run the external command in the child process */ 98*5b9c547cSRui Paulo char *argv[9]; 99*5b9c547cSRui Paulo 100*5b9c547cSRui Paulo argv[0] = "browser-android"; 101*5b9c547cSRui Paulo argv[1] = "start"; 102*5b9c547cSRui Paulo argv[2] = "-a"; 103*5b9c547cSRui Paulo argv[3] = "android.intent.action.VIEW"; 104*5b9c547cSRui Paulo argv[4] = "-d"; 105*5b9c547cSRui Paulo argv[5] = (void *) url; 106*5b9c547cSRui Paulo argv[6] = "-n"; 107*5b9c547cSRui Paulo argv[7] = "com.android.browser/.BrowserActivity"; 108*5b9c547cSRui Paulo argv[8] = NULL; 109*5b9c547cSRui Paulo 110*5b9c547cSRui Paulo execv("/system/bin/am", argv); 111*5b9c547cSRui Paulo wpa_printf(MSG_ERROR, "execv: %s", strerror(errno)); 112*5b9c547cSRui Paulo exit(0); 113*5b9c547cSRui Paulo return -1; 114*5b9c547cSRui Paulo } 115*5b9c547cSRui Paulo 116*5b9c547cSRui Paulo eloop_register_timeout(30, 0, browser_timeout, &data, NULL); 117*5b9c547cSRui Paulo eloop_run(); 118*5b9c547cSRui Paulo eloop_cancel_timeout(browser_timeout, &data, NULL); 119*5b9c547cSRui Paulo http_server_deinit(http); 120*5b9c547cSRui Paulo eloop_destroy(); 121*5b9c547cSRui Paulo 122*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Closing Android browser"); 123*5b9c547cSRui Paulo if (system("/system/bin/input keyevent KEYCODE_HOME") != 0) { 124*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to inject keyevent"); 125*5b9c547cSRui Paulo } 126*5b9c547cSRui Paulo 127*5b9c547cSRui Paulo return data.success; 128*5b9c547cSRui Paulo } 129