| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Portal Check - Determines if a user is in an IP restrict pool or behind a | 2 * Portal Check - Determines if a user is in an IP restrict pool or behind a |
| 3 * captive portal. | 3 * captive portal. |
| 4 * | 4 * |
| 5 * This file initially created by Google, Inc. | 5 * This file initially created by Google, Inc. |
| 6 * | 6 * |
| 7 * This program is free software; you can redistribute it and/or modify | 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 | 8 * it under the terms of the GNU General Public License version 2 as |
| 9 * published by the Free Software Foundation. | 9 * published by the Free Software Foundation. |
| 10 * | 10 * |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 80 */ | 80 */ |
| 81 static long get_http_code(CURL *curl_handle) | 81 static long get_http_code(CURL *curl_handle) |
| 82 { | 82 { |
| 83 long http_code = 0; | 83 long http_code = 0; |
| 84 curl_easy_getinfo (curl_handle, CURLINFO_RESPONSE_CODE, &http_code); | 84 curl_easy_getinfo (curl_handle, CURLINFO_RESPONSE_CODE, &http_code); |
| 85 _DBG_PORTAL("http response code is %d", (int) http_code); | 85 _DBG_PORTAL("http response code is %d", (int) http_code); |
| 86 return http_code; | 86 return http_code; |
| 87 } | 87 } |
| 88 | 88 |
| 89 /** | 89 /** |
| 90 * Returns true iff we received an HTTP 204. | 90 * Returns a connectivity state based on the status of an HTTP request |
| 91 * to kGoogle204Url |
| 91 */ | 92 */ |
| 92 static gboolean check_ip_pool(CURLMsg *request_status) | 93 static enum connman_service_connectivity_state check_connectivity_state( |
| 94 » CURLMsg *request_status) |
| 93 { | 95 { |
| 94 » // Check the request state | 96 » CURLcode code = (CURLcode)request_status->data.result; |
| 97 |
| 98 » /* Check the request state */ |
| 95 _DBG_PORTAL("curl code is %d", (int)request_status->data.result); | 99 _DBG_PORTAL("curl code is %d", (int)request_status->data.result); |
| 96 » if (CURLE_OK == (CURLcode)request_status->data.result) { | 100 » if (CURLE_COULDNT_RESOLVE_HOST == code) { |
| 101 » » /* |
| 102 » » * TODO(jglasgow): test resolving the address of the |
| 103 » » * captive portal web server instead |
| 104 » » */ |
| 105 » » _DBG_PORTAL("Cannot resolve %s", kGoogle204Url); |
| 106 » » return CONNMAN_SERVICE_CONNECTIVITY_STATE_NONE; |
| 107 » } |
| 108 |
| 109 » if (CURLE_OK == code) { |
| 97 if (get_http_code(request_status->easy_handle) == 204) { | 110 if (get_http_code(request_status->easy_handle) == 204) { |
| 98 _DBG_PORTAL("The user can route traffic"); | 111 _DBG_PORTAL("The user can route traffic"); |
| 99 » » » return FALSE; | 112 » » » return CONNMAN_SERVICE_CONNECTIVITY_STATE_UNRESTRICTED; |
| 100 } | 113 } |
| 101 } | 114 } |
| 102 _DBG_PORTAL("We're in an IP restrict pool"); | 115 _DBG_PORTAL("We're in an IP restrict pool"); |
| 103 » return TRUE; | 116 » return CONNMAN_SERVICE_CONNECTIVITY_STATE_RESTRICTED; |
| 104 } | 117 } |
| 105 | 118 |
| 106 /** | 119 /** |
| 107 * Calls curl_multi_perform until CURLM_CALL_MULTI_PERFORM is no longer | 120 * Calls curl_multi_perform until CURLM_CALL_MULTI_PERFORM is no longer |
| 108 * returned. | 121 * returned. |
| 109 */ | 122 */ |
| 110 static void handle_multi_perform() | 123 static void handle_multi_perform() |
| 111 { | 124 { |
| 112 » // Multi perform may need to be called multiple times to set | 125 » /* |
| 113 » // the request up successfully. | 126 » * Multi perform may need to be called multiple times to set |
| 127 » * the request up successfully. |
| 128 » */ |
| 114 CURLMcode err; | 129 CURLMcode err; |
| 115 do { | 130 do { |
| 116 err = curl_multi_perform(curl_multi_handle_, | 131 err = curl_multi_perform(curl_multi_handle_, |
| 117 &pending_requests_); | 132 &pending_requests_); |
| 118 _DBG_PORTAL("Calling multi perform"); | 133 _DBG_PORTAL("Calling multi perform"); |
| 119 } while (CURLM_CALL_MULTI_PERFORM == err); | 134 } while (CURLM_CALL_MULTI_PERFORM == err); |
| 120 | 135 |
| 121 if (err != CURLM_OK) { | 136 if (err != CURLM_OK) { |
| 122 connman_error("%s: curl_multi_perform() = %s", __func__, | 137 connman_error("%s: curl_multi_perform() = %s", __func__, |
| 123 curl_multi_strerror(err)); | 138 curl_multi_strerror(err)); |
| 124 } | 139 } |
| 125 } | 140 } |
| 126 | 141 |
| 127 /** | 142 /** |
| 128 * Processes all currently queued libcurl requests. | 143 * Processes all currently queued libcurl requests. |
| 129 * | 144 * |
| 130 * Returns TRUE if there are pending requests. Returning true re-arms | 145 * Returns TRUE if there are pending requests. Returning true re-arms |
| 131 * the timer and causes this function to be called again. | 146 * the timer and causes this function to be called again. |
| 132 */ | 147 */ |
| 133 static gboolean pending_request_callback(gpointer data) | 148 static gboolean pending_request_callback(gpointer data) |
| 134 { | 149 { |
| 135 int remaining_updates; | 150 int remaining_updates; |
| 136 CURLMsg* request_status; | 151 CURLMsg* request_status; |
| 152 struct portal_request *portal_request = NULL; |
| 153 struct connman_service *service; |
| 137 | 154 |
| 138 _DBG_PORTAL("callback fired, %d jobs remain", pending_requests_); | 155 _DBG_PORTAL("callback fired, %d jobs remain", pending_requests_); |
| 139 | 156 |
| 140 handle_multi_perform(); | 157 handle_multi_perform(); |
| 141 | 158 |
| 142 request_status = | 159 request_status = |
| 143 curl_multi_info_read(curl_multi_handle_, &remaining_updates); | 160 curl_multi_info_read(curl_multi_handle_, &remaining_updates); |
| 144 | 161 |
| 145 » if (request_status != NULL && CURLMSG_DONE == request_status->msg) { | 162 » if (request_status == NULL || CURLMSG_DONE != request_status->msg) { |
| 146 » » struct portal_request *portal_request = NULL; | 163 » » _DBG_PORTAL("remaining status is %d", remaining_updates); |
| 147 » » struct connman_service *service; | 164 » » return TRUE; |
| 165 » } |
| 148 | 166 |
| 149 curl_easy_getinfo(request_status->easy_handle, CURLINFO_PRIVATE, | |
| 150 (char **)&portal_request); | |
| 151 service = portal_request->service; | |
| 152 | 167 |
| 153 » » _DBG_PORTAL("service = %s", | 168 » curl_easy_getinfo(request_status->easy_handle, CURLINFO_PRIVATE, |
| 154 » » » connman_service_get_identifier(service)); | 169 » » » (char **)&portal_request); |
| 170 » service = portal_request->service; |
| 155 | 171 |
| 156 » » if (portal_request == latest_request) { | 172 » _DBG_PORTAL("service = %s", connman_service_get_identifier(service)); |
| 157 » » » gboolean restricted = check_ip_pool(request_status); | |
| 158 | 173 |
| 159 » » » connman_service_set_restricted_pool(service, restricted)
; | 174 » if (portal_request == latest_request) { |
| 160 » » } else { | 175 » » enum connman_service_connectivity_state state = |
| 161 » » » _DBG_PORTAL("Ignoring stale results"); | 176 » » » check_connectivity_state(request_status); |
| 162 » » } | 177 |
| 163 » » curl_multi_remove_handle(curl_multi_handle_, | 178 » » connman_service_set_connectivity_state(service, state); |
| 164 » » » » » request_status->easy_handle); | 179 |
| 165 » » free_request(portal_request); | 180 » } else { |
| 166 » » _DBG_PORTAL("Cancelling the timer"); | 181 » » _DBG_PORTAL("Ignoring stale results"); |
| 167 » » return FALSE; | |
| 168 } | 182 } |
| 169 » _DBG_PORTAL("remaining status is %d", remaining_updates); | 183 » curl_multi_remove_handle(curl_multi_handle_, |
| 170 » return TRUE; | 184 » » » » request_status->easy_handle); |
| 185 » free_request(portal_request); |
| 186 » _DBG_PORTAL("Cancelling the timer"); |
| 187 » return FALSE; |
| 171 } | 188 } |
| 172 | 189 |
| 173 /** | 190 /** |
| 174 * Returns TRUE if the new default route is connected via cellular. | 191 * Returns TRUE if the new default route is connected via cellular. |
| 175 */ | 192 */ |
| 176 static gboolean should_process_request(struct connman_service *service) { | 193 static gboolean should_process_request(struct connman_service *service) { |
| 177 if (service == NULL) { | 194 if (service == NULL) { |
| 178 _DBG_PORTAL("Skipping portal check for NULL service"); | 195 _DBG_PORTAL("Skipping portal check for NULL service"); |
| 179 return FALSE; | 196 return FALSE; |
| 180 } | 197 } |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 276 } | 293 } |
| 277 | 294 |
| 278 mcode = curl_multi_add_handle(curl_multi_handle_, request_handle); | 295 mcode = curl_multi_add_handle(curl_multi_handle_, request_handle); |
| 279 if (mcode != CURLM_OK) { | 296 if (mcode != CURLM_OK) { |
| 280 connman_error("%s: curl_multi_add_handle() = %s", __func__, | 297 connman_error("%s: curl_multi_add_handle() = %s", __func__, |
| 281 curl_multi_strerror(mcode)); | 298 curl_multi_strerror(mcode)); |
| 282 goto error; | 299 goto error; |
| 283 } | 300 } |
| 284 handle_multi_perform(); | 301 handle_multi_perform(); |
| 285 | 302 |
| 286 » // The timer will fire once per second until the request | 303 » /* |
| 287 » // has been processed. | 304 » * The timer will fire once per second until the request |
| 288 » // | 305 » * has been processed. |
| 289 » // TODO(rtc): Consider using fd_sets instead. | 306 » * |
| 307 » * TODO(rtc): Consider using fd_sets instead. |
| 308 » */ |
| 290 g_timeout_add_seconds(1, pending_request_callback, NULL); | 309 g_timeout_add_seconds(1, pending_request_callback, NULL); |
| 291 return; | 310 return; |
| 292 | 311 |
| 293 error: | 312 error: |
| 294 free_request(portal_request); | 313 free_request(portal_request); |
| 295 } | 314 } |
| 296 | 315 |
| 297 /** | 316 /** |
| 298 * If the service transitions to not ready clear the restricted IP | 317 * If the service transitions to not ready clear the restricted IP |
| 299 * pool flag. | 318 * pool flag. |
| 300 */ | 319 */ |
| 301 void portal_service_state_changed(struct connman_service *service) | 320 void portal_service_state_changed(struct connman_service *service) |
| 302 { | 321 { |
| 303 const char *service_type = connman_service_get_type(service); | 322 const char *service_type = connman_service_get_type(service); |
| 304 const char *service_state = connman_service_get_state(service); | 323 const char *service_state = connman_service_get_state(service); |
| 305 | 324 |
| 306 if (g_strcmp0(service_type, "cellular") != 0) { | 325 if (g_strcmp0(service_type, "cellular") != 0) { |
| 307 return; | 326 return; |
| 308 } | 327 } |
| 309 | 328 |
| 310 if (g_strcmp0(service_state, "ready") != 0) { | 329 if (g_strcmp0(service_state, "ready") != 0) { |
| 311 » » _DBG_PORTAL("%s: Clearing restricted pool flag, not ready", | 330 » » _DBG_PORTAL("%s: Setting connectivity state unknown, not ready", |
| 312 connman_service_get_identifier(service)); | 331 connman_service_get_identifier(service)); |
| 313 » » connman_service_set_restricted_pool(service, FALSE); | 332 » » connman_service_set_connectivity_state(service, |
| 333 » » » CONNMAN_SERVICE_CONNECTIVITY_STATE_UNKNOWN); |
| 314 } | 334 } |
| 315 } | 335 } |
| 316 | 336 |
| 317 static struct connman_notifier portal_notifier = { | 337 static struct connman_notifier portal_notifier = { |
| 318 .name = "portal", | 338 .name = "portal", |
| 319 .priority = CONNMAN_NOTIFIER_PRIORITY_LOW, | 339 .priority = CONNMAN_NOTIFIER_PRIORITY_LOW, |
| 320 .default_changed = portal_default_changed, | 340 .default_changed = portal_default_changed, |
| 321 .service_state_changed = portal_service_state_changed, | 341 .service_state_changed = portal_service_state_changed, |
| 322 }; | 342 }; |
| 323 | 343 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 339 } | 359 } |
| 340 | 360 |
| 341 static void portal_finis(void) | 361 static void portal_finis(void) |
| 342 { | 362 { |
| 343 connman_notifier_unregister(&portal_notifier); | 363 connman_notifier_unregister(&portal_notifier); |
| 344 curl_multi_cleanup(curl_multi_handle_); | 364 curl_multi_cleanup(curl_multi_handle_); |
| 345 } | 365 } |
| 346 | 366 |
| 347 CONNMAN_PLUGIN_DEFINE(portal_check, "Chrome OS metrics plugin", VERSION, | 367 CONNMAN_PLUGIN_DEFINE(portal_check, "Chrome OS metrics plugin", VERSION, |
| 348 CONNMAN_PLUGIN_PRIORITY_DEFAULT, portal_init, portal_finis) | 368 CONNMAN_PLUGIN_PRIORITY_DEFAULT, portal_init, portal_finis) |
| OLD | NEW |