X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fwispr.c;h=3b203fba7c57244cfdd252a9a7da8ed3c6a74d53;hb=17c2dfb865433db2e64f1e64fcd5fac7cb445c23;hp=299754e508c87bcaeca3bd57ab214a5cf57e68d5;hpb=39d675b3ff57daa893239afff879757eb692122e;p=platform%2Fupstream%2Fconnman.git diff --git a/src/wispr.c b/src/wispr.c old mode 100644 new mode 100755 index 299754e..3b203fb --- a/src/wispr.c +++ b/src/wispr.c @@ -2,7 +2,7 @@ * * Connection Manager * - * Copyright (C) 2007-2010 Intel Corporation. All rights reserved. + * Copyright (C) 2007-2013 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -34,7 +34,7 @@ #define STATUS_URL_IPV6 "http://ipv6.connman.net/online/status.html" struct connman_wispr_message { - gboolean has_error; + bool has_error; const char *current_element; int message_type; int response_code; @@ -53,9 +53,15 @@ enum connman_wispr_result { CONNMAN_WISPR_RESULT_FAILED = 3, }; +struct wispr_route { + char *address; + int if_index; +}; + struct connman_wispr_portal_context { struct connman_service *service; enum connman_ipconfig_type type; + struct connman_wispr_portal *wispr_portal; /* Portal/WISPr common */ GWeb *web; @@ -75,6 +81,10 @@ struct connman_wispr_portal_context { char *wispr_formdata; enum connman_wispr_result wispr_result; + + GSList *route_list; + + guint timeout; }; struct connman_wispr_portal { @@ -82,7 +92,7 @@ struct connman_wispr_portal { struct connman_wispr_portal_context *ipv6_context; }; -static gboolean wispr_portal_web_result(GWebResult *result, gpointer user_data); +static bool wispr_portal_web_result(GWebResult *result, gpointer user_data); static GHashTable *wispr_portal_list = NULL; @@ -90,7 +100,7 @@ static void connman_wispr_message_init(struct connman_wispr_message *msg) { DBG(""); - msg->has_error = FALSE; + msg->has_error = false; msg->current_element = NULL; msg->message_type = -1; @@ -115,14 +125,52 @@ static void connman_wispr_message_init(struct connman_wispr_message *msg) msg->location_name = NULL; } -static void free_connman_wispr_portal_context(struct connman_wispr_portal_context *wp_context) +static void free_wispr_routes(struct connman_wispr_portal_context *wp_context) { - DBG(""); + while (wp_context->route_list) { + struct wispr_route *route = wp_context->route_list->data; + + DBG("free route to %s if %d type %d", route->address, + route->if_index, wp_context->type); - if (wp_context == NULL) + switch (wp_context->type) { + case CONNMAN_IPCONFIG_TYPE_IPV4: + connman_inet_del_host_route(route->if_index, + route->address); + break; + case CONNMAN_IPCONFIG_TYPE_IPV6: + connman_inet_del_ipv6_host_route(route->if_index, + route->address); + break; + case CONNMAN_IPCONFIG_TYPE_UNKNOWN: + case CONNMAN_IPCONFIG_TYPE_ALL: + break; + } + + g_free(route->address); + g_free(route); + + wp_context->route_list = + g_slist_delete_link(wp_context->route_list, + wp_context->route_list); + } +} + +static void free_connman_wispr_portal_context( + struct connman_wispr_portal_context *wp_context) +{ + DBG("context %p", wp_context); + + if (!wp_context) return; - connman_service_unref(wp_context->service); + if (wp_context->wispr_portal) { + if (wp_context->wispr_portal->ipv4_context == wp_context) + wp_context->wispr_portal->ipv4_context = NULL; + + if (wp_context->wispr_portal->ipv6_context == wp_context) + wp_context->wispr_portal->ipv6_context = NULL; + } if (wp_context->token > 0) connman_proxy_lookup_cancel(wp_context->token); @@ -130,27 +178,40 @@ static void free_connman_wispr_portal_context(struct connman_wispr_portal_contex if (wp_context->request_id > 0) g_web_cancel_request(wp_context->web, wp_context->request_id); - g_web_unref(wp_context->web); + if (wp_context->timeout > 0) + g_source_remove(wp_context->timeout); + + if (wp_context->web) + g_web_unref(wp_context->web); g_free(wp_context->redirect_url); - g_web_parser_unref(wp_context->wispr_parser); + if (wp_context->wispr_parser) + g_web_parser_unref(wp_context->wispr_parser); + connman_wispr_message_init(&wp_context->wispr_msg); g_free(wp_context->wispr_username); g_free(wp_context->wispr_password); g_free(wp_context->wispr_formdata); + free_wispr_routes(wp_context); + g_free(wp_context); } +static struct connman_wispr_portal_context *create_wispr_portal_context(void) +{ + return g_try_new0(struct connman_wispr_portal_context, 1); +} + static void free_connman_wispr_portal(gpointer data) { struct connman_wispr_portal *wispr_portal = data; DBG(""); - if (wispr_portal == NULL) + if (!wispr_portal) return; free_connman_wispr_portal_context(wispr_portal->ipv4_context); @@ -267,12 +328,11 @@ static void xml_wispr_text_handler(GMarkupParseContext *context, struct connman_wispr_message *msg = user_data; int i; - if (msg->current_element == NULL) + if (!msg->current_element) return; for (i = 0; wispr_element_map[i].str; i++) { - if (g_str_equal(wispr_element_map[i].str, - msg->current_element) == FALSE) + if (!g_str_equal(wispr_element_map[i].str, msg->current_element)) continue; switch (wispr_element_map[i].element) { @@ -321,7 +381,7 @@ static void xml_wispr_error_handler(GMarkupParseContext *context, { struct connman_wispr_message *msg = user_data; - msg->has_error = TRUE; + msg->has_error = true; } static const GMarkupParser xml_wispr_parser_handlers = { @@ -336,7 +396,7 @@ static void xml_wispr_parser_callback(const char *str, gpointer user_data) { struct connman_wispr_portal_context *wp_context = user_data; GMarkupParseContext *parser_context = NULL; - gboolean result; + bool result; DBG(""); @@ -346,8 +406,8 @@ static void xml_wispr_parser_callback(const char *str, gpointer user_data) result = g_markup_parse_context_parse(parser_context, str, strlen(str), NULL); - if (result == TRUE) - result = g_markup_parse_context_end_parse(parser_context, NULL); + if (result) + g_markup_parse_context_end_parse(parser_context, NULL); g_markup_parse_context_free(parser_context); } @@ -362,47 +422,108 @@ static void wispr_portal_error(struct connman_wispr_portal_context *wp_context) DBG("Failed to proceed wispr/portal web request"); wp_context->wispr_result = CONNMAN_WISPR_RESULT_FAILED; + +#if defined TIZEN_EXT + connman_service_set_internet_connection(wp_context->service, false); +#endif } static void portal_manage_status(GWebResult *result, struct connman_wispr_portal_context *wp_context) { + struct connman_service *service = wp_context->service; + enum connman_ipconfig_type type = wp_context->type; const char *str = NULL; DBG(""); /* We currently don't do anything with this info */ if (g_web_result_get_header(result, "X-ConnMan-Client-IP", - &str) == TRUE) + &str)) connman_info("Client-IP: %s", str); if (g_web_result_get_header(result, "X-ConnMan-Client-Country", - &str) == TRUE) + &str)) connman_info("Client-Country: %s", str); if (g_web_result_get_header(result, "X-ConnMan-Client-Region", - &str) == TRUE) + &str)) connman_info("Client-Region: %s", str); - __connman_service_ipconfig_indicate_state(wp_context->service, - CONNMAN_SERVICE_STATE_ONLINE, - wp_context->type); + if (g_web_result_get_header(result, "X-ConnMan-Client-Timezone", + &str)) + connman_info("Client-Timezone: %s", str); + + free_connman_wispr_portal_context(wp_context); + + __connman_service_ipconfig_indicate_state(service, + CONNMAN_SERVICE_STATE_ONLINE, type); } -static void wispr_portal_request_portal(struct connman_wispr_portal_context *wp_context) +static bool wispr_route_request(const char *address, int ai_family, + int if_index, gpointer user_data) +{ + int result = -1; + struct connman_wispr_portal_context *wp_context = user_data; + const char *gateway; + struct wispr_route *route; + + gateway = __connman_ipconfig_get_gateway_from_index(if_index, + wp_context->type); + + DBG("address %s if %d gw %s", address, if_index, gateway); + + if (!gateway) + return false; + + route = g_try_new0(struct wispr_route, 1); + if (route == 0) { + DBG("could not create struct"); + return false; + } + + switch (wp_context->type) { + case CONNMAN_IPCONFIG_TYPE_IPV4: + result = connman_inet_add_host_route(if_index, address, + gateway); + break; + case CONNMAN_IPCONFIG_TYPE_IPV6: + result = connman_inet_add_ipv6_host_route(if_index, address, + gateway); + break; + case CONNMAN_IPCONFIG_TYPE_UNKNOWN: + case CONNMAN_IPCONFIG_TYPE_ALL: + break; + } + + if (result < 0) { + g_free(route); + return false; + } + + route->address = g_strdup(address); + route->if_index = if_index; + wp_context->route_list = g_slist_prepend(wp_context->route_list, route); + + return true; +} + +static void wispr_portal_request_portal( + struct connman_wispr_portal_context *wp_context) { DBG(""); wp_context->request_id = g_web_request_get(wp_context->web, wp_context->status_url, - wispr_portal_web_result, NULL, + wispr_portal_web_result, + wispr_route_request, wp_context); if (wp_context->request_id == 0) wispr_portal_error(wp_context); } -static gboolean wispr_input(const guint8 **data, gsize *length, +static bool wispr_input(const guint8 **data, gsize *length, gpointer user_data) { struct connman_wispr_portal_context *wp_context = user_data; @@ -430,20 +551,74 @@ static gboolean wispr_input(const guint8 **data, gsize *length, *data = (guint8 *) wp_context->wispr_formdata; *length = count; - return FALSE; + return false; +} + +static void wispr_portal_browser_reply_cb(struct connman_service *service, + bool authentication_done, + const char *error, void *user_data) +{ + struct connman_wispr_portal_context *wp_context = user_data; + struct connman_wispr_portal *wispr_portal; + int index; + + DBG(""); + + if (!service || !wp_context) + return; + + /* + * No way to cancel this if wp_context has been freed, so we lookup + * from the service and check that this is still the right context. + */ + index = __connman_service_get_index(service); + if (index < 0) + return; + + wispr_portal = g_hash_table_lookup(wispr_portal_list, + GINT_TO_POINTER(index)); + if (!wispr_portal) + return; + + if (wp_context != wispr_portal->ipv4_context && + wp_context != wispr_portal->ipv6_context) + return; + + if (!authentication_done) { + wispr_portal_error(wp_context); + free_wispr_routes(wp_context); + return; + } + + /* Restarting the test */ + __connman_service_wispr_start(service, wp_context->type); } static void wispr_portal_request_wispr_login(struct connman_service *service, - connman_bool_t success, + bool success, const char *ssid, int ssid_len, const char *username, const char *password, - gboolean wps, const char *wpspin, - void *user_data) + bool wps, const char *wpspin, + const char *error, void *user_data) { struct connman_wispr_portal_context *wp_context = user_data; DBG(""); + if (error) { + if (g_strcmp0(error, + "net.connman.Agent.Error.LaunchBrowser") == 0) { + if (__connman_agent_request_browser(service, + wispr_portal_browser_reply_cb, + wp_context->redirect_url, + wp_context) == -EINPROGRESS) + return; + } + + free_connman_wispr_portal_context(wp_context); + return; + } + g_free(wp_context->wispr_username); wp_context->wispr_username = g_strdup(username); @@ -459,7 +634,7 @@ static void wispr_portal_request_wispr_login(struct connman_service *service, connman_wispr_message_init(&wp_context->wispr_msg); } -static gboolean wispr_manage_message(GWebResult *result, +static bool wispr_manage_message(GWebResult *result, struct connman_wispr_portal_context *wp_context) { DBG("Message type: %s (%d)", @@ -469,21 +644,21 @@ static gboolean wispr_manage_message(GWebResult *result, response_code_to_string(wp_context->wispr_msg.response_code), wp_context->wispr_msg.response_code); - if (wp_context->wispr_msg.access_procedure != NULL) + if (wp_context->wispr_msg.access_procedure) DBG("Access procedure: %s", wp_context->wispr_msg.access_procedure); - if (wp_context->wispr_msg.access_location != NULL) + if (wp_context->wispr_msg.access_location) DBG("Access location: %s", wp_context->wispr_msg.access_location); - if (wp_context->wispr_msg.location_name != NULL) + if (wp_context->wispr_msg.location_name) DBG("Location name: %s", wp_context->wispr_msg.location_name); - if (wp_context->wispr_msg.login_url != NULL) + if (wp_context->wispr_msg.login_url) DBG("Login URL: %s", wp_context->wispr_msg.login_url); - if (wp_context->wispr_msg.abort_login_url != NULL) + if (wp_context->wispr_msg.abort_login_url) DBG("Abort login URL: %s", wp_context->wispr_msg.abort_login_url); - if (wp_context->wispr_msg.logoff_url != NULL) + if (wp_context->wispr_msg.logoff_url) DBG("Logoff URL: %s", wp_context->wispr_msg.logoff_url); switch (wp_context->wispr_msg.message_type) { @@ -494,8 +669,10 @@ static gboolean wispr_manage_message(GWebResult *result, if (__connman_agent_request_login_input(wp_context->service, wispr_portal_request_wispr_login, - wp_context) != -EIO) + wp_context) != -EINPROGRESS) wispr_portal_error(wp_context); + else + return true; break; case 120: /* Falling down */ @@ -514,7 +691,7 @@ static gboolean wispr_manage_message(GWebResult *result, wispr_portal_request_portal(wp_context); - return TRUE; + return true; } else wispr_portal_error(wp_context); @@ -523,28 +700,10 @@ static gboolean wispr_manage_message(GWebResult *result, break; } - return FALSE; -} - -static void wispr_portal_browser_reply_cb(struct connman_service *service, - connman_bool_t authentication_done, - void *user_data) -{ - struct connman_wispr_portal_context *wp_context = user_data; - - if (service == NULL || wp_context == NULL) - return; - - if (authentication_done == FALSE) { - wispr_portal_error(wp_context); - return; - } - - /* Restarting the test */ - __connman_wispr_start(service, wp_context->type); + return false; } -static gboolean wispr_portal_web_result(GWebResult *result, gpointer user_data) +static bool wispr_portal_web_result(GWebResult *result, gpointer user_data) { struct connman_wispr_portal_context *wp_context = user_data; const char *redirect = NULL; @@ -552,25 +711,25 @@ static gboolean wispr_portal_web_result(GWebResult *result, gpointer user_data) const char *str = NULL; guint16 status; gsize length; +#if defined TIZEN_MAINTAIN_ONLINE + static int retried = 0; +#endif DBG(""); - if (wp_context->request_id == 0) - return FALSE; - if (wp_context->wispr_result != CONNMAN_WISPR_RESULT_ONLINE) { g_web_result_get_chunk(result, &chunk, &length); if (length > 0) { g_web_parser_feed_data(wp_context->wispr_parser, chunk, length); - return TRUE; + return true; } g_web_parser_end_data(wp_context->wispr_parser); if (wp_context->wispr_msg.message_type >= 0) { - if (wispr_manage_message(result, wp_context) == TRUE) + if (wispr_manage_message(result, wp_context)) goto done; } } @@ -580,22 +739,33 @@ static gboolean wispr_portal_web_result(GWebResult *result, gpointer user_data) DBG("status: %03u", status); switch (status) { + case 000: + __connman_agent_request_browser(wp_context->service, + wispr_portal_browser_reply_cb, + wp_context->status_url, wp_context); + break; case 200: +#if defined TIZEN_MAINTAIN_ONLINE + retried = 0; +#endif if (wp_context->wispr_msg.message_type >= 0) break; if (g_web_result_get_header(result, "X-ConnMan-Status", - &str) == TRUE) + &str)) { portal_manage_status(result, wp_context); - else + return false; + } else __connman_agent_request_browser(wp_context->service, wispr_portal_browser_reply_cb, wp_context->redirect_url, wp_context); break; case 302: - if (g_web_result_get_header(result, "Location", - &redirect) == FALSE) { + if (!g_web_supports_tls() || + !g_web_result_get_header(result, "Location", + &redirect)) { + __connman_agent_request_browser(wp_context->service, wispr_portal_browser_reply_cb, wp_context->status_url, wp_context); @@ -607,24 +777,47 @@ static gboolean wispr_portal_web_result(GWebResult *result, gpointer user_data) wp_context->redirect_url = g_strdup(redirect); wp_context->request_id = g_web_request_get(wp_context->web, - redirect, wispr_portal_web_result, NULL, - wp_context); + redirect, wispr_portal_web_result, + wispr_route_request, wp_context); goto done; + case 400: case 404: if (__connman_service_online_check_failed(wp_context->service, - wp_context->type) == 0) + wp_context->type) == 0) { +#if defined TIZEN_MAINTAIN_ONLINE + if (wp_context->type == CONNMAN_IPCONFIG_TYPE_IPV4) { + if (retried == 0) { + connman_agent_report_error(wp_context->service, + __connman_service_get_path(wp_context->service), + "internet-unreachable", + NULL, NULL, NULL); + + retried = 1; + } + break; + } +#endif wispr_portal_error(wp_context); + free_connman_wispr_portal_context(wp_context); + return false; + } break; + case 505: + __connman_agent_request_browser(wp_context->service, + wispr_portal_browser_reply_cb, + wp_context->status_url, wp_context); + break; default: break; } + free_wispr_routes(wp_context); wp_context->request_id = 0; done: wp_context->wispr_msg.message_type = -1; - return FALSE; + return false; } static void proxy_callback(const char *proxy, void *user_data) @@ -633,13 +826,18 @@ static void proxy_callback(const char *proxy, void *user_data) DBG("proxy %s", proxy); - wp_context->token = 0; + if (!wp_context) + return; - if (getenv("CONNMAN_WEB_DEBUG")) - g_web_set_debug(wp_context->web, web_debug, "WEB"); + wp_context->token = 0; - if (proxy != NULL && g_strcmp0(proxy, "DIRECT") != 0) + if (proxy && g_strcmp0(proxy, "DIRECT") != 0) { + if (g_str_has_prefix(proxy, "PROXY")) { + proxy += 5; + for (; *proxy == ' ' && *proxy != '\0'; proxy++); + } g_web_set_proxy(wp_context->web, proxy); + } g_web_set_accept(wp_context->web, NULL); g_web_set_user_agent(wp_context->web, "ConnMan/%s wispr", VERSION); @@ -659,6 +857,8 @@ static gboolean no_proxy_callback(gpointer user_data) { struct connman_wispr_portal_context *wp_context = user_data; + wp_context->timeout = 0; + proxy_callback("DIRECT", wp_context); return FALSE; @@ -674,50 +874,61 @@ static int wispr_portal_detect(struct connman_wispr_portal_context *wp_context) int err = 0; int i; - DBG("wispr/portal context %p", wp_context); - DBG("service %p", wp_context->service); + DBG("wispr/portal context %p service %p", wp_context, + wp_context->service); service_type = connman_service_get_type(wp_context->service); switch (service_type) { case CONNMAN_SERVICE_TYPE_ETHERNET: case CONNMAN_SERVICE_TYPE_WIFI: - case CONNMAN_SERVICE_TYPE_WIMAX: case CONNMAN_SERVICE_TYPE_BLUETOOTH: case CONNMAN_SERVICE_TYPE_CELLULAR: + case CONNMAN_SERVICE_TYPE_GADGET: break; case CONNMAN_SERVICE_TYPE_UNKNOWN: case CONNMAN_SERVICE_TYPE_SYSTEM: case CONNMAN_SERVICE_TYPE_GPS: case CONNMAN_SERVICE_TYPE_VPN: - case CONNMAN_SERVICE_TYPE_GADGET: + case CONNMAN_SERVICE_TYPE_P2P: +#if defined TIZEN_EXT_WIFI_MESH + case CONNMAN_SERVICE_TYPE_MESH: +#endif return -EOPNOTSUPP; } interface = connman_service_get_interface(wp_context->service); - if (interface == NULL) + if (!interface) return -EINVAL; DBG("interface %s", interface); if_index = connman_inet_ifindex(interface); if (if_index < 0) { + DBG("Could not get ifindex"); err = -EINVAL; goto done; } nameservers = connman_service_get_nameservers(wp_context->service); - if (nameservers == NULL) { + if (!nameservers) { + DBG("Could not get nameservers"); err = -EINVAL; goto done; } wp_context->web = g_web_new(if_index); - if (wp_context->web == NULL) { + if (!wp_context->web) { + DBG("Could not set up GWeb"); err = -ENOMEM; goto done; } +#if !defined TIZEN_EXT + if (getenv("CONNMAN_WEB_DEBUG")) +#endif + g_web_set_debug(wp_context->web, web_debug, "WEB"); + if (wp_context->type == CONNMAN_IPCONFIG_TYPE_IPV4) { g_web_set_address_family(wp_context->web, AF_INET); wp_context->status_url = STATUS_URL_IPV4; @@ -726,7 +937,7 @@ static int wispr_portal_detect(struct connman_wispr_portal_context *wp_context) wp_context->status_url = STATUS_URL_IPV6; } - for (i = 0; nameservers[i] != NULL; i++) + for (i = 0; nameservers[i]; i++) g_web_add_nameserver(wp_context->web, nameservers[i]); proxy_method = connman_service_get_proxy_method(wp_context->service); @@ -737,10 +948,12 @@ static int wispr_portal_detect(struct connman_wispr_portal_context *wp_context) wp_context->service, proxy_callback, wp_context); - if (wp_context->token == 0) + if (wp_context->token == 0) { err = -EINVAL; - } else { - g_timeout_add_seconds(0, no_proxy_callback, wp_context); + free_connman_wispr_portal_context(wp_context); + } + } else if (wp_context->timeout == 0) { + wp_context->timeout = g_idle_add(no_proxy_callback, wp_context); } done: @@ -759,7 +972,12 @@ int __connman_wispr_start(struct connman_service *service, DBG("service %p", service); - if (wispr_portal_list == NULL) +#if defined TIZEN_EXT + if (connman_service_get_type(service) == CONNMAN_SERVICE_TYPE_CELLULAR) + return -EPERM; +#endif + + if (!wispr_portal_list) return -EINVAL; index = __connman_service_get_index(service); @@ -768,9 +986,9 @@ int __connman_wispr_start(struct connman_service *service, wispr_portal = g_hash_table_lookup(wispr_portal_list, GINT_TO_POINTER(index)); - if (wispr_portal == NULL) { + if (!wispr_portal) { wispr_portal = g_try_new0(struct connman_wispr_portal, 1); - if (wispr_portal == NULL) + if (!wispr_portal) return -ENOMEM; g_hash_table_replace(wispr_portal_list, @@ -785,17 +1003,16 @@ int __connman_wispr_start(struct connman_service *service, return -EINVAL; /* If there is already an existing context, we wipe it */ - if (wp_context != NULL) + if (wp_context) free_connman_wispr_portal_context(wp_context); - wp_context = g_try_new0(struct connman_wispr_portal_context, 1); - if (wp_context == NULL) + wp_context = create_wispr_portal_context(); + if (!wp_context) return -ENOMEM; - connman_service_ref(service); - wp_context->service = service; wp_context->type = type; + wp_context->wispr_portal = wispr_portal; if (type == CONNMAN_IPCONFIG_TYPE_IPV4) wispr_portal->ipv4_context = wp_context; @@ -811,7 +1028,7 @@ void __connman_wispr_stop(struct connman_service *service) DBG("service %p", service); - if (wispr_portal_list == NULL) + if (!wispr_portal_list) return; index = __connman_service_get_index(service);