diff options
Diffstat (limited to 'src/nm-connectivity.c')
| -rw-r--r-- | src/nm-connectivity.c | 1954 |
1 files changed, 967 insertions, 987 deletions
diff --git a/src/nm-connectivity.c b/src/nm-connectivity.c index 2d80fd90..3cd1d4b8 100644 --- a/src/nm-connectivity.c +++ b/src/nm-connectivity.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (C) 2011 Thomas Bechtold <thomasbechtold@jpberlin.de> * Copyright (C) 2011 Dan Williams <dcbw@redhat.com> @@ -10,7 +10,7 @@ #include "nm-connectivity.h" #if WITH_CONCHECK -#include <curl/curl.h> + #include <curl/curl.h> #endif #include <linux/rtnetlink.h> #include <glib-unix.h> @@ -26,245 +26,242 @@ /*****************************************************************************/ -static -NM_UTILS_LOOKUP_STR_DEFINE (_state_to_string, int /*NMConnectivityState*/, - NM_UTILS_LOOKUP_DEFAULT_WARN ("???"), - NM_UTILS_LOOKUP_STR_ITEM (NM_CONNECTIVITY_UNKNOWN, "UNKNOWN"), - NM_UTILS_LOOKUP_STR_ITEM (NM_CONNECTIVITY_NONE, "NONE"), - NM_UTILS_LOOKUP_STR_ITEM (NM_CONNECTIVITY_LIMITED, "LIMITED"), - NM_UTILS_LOOKUP_STR_ITEM (NM_CONNECTIVITY_PORTAL, "PORTAL"), - NM_UTILS_LOOKUP_STR_ITEM (NM_CONNECTIVITY_FULL, "FULL"), - - NM_UTILS_LOOKUP_STR_ITEM (NM_CONNECTIVITY_ERROR, "ERROR"), - NM_UTILS_LOOKUP_STR_ITEM (NM_CONNECTIVITY_FAKE, "FAKE"), - NM_UTILS_LOOKUP_STR_ITEM (NM_CONNECTIVITY_CANCELLED, "CANCELLED"), - NM_UTILS_LOOKUP_STR_ITEM (NM_CONNECTIVITY_DISPOSING, "DISPOSING"), -); +static NM_UTILS_LOOKUP_STR_DEFINE(_state_to_string, + int /*NMConnectivityState*/, + NM_UTILS_LOOKUP_DEFAULT_WARN("???"), + NM_UTILS_LOOKUP_STR_ITEM(NM_CONNECTIVITY_UNKNOWN, "UNKNOWN"), + NM_UTILS_LOOKUP_STR_ITEM(NM_CONNECTIVITY_NONE, "NONE"), + NM_UTILS_LOOKUP_STR_ITEM(NM_CONNECTIVITY_LIMITED, "LIMITED"), + NM_UTILS_LOOKUP_STR_ITEM(NM_CONNECTIVITY_PORTAL, "PORTAL"), + NM_UTILS_LOOKUP_STR_ITEM(NM_CONNECTIVITY_FULL, "FULL"), + + NM_UTILS_LOOKUP_STR_ITEM(NM_CONNECTIVITY_ERROR, "ERROR"), + NM_UTILS_LOOKUP_STR_ITEM(NM_CONNECTIVITY_FAKE, "FAKE"), + NM_UTILS_LOOKUP_STR_ITEM(NM_CONNECTIVITY_CANCELLED, "CANCELLED"), + NM_UTILS_LOOKUP_STR_ITEM(NM_CONNECTIVITY_DISPOSING, + "DISPOSING"), ); const char * -nm_connectivity_state_to_string (NMConnectivityState state) +nm_connectivity_state_to_string(NMConnectivityState state) { - return _state_to_string (state); + return _state_to_string(state); } /*****************************************************************************/ typedef struct { - guint ref_count; - char *uri; - char *host; - char *port; - char *response; + guint ref_count; + char *uri; + char *host; + char *port; + char *response; } ConConfig; struct _NMConnectivityCheckHandle { - CList handles_lst; - NMConnectivity *self; - NMConnectivityCheckCallback callback; - gpointer user_data; + CList handles_lst; + NMConnectivity * self; + NMConnectivityCheckCallback callback; + gpointer user_data; - char *ifspec; + char *ifspec; - const char *completed_log_message; - char *completed_log_message_free; + const char *completed_log_message; + char * completed_log_message_free; #if WITH_CONCHECK - struct { - ConConfig *con_config; + struct { + ConConfig *con_config; - GCancellable *resolve_cancellable; - CURLM *curl_mhandle; - CURL *curl_ehandle; - struct curl_slist *request_headers; - struct curl_slist *hosts; + GCancellable * resolve_cancellable; + CURLM * curl_mhandle; + CURL * curl_ehandle; + struct curl_slist *request_headers; + struct curl_slist *hosts; - gsize response_good_cnt; + gsize response_good_cnt; - guint curl_timer; - int ch_ifindex; - } concheck; + guint curl_timer; + int ch_ifindex; + } concheck; #endif - guint64 request_counter; + guint64 request_counter; - int addr_family; + int addr_family; - guint timeout_id; + guint timeout_id; - NMConnectivityState completed_state; - const char *completed_reason; + NMConnectivityState completed_state; + const char * completed_reason; }; enum { - CONFIG_CHANGED, + CONFIG_CHANGED, - LAST_SIGNAL + LAST_SIGNAL }; -static guint signals[LAST_SIGNAL] = { 0 }; +static guint signals[LAST_SIGNAL] = {0}; typedef struct { - CList handles_lst_head; - CList completed_handles_lst_head; - NMConfig *config; - ConConfig *con_config; - guint interval; - - bool enabled:1; - bool uri_valid:1; + CList handles_lst_head; + CList completed_handles_lst_head; + NMConfig * config; + ConConfig *con_config; + guint interval; + + bool enabled : 1; + bool uri_valid : 1; } NMConnectivityPrivate; struct _NMConnectivity { - GObject parent; - NMConnectivityPrivate _priv; + GObject parent; + NMConnectivityPrivate _priv; }; struct _NMConnectivityClass { - GObjectClass parent; + GObjectClass parent; }; -G_DEFINE_TYPE (NMConnectivity, nm_connectivity, G_TYPE_OBJECT) +G_DEFINE_TYPE(NMConnectivity, nm_connectivity, G_TYPE_OBJECT) -#define NM_CONNECTIVITY_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMConnectivity, NM_IS_CONNECTIVITY) +#define NM_CONNECTIVITY_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMConnectivity, NM_IS_CONNECTIVITY) -NM_DEFINE_SINGLETON_GETTER (NMConnectivity, nm_connectivity_get, NM_TYPE_CONNECTIVITY); +NM_DEFINE_SINGLETON_GETTER(NMConnectivity, nm_connectivity_get, NM_TYPE_CONNECTIVITY); /*****************************************************************************/ #define _NMLOG_DOMAIN LOGD_CONCHECK -#define _NMLOG(level, ...) __NMLOG_DEFAULT (level, _NMLOG_DOMAIN, "connectivity", __VA_ARGS__) - -#define _NMLOG2_DOMAIN LOGD_CONCHECK -#define _NMLOG2(level, ...) \ - G_STMT_START { \ - const NMLogLevel __level = (level); \ - \ - if (nm_logging_enabled (__level, _NMLOG2_DOMAIN)) { \ - _nm_log (__level, _NMLOG2_DOMAIN, 0, \ - (cb_data->ifspec ? &cb_data->ifspec[3] : NULL), \ - NULL, \ - "connectivity: (%s,IPv%c,%"G_GUINT64_FORMAT") " \ - _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ - (cb_data->ifspec ? &cb_data->ifspec[3] : ""), \ - nm_utils_addr_family_to_char (cb_data->addr_family), \ - cb_data->request_counter \ - _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ - } \ - } G_STMT_END +#define _NMLOG(level, ...) __NMLOG_DEFAULT(level, _NMLOG_DOMAIN, "connectivity", __VA_ARGS__) + +#define _NMLOG2_DOMAIN LOGD_CONCHECK +#define _NMLOG2(level, ...) \ + G_STMT_START \ + { \ + const NMLogLevel __level = (level); \ + \ + if (nm_logging_enabled(__level, _NMLOG2_DOMAIN)) { \ + _nm_log(__level, \ + _NMLOG2_DOMAIN, \ + 0, \ + (cb_data->ifspec ? &cb_data->ifspec[3] : NULL), \ + NULL, \ + "connectivity: (%s,IPv%c,%" G_GUINT64_FORMAT \ + ") " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + (cb_data->ifspec ? &cb_data->ifspec[3] : ""), \ + nm_utils_addr_family_to_char(cb_data->addr_family), \ + cb_data->request_counter _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ + } \ + G_STMT_END /*****************************************************************************/ #if WITH_CONCHECK static ConConfig * -_con_config_ref (ConConfig *con_config) +_con_config_ref(ConConfig *con_config) { - if (con_config) { - nm_assert (con_config->ref_count > 0); - ++con_config->ref_count; - } - return con_config; + if (con_config) { + nm_assert(con_config->ref_count > 0); + ++con_config->ref_count; + } + return con_config; } #endif static void -_con_config_unref (ConConfig *con_config) +_con_config_unref(ConConfig *con_config) { - if (!con_config) - return; + if (!con_config) + return; - nm_assert (con_config->ref_count > 0); + nm_assert(con_config->ref_count > 0); - if (--con_config->ref_count != 0) - return; + if (--con_config->ref_count != 0) + return; - g_free (con_config->uri); - g_free (con_config->host); - g_free (con_config->port); - g_free (con_config->response); - g_slice_free (ConConfig, con_config); + g_free(con_config->uri); + g_free(con_config->host); + g_free(con_config->port); + g_free(con_config->response); + g_slice_free(ConConfig, con_config); } #if WITH_CONCHECK static const char * -_con_config_get_response (const ConConfig *con_config) +_con_config_get_response(const ConConfig *con_config) { - return con_config->response ?: NM_CONFIG_DEFAULT_CONNECTIVITY_RESPONSE; + return con_config->response ?: NM_CONFIG_DEFAULT_CONNECTIVITY_RESPONSE; } #endif /*****************************************************************************/ static void -cb_data_complete (NMConnectivityCheckHandle *cb_data, - NMConnectivityState state, - const char *log_message) +cb_data_complete(NMConnectivityCheckHandle *cb_data, + NMConnectivityState state, + const char * log_message) { - NMConnectivity *self; + NMConnectivity *self; - nm_assert (cb_data); - nm_assert (NM_IS_CONNECTIVITY (cb_data->self)); - nm_assert (cb_data->callback); - nm_assert (state != NM_CONNECTIVITY_UNKNOWN); - nm_assert (log_message); + nm_assert(cb_data); + nm_assert(NM_IS_CONNECTIVITY(cb_data->self)); + nm_assert(cb_data->callback); + nm_assert(state != NM_CONNECTIVITY_UNKNOWN); + nm_assert(log_message); - self = cb_data->self; + self = cb_data->self; - /* mark the handle as completing. After this point, nm_connectivity_check_cancel() - * is no longer possible. */ - cb_data->self = NULL; + /* mark the handle as completing. After this point, nm_connectivity_check_cancel() + * is no longer possible. */ + cb_data->self = NULL; - c_list_unlink_stale (&cb_data->handles_lst); + c_list_unlink_stale(&cb_data->handles_lst); #if WITH_CONCHECK - if (cb_data->concheck.curl_ehandle) { - /* Contrary to what cURL manual claim it is *not* safe to remove - * the easy handle "at any moment"; specifically it's not safe to - * remove *any* handle from within a libcurl callback. That is - * why we queue completed handles in this case. - * - * cb_data_complete() is however only called *not* from within a - * libcurl callback. So, this is fine. */ - curl_easy_setopt (cb_data->concheck.curl_ehandle, CURLOPT_WRITEFUNCTION, NULL); - curl_easy_setopt (cb_data->concheck.curl_ehandle, CURLOPT_WRITEDATA, NULL); - curl_easy_setopt (cb_data->concheck.curl_ehandle, CURLOPT_HEADERFUNCTION, NULL); - curl_easy_setopt (cb_data->concheck.curl_ehandle, CURLOPT_HEADERDATA, NULL); - curl_easy_setopt (cb_data->concheck.curl_ehandle, CURLOPT_PRIVATE, NULL); - curl_easy_setopt (cb_data->concheck.curl_ehandle, CURLOPT_HTTPHEADER, NULL); - - curl_multi_remove_handle (cb_data->concheck.curl_mhandle, - cb_data->concheck.curl_ehandle); - curl_easy_cleanup (cb_data->concheck.curl_ehandle); - curl_multi_cleanup (cb_data->concheck.curl_mhandle); - - curl_slist_free_all (cb_data->concheck.request_headers); - curl_slist_free_all (cb_data->concheck.hosts); - } - nm_clear_g_source (&cb_data->concheck.curl_timer); - nm_clear_g_cancellable (&cb_data->concheck.resolve_cancellable); + if (cb_data->concheck.curl_ehandle) { + /* Contrary to what cURL manual claim it is *not* safe to remove + * the easy handle "at any moment"; specifically it's not safe to + * remove *any* handle from within a libcurl callback. That is + * why we queue completed handles in this case. + * + * cb_data_complete() is however only called *not* from within a + * libcurl callback. So, this is fine. */ + curl_easy_setopt(cb_data->concheck.curl_ehandle, CURLOPT_WRITEFUNCTION, NULL); + curl_easy_setopt(cb_data->concheck.curl_ehandle, CURLOPT_WRITEDATA, NULL); + curl_easy_setopt(cb_data->concheck.curl_ehandle, CURLOPT_HEADERFUNCTION, NULL); + curl_easy_setopt(cb_data->concheck.curl_ehandle, CURLOPT_HEADERDATA, NULL); + curl_easy_setopt(cb_data->concheck.curl_ehandle, CURLOPT_PRIVATE, NULL); + curl_easy_setopt(cb_data->concheck.curl_ehandle, CURLOPT_HTTPHEADER, NULL); + + curl_multi_remove_handle(cb_data->concheck.curl_mhandle, cb_data->concheck.curl_ehandle); + curl_easy_cleanup(cb_data->concheck.curl_ehandle); + curl_multi_cleanup(cb_data->concheck.curl_mhandle); + + curl_slist_free_all(cb_data->concheck.request_headers); + curl_slist_free_all(cb_data->concheck.hosts); + } + nm_clear_g_source(&cb_data->concheck.curl_timer); + nm_clear_g_cancellable(&cb_data->concheck.resolve_cancellable); #endif - nm_clear_g_source (&cb_data->timeout_id); + nm_clear_g_source(&cb_data->timeout_id); - _LOG2D ("check completed: %s; %s", - nm_connectivity_state_to_string (state), - log_message); + _LOG2D("check completed: %s; %s", nm_connectivity_state_to_string(state), log_message); - cb_data->callback (self, - cb_data, - state, - cb_data->user_data); + cb_data->callback(self, cb_data, state, cb_data->user_data); - /* Note: self might be a danling pointer at this point. It must not be used - * after this point, and all callers must either take a reference first, or - * not use the self pointer too. */ + /* Note: self might be a danling pointer at this point. It must not be used + * after this point, and all callers must either take a reference first, or + * not use the self pointer too. */ #if WITH_CONCHECK - _con_config_unref (cb_data->concheck.con_config); + _con_config_unref(cb_data->concheck.con_config); #endif - g_free (cb_data->ifspec); - if (cb_data->completed_log_message_free) - g_free (cb_data->completed_log_message_free); - g_slice_free (NMConnectivityCheckHandle, cb_data); + g_free(cb_data->ifspec); + if (cb_data->completed_log_message_free) + g_free(cb_data->completed_log_message_free); + g_slice_free(NMConnectivityCheckHandle, cb_data); } /*****************************************************************************/ @@ -272,978 +269,961 @@ cb_data_complete (NMConnectivityCheckHandle *cb_data, #if WITH_CONCHECK static void -cb_data_queue_completed (NMConnectivityCheckHandle *cb_data, - NMConnectivityState state, - const char *log_message_static, - char *log_message_take /* take */) +cb_data_queue_completed(NMConnectivityCheckHandle *cb_data, + NMConnectivityState state, + const char * log_message_static, + char * log_message_take /* take */) { - nm_assert (cb_data); - nm_assert (NM_IS_CONNECTIVITY (cb_data->self)); - nm_assert (state != NM_CONNECTIVITY_UNKNOWN); - nm_assert (log_message_static || log_message_take); - nm_assert (cb_data->completed_state == NM_CONNECTIVITY_UNKNOWN); - nm_assert (!cb_data->completed_log_message); - nm_assert (c_list_contains (&NM_CONNECTIVITY_GET_PRIVATE (cb_data->self)->handles_lst_head, &cb_data->handles_lst)); - - cb_data->completed_state = state; - cb_data->completed_log_message = log_message_static ?: log_message_take; - cb_data->completed_log_message_free = log_message_take; - - c_list_unlink_stale (&cb_data->handles_lst); - c_list_link_tail (&NM_CONNECTIVITY_GET_PRIVATE (cb_data->self)->completed_handles_lst_head, &cb_data->handles_lst); + nm_assert(cb_data); + nm_assert(NM_IS_CONNECTIVITY(cb_data->self)); + nm_assert(state != NM_CONNECTIVITY_UNKNOWN); + nm_assert(log_message_static || log_message_take); + nm_assert(cb_data->completed_state == NM_CONNECTIVITY_UNKNOWN); + nm_assert(!cb_data->completed_log_message); + nm_assert(c_list_contains(&NM_CONNECTIVITY_GET_PRIVATE(cb_data->self)->handles_lst_head, + &cb_data->handles_lst)); + + cb_data->completed_state = state; + cb_data->completed_log_message = log_message_static ?: log_message_take; + cb_data->completed_log_message_free = log_message_take; + + c_list_unlink_stale(&cb_data->handles_lst); + c_list_link_tail(&NM_CONNECTIVITY_GET_PRIVATE(cb_data->self)->completed_handles_lst_head, + &cb_data->handles_lst); } static void -_complete_queued (NMConnectivity *self) +_complete_queued(NMConnectivity *self) { - NMConnectivity *self_keep_alive = NULL; - NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self); - NMConnectivityCheckHandle *cb_data; - - while ((cb_data = c_list_first_entry (&priv->completed_handles_lst_head, NMConnectivityCheckHandle, handles_lst))) { - if (!self_keep_alive) - self_keep_alive = g_object_ref (self); - cb_data_complete (cb_data, - cb_data->completed_state, - cb_data->completed_log_message); - } - nm_g_object_unref (self_keep_alive); + NMConnectivity * self_keep_alive = NULL; + NMConnectivityPrivate * priv = NM_CONNECTIVITY_GET_PRIVATE(self); + NMConnectivityCheckHandle *cb_data; + + while ((cb_data = c_list_first_entry(&priv->completed_handles_lst_head, + NMConnectivityCheckHandle, + handles_lst))) { + if (!self_keep_alive) + self_keep_alive = g_object_ref(self); + cb_data_complete(cb_data, cb_data->completed_state, cb_data->completed_log_message); + } + nm_g_object_unref(self_keep_alive); } static gboolean -_con_curl_check_connectivity (CURLM *mhandle, int sockfd, int ev_bitmask) +_con_curl_check_connectivity(CURLM *mhandle, int sockfd, int ev_bitmask) { - NMConnectivityCheckHandle *cb_data; - CURLMsg *msg; - int m_left; - long response_code; - CURLMcode ret; - int running_handles; - gboolean success = TRUE; - - ret = curl_multi_socket_action (mhandle, sockfd, ev_bitmask, &running_handles); - if (ret != CURLM_OK) { - _LOGD ("connectivity check failed: (%d) %s", ret, curl_multi_strerror (ret)); - success = FALSE; - } - - while ((msg = curl_multi_info_read (mhandle, &m_left))) { - const char *response; - CURLcode eret; - - if (msg->msg != CURLMSG_DONE) - continue; - - /* Here we have completed a session. Check easy session result. */ - eret = curl_easy_getinfo (msg->easy_handle, CURLINFO_PRIVATE, (char **) &cb_data); - if (eret != CURLE_OK) { - _LOGD ("curl cannot extract cb_data for easy handle, skipping msg: (%d) %s", - eret, curl_easy_strerror (eret)); - success = FALSE; - continue; - } - - nm_assert (cb_data); - nm_assert (NM_IS_CONNECTIVITY (cb_data->self)); - - if (cb_data->completed_state != NM_CONNECTIVITY_UNKNOWN) { - /* callback was already invoked earlier. Nothing to do. */ - continue; - } - - if (msg->data.result != CURLE_OK) { - cb_data_queue_completed (cb_data, - NM_CONNECTIVITY_LIMITED, - NULL, - g_strdup_printf ("check failed: (%d) %s", - msg->data.result, - curl_easy_strerror (msg->data.result))); - continue; - } - - response = _con_config_get_response (cb_data->concheck.con_config); - - if ( response[0] == '\0' - && (curl_easy_getinfo (msg->easy_handle, CURLINFO_RESPONSE_CODE, &response_code) == CURLE_OK)) { - - if (response_code == 204) { - /* We expected an empty response, and we got a 204 response code (no content). - * We may or may not have received any content (we would ignore it). - * Anyway, the response_code 204 means we are good. */ - cb_data_queue_completed (cb_data, - NM_CONNECTIVITY_FULL, - "no content, as expected", - NULL); - continue; - } - - if ( response_code == 200 - && cb_data->concheck.response_good_cnt == 0) { - /* we expected no response, and indeed we got an empty reply (with status code 200) */ - cb_data_queue_completed (cb_data, - NM_CONNECTIVITY_FULL, - "empty response, as expected", - NULL); - continue; - } - } - - /* If we get here, it means that easy_write_cb() didn't read enough - * bytes to be able to do a match, or that we were asking for no content - * (204 response code) and we actually got some. Either way, that is - * an indication of a captive portal */ - cb_data_queue_completed (cb_data, - NM_CONNECTIVITY_PORTAL, - "unexpected short response", - NULL); - } - - /* if we return a failure, we don't know what went wrong. It's likely serious, because - * a failure here is not expected. Return FALSE, so that we stop polling the file descriptor. - * Worst case, this leaves the pending connectivity check unhandled, until our regular - * time-out kicks in. */ - return success; + NMConnectivityCheckHandle *cb_data; + CURLMsg * msg; + int m_left; + long response_code; + CURLMcode ret; + int running_handles; + gboolean success = TRUE; + + ret = curl_multi_socket_action(mhandle, sockfd, ev_bitmask, &running_handles); + if (ret != CURLM_OK) { + _LOGD("connectivity check failed: (%d) %s", ret, curl_multi_strerror(ret)); + success = FALSE; + } + + while ((msg = curl_multi_info_read(mhandle, &m_left))) { + const char *response; + CURLcode eret; + + if (msg->msg != CURLMSG_DONE) + continue; + + /* Here we have completed a session. Check easy session result. */ + eret = curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, (char **) &cb_data); + if (eret != CURLE_OK) { + _LOGD("curl cannot extract cb_data for easy handle, skipping msg: (%d) %s", + eret, + curl_easy_strerror(eret)); + success = FALSE; + continue; + } + + nm_assert(cb_data); + nm_assert(NM_IS_CONNECTIVITY(cb_data->self)); + + if (cb_data->completed_state != NM_CONNECTIVITY_UNKNOWN) { + /* callback was already invoked earlier. Nothing to do. */ + continue; + } + + if (msg->data.result != CURLE_OK) { + cb_data_queue_completed(cb_data, + NM_CONNECTIVITY_LIMITED, + NULL, + g_strdup_printf("check failed: (%d) %s", + msg->data.result, + curl_easy_strerror(msg->data.result))); + continue; + } + + response = _con_config_get_response(cb_data->concheck.con_config); + + if (response[0] == '\0' + && (curl_easy_getinfo(msg->easy_handle, CURLINFO_RESPONSE_CODE, &response_code) + == CURLE_OK)) { + if (response_code == 204) { + /* We expected an empty response, and we got a 204 response code (no content). + * We may or may not have received any content (we would ignore it). + * Anyway, the response_code 204 means we are good. */ + cb_data_queue_completed(cb_data, + NM_CONNECTIVITY_FULL, + "no content, as expected", + NULL); + continue; + } + + if (response_code == 200 && cb_data->concheck.response_good_cnt == 0) { + /* we expected no response, and indeed we got an empty reply (with status code 200) */ + cb_data_queue_completed(cb_data, + NM_CONNECTIVITY_FULL, + "empty response, as expected", + NULL); + continue; + } + } + + /* If we get here, it means that easy_write_cb() didn't read enough + * bytes to be able to do a match, or that we were asking for no content + * (204 response code) and we actually got some. Either way, that is + * an indication of a captive portal */ + cb_data_queue_completed(cb_data, NM_CONNECTIVITY_PORTAL, "unexpected short response", NULL); + } + + /* if we return a failure, we don't know what went wrong. It's likely serious, because + * a failure here is not expected. Return FALSE, so that we stop polling the file descriptor. + * Worst case, this leaves the pending connectivity check unhandled, until our regular + * time-out kicks in. */ + return success; } static gboolean -_con_curl_timeout_cb (gpointer user_data) +_con_curl_timeout_cb(gpointer user_data) { - NMConnectivityCheckHandle *cb_data = user_data; + NMConnectivityCheckHandle *cb_data = user_data; - _con_curl_check_connectivity (cb_data->concheck.curl_mhandle, CURL_SOCKET_TIMEOUT, 0); - _complete_queued (cb_data->self); - return G_SOURCE_CONTINUE; + _con_curl_check_connectivity(cb_data->concheck.curl_mhandle, CURL_SOCKET_TIMEOUT, 0); + _complete_queued(cb_data->self); + return G_SOURCE_CONTINUE; } static int -multi_timer_cb (CURLM *multi, long timeout_msec, void *userdata) +multi_timer_cb(CURLM *multi, long timeout_msec, void *userdata) { - NMConnectivityCheckHandle *cb_data = userdata; + NMConnectivityCheckHandle *cb_data = userdata; - nm_clear_g_source (&cb_data->concheck.curl_timer); - if (timeout_msec != -1) - cb_data->concheck.curl_timer = g_timeout_add (timeout_msec, _con_curl_timeout_cb, cb_data); - return 0; + nm_clear_g_source(&cb_data->concheck.curl_timer); + if (timeout_msec != -1) + cb_data->concheck.curl_timer = g_timeout_add(timeout_msec, _con_curl_timeout_cb, cb_data); + return 0; } typedef struct { - NMConnectivityCheckHandle *cb_data; + NMConnectivityCheckHandle *cb_data; - GSource *source; + GSource *source; - /* this is a very simplistic weak-pointer. If ConCurlSockData gets - * destroyed, it will set *destroy_notify to TRUE. - * - * _con_curl_socketevent_cb() uses this to detect whether it can - * safely access @fdp after _con_curl_check_connectivity(). */ - gboolean *destroy_notify; + /* this is a very simplistic weak-pointer. If ConCurlSockData gets + * destroyed, it will set *destroy_notify to TRUE. + * + * _con_curl_socketevent_cb() uses this to detect whether it can + * safely access @fdp after _con_curl_check_connectivity(). */ + gboolean *destroy_notify; } ConCurlSockData; static gboolean -_con_curl_socketevent_cb (int fd, - GIOCondition condition, - gpointer user_data) +_con_curl_socketevent_cb(int fd, GIOCondition condition, gpointer user_data) { - ConCurlSockData *fdp = user_data; - NMConnectivityCheckHandle *cb_data = fdp->cb_data; - int action = 0; - gboolean fdp_destroyed = FALSE; - gboolean success; - - if (condition & G_IO_IN) - action |= CURL_CSELECT_IN; - if (condition & G_IO_OUT) - action |= CURL_CSELECT_OUT; - if (condition & G_IO_ERR) - action |= CURL_CSELECT_ERR; - - nm_assert (!fdp->destroy_notify); - fdp->destroy_notify = &fdp_destroyed; - - success = _con_curl_check_connectivity (cb_data->concheck.curl_mhandle, fd, action); - - if (fdp_destroyed) { - /* hups. fdp got invalidated during _con_curl_check_connectivity(). That's fine, - * just don't touch it. */ - } else { - nm_assert (fdp->destroy_notify == &fdp_destroyed); - fdp->destroy_notify = NULL; - if (!success) - nm_clear_g_source_inst (&fdp->source); - } - - _complete_queued (cb_data->self); - - return G_SOURCE_CONTINUE; + ConCurlSockData * fdp = user_data; + NMConnectivityCheckHandle *cb_data = fdp->cb_data; + int action = 0; + gboolean fdp_destroyed = FALSE; + gboolean success; + + if (condition & G_IO_IN) + action |= CURL_CSELECT_IN; + if (condition & G_IO_OUT) + action |= CURL_CSELECT_OUT; + if (condition & G_IO_ERR) + action |= CURL_CSELECT_ERR; + + nm_assert(!fdp->destroy_notify); + fdp->destroy_notify = &fdp_destroyed; + + success = _con_curl_check_connectivity(cb_data->concheck.curl_mhandle, fd, action); + + if (fdp_destroyed) { + /* hups. fdp got invalidated during _con_curl_check_connectivity(). That's fine, + * just don't touch it. */ + } else { + nm_assert(fdp->destroy_notify == &fdp_destroyed); + fdp->destroy_notify = NULL; + if (!success) + nm_clear_g_source_inst(&fdp->source); + } + + _complete_queued(cb_data->self); + + return G_SOURCE_CONTINUE; } static int -multi_socket_cb (CURL *e_handle, curl_socket_t fd, int what, void *userdata, void *socketp) +multi_socket_cb(CURL *e_handle, curl_socket_t fd, int what, void *userdata, void *socketp) { - NMConnectivityCheckHandle *cb_data = userdata; - ConCurlSockData *fdp = socketp; - - (void) _NM_ENSURE_TYPE (int, fd); - - if (what == CURL_POLL_REMOVE) { - if (fdp) { - if (fdp->destroy_notify) - *fdp->destroy_notify = TRUE; - nm_clear_g_source_inst (&fdp->source); - curl_multi_assign (cb_data->concheck.curl_mhandle, fd, NULL); - g_slice_free (ConCurlSockData, fdp); - } - } else { - GIOCondition condition; - - if (!fdp) { - fdp = g_slice_new (ConCurlSockData); - *fdp = (ConCurlSockData) { - .cb_data = cb_data, - }; - curl_multi_assign (cb_data->concheck.curl_mhandle, fd, fdp); - } else - nm_clear_g_source_inst (&fdp->source); - - if (what == CURL_POLL_IN) - condition = G_IO_IN; - else if (what == CURL_POLL_OUT) - condition = G_IO_OUT; - else if (what == CURL_POLL_INOUT) - condition = G_IO_IN | G_IO_OUT; - else - condition = 0; - - if (condition) { - fdp->source = nm_g_unix_fd_source_new (fd, - condition, - G_PRIORITY_DEFAULT, - _con_curl_socketevent_cb, - fdp, - NULL); - g_source_attach (fdp->source, NULL); - } - } - - return CURLM_OK; + NMConnectivityCheckHandle *cb_data = userdata; + ConCurlSockData * fdp = socketp; + + (void) _NM_ENSURE_TYPE(int, fd); + + if (what == CURL_POLL_REMOVE) { + if (fdp) { + if (fdp->destroy_notify) + *fdp->destroy_notify = TRUE; + nm_clear_g_source_inst(&fdp->source); + curl_multi_assign(cb_data->concheck.curl_mhandle, fd, NULL); + g_slice_free(ConCurlSockData, fdp); + } + } else { + GIOCondition condition; + + if (!fdp) { + fdp = g_slice_new(ConCurlSockData); + *fdp = (ConCurlSockData){ + .cb_data = cb_data, + }; + curl_multi_assign(cb_data->concheck.curl_mhandle, fd, fdp); + } else + nm_clear_g_source_inst(&fdp->source); + + if (what == CURL_POLL_IN) + condition = G_IO_IN; + else if (what == CURL_POLL_OUT) + condition = G_IO_OUT; + else if (what == CURL_POLL_INOUT) + condition = G_IO_IN | G_IO_OUT; + else + condition = 0; + + if (condition) { + fdp->source = nm_g_unix_fd_source_new(fd, + condition, + G_PRIORITY_DEFAULT, + _con_curl_socketevent_cb, + fdp, + NULL); + g_source_attach(fdp->source, NULL); + } + } + + return CURLM_OK; } static size_t -easy_header_cb (char *buffer, size_t size, size_t nitems, void *userdata) +easy_header_cb(char *buffer, size_t size, size_t nitems, void *userdata) { - NMConnectivityCheckHandle *cb_data = userdata; - size_t len = size * nitems; - - if (cb_data->completed_state != NM_CONNECTIVITY_UNKNOWN) { - /* already completed. */ - return 0; - } - - if ( len >= sizeof (HEADER_STATUS_ONLINE) - 1 - && !g_ascii_strncasecmp (buffer, HEADER_STATUS_ONLINE, sizeof (HEADER_STATUS_ONLINE) - 1)) { - cb_data_queue_completed (cb_data, - NM_CONNECTIVITY_FULL, - "status header found", - NULL); - return 0; - } - - return len; + NMConnectivityCheckHandle *cb_data = userdata; + size_t len = size * nitems; + + if (cb_data->completed_state != NM_CONNECTIVITY_UNKNOWN) { + /* already completed. */ + return 0; + } + + if (len >= sizeof(HEADER_STATUS_ONLINE) - 1 + && !g_ascii_strncasecmp(buffer, HEADER_STATUS_ONLINE, sizeof(HEADER_STATUS_ONLINE) - 1)) { + cb_data_queue_completed(cb_data, NM_CONNECTIVITY_FULL, "status header found", NULL); + return 0; + } + + return len; } static size_t -easy_write_cb (void *buffer, size_t size, size_t nmemb, void *userdata) +easy_write_cb(void *buffer, size_t size, size_t nmemb, void *userdata) { - NMConnectivityCheckHandle *cb_data = userdata; - size_t len = size * nmemb; - size_t response_len; - size_t check_len; - const char *response; - - if (cb_data->completed_state != NM_CONNECTIVITY_UNKNOWN) { - /* already completed. */ - return 0; - } - - if (len == 0) { - /* no data. That can happen, it's fine. */ - return len; - } - - response = _con_config_get_response (cb_data->concheck.con_config);; - - if (response[0] == '\0') { - /* no response expected. We are however graceful and accept any - * extra response that we might receive. We determine the empty - * response based on the status code 204. - * - * Continue receiving... */ - cb_data->concheck.response_good_cnt += len; - - if (cb_data->concheck.response_good_cnt > (gsize) (100 * 1024)) { - /* we expect an empty response. We accept either - * 1) status code 204 and any response - * 2) status code 200 and an empty response. - * - * Here, we want to continue receiving data, to see whether we have - * case 1). Arguably, the server shouldn't send us 204 with a non-empty - * response, but we accept that also with a non-empty response, so - * keep receiving. - * - * However, if we get an excessive amount of data, we put a stop on it - * and fail. */ - cb_data_queue_completed (cb_data, - NM_CONNECTIVITY_PORTAL, - "unexpected non-empty response", - NULL); - return 0; - } - - return len; - } - - nm_assert (cb_data->concheck.response_good_cnt < strlen (response)); - - response_len = strlen (response); - - check_len = NM_MIN (len, - response_len - cb_data->concheck.response_good_cnt); - - if (strncmp (&response[cb_data->concheck.response_good_cnt], - buffer, - check_len) != 0) { - cb_data_queue_completed (cb_data, - NM_CONNECTIVITY_PORTAL, - "unexpected response", - NULL); - return 0; - } - - cb_data->concheck.response_good_cnt += len; - - if (cb_data->concheck.response_good_cnt >= response_len) { - /* We already have enough data, and it matched. */ - cb_data_queue_completed (cb_data, - NM_CONNECTIVITY_FULL, - "expected response", - NULL); - return 0; - } - - return len; + NMConnectivityCheckHandle *cb_data = userdata; + size_t len = size * nmemb; + size_t response_len; + size_t check_len; + const char * response; + + if (cb_data->completed_state != NM_CONNECTIVITY_UNKNOWN) { + /* already completed. */ + return 0; + } + + if (len == 0) { + /* no data. That can happen, it's fine. */ + return len; + } + + response = _con_config_get_response(cb_data->concheck.con_config); + + if (response[0] == '\0') { + /* no response expected. We are however graceful and accept any + * extra response that we might receive. We determine the empty + * response based on the status code 204. + * + * Continue receiving... */ + cb_data->concheck.response_good_cnt += len; + + if (cb_data->concheck.response_good_cnt > (gsize)(100 * 1024)) { + /* we expect an empty response. We accept either + * 1) status code 204 and any response + * 2) status code 200 and an empty response. + * + * Here, we want to continue receiving data, to see whether we have + * case 1). Arguably, the server shouldn't send us 204 with a non-empty + * response, but we accept that also with a non-empty response, so + * keep receiving. + * + * However, if we get an excessive amount of data, we put a stop on it + * and fail. */ + cb_data_queue_completed(cb_data, + NM_CONNECTIVITY_PORTAL, + "unexpected non-empty response", + NULL); + return 0; + } + + return len; + } + + nm_assert(cb_data->concheck.response_good_cnt < strlen(response)); + + response_len = strlen(response); + + check_len = NM_MIN(len, response_len - cb_data->concheck.response_good_cnt); + + if (strncmp(&response[cb_data->concheck.response_good_cnt], buffer, check_len) != 0) { + cb_data_queue_completed(cb_data, NM_CONNECTIVITY_PORTAL, "unexpected response", NULL); + return 0; + } + + cb_data->concheck.response_good_cnt += len; + + if (cb_data->concheck.response_good_cnt >= response_len) { + /* We already have enough data, and it matched. */ + cb_data_queue_completed(cb_data, NM_CONNECTIVITY_FULL, "expected response", NULL); + return 0; + } + + return len; } static gboolean -_timeout_cb (gpointer user_data) +_timeout_cb(gpointer user_data) { - NMConnectivityCheckHandle *cb_data = user_data; + NMConnectivityCheckHandle *cb_data = user_data; - nm_assert (NM_IS_CONNECTIVITY (cb_data->self)); - nm_assert (c_list_contains (&NM_CONNECTIVITY_GET_PRIVATE (cb_data->self)->handles_lst_head, &cb_data->handles_lst)); + nm_assert(NM_IS_CONNECTIVITY(cb_data->self)); + nm_assert(c_list_contains(&NM_CONNECTIVITY_GET_PRIVATE(cb_data->self)->handles_lst_head, + &cb_data->handles_lst)); - cb_data_complete (cb_data, NM_CONNECTIVITY_LIMITED, "timeout"); - return G_SOURCE_REMOVE; + cb_data_complete(cb_data, NM_CONNECTIVITY_LIMITED, "timeout"); + return G_SOURCE_REMOVE; } #endif static gboolean -_idle_cb (gpointer user_data) +_idle_cb(gpointer user_data) { - NMConnectivityCheckHandle *cb_data = user_data; + NMConnectivityCheckHandle *cb_data = user_data; - nm_assert (NM_IS_CONNECTIVITY (cb_data->self)); - nm_assert (c_list_contains (&NM_CONNECTIVITY_GET_PRIVATE (cb_data->self)->handles_lst_head, &cb_data->handles_lst)); - nm_assert (cb_data->completed_reason); + nm_assert(NM_IS_CONNECTIVITY(cb_data->self)); + nm_assert(c_list_contains(&NM_CONNECTIVITY_GET_PRIVATE(cb_data->self)->handles_lst_head, + &cb_data->handles_lst)); + nm_assert(cb_data->completed_reason); - cb_data->timeout_id = 0; - cb_data_complete (cb_data, cb_data->completed_state, cb_data->completed_reason); - return G_SOURCE_REMOVE; + cb_data->timeout_id = 0; + cb_data_complete(cb_data, cb_data->completed_state, cb_data->completed_reason); + return G_SOURCE_REMOVE; } #if WITH_CONCHECK static void -do_curl_request (NMConnectivityCheckHandle *cb_data) +do_curl_request(NMConnectivityCheckHandle *cb_data) { - CURLM *mhandle; - CURL *ehandle; - long resolve; - - mhandle = curl_multi_init (); - if (!mhandle) { - cb_data_complete (cb_data, NM_CONNECTIVITY_ERROR, "curl error"); - return; - } - - ehandle = curl_easy_init (); - if (!ehandle) { - curl_multi_cleanup (mhandle); - cb_data_complete (cb_data, NM_CONNECTIVITY_ERROR, "curl error"); - return; - } - - cb_data->concheck.curl_mhandle = mhandle; - cb_data->concheck.curl_ehandle = ehandle; - cb_data->concheck.request_headers = curl_slist_append (NULL, "Connection: close"); - cb_data->timeout_id = g_timeout_add_seconds (20, _timeout_cb, cb_data); - - curl_multi_setopt (mhandle, CURLMOPT_SOCKETFUNCTION, multi_socket_cb); - curl_multi_setopt (mhandle, CURLMOPT_SOCKETDATA, cb_data); - curl_multi_setopt (mhandle, CURLMOPT_TIMERFUNCTION, multi_timer_cb); - curl_multi_setopt (mhandle, CURLMOPT_TIMERDATA, cb_data); - - switch (cb_data->addr_family) { - case AF_INET: - resolve = CURL_IPRESOLVE_V4; - break; - case AF_INET6: - resolve = CURL_IPRESOLVE_V6; - break; - case AF_UNSPEC: - resolve = CURL_IPRESOLVE_WHATEVER; - break; - default: - resolve = CURL_IPRESOLVE_WHATEVER; - g_warn_if_reached (); - } - - curl_easy_setopt (ehandle, CURLOPT_URL, cb_data->concheck.con_config->uri); - curl_easy_setopt (ehandle, CURLOPT_WRITEFUNCTION, easy_write_cb); - curl_easy_setopt (ehandle, CURLOPT_WRITEDATA, cb_data); - curl_easy_setopt (ehandle, CURLOPT_HEADERFUNCTION, easy_header_cb); - curl_easy_setopt (ehandle, CURLOPT_HEADERDATA, cb_data); - curl_easy_setopt (ehandle, CURLOPT_PRIVATE, cb_data); - curl_easy_setopt (ehandle, CURLOPT_HTTPHEADER, cb_data->concheck.request_headers); - curl_easy_setopt (ehandle, CURLOPT_INTERFACE, cb_data->ifspec); - curl_easy_setopt (ehandle, CURLOPT_RESOLVE, cb_data->concheck.hosts); - curl_easy_setopt (ehandle, CURLOPT_IPRESOLVE, resolve); - - curl_multi_add_handle (mhandle, ehandle); + CURLM *mhandle; + CURL * ehandle; + long resolve; + + mhandle = curl_multi_init(); + if (!mhandle) { + cb_data_complete(cb_data, NM_CONNECTIVITY_ERROR, "curl error"); + return; + } + + ehandle = curl_easy_init(); + if (!ehandle) { + curl_multi_cleanup(mhandle); + cb_data_complete(cb_data, NM_CONNECTIVITY_ERROR, "curl error"); + return; + } + + cb_data->concheck.curl_mhandle = mhandle; + cb_data->concheck.curl_ehandle = ehandle; + cb_data->concheck.request_headers = curl_slist_append(NULL, "Connection: close"); + cb_data->timeout_id = g_timeout_add_seconds(20, _timeout_cb, cb_data); + + curl_multi_setopt(mhandle, CURLMOPT_SOCKETFUNCTION, multi_socket_cb); + curl_multi_setopt(mhandle, CURLMOPT_SOCKETDATA, cb_data); + curl_multi_setopt(mhandle, CURLMOPT_TIMERFUNCTION, multi_timer_cb); + curl_multi_setopt(mhandle, CURLMOPT_TIMERDATA, cb_data); + + switch (cb_data->addr_family) { + case AF_INET: + resolve = CURL_IPRESOLVE_V4; + break; + case AF_INET6: + resolve = CURL_IPRESOLVE_V6; + break; + case AF_UNSPEC: + resolve = CURL_IPRESOLVE_WHATEVER; + break; + default: + resolve = CURL_IPRESOLVE_WHATEVER; + g_warn_if_reached(); + } + + curl_easy_setopt(ehandle, CURLOPT_URL, cb_data->concheck.con_config->uri); + curl_easy_setopt(ehandle, CURLOPT_WRITEFUNCTION, easy_write_cb); + curl_easy_setopt(ehandle, CURLOPT_WRITEDATA, cb_data); + curl_easy_setopt(ehandle, CURLOPT_HEADERFUNCTION, easy_header_cb); + curl_easy_setopt(ehandle, CURLOPT_HEADERDATA, cb_data); + curl_easy_setopt(ehandle, CURLOPT_PRIVATE, cb_data); + curl_easy_setopt(ehandle, CURLOPT_HTTPHEADER, cb_data->concheck.request_headers); + curl_easy_setopt(ehandle, CURLOPT_INTERFACE, cb_data->ifspec); + curl_easy_setopt(ehandle, CURLOPT_RESOLVE, cb_data->concheck.hosts); + curl_easy_setopt(ehandle, CURLOPT_IPRESOLVE, resolve); + + curl_multi_add_handle(mhandle, ehandle); } static void -resolve_cb (GObject *object, GAsyncResult *res, gpointer user_data) +resolve_cb(GObject *object, GAsyncResult *res, gpointer user_data) { - NMConnectivityCheckHandle *cb_data; - gs_unref_variant GVariant *result = NULL; - gs_unref_variant GVariant *addresses = NULL; - gsize no_addresses; - int ifindex; - int addr_family; - gsize len = 0; - gsize i; - gs_free_error GError *error = NULL; - - result = g_dbus_connection_call_finish (G_DBUS_CONNECTION (object), res, &error); - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - cb_data = user_data; - - g_clear_object (&cb_data->concheck.resolve_cancellable); - - if (!result) { - /* Never mind. Just let do curl do its own resolving. */ - _LOG2D ("can't resolve a name via systemd-resolved: %s", error->message); - do_curl_request (cb_data); - return; - } - - addresses = g_variant_get_child_value (result, 0); - no_addresses = g_variant_n_children (addresses); - - for (i = 0; i < no_addresses; i++) { - gs_unref_variant GVariant *address = NULL; - char str_addr[NM_UTILS_INET_ADDRSTRLEN]; - gs_free char *host_entry = NULL; - const guchar *address_buf; - - g_variant_get_child (addresses, i, "(ii@ay)", &ifindex, &addr_family, &address); - - if ( cb_data->addr_family != AF_UNSPEC - && cb_data->addr_family != addr_family) - continue; - - address_buf = g_variant_get_fixed_array (address, &len, 1); - if ( (addr_family == AF_INET && len != sizeof (struct in_addr)) - || (addr_family == AF_INET6 && len != sizeof (struct in6_addr))) - continue; - - host_entry = g_strdup_printf ("%s:%s:%s", - cb_data->concheck.con_config->host, - cb_data->concheck.con_config->port ?: "80", - nm_utils_inet_ntop (addr_family, address_buf, str_addr)); - cb_data->concheck.hosts = curl_slist_append (cb_data->concheck.hosts, host_entry); - _LOG2T ("adding '%s' to curl resolve list", host_entry); - } - - do_curl_request (cb_data); + NMConnectivityCheckHandle *cb_data; + gs_unref_variant GVariant *result = NULL; + gs_unref_variant GVariant *addresses = NULL; + gsize no_addresses; + int ifindex; + int addr_family; + gsize len = 0; + gsize i; + gs_free_error GError *error = NULL; + + result = g_dbus_connection_call_finish(G_DBUS_CONNECTION(object), res, &error); + if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + cb_data = user_data; + + g_clear_object(&cb_data->concheck.resolve_cancellable); + + if (!result) { + /* Never mind. Just let do curl do its own resolving. */ + _LOG2D("can't resolve a name via systemd-resolved: %s", error->message); + do_curl_request(cb_data); + return; + } + + addresses = g_variant_get_child_value(result, 0); + no_addresses = g_variant_n_children(addresses); + + for (i = 0; i < no_addresses; i++) { + gs_unref_variant GVariant *address = NULL; + char str_addr[NM_UTILS_INET_ADDRSTRLEN]; + gs_free char * host_entry = NULL; + const guchar * address_buf; + + g_variant_get_child(addresses, i, "(ii@ay)", &ifindex, &addr_family, &address); + + if (cb_data->addr_family != AF_UNSPEC && cb_data->addr_family != addr_family) + continue; + + address_buf = g_variant_get_fixed_array(address, &len, 1); + if ((addr_family == AF_INET && len != sizeof(struct in_addr)) + || (addr_family == AF_INET6 && len != sizeof(struct in6_addr))) + continue; + + host_entry = g_strdup_printf("%s:%s:%s", + cb_data->concheck.con_config->host, + cb_data->concheck.con_config->port ?: "80", + nm_utils_inet_ntop(addr_family, address_buf, str_addr)); + cb_data->concheck.hosts = curl_slist_append(cb_data->concheck.hosts, host_entry); + _LOG2T("adding '%s' to curl resolve list", host_entry); + } + + do_curl_request(cb_data); } #endif -#define SD_RESOLVED_DNS ((guint64) (1LL << 0)) +#define SD_RESOLVED_DNS ((guint64)(1LL << 0)) static NMConnectivityState -check_platform_config (NMConnectivity *self, - NMPlatform *platform, - int ifindex, - int addr_family, - const char **reason) +check_platform_config(NMConnectivity *self, + NMPlatform * platform, + int ifindex, + int addr_family, + const char ** reason) { - const NMDedupMultiHeadEntry *addresses; - const NMDedupMultiHeadEntry *routes; - - if (!nm_platform_link_is_connected (platform, ifindex)) { - NM_SET_OUT (reason, "no carrier"); - return NM_CONNECTIVITY_NONE; - } - - addresses = nm_platform_lookup_object (platform, - addr_family == AF_INET - ? NMP_OBJECT_TYPE_IP4_ADDRESS - : NMP_OBJECT_TYPE_IP6_ADDRESS, - ifindex); - if (!addresses || addresses->len == 0) { - NM_SET_OUT (reason, "no IP address configured"); - return NM_CONNECTIVITY_NONE; - } - - routes = nm_platform_lookup_object (platform, - addr_family == AF_INET - ? NMP_OBJECT_TYPE_IP4_ROUTE - : NMP_OBJECT_TYPE_IP6_ROUTE, - ifindex); - if (!routes || routes->len == 0) { - NM_SET_OUT (reason, "no IP route configured"); - return NM_CONNECTIVITY_NONE; - } - - switch (addr_family) { - case AF_INET: { - const NMPlatformIP4Route *route; - gboolean found_global = FALSE; - NMDedupMultiIter iter; - const NMPObject *plobj; - - /* For IPv4 also require a route with global scope. */ - nmp_cache_iter_for_each (&iter, routes, &plobj) { - route = NMP_OBJECT_CAST_IP4_ROUTE (plobj); - if (nm_platform_route_scope_inv (route->scope_inv) == RT_SCOPE_UNIVERSE) { - found_global = TRUE; - break; - } - } - - if (!found_global) { - NM_SET_OUT (reason, "no global route configured"); - return NM_CONNECTIVITY_LIMITED; - } - break; - } - case AF_INET6: - /* Route scopes aren't meaningful for IPv6 so any route is fine. */ - break; - default: - g_return_val_if_reached (FALSE); - } - - NM_SET_OUT (reason, NULL); - return NM_CONNECTIVITY_UNKNOWN; + const NMDedupMultiHeadEntry *addresses; + const NMDedupMultiHeadEntry *routes; + + if (!nm_platform_link_is_connected(platform, ifindex)) { + NM_SET_OUT(reason, "no carrier"); + return NM_CONNECTIVITY_NONE; + } + + addresses = nm_platform_lookup_object(platform, + addr_family == AF_INET ? NMP_OBJECT_TYPE_IP4_ADDRESS + : NMP_OBJECT_TYPE_IP6_ADDRESS, + ifindex); + if (!addresses || addresses->len == 0) { + NM_SET_OUT(reason, "no IP address configured"); + return NM_CONNECTIVITY_NONE; + } + + routes = nm_platform_lookup_object(platform, + addr_family == AF_INET ? NMP_OBJECT_TYPE_IP4_ROUTE + : NMP_OBJECT_TYPE_IP6_ROUTE, + ifindex); + if (!routes || routes->len == 0) { + NM_SET_OUT(reason, "no IP route configured"); + return NM_CONNECTIVITY_NONE; + } + + switch (addr_family) { + case AF_INET: + { + const NMPlatformIP4Route *route; + gboolean found_global = FALSE; + NMDedupMultiIter iter; + const NMPObject * plobj; + + /* For IPv4 also require a route with global scope. */ + nmp_cache_iter_for_each (&iter, routes, &plobj) { + route = NMP_OBJECT_CAST_IP4_ROUTE(plobj); + if (nm_platform_route_scope_inv(route->scope_inv) == RT_SCOPE_UNIVERSE) { + found_global = TRUE; + break; + } + } + + if (!found_global) { + NM_SET_OUT(reason, "no global route configured"); + return NM_CONNECTIVITY_LIMITED; + } + break; + } + case AF_INET6: + /* Route scopes aren't meaningful for IPv6 so any route is fine. */ + break; + default: + g_return_val_if_reached(FALSE); + } + + NM_SET_OUT(reason, NULL); + return NM_CONNECTIVITY_UNKNOWN; } NMConnectivityCheckHandle * -nm_connectivity_check_start (NMConnectivity *self, - int addr_family, - NMPlatform *platform, - int ifindex, - const char *iface, - NMConnectivityCheckCallback callback, - gpointer user_data) +nm_connectivity_check_start(NMConnectivity * self, + int addr_family, + NMPlatform * platform, + int ifindex, + const char * iface, + NMConnectivityCheckCallback callback, + gpointer user_data) { - NMConnectivityPrivate *priv; - NMConnectivityCheckHandle *cb_data; - static guint64 request_counter = 0; - - g_return_val_if_fail (NM_IS_CONNECTIVITY (self), NULL); - g_return_val_if_fail (callback, NULL); - nm_assert (!platform || NM_IS_PLATFORM (platform)); - - priv = NM_CONNECTIVITY_GET_PRIVATE (self); - - cb_data = g_slice_new0 (NMConnectivityCheckHandle); - cb_data->self = self; - cb_data->request_counter = ++request_counter; - c_list_link_tail (&priv->handles_lst_head, &cb_data->handles_lst); - cb_data->callback = callback; - cb_data->user_data = user_data; - cb_data->completed_state = NM_CONNECTIVITY_UNKNOWN; - cb_data->addr_family = addr_family; - if (iface) - cb_data->ifspec = g_strdup_printf ("if!%s", iface); + NMConnectivityPrivate * priv; + NMConnectivityCheckHandle *cb_data; + static guint64 request_counter = 0; + + g_return_val_if_fail(NM_IS_CONNECTIVITY(self), NULL); + g_return_val_if_fail(callback, NULL); + nm_assert(!platform || NM_IS_PLATFORM(platform)); + + priv = NM_CONNECTIVITY_GET_PRIVATE(self); + + cb_data = g_slice_new0(NMConnectivityCheckHandle); + cb_data->self = self; + cb_data->request_counter = ++request_counter; + c_list_link_tail(&priv->handles_lst_head, &cb_data->handles_lst); + cb_data->callback = callback; + cb_data->user_data = user_data; + cb_data->completed_state = NM_CONNECTIVITY_UNKNOWN; + cb_data->addr_family = addr_family; + if (iface) + cb_data->ifspec = g_strdup_printf("if!%s", iface); #if WITH_CONCHECK - cb_data->concheck.con_config = _con_config_ref (priv->con_config); - - if ( iface - && ifindex > 0 - && priv->enabled - && priv->uri_valid) { - gboolean has_systemd_resolved; - NMConnectivityState state; - const char *reason; - - cb_data->concheck.ch_ifindex = ifindex; - - if (platform) { - state = check_platform_config (self, - platform, - ifindex, - addr_family, - &reason); - nm_assert ((state == NM_CONNECTIVITY_UNKNOWN) == !reason); - if (state != NM_CONNECTIVITY_UNKNOWN) { - _LOG2D ("skip connectivity check due to %s", reason); - cb_data->completed_state = state; - cb_data->completed_reason = reason; - cb_data->timeout_id = g_idle_add (_idle_cb, cb_data); - return cb_data; - } - } - - /* note that we pick up support for systemd-resolved right away when we need it. - * We don't need to remember the setting, because we can (cheaply) check anew - * on each request. - * - * Yes, this makes NMConnectivity singleton dependent on NMDnsManager singleton. - * Well, not really: it makes connectivity-check-start dependent on NMDnsManager - * which merely means, not to start a connectivity check, late during shutdown. - * - * NMDnsSystemdResolved tries to D-Bus activate systemd-resolved only once, - * to not spam syslog with failures messages from dbus-daemon. - * Note that unless NMDnsSystemdResolved tried and failed to start systemd-resolved, - * it guesses that systemd-resolved is activatable and returns %TRUE here. That - * means, while NMDnsSystemdResolved would not try to D-Bus activate systemd-resolved - * more than once, NMConnectivity might -- until NMDnsSystemdResolved tried itself - * and noticed that systemd-resolved is not available. - * This is relatively cumbersome to avoid, because we would have to go through - * NMDnsSystemdResolved trying to asynchronously start the service, to ensure there - * is only one attempt to start the service. */ - has_systemd_resolved = nm_dns_manager_has_systemd_resolved (nm_dns_manager_get ()); - - if (has_systemd_resolved) { - GDBusConnection *dbus_connection; - - dbus_connection = NM_MAIN_DBUS_CONNECTION_GET; - if (!dbus_connection) { - /* we have no D-Bus connection? That might happen in configure and quit mode. - * - * Anyway, something is very odd, just fail connectivity check. */ - _LOG2D ("start fake request (fail due to no D-Bus connection)"); - cb_data->completed_state = NM_CONNECTIVITY_ERROR; - cb_data->completed_reason = "no D-Bus connection"; - cb_data->timeout_id = g_idle_add (_idle_cb, cb_data); - return cb_data; - } - - cb_data->concheck.resolve_cancellable = g_cancellable_new (); - - g_dbus_connection_call (dbus_connection, - "org.freedesktop.resolve1", - "/org/freedesktop/resolve1", - "org.freedesktop.resolve1.Manager", - "ResolveHostname", - g_variant_new ("(isit)", - (gint32) cb_data->concheck.ch_ifindex, - cb_data->concheck.con_config->host, - (gint32) cb_data->addr_family, - SD_RESOLVED_DNS), - G_VARIANT_TYPE ("(a(iiay)st)"), - G_DBUS_CALL_FLAGS_NONE, - -1, - cb_data->concheck.resolve_cancellable, - resolve_cb, - cb_data); - _LOG2D ("start request to '%s' (try resolving '%s' using systemd-resolved)", - cb_data->concheck.con_config->uri, - cb_data->concheck.con_config->host); - } else { - _LOG2D ("start request to '%s' (systemd-resolved not available)", - cb_data->concheck.con_config->uri); - do_curl_request (cb_data); - } - - return cb_data; - } + cb_data->concheck.con_config = _con_config_ref(priv->con_config); + + if (iface && ifindex > 0 && priv->enabled && priv->uri_valid) { + gboolean has_systemd_resolved; + NMConnectivityState state; + const char * reason; + + cb_data->concheck.ch_ifindex = ifindex; + + if (platform) { + state = check_platform_config(self, platform, ifindex, addr_family, &reason); + nm_assert((state == NM_CONNECTIVITY_UNKNOWN) == !reason); + if (state != NM_CONNECTIVITY_UNKNOWN) { + _LOG2D("skip connectivity check due to %s", reason); + cb_data->completed_state = state; + cb_data->completed_reason = reason; + cb_data->timeout_id = g_idle_add(_idle_cb, cb_data); + return cb_data; + } + } + + /* note that we pick up support for systemd-resolved right away when we need it. + * We don't need to remember the setting, because we can (cheaply) check anew + * on each request. + * + * Yes, this makes NMConnectivity singleton dependent on NMDnsManager singleton. + * Well, not really: it makes connectivity-check-start dependent on NMDnsManager + * which merely means, not to start a connectivity check, late during shutdown. + * + * NMDnsSystemdResolved tries to D-Bus activate systemd-resolved only once, + * to not spam syslog with failures messages from dbus-daemon. + * Note that unless NMDnsSystemdResolved tried and failed to start systemd-resolved, + * it guesses that systemd-resolved is activatable and returns %TRUE here. That + * means, while NMDnsSystemdResolved would not try to D-Bus activate systemd-resolved + * more than once, NMConnectivity might -- until NMDnsSystemdResolved tried itself + * and noticed that systemd-resolved is not available. + * This is relatively cumbersome to avoid, because we would have to go through + * NMDnsSystemdResolved trying to asynchronously start the service, to ensure there + * is only one attempt to start the service. */ + has_systemd_resolved = nm_dns_manager_has_systemd_resolved(nm_dns_manager_get()); + + if (has_systemd_resolved) { + GDBusConnection *dbus_connection; + + dbus_connection = NM_MAIN_DBUS_CONNECTION_GET; + if (!dbus_connection) { + /* we have no D-Bus connection? That might happen in configure and quit mode. + * + * Anyway, something is very odd, just fail connectivity check. */ + _LOG2D("start fake request (fail due to no D-Bus connection)"); + cb_data->completed_state = NM_CONNECTIVITY_ERROR; + cb_data->completed_reason = "no D-Bus connection"; + cb_data->timeout_id = g_idle_add(_idle_cb, cb_data); + return cb_data; + } + + cb_data->concheck.resolve_cancellable = g_cancellable_new(); + + g_dbus_connection_call(dbus_connection, + "org.freedesktop.resolve1", + "/org/freedesktop/resolve1", + "org.freedesktop.resolve1.Manager", + "ResolveHostname", + g_variant_new("(isit)", + (gint32) cb_data->concheck.ch_ifindex, + cb_data->concheck.con_config->host, + (gint32) cb_data->addr_family, + SD_RESOLVED_DNS), + G_VARIANT_TYPE("(a(iiay)st)"), + G_DBUS_CALL_FLAGS_NONE, + -1, + cb_data->concheck.resolve_cancellable, + resolve_cb, + cb_data); + _LOG2D("start request to '%s' (try resolving '%s' using systemd-resolved)", + cb_data->concheck.con_config->uri, + cb_data->concheck.con_config->host); + } else { + _LOG2D("start request to '%s' (systemd-resolved not available)", + cb_data->concheck.con_config->uri); + do_curl_request(cb_data); + } + + return cb_data; + } #endif - if (!cb_data->ifspec) { - cb_data->completed_state = NM_CONNECTIVITY_ERROR; - cb_data->completed_reason = "missing interface"; - } else { - cb_data->completed_state = NM_CONNECTIVITY_FAKE; - cb_data->completed_reason = "fake result"; - } - _LOG2D ("start fake request (%s)", cb_data->completed_reason); - cb_data->timeout_id = g_idle_add (_idle_cb, cb_data); - - return cb_data; + if (!cb_data->ifspec) { + cb_data->completed_state = NM_CONNECTIVITY_ERROR; + cb_data->completed_reason = "missing interface"; + } else { + cb_data->completed_state = NM_CONNECTIVITY_FAKE; + cb_data->completed_reason = "fake result"; + } + _LOG2D("start fake request (%s)", cb_data->completed_reason); + cb_data->timeout_id = g_idle_add(_idle_cb, cb_data); + + return cb_data; } void -nm_connectivity_check_cancel (NMConnectivityCheckHandle *cb_data) +nm_connectivity_check_cancel(NMConnectivityCheckHandle *cb_data) { - g_return_if_fail (cb_data); - g_return_if_fail (NM_IS_CONNECTIVITY (cb_data->self)); + g_return_if_fail(cb_data); + g_return_if_fail(NM_IS_CONNECTIVITY(cb_data->self)); - nm_assert ( c_list_contains (&NM_CONNECTIVITY_GET_PRIVATE (cb_data->self)->handles_lst_head, &cb_data->handles_lst) - || c_list_contains (&NM_CONNECTIVITY_GET_PRIVATE (cb_data->self)->completed_handles_lst_head, &cb_data->handles_lst)); + nm_assert( + c_list_contains(&NM_CONNECTIVITY_GET_PRIVATE(cb_data->self)->handles_lst_head, + &cb_data->handles_lst) + || c_list_contains(&NM_CONNECTIVITY_GET_PRIVATE(cb_data->self)->completed_handles_lst_head, + &cb_data->handles_lst)); - cb_data_complete (cb_data, NM_CONNECTIVITY_CANCELLED, "cancelled"); + cb_data_complete(cb_data, NM_CONNECTIVITY_CANCELLED, "cancelled"); } /*****************************************************************************/ gboolean -nm_connectivity_check_enabled (NMConnectivity *self) +nm_connectivity_check_enabled(NMConnectivity *self) { - g_return_val_if_fail (NM_IS_CONNECTIVITY (self), FALSE); + g_return_val_if_fail(NM_IS_CONNECTIVITY(self), FALSE); - return NM_CONNECTIVITY_GET_PRIVATE (self)->enabled; + return NM_CONNECTIVITY_GET_PRIVATE(self)->enabled; } /*****************************************************************************/ guint -nm_connectivity_get_interval (NMConnectivity *self) +nm_connectivity_get_interval(NMConnectivity *self) { - return nm_connectivity_check_enabled (self) - ? NM_CONNECTIVITY_GET_PRIVATE (self)->interval - : 0; + return nm_connectivity_check_enabled(self) ? NM_CONNECTIVITY_GET_PRIVATE(self)->interval : 0; } static gboolean -host_and_port_from_uri (const char *uri, char **host, char **port) +host_and_port_from_uri(const char *uri, char **host, char **port) { - const char *p = uri; - const char *host_begin = NULL; - size_t host_len = 0; - const char *port_begin = NULL; - size_t port_len = 0; - - /* scheme */ - while (*p != ':' && *p != '/') { - if (!*p++) - return FALSE; - } - - /* :// */ - if (*p++ != ':') - return FALSE; - if (*p++ != '/') - return FALSE; - if (*p++ != '/') - return FALSE; - /* host */ - if (*p == '[') - return FALSE; - host_begin = p; - while (*p && *p != ':' && *p != '/') { - host_len++; - p++; - } - if (host_len == 0) - return FALSE; - *host = g_strndup (host_begin, host_len); - - /* port */ - if (*p++ == ':') { - port_begin = p; - while (*p && *p != '/') { - port_len++; - p++; - } - if (port_len) - *port = g_strndup (port_begin, port_len); - } - - return TRUE; + const char *p = uri; + const char *host_begin = NULL; + size_t host_len = 0; + const char *port_begin = NULL; + size_t port_len = 0; + + /* scheme */ + while (*p != ':' && *p != '/') { + if (!*p++) + return FALSE; + } + + /* :// */ + if (*p++ != ':') + return FALSE; + if (*p++ != '/') + return FALSE; + if (*p++ != '/') + return FALSE; + /* host */ + if (*p == '[') + return FALSE; + host_begin = p; + while (*p && *p != ':' && *p != '/') { + host_len++; + p++; + } + if (host_len == 0) + return FALSE; + *host = g_strndup(host_begin, host_len); + + /* port */ + if (*p++ == ':') { + port_begin = p; + while (*p && *p != '/') { + port_len++; + p++; + } + if (port_len) + *port = g_strndup(port_begin, port_len); + } + + return TRUE; } static void -update_config (NMConnectivity *self, NMConfigData *config_data) +update_config(NMConnectivity *self, NMConfigData *config_data) { - NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self); - guint interval; - gboolean enabled; - gboolean changed = FALSE; - const char *cur_uri = priv->con_config ? priv->con_config->uri : NULL; - const char *cur_response = priv->con_config ? priv->con_config->response : NULL; - const char *new_response; - const char *new_uri; - gboolean new_uri_valid = priv->uri_valid; - gboolean new_host_port = FALSE; - gs_free char *new_host = NULL; - gs_free char *new_port = NULL; - - new_uri = nm_config_data_get_connectivity_uri (config_data); - if (!nm_streq0 (new_uri, cur_uri)) { - - new_uri_valid = (new_uri && *new_uri); - if (new_uri_valid) { - gs_free char *scheme = g_uri_parse_scheme (new_uri); - gboolean is_https = FALSE; - - if (!scheme) { - _LOGE ("invalid URI '%s' for connectivity check.", new_uri); - new_uri_valid = FALSE; - } else if (g_ascii_strcasecmp (scheme, "https") == 0) { - _LOGW ("use of HTTPS for connectivity checking is not reliable and is discouraged (URI: %s)", new_uri); - is_https = TRUE; - } else if (g_ascii_strcasecmp (scheme, "http") != 0) { - _LOGE ("scheme of '%s' uri doesn't use a scheme that is allowed for connectivity check.", new_uri); - new_uri_valid = FALSE; - } - if (new_uri_valid) { - new_host_port = TRUE; - if (!host_and_port_from_uri (new_uri, &new_host, &new_port)) { - _LOGE ("cannot parse host and port from '%s'", new_uri); - new_uri_valid = FALSE; - } else if (!new_port && is_https) - new_port = g_strdup ("443"); - } - } - - if ( new_uri_valid - || priv->uri_valid != new_uri_valid) - changed = TRUE; - } - - new_response = nm_config_data_get_connectivity_response (config_data); - if (!nm_streq0 (new_response, cur_response)) - changed = TRUE; - - if ( !priv->con_config - || !nm_streq0 (new_uri, priv->con_config->uri) - || !nm_streq0 (new_response, priv->con_config->response)) { - if (!new_host_port) { - new_host = priv->con_config ? g_strdup (priv->con_config->host) : NULL; - new_port = priv->con_config ? g_strdup (priv->con_config->port) : NULL; - } - _con_config_unref (priv->con_config); - priv->con_config = g_slice_new (ConConfig); - *priv->con_config = (ConConfig) { - .ref_count = 1, - .uri = g_strdup (new_uri), - .response = g_strdup (new_response), - .host = g_steal_pointer (&new_host), - .port = g_steal_pointer (&new_port), - }; - } - priv->uri_valid = new_uri_valid; - - interval = nm_config_data_get_connectivity_interval (config_data); - interval = MIN (interval, (7 * 24 * 3600)); - if (priv->interval != interval) { - priv->interval = interval; - changed = TRUE; - } - - enabled = FALSE; + NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE(self); + guint interval; + gboolean enabled; + gboolean changed = FALSE; + const char * cur_uri = priv->con_config ? priv->con_config->uri : NULL; + const char * cur_response = priv->con_config ? priv->con_config->response : NULL; + const char * new_response; + const char * new_uri; + gboolean new_uri_valid = priv->uri_valid; + gboolean new_host_port = FALSE; + gs_free char * new_host = NULL; + gs_free char * new_port = NULL; + + new_uri = nm_config_data_get_connectivity_uri(config_data); + if (!nm_streq0(new_uri, cur_uri)) { + new_uri_valid = (new_uri && *new_uri); + if (new_uri_valid) { + gs_free char *scheme = g_uri_parse_scheme(new_uri); + gboolean is_https = FALSE; + + if (!scheme) { + _LOGE("invalid URI '%s' for connectivity check.", new_uri); + new_uri_valid = FALSE; + } else if (g_ascii_strcasecmp(scheme, "https") == 0) { + _LOGW("use of HTTPS for connectivity checking is not reliable and is discouraged " + "(URI: %s)", + new_uri); + is_https = TRUE; + } else if (g_ascii_strcasecmp(scheme, "http") != 0) { + _LOGE("scheme of '%s' uri doesn't use a scheme that is allowed for connectivity " + "check.", + new_uri); + new_uri_valid = FALSE; + } + if (new_uri_valid) { + new_host_port = TRUE; + if (!host_and_port_from_uri(new_uri, &new_host, &new_port)) { + _LOGE("cannot parse host and port from '%s'", new_uri); + new_uri_valid = FALSE; + } else if (!new_port && is_https) + new_port = g_strdup("443"); + } + } + + if (new_uri_valid || priv->uri_valid != new_uri_valid) + changed = TRUE; + } + + new_response = nm_config_data_get_connectivity_response(config_data); + if (!nm_streq0(new_response, cur_response)) + changed = TRUE; + + if (!priv->con_config || !nm_streq0(new_uri, priv->con_config->uri) + || !nm_streq0(new_response, priv->con_config->response)) { + if (!new_host_port) { + new_host = priv->con_config ? g_strdup(priv->con_config->host) : NULL; + new_port = priv->con_config ? g_strdup(priv->con_config->port) : NULL; + } + _con_config_unref(priv->con_config); + priv->con_config = g_slice_new(ConConfig); + *priv->con_config = (ConConfig){ + .ref_count = 1, + .uri = g_strdup(new_uri), + .response = g_strdup(new_response), + .host = g_steal_pointer(&new_host), + .port = g_steal_pointer(&new_port), + }; + } + priv->uri_valid = new_uri_valid; + + interval = nm_config_data_get_connectivity_interval(config_data); + interval = MIN(interval, (7 * 24 * 3600)); + if (priv->interval != interval) { + priv->interval = interval; + changed = TRUE; + } + + enabled = FALSE; #if WITH_CONCHECK - if ( priv->uri_valid - && priv->interval) - enabled = nm_config_data_get_connectivity_enabled (config_data); + if (priv->uri_valid && priv->interval) + enabled = nm_config_data_get_connectivity_enabled(config_data); #endif - if (priv->enabled != enabled) { - priv->enabled = enabled; - changed = TRUE; - } + if (priv->enabled != enabled) { + priv->enabled = enabled; + changed = TRUE; + } - if (changed) - g_signal_emit (self, signals[CONFIG_CHANGED], 0); + if (changed) + g_signal_emit(self, signals[CONFIG_CHANGED], 0); } static void -config_changed_cb (NMConfig *config, - NMConfigData *config_data, - NMConfigChangeFlags changes, - NMConfigData *old_data, - NMConnectivity *self) +config_changed_cb(NMConfig * config, + NMConfigData * config_data, + NMConfigChangeFlags changes, + NMConfigData * old_data, + NMConnectivity * self) { - update_config (self, config_data); + update_config(self, config_data); } /*****************************************************************************/ static void -nm_connectivity_init (NMConnectivity *self) +nm_connectivity_init(NMConnectivity *self) { - NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self); + NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE(self); #if WITH_CONCHECK - CURLcode ret; + CURLcode ret; #endif - c_list_init (&priv->handles_lst_head); - c_list_init (&priv->completed_handles_lst_head); + c_list_init(&priv->handles_lst_head); + c_list_init(&priv->completed_handles_lst_head); - priv->config = g_object_ref (nm_config_get ()); - g_signal_connect (G_OBJECT (priv->config), - NM_CONFIG_SIGNAL_CONFIG_CHANGED, - G_CALLBACK (config_changed_cb), - self); + priv->config = g_object_ref(nm_config_get()); + g_signal_connect(G_OBJECT(priv->config), + NM_CONFIG_SIGNAL_CONFIG_CHANGED, + G_CALLBACK(config_changed_cb), + self); #if WITH_CONCHECK - ret = curl_global_init (CURL_GLOBAL_ALL); - if (ret != CURLE_OK) { - _LOGE ("unable to init cURL, connectivity check will not work: (%d) %s", - ret, curl_easy_strerror (ret)); - } + ret = curl_global_init(CURL_GLOBAL_ALL); + if (ret != CURLE_OK) { + _LOGE("unable to init cURL, connectivity check will not work: (%d) %s", + ret, + curl_easy_strerror(ret)); + } #endif - update_config (self, nm_config_get_data (priv->config)); + update_config(self, nm_config_get_data(priv->config)); } static void -dispose (GObject *object) +dispose(GObject *object) { - NMConnectivity *self = NM_CONNECTIVITY (object); - NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self); - NMConnectivityCheckHandle *cb_data; + NMConnectivity * self = NM_CONNECTIVITY(object); + NMConnectivityPrivate * priv = NM_CONNECTIVITY_GET_PRIVATE(self); + NMConnectivityCheckHandle *cb_data; - nm_assert (c_list_is_empty (&priv->completed_handles_lst_head)); + nm_assert(c_list_is_empty(&priv->completed_handles_lst_head)); - while ((cb_data = c_list_first_entry (&priv->handles_lst_head, - NMConnectivityCheckHandle, - handles_lst))) - cb_data_complete (cb_data, NM_CONNECTIVITY_DISPOSING, "shutting down"); + while ( + (cb_data = + c_list_first_entry(&priv->handles_lst_head, NMConnectivityCheckHandle, handles_lst))) + cb_data_complete(cb_data, NM_CONNECTIVITY_DISPOSING, "shutting down"); - nm_clear_pointer (&priv->con_config, _con_config_unref); + nm_clear_pointer(&priv->con_config, _con_config_unref); #if WITH_CONCHECK - curl_global_cleanup (); + curl_global_cleanup(); #endif - if (priv->config) { - g_signal_handlers_disconnect_by_func (priv->config, config_changed_cb, self); - g_clear_object (&priv->config); - } + if (priv->config) { + g_signal_handlers_disconnect_by_func(priv->config, config_changed_cb, self); + g_clear_object(&priv->config); + } - G_OBJECT_CLASS (nm_connectivity_parent_class)->dispose (object); + G_OBJECT_CLASS(nm_connectivity_parent_class)->dispose(object); } static void -nm_connectivity_class_init (NMConnectivityClass *klass) +nm_connectivity_class_init(NMConnectivityClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - signals[CONFIG_CHANGED] = - g_signal_new (NM_CONNECTIVITY_CONFIG_CHANGED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - 0, NULL, NULL, NULL, - G_TYPE_NONE, 0); - - object_class->dispose = dispose; + GObjectClass *object_class = G_OBJECT_CLASS(klass); + + signals[CONFIG_CHANGED] = g_signal_new(NM_CONNECTIVITY_CONFIG_CHANGED, + G_OBJECT_CLASS_TYPE(object_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 0); + + object_class->dispose = dispose; } |