summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLubomir Rintel <lkundrak@v3.sk>2017-03-20 13:36:00 +0000
committerLubomir Rintel <lkundrak@v3.sk>2017-03-28 15:26:47 +0200
commit9d43869e473b47542520c807dace93a6f9520964 (patch)
tree7c5b767b4b1afdad3a08fcf353e23c6aff57653b
parent4ec7dd987e5f05dd0889f2d417c93a605b15be46 (diff)
core: make connectivity checking per-device
This moves tracking of connectivity to NMDevice and makes the NMManager negotiate the best of known connectivity states of devices. The NMConnectivity singleton handles its own configuration and scheduling of the permission checks, but otherwise greatly simplifies it. This will be useful to determine correct metrics for multiple default routes depending on actual internet connectivity. The per-device connection checks is not yet exposed on the D-Bus, since they probably should be per-address-family as well.
-rw-r--r--Makefile.am6
-rw-r--r--src/devices/nm-device.c183
-rw-r--r--src/devices/nm-device.h12
-rw-r--r--src/main.c6
-rw-r--r--src/nm-connectivity.c433
-rw-r--r--src/nm-connectivity.h18
-rw-r--r--src/nm-dispatcher.c11
-rw-r--r--src/nm-manager.c157
8 files changed, 404 insertions, 422 deletions
diff --git a/Makefile.am b/Makefile.am
index f8c18d9620..f254109bc4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1428,7 +1428,6 @@ src_libNetworkManager_la_SOURCES = \
src/nm-config.h \
src/nm-config-data.c \
src/nm-config-data.h \
- src/nm-connectivity.c \
src/nm-connectivity.h \
src/nm-dcb.c \
src/nm-dcb.h \
@@ -1466,6 +1465,11 @@ src_libNetworkManager_la_SOURCES = \
\
$(NULL)
+if WITH_CONCHECK
+src_libNetworkManager_la_SOURCES += \
+ src/nm-connectivity.c
+endif
+
src_libNetworkManager_la_LIBADD = \
src/libNetworkManagerBase.la \
src/libsystemd-nm.la \
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 7a61cf6861..0f92d42dd4 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -15,7 +15,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Copyright (C) 2005 - 2013 Red Hat, Inc.
+ * Copyright (C) 2005 - 2017 Red Hat, Inc.
* Copyright (C) 2006 - 2008 Novell, Inc.
*/
@@ -66,6 +66,8 @@
#include "nm-lldp-listener.h"
#include "nm-audit-manager.h"
#include "nm-arping-manager.h"
+#include "nm-connectivity.h"
+#include "nm-dbus-interface.h"
#include "nm-device-logging.h"
_LOG_DECLARE_SELF (NMDevice);
@@ -189,6 +191,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDevice,
PROP_REFRESH_RATE_MS,
PROP_TX_BYTES,
PROP_RX_BYTES,
+ PROP_CONNECTIVITY,
);
typedef struct _NMDevicePrivate {
@@ -442,6 +445,9 @@ typedef struct _NMDevicePrivate {
NMSettings *settings;
NMLldpListener *lldp_listener;
+ NMConnectivityState connectivity_state;
+ guint concheck_periodic_id;
+ guint64 concheck_seq;
guint check_delete_unrealized_id;
@@ -1697,6 +1703,167 @@ nm_device_get_physical_port_id (NMDevice *self)
/*****************************************************************************/
+static void
+update_connectivity_state (NMDevice *self, NMConnectivityState state)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+
+ /* If the connectivity check is disabled, make an optimistic guess. */
+ if (state == NM_CONNECTIVITY_UNKNOWN) {
+ if (priv->state == NM_DEVICE_STATE_ACTIVATED) {
+ if (priv->default_route.v4_has || priv->default_route.v6_has)
+ state = NM_CONNECTIVITY_FULL;
+ else
+ state = NM_CONNECTIVITY_LIMITED;
+ } else {
+ state = NM_CONNECTIVITY_NONE;
+ }
+ }
+
+ if (priv->connectivity_state != state) {
+#if WITH_CONCHECK
+ _LOGD (LOGD_CONCHECK, "state changed from %s to %s",
+ nm_connectivity_state_to_string (priv->connectivity_state),
+ nm_connectivity_state_to_string (state));
+#endif
+ priv->connectivity_state = state;
+ _notify (self, PROP_CONNECTIVITY);
+ }
+}
+
+typedef struct {
+ NMDevice *self;
+ NMDeviceConnectivityCallback callback;
+ gpointer user_data;
+ guint64 seq;
+} ConnectivityCheckData;
+
+static void
+concheck_done (ConnectivityCheckData *data)
+{
+ NMDevice *self = data->self;
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+
+ /* The unsolicited connectivity checks don't hook a callback. */
+ if (data->callback)
+ data->callback (data->self, priv->connectivity_state, data->user_data);
+ g_object_unref (data->self);
+ g_slice_free (ConnectivityCheckData, data);
+}
+
+#if WITH_CONCHECK
+static void
+concheck_cb (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+ ConnectivityCheckData *data = user_data;
+ NMDevice *self = data->self;
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+ NMConnectivity *connectivity = NM_CONNECTIVITY (source_object);
+ NMConnectivityState state;
+ GError *error = NULL;
+
+ state = nm_connectivity_check_finish (connectivity, result, &error);
+ if (error) {
+ _LOGW (LOGD_DEVICE, "connectivity checking on '%s' failed: %s",
+ nm_device_get_iface (self), error->message);
+ g_error_free (error);
+ }
+
+ if (data->seq == priv->concheck_seq)
+ update_connectivity_state (data->self, state);
+ concheck_done (data);
+}
+#endif /* WITH_CONCHECK */
+
+static gboolean
+no_concheck (gpointer user_data)
+{
+ ConnectivityCheckData *data = user_data;
+
+ concheck_done (data);
+ return G_SOURCE_REMOVE;
+}
+
+void
+nm_device_check_connectivity (NMDevice *self,
+ NMDeviceConnectivityCallback callback,
+ gpointer user_data)
+{
+ ConnectivityCheckData *data;
+#if WITH_CONCHECK
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+#endif
+
+ data = g_slice_new0 (ConnectivityCheckData);
+ data->self = g_object_ref (self);
+ data->callback = callback;
+ data->user_data = user_data;
+
+#if WITH_CONCHECK
+ if (priv->concheck_periodic_id) {
+ data->seq = ++priv->concheck_seq;
+
+ /* Kick off a real connectivity check. */
+ nm_connectivity_check_async (nm_connectivity_get (),
+ nm_device_get_iface (self),
+ concheck_cb,
+ data);
+ return;
+ }
+#endif
+
+ /* Fake one. */
+ g_idle_add (no_concheck, data);
+}
+
+NMConnectivityState
+nm_device_get_connectivity_state (NMDevice *self)
+{
+ g_return_val_if_fail (NM_IS_DEVICE (self), NM_CONNECTIVITY_UNKNOWN);
+
+ return NM_DEVICE_GET_PRIVATE (self)->connectivity_state;
+}
+
+#if WITH_CONCHECK
+static void
+concheck_periodic (NMConnectivity *connectivity, NMDevice *self)
+{
+ nm_device_check_connectivity (self, NULL, NULL);
+}
+#endif
+
+static void
+concheck_periodic_update (NMDevice *self)
+{
+#if WITH_CONCHECK
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+ gboolean check_enable;
+
+ check_enable = (priv->state == NM_DEVICE_STATE_ACTIVATED)
+ && (priv->default_route.v4_has || priv->default_route.v6_has);
+
+ if (check_enable && !priv->concheck_periodic_id) {
+ /* We just gained a default route. Enable periodic checking. */
+ priv->concheck_periodic_id = g_signal_connect (nm_connectivity_get (),
+ NM_CONNECTIVITY_PERIODIC_CHECK,
+ G_CALLBACK (concheck_periodic), self);
+ /* Also kick off a check right away. */
+ nm_device_check_connectivity (self, NULL, NULL);
+ } else if (!check_enable && priv->concheck_periodic_id) {
+ /* The default route has gone off, and so has connectivity. */
+ update_connectivity_state (self, NM_CONNECTIVITY_NONE);
+ g_signal_handler_disconnect (nm_connectivity_get (), priv->concheck_periodic_id);
+ priv->concheck_periodic_id = 0;
+ }
+#else
+ /* update_connectivity_state() figures out how to lie about
+ * connectivity state if the actual state is not really known. */
+ update_connectivity_state (self, NM_CONNECTIVITY_UNKNOWN);
+#endif
+}
+
+/*****************************************************************************/
+
static SlaveInfo *
find_slave_info (NMDevice *self, NMDevice *slave)
{
@@ -9483,6 +9650,8 @@ nm_device_set_ip4_config (NMDevice *self,
}
nm_default_route_manager_ip4_update_default_route (nm_default_route_manager_get (), self);
+ concheck_periodic_update (self);
+
if (!nm_device_sys_iface_state_is_external_or_assume (self))
ip4_rp_filter_update (self);
@@ -12445,6 +12614,8 @@ _set_state_full (NMDevice *self,
if (ip_config_valid (old_state) && !ip_config_valid (state))
notify_ip_properties (self);
+ concheck_periodic_update (self);
+
/* Dispose of the cached activation request */
if (req)
g_object_unref (req);
@@ -13837,6 +14008,9 @@ get_property (GObject *object, guint prop_id,
case PROP_RX_BYTES:
g_value_set_uint64 (value, priv->stats.rx_bytes);
break;
+ case PROP_CONNECTIVITY:
+ g_value_set_uint (value, priv->connectivity_state);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -14107,6 +14281,13 @@ nm_device_class_init (NMDeviceClass *klass)
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS);
+ /* Connectivity */
+ obj_properties[PROP_CONNECTIVITY] =
+ g_param_spec_uint (NM_DEVICE_CONNECTIVITY, "", "",
+ NM_CONNECTIVITY_UNKNOWN, NM_CONNECTIVITY_FULL, NM_CONNECTIVITY_UNKNOWN,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
signals[STATE_CHANGED] =
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index 073e1fbdf2..eedd2fcd1c 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -15,7 +15,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Copyright (C) 2005 - 2013 Red Hat, Inc.
+ * Copyright (C) 2005 - 2017 Red Hat, Inc.
* Copyright (C) 2006 - 2008 Novell, Inc.
*/
@@ -135,6 +135,8 @@ nm_device_state_reason_check (NMDeviceStateReason reason)
#define NM_DEVICE_STATISTICS_TX_BYTES "tx-bytes"
#define NM_DEVICE_STATISTICS_RX_BYTES "rx-bytes"
+#define NM_DEVICE_CONNECTIVITY "connectivity"
+
#define NM_TYPE_DEVICE (nm_device_get_type ())
#define NM_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE, NMDevice))
#define NM_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE, NMDeviceClass))
@@ -689,4 +691,12 @@ gboolean nm_device_hw_addr_get_cloned (NMDevice *self,
gboolean *preserve,
GError **error);
+typedef void (*NMDeviceConnectivityCallback) (NMDevice *self,
+ NMConnectivityState state,
+ gpointer user_data);
+void nm_device_check_connectivity (NMDevice *self,
+ NMDeviceConnectivityCallback callback,
+ gpointer user_data);
+NMConnectivityState nm_device_get_connectivity_state (NMDevice *self);
+
#endif /* __NETWORKMANAGER_DEVICE_H__ */
diff --git a/src/main.c b/src/main.c
index 56b14c9144..04c837cb8f 100644
--- a/src/main.c
+++ b/src/main.c
@@ -15,7 +15,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Copyright (C) 2004 - 2012 Red Hat, Inc.
+ * Copyright (C) 2004 - 2017 Red Hat, Inc.
* Copyright (C) 2005 - 2008 Novell, Inc.
*/
@@ -49,6 +49,7 @@
#include "nm-auth-manager.h"
#include "nm-core-internal.h"
#include "nm-exported-object.h"
+#include "nm-connectivity.h"
#include "dns/nm-dns-manager.h"
#include "systemd/nm-sd.h"
@@ -391,6 +392,9 @@ main (int argc, char *argv[])
nm_linux_platform_setup ();
NM_UTILS_KEEP_ALIVE (config, NM_PLATFORM_GET, "NMConfig-depends-on-NMPlatform");
+#if WITH_CONCHECK
+ NM_UTILS_KEEP_ALIVE (nm_manager_get (), nm_connectivity_get (), "NMManager-depends-on-NMConnectivity");
+#endif
nm_dispatcher_init ();
diff --git a/src/nm-connectivity.c b/src/nm-connectivity.c
index ce1c25999b..68b23b909f 100644
--- a/src/nm-connectivity.c
+++ b/src/nm-connectivity.c
@@ -25,37 +25,21 @@
#include "nm-connectivity.h"
#include <string.h>
-#if WITH_CONCHECK
#include <curl/curl.h>
-#endif
#include "nm-config.h"
-#include "nm-dispatcher.h"
#include "NetworkManagerUtils.h"
/*****************************************************************************/
-NM_GOBJECT_PROPERTIES_DEFINE (NMConnectivity,
- PROP_URI,
- PROP_INTERVAL,
- PROP_RESPONSE,
- PROP_STATE,
-);
-
typedef struct {
char *uri;
char *response;
guint interval;
- gboolean online; /* whether periodic connectivity checking is enabled. */
-
-#if WITH_CONCHECK
+ NMConfig *config;
+ guint periodic_check_id;
CURLM *curl_mhandle;
guint curl_timer;
- gboolean initial_check_obsoleted;
- guint check_id;
-#endif
-
- NMConnectivityState state;
} NMConnectivityPrivate;
struct _NMConnectivity {
@@ -71,20 +55,37 @@ G_DEFINE_TYPE (NMConnectivity, nm_connectivity, G_TYPE_OBJECT)
#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);
+
+enum {
+ PERIODIC_CHECK,
+
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
/*****************************************************************************/
#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[3], NULL, \
+ "connectivity: (%s) " \
+ _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
+ &cb_data->ifspec[3] \
+ _NM_UTILS_MACRO_REST (__VA_ARGS__)); \
+ } \
+ } G_STMT_END
-NMConnectivityState
-nm_connectivity_get_state (NMConnectivity *connectivity)
-{
- g_return_val_if_fail (NM_IS_CONNECTIVITY (connectivity), NM_CONNECTIVITY_UNKNOWN);
-
- return NM_CONNECTIVITY_GET_PRIVATE (connectivity)->state;
-}
+/*****************************************************************************/
NM_UTILS_LOOKUP_STR_DEFINE (nm_connectivity_state_to_string, NMConnectivityState,
NM_UTILS_LOOKUP_DEFAULT_WARN ("???"),
@@ -95,139 +96,22 @@ NM_UTILS_LOOKUP_STR_DEFINE (nm_connectivity_state_to_string, NMConnectivityState
NM_UTILS_LOOKUP_STR_ITEM (NM_CONNECTIVITY_FULL, "FULL"),
);
-static void
-update_state (NMConnectivity *self, NMConnectivityState state)
-{
- NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
-
- if (priv->state != state) {
- _LOGD ("state changed from %s to %s",
- nm_connectivity_state_to_string (priv->state),
- nm_connectivity_state_to_string (state));
- priv->state = state;
- _notify (self, PROP_STATE);
-
- nm_dispatcher_call_connectivity (state, NULL, NULL, NULL);
- }
-}
-
-/*****************************************************************************/
-
-#if WITH_CONCHECK
-static void
-run_check_complete (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- NMConnectivity *self = NM_CONNECTIVITY (object);
- GError *error = NULL;
-
- nm_connectivity_check_finish (self, result, &error);
- if (error) {
- _LOGE ("check failed: %s", error->message);
- g_error_free (error);
- }
-}
-
-static gboolean
-run_check (gpointer user_data)
-{
- NMConnectivity *self = NM_CONNECTIVITY (user_data);
-
- nm_connectivity_check_async (self, run_check_complete, NULL);
- return TRUE;
-}
-
-static gboolean
-idle_start_periodic_checks (gpointer user_data)
-{
- NMConnectivity *self = user_data;
- NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
-
- priv->check_id = g_timeout_add_seconds (priv->interval, run_check, self);
- if (!priv->initial_check_obsoleted)
- run_check (self);
-
- return FALSE;
-}
-#endif
-
-static void
-_reschedule_periodic_checks (NMConnectivity *self, gboolean force_reschedule)
-{
- NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
-
-#if WITH_CONCHECK
- if (priv->online && priv->uri && priv->interval) {
- if (force_reschedule || !priv->check_id) {
- if (priv->check_id)
- g_source_remove (priv->check_id);
- priv->check_id = g_timeout_add (0, idle_start_periodic_checks, self);
- priv->initial_check_obsoleted = FALSE;
- }
- } else {
- nm_clear_g_source (&priv->check_id);
- }
- if (priv->check_id)
- return;
-#endif
-
- /* Either @online is %TRUE but we aren't checking connectivity, or
- * @online is %FALSE. Either way we can update our status immediately.
- */
- update_state (self, priv->online ? NM_CONNECTIVITY_FULL : NM_CONNECTIVITY_NONE);
-}
-
-void
-nm_connectivity_set_online (NMConnectivity *self,
- gboolean online)
-{
- NMConnectivityPrivate *priv= NM_CONNECTIVITY_GET_PRIVATE (self);
-
- online = !!online;
- if (priv->online != online) {
- _LOGD ("set %s", online ? "online" : "offline");
- priv->online = online;
- _reschedule_periodic_checks (self, FALSE);
- }
-}
-
/*****************************************************************************/
-#if WITH_CONCHECK
typedef struct {
GSimpleAsyncResult *simple;
- char *uri;
char *response;
- guint check_id_when_scheduled;
CURL *curl_ehandle;
size_t msg_size;
char *msg;
struct curl_slist *request_headers;
guint timeout_id;
+ char *ifspec;
} ConCheckCbData;
static void
finish_cb_data (ConCheckCbData *cb_data, NMConnectivityState new_state)
{
- NMConnectivity *self = NM_CONNECTIVITY (g_async_result_get_source_object (G_ASYNC_RESULT (cb_data->simple)));
- NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
-
- /* Only update the state, if the call was done from external, or if the periodic check
- * is still the one that called this async check. */
- if (!cb_data->check_id_when_scheduled || cb_data->check_id_when_scheduled == priv->check_id) {
- /* Only update the state, if the URI and response parameters did not change
- * since invocation.
- * The interval does not matter for exernal calls, and for internal calls
- * we don't reach this line if the interval changed. */
- if ( !g_strcmp0 (cb_data->uri, priv->uri)
- && !g_strcmp0 (cb_data->response, priv->response)) {
- _LOGT ("Update to connectivity state %s",
- nm_connectivity_state_to_string (new_state));
- update_state (self, new_state);
- }
- }
-
/* Contrary to what cURL manual claim it is *not* safe to remove
* the easy handle "at any moment"; specifically not from the
* write function. Thus here we just dissociate the cb_data from
@@ -239,7 +123,6 @@ finish_cb_data (ConCheckCbData *cb_data, NMConnectivityState new_state)
g_simple_async_result_complete (cb_data->simple);
g_object_unref (cb_data->simple);
curl_slist_free_all (cb_data->request_headers);
- g_free (cb_data->uri);
g_free (cb_data->response);
g_source_remove (cb_data->timeout_id);
g_slice_free (ConCheckCbData, cb_data);
@@ -254,7 +137,7 @@ curl_check_connectivity (CURLM *mhandle, CURLMcode ret)
gint m_left;
if (ret != CURLM_OK)
- _LOGW ("Connectivity check failed");
+ _LOGW ("connectivity check failed");
while ((msg = curl_multi_info_read (mhandle, &m_left))) {
if (msg->msg != CURLMSG_DONE)
@@ -263,7 +146,7 @@ curl_check_connectivity (CURLM *mhandle, CURLMcode ret)
/* Here we have completed a session. Check easy session result. */
eret = curl_easy_getinfo (msg->easy_handle, CURLINFO_PRIVATE, &cb_data);
if (eret != CURLE_OK) {
- _LOGE ("curl cannot extract cb_data for easy handle %p, skipping msg", msg->easy_handle);
+ _LOG2E ("curl cannot extract cb_data for easy handle %p, skipping msg", msg->easy_handle);
continue;
}
@@ -273,11 +156,11 @@ curl_check_connectivity (CURLM *mhandle, CURLMcode ret)
if (msg->data.result == CURLE_OK) {
/* If we get here, it means that easy_write_cb() didn't read enough
* bytes to be able to do a match. */
- _LOGI ("Check for uri '%s' returned a shorter response than expected '%s'; assuming captive portal.",
- cb_data->uri, cb_data->response);
+ _LOG2I ("response shorter than expected '%s'; assuming captive portal.",
+ cb_data->response);
finish_cb_data (cb_data, NM_CONNECTIVITY_PORTAL);
} else {
- _LOGD ("Check for uri '%s' failed", cb_data->uri);
+ _LOG2D ("check failed (%d)", msg->data.result);
finish_cb_data (cb_data, NM_CONNECTIVITY_LIMITED);
}
}
@@ -393,7 +276,7 @@ easy_header_cb (char *buffer, size_t size, size_t nitems, void *userdata)
if ( len >= sizeof (HEADER_STATUS_ONLINE) - 1
&& !g_ascii_strncasecmp (buffer, HEADER_STATUS_ONLINE, sizeof (HEADER_STATUS_ONLINE) - 1)) {
- _LOGD ("check for uri '%s' with Status header successful.", cb_data->uri);
+ _LOG2D ("status header found, check successful");
finish_cb_data (cb_data, NM_CONNECTIVITY_FULL);
return 0;
}
@@ -414,11 +297,11 @@ easy_write_cb (void *buffer, size_t size, size_t nmemb, void *userdata)
if (cb_data->msg_size >= strlen (cb_data->response)) {
/* We already have enough data -- check response */
if (g_str_has_prefix (cb_data->msg, cb_data->response)) {
- _LOGD ("Check for uri '%s' successful.", cb_data->uri);
+ _LOG2D ("check successful.");
finish_cb_data (cb_data, NM_CONNECTIVITY_FULL);
} else {
- _LOGI ("Check for uri '%s' did not match expected response '%s'; assuming captive portal.",
- cb_data->uri, cb_data->response);
+ _LOG2I ("response did not match expected response '%s'; assuming captive portal.",
+ cb_data->response);
finish_cb_data (cb_data, NM_CONNECTIVITY_PORTAL);
}
return 0;
@@ -435,27 +318,23 @@ timeout_cb (gpointer user_data)
NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
CURL *ehandle = cb_data->curl_ehandle;
- _LOGI ("Check for uri '%s' timed out.", cb_data->uri);
+ _LOG2I ("timed out");
finish_cb_data (cb_data, NM_CONNECTIVITY_LIMITED);
curl_multi_remove_handle (priv->curl_mhandle, ehandle);
curl_easy_cleanup (ehandle);
return G_SOURCE_REMOVE;
}
-#endif
-
-#define IS_PERIODIC_CHECK(callback) ((callback) == run_check_complete)
void
nm_connectivity_check_async (NMConnectivity *self,
+ const char *iface,
GAsyncReadyCallback callback,
gpointer user_data)
{
NMConnectivityPrivate *priv;
GSimpleAsyncResult *simple;
-#if WITH_CONCHECK
CURL *ehandle = NULL;
-#endif
g_return_if_fail (NM_IS_CONNECTIVITY (self));
priv = NM_CONNECTIVITY_GET_PRIVATE (self);
@@ -463,7 +342,6 @@ nm_connectivity_check_async (NMConnectivity *self,
simple = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
nm_connectivity_check_async);
-#if WITH_CONCHECK
if (priv->uri && priv->interval && priv->curl_mhandle)
ehandle = curl_easy_init ();
@@ -472,16 +350,13 @@ nm_connectivity_check_async (NMConnectivity *self,
cb_data->curl_ehandle = ehandle;
cb_data->request_headers = curl_slist_append (NULL, "Connection: close");
+ cb_data->ifspec = g_strdup_printf ("if!%s", iface);
cb_data->simple = simple;
- cb_data->uri = g_strdup (priv->uri);
if (priv->response)
cb_data->response = g_strdup (priv->response);
else
cb_data->response = g_strdup (NM_CONFIG_DEFAULT_CONNECTIVITY_RESPONSE);
- /* For internal calls (periodic), remember the check-id at time of scheduling. */
- cb_data->check_id_when_scheduled = IS_PERIODIC_CHECK (callback) ? priv->check_id : 0;
-
curl_easy_setopt (ehandle, CURLOPT_URL, priv->uri);
curl_easy_setopt (ehandle, CURLOPT_WRITEFUNCTION, easy_write_cb);
curl_easy_setopt (ehandle, CURLOPT_WRITEDATA, cb_data);
@@ -489,23 +364,18 @@ nm_connectivity_check_async (NMConnectivity *self,
curl_easy_setopt (ehandle, CURLOPT_HEADERDATA, cb_data);
curl_easy_setopt (ehandle, CURLOPT_PRIVATE, cb_data);
curl_easy_setopt (ehandle, CURLOPT_HTTPHEADER, cb_data->request_headers);
+ curl_easy_setopt (ehandle, CURLOPT_INTERFACE, cb_data->ifspec);
curl_multi_add_handle (priv->curl_mhandle, ehandle);
cb_data->timeout_id = g_timeout_add_seconds (30, timeout_cb, cb_data);
- priv->initial_check_obsoleted = TRUE;
-
- _LOGD ("check: send %s request to '%s'", IS_PERIODIC_CHECK (callback) ? "periodic " : "", priv->uri);
+ _LOG2D ("sending request to '%s'", priv->uri);
return;
} else {
- g_warn_if_fail (!IS_PERIODIC_CHECK (callback));
- _LOGD ("check: faking request. Connectivity check disabled");
+ _LOGD ("(%s) faking request. Connectivity check disabled", iface);
}
-#else
- _LOGD ("check: faking request. Compiled without connectivity-check support");
-#endif
- g_simple_async_result_set_op_res_gssize (simple, priv->state);
+ g_simple_async_result_set_op_res_gssize (simple, NM_CONNECTIVITY_UNKNOWN);
g_simple_async_result_complete_in_idle (simple);
g_object_unref (simple);
}
@@ -527,117 +397,99 @@ nm_connectivity_check_finish (NMConnectivity *self,
/*****************************************************************************/
-static void
-get_property (GObject *object, guint property_id,
- GValue *value, GParamSpec *pspec)
+static gboolean
+periodic_check (gpointer user_data)
{
- NMConnectivity *self = NM_CONNECTIVITY (object);
- NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
-
- switch (property_id) {
- case PROP_URI:
- g_value_set_string (value, priv->uri);
- break;
- case PROP_INTERVAL:
- g_value_set_uint (value, priv->interval);
- break;
- case PROP_RESPONSE:
- if (priv->response)
- g_value_set_string (value, priv->response);
- else
- g_value_set_static_string (value, NM_CONFIG_DEFAULT_CONNECTIVITY_RESPONSE);
- break;
- case PROP_STATE:
- g_value_set_uint (value, priv->state);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
- break;
- }
+ g_signal_emit (NM_CONNECTIVITY (user_data), signals[PERIODIC_CHECK], 0);
+ return G_SOURCE_CONTINUE;
}
static void
-set_property (GObject *object, guint property_id,
- const GValue *value, GParamSpec *pspec)
+update_config (NMConnectivity *self, NMConfigData *config_data)
{
- NMConnectivity *self = NM_CONNECTIVITY (object);
NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
const char *uri, *response;
guint interval;
- gboolean changed;
-
- switch (property_id) {
- case PROP_URI:
- uri = g_value_get_string (value);
- if (uri && !*uri)
+ gboolean changed = FALSE;
+
+ /* Set the URI. */
+ uri = nm_config_data_get_connectivity_uri (config_data);
+ if (uri && !*uri)
+ uri = NULL;
+ changed = g_strcmp0 (uri, priv->uri) != 0;
+ if (uri) {
+ char *scheme = g_uri_parse_scheme (uri);
+
+ if (!scheme) {
+ _LOGE ("invalid URI '%s' for connectivity check.", uri);
+ uri = NULL;
+ } else if (strcasecmp (scheme, "https") == 0) {
+ _LOGW ("use of HTTPS for connectivity checking is not reliable and is discouraged (URI: %s)", uri);
+ } else if (strcasecmp (scheme, "http") != 0) {
+ _LOGE ("scheme of '%s' uri does't use a scheme that is allowed for connectivity check.", uri);
uri = NULL;
- changed = g_strcmp0 (uri, priv->uri) != 0;
-#if WITH_CONCHECK
- if (uri) {
- char *scheme = g_uri_parse_scheme (uri);
-
- if (!scheme) {
- _LOGE ("invalid URI '%s' for connectivity check.", uri);
- uri = NULL;
- } else if (strcasecmp (scheme, "https") == 0) {
- _LOGW ("use of HTTPS for connectivity checking is not reliable and is discouraged (URI: %s)", uri);
- } else if (strcasecmp (scheme, "http") != 0) {
- _LOGE ("scheme of '%s' uri does't use a scheme that is allowed for connectivity check.", uri);
- uri = NULL;
- }
-
- if (scheme)
- g_free (scheme);
- }
-#endif
- if (changed) {
- g_free (priv->uri);
- priv->uri = g_strdup (uri);
- _reschedule_periodic_checks (self, TRUE);
- }
- break;
- case PROP_INTERVAL:
- interval = g_value_get_uint (value);
- if (priv->interval != interval) {
- priv->interval = interval;
- _reschedule_periodic_checks (self, TRUE);
- }
- break;
- case PROP_RESPONSE:
- response = g_value_get_string (value);
- if (g_strcmp0 (response, priv->response) != 0) {
- /* a response %NULL means, NM_CONFIG_DEFAULT_CONNECTIVITY_RESPONSE. Any other response
- * (including "") is accepted. */
- g_free (priv->response);
- priv->response = g_strdup (response);
- _reschedule_periodic_checks (self, TRUE);
}
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
- break;
+
+ if (scheme)
+ g_free (scheme);
+ }
+ if (changed) {
+ g_free (priv->uri);
+ priv->uri = g_strdup (uri);
}
-}
-/*****************************************************************************/
+ /* Set the interval. */
+ interval = nm_config_data_get_connectivity_interval (config_data);
+ if (priv->interval != interval) {
+ priv->interval = interval;
+ changed = TRUE;
+ }
+ /* Set the response. */
+ response = nm_config_data_get_connectivity_response (config_data);
+ if (g_strcmp0 (response, priv->response) != 0) {
+ /* a response %NULL means, NM_CONFIG_DEFAULT_CONNECTIVITY_RESPONSE. Any other response
+ * (including "") is accepted. */
+ g_free (priv->response);
+ priv->response = g_strdup (response);
+ changed = TRUE;
+ }
+
+ if (changed) {
+ nm_clear_g_source (&priv->periodic_check_id);
+ priv->periodic_check_id = g_timeout_add_seconds (priv->interval, periodic_check, self);
+ }
+}
+
+static void
+config_changed_cb (NMConfig *config,
+ NMConfigData *config_data,
+ NMConfigChangeFlags changes,
+ NMConfigData *old_data,
+ NMConnectivity *self)
+{
+ update_config (self, config_data);
+}
static void
nm_connectivity_init (NMConnectivity *self)
{
NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
-#if WITH_CONCHECK
CURLcode retv;
-#endif
- priv->state = NM_CONNECTIVITY_NONE;
-#if WITH_CONCHECK
+ priv->config = g_object_ref (nm_config_get ());
+ update_config (self, nm_config_get_data (priv->config));
+ g_signal_connect (G_OBJECT (priv->config),
+ NM_CONFIG_SIGNAL_CONFIG_CHANGED,
+ G_CALLBACK (config_changed_cb),
+ self);
+
retv = curl_global_init (CURL_GLOBAL_ALL);
if (retv == CURLE_OK)
priv->curl_mhandle = curl_multi_init ();
if (priv->curl_mhandle == NULL) {
- _LOGE ("Unable to init cURL, connectivity check will not work");
+ _LOGE ("cnable to init cURL, connectivity check will not work");
return;
}
@@ -646,19 +498,6 @@ nm_connectivity_init (NMConnectivity *self)
curl_multi_setopt (priv->curl_mhandle, CURLMOPT_TIMERFUNCTION, multi_timer_cb);
curl_multi_setopt (priv->curl_mhandle, CURLMOPT_TIMERDATA, self);
curl_multi_setopt (priv->curl_mhandle, CURLOPT_VERBOSE, 1);
-#endif
-}
-
-NMConnectivity *
-nm_connectivity_new (const char *uri,
- guint interval,
- const char *response)
-{
- return g_object_new (NM_TYPE_CONNECTIVITY,
- NM_CONNECTIVITY_URI, uri,
- NM_CONNECTIVITY_INTERVAL, interval,
- NM_CONNECTIVITY_RESPONSE, response,
- NULL);
}
static void
@@ -670,12 +509,14 @@ dispose (GObject *object)
g_clear_pointer (&priv->uri, g_free);
g_clear_pointer (&priv->response, g_free);
-#if WITH_CONCHECK
+ if (priv->config) {
+ g_signal_handlers_disconnect_by_func (priv->config, config_changed_cb, self);
+ g_clear_object (&priv->config);
+ }
+
curl_multi_cleanup (priv->curl_mhandle);
curl_global_cleanup ();
-
- nm_clear_g_source (&priv->check_id);
-#endif
+ nm_clear_g_source (&priv->periodic_check_id);
G_OBJECT_CLASS (nm_connectivity_parent_class)->dispose (object);
}
@@ -685,36 +526,12 @@ nm_connectivity_class_init (NMConnectivityClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
- object_class->set_property = set_property;
- object_class->get_property = get_property;
- object_class->dispose = dispose;
+ signals[PERIODIC_CHECK] =
+ g_signal_new (NM_CONNECTIVITY_PERIODIC_CHECK,
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 0);
- obj_properties[PROP_URI] =
- g_param_spec_string (NM_CONNECTIVITY_URI, "", "",
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT |
- G_PARAM_STATIC_STRINGS);
-
- obj_properties[PROP_INTERVAL] =
- g_param_spec_uint (NM_CONNECTIVITY_INTERVAL, "", "",
- 0, G_MAXUINT, NM_CONFIG_DEFAULT_CONNECTIVITY_INTERVAL,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT |
- G_PARAM_STATIC_STRINGS);
-
- obj_properties[PROP_RESPONSE] =
- g_param_spec_string (NM_CONNECTIVITY_RESPONSE, "", "",
- NM_CONFIG_DEFAULT_CONNECTIVITY_RESPONSE,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT |
- G_PARAM_STATIC_STRINGS);
-
- obj_properties[PROP_STATE] =
- g_param_spec_uint (NM_CONNECTIVITY_STATE, "", "",
- NM_CONNECTIVITY_UNKNOWN, NM_CONNECTIVITY_FULL, NM_CONNECTIVITY_UNKNOWN,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS);
-
- g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
+ object_class->dispose = dispose;
}
diff --git a/src/nm-connectivity.h b/src/nm-connectivity.h
index 6900bd0fa8..0522381a91 100644
--- a/src/nm-connectivity.h
+++ b/src/nm-connectivity.h
@@ -16,6 +16,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2011 Thomas Bechtold <thomasbechtold@jpberlin.de>
+ * Copyright (C) 2017 Red Hat, Inc.
*/
#ifndef __NETWORKMANAGER_CONNECTIVITY_H__
@@ -30,27 +31,18 @@
#define NM_IS_CONNECTIVITY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_CONNECTIVITY))
#define NM_CONNECTIVITY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_CONNECTIVITY, NMConnectivityClass))
-#define NM_CONNECTIVITY_URI "uri"
-#define NM_CONNECTIVITY_INTERVAL "interval"
-#define NM_CONNECTIVITY_RESPONSE "response"
-#define NM_CONNECTIVITY_STATE "state"
+#define NM_CONNECTIVITY_PERIODIC_CHECK "nm-connectivity-periodic-check"
typedef struct _NMConnectivityClass NMConnectivityClass;
GType nm_connectivity_get_type (void);
-const char *nm_connectivity_state_to_string (NMConnectivityState state);
-
-NMConnectivity *nm_connectivity_new (const char *uri,
- guint interval,
- const char *response);
+NMConnectivity *nm_connectivity_get (void);
-void nm_connectivity_set_online (NMConnectivity *self,
- gboolean online);
-
-NMConnectivityState nm_connectivity_get_state (NMConnectivity *self);
+const char *nm_connectivity_state_to_string (NMConnectivityState state);
void nm_connectivity_check_async (NMConnectivity *self,
+ const char *iface,
GAsyncReadyCallback callback,
gpointer user_data);
NMConnectivityState nm_connectivity_check_finish (NMConnectivity *self,
diff --git a/src/nm-dispatcher.c b/src/nm-dispatcher.c
index 1bb26e1c45..0d482e0cad 100644
--- a/src/nm-dispatcher.c
+++ b/src/nm-dispatcher.c
@@ -15,7 +15,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Copyright (C) 2004 - 2012 Red Hat, Inc.
+ * Copyright (C) 2004 - 2017 Red Hat, Inc.
* Copyright (C) 2005 - 2008 Novell, Inc.
*/
@@ -507,6 +507,7 @@ _dispatcher_call (NMDispatcherAction action,
GError *error = NULL;
static guint request_counter = 0;
guint reqid = ++request_counter;
+ const char *connectivity_state_string = "UNKNOWN";
if (!dispatcher_proxy)
return FALSE;
@@ -616,6 +617,10 @@ _dispatcher_call (NMDispatcherAction action,
if (!device_dhcp6_props)
device_dhcp6_props = g_variant_ref_sink (g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0));
+#if WITH_CONCHECK
+ connectivity_state_string = nm_connectivity_state_to_string (connectivity_state);
+#endif
+
/* Send the action to the dispatcher */
if (blocking) {
GVariant *ret;
@@ -632,7 +637,7 @@ _dispatcher_call (NMDispatcherAction action,
&device_ip6_props,
device_dhcp4_props,
device_dhcp6_props,
- nm_connectivity_state_to_string (connectivity_state),
+ connectivity_state_string,
vpn_iface ? vpn_iface : "",
&vpn_proxy_props,
&vpn_ip4_props,
@@ -670,7 +675,7 @@ _dispatcher_call (NMDispatcherAction action,
&device_ip6_props,
device_dhcp4_props,
device_dhcp6_props,
- nm_connectivity_state_to_string (connectivity_state),
+ connectivity_state_string,
vpn_iface ? vpn_iface : "",
&vpn_proxy_props,
&vpn_ip4_props,
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 5f06f23ff5..3b873bd4d4 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -16,7 +16,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2007 - 2009 Novell, Inc.
- * Copyright (C) 2007 - 2012 Red Hat, Inc.
+ * Copyright (C) 2007 - 2017 Red Hat, Inc.
*/
#include "nm-default.h"
@@ -54,6 +54,7 @@
#include "nm-dbus-compat.h"
#include "nm-checkpoint.h"
#include "nm-checkpoint-manager.h"
+#include "nm-dispatcher.h"
#include "NetworkManagerUtils.h"
#include "introspection/org.freedesktop.NetworkManager.h"
@@ -117,7 +118,7 @@ typedef struct {
GSList *devices;
NMState state;
NMConfig *config;
- NMConnectivity *connectivity;
+ NMConnectivityState connectivity_state;
NMPolicy *policy;
@@ -497,12 +498,6 @@ active_connection_get_by_path (NMManager *manager, const char *path)
static void
_config_changed_cb (NMConfig *config, NMConfigData *config_data, NMConfigChangeFlags changes, NMConfigData *old_data, NMManager *self)
{
- g_object_set (NM_MANAGER_GET_PRIVATE (self)->connectivity,
- NM_CONNECTIVITY_URI, nm_config_data_get_connectivity_uri (config_data),
- NM_CONNECTIVITY_INTERVAL, nm_config_data_get_connectivity_interval (config_data),
- NM_CONNECTIVITY_RESPONSE, nm_config_data_get_connectivity_response (config_data),
- NULL);
-
if (NM_FLAGS_HAS (changes, NM_CONFIG_CHANGE_GLOBAL_DNS_CONFIG))
_notify (self, PROP_GLOBAL_DNS_CONFIGURATION);
}
@@ -770,27 +765,8 @@ set_state (NMManager *self, NMState state)
g_signal_emit (self, signals[STATE_CHANGED], 0, priv->state);
}
-static void
-checked_connectivity (GObject *object, GAsyncResult *result, gpointer user_data)
-{
- NMManager *manager = user_data;
- NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
- NMConnectivityState connectivity;
-
- if (priv->state == NM_STATE_CONNECTING || priv->state == NM_STATE_CONNECTED_SITE) {
- connectivity = nm_connectivity_check_finish (priv->connectivity, result, NULL);
-
- if (connectivity == NM_CONNECTIVITY_FULL)
- set_state (manager, NM_STATE_CONNECTED_GLOBAL);
-
- _notify (manager, PROP_CONNECTIVITY);
- }
-
- g_object_unref (manager);
-}
-
static NMState
-find_best_device_state (NMManager *manager, gboolean *force_connectivity_check)
+find_best_device_state (NMManager *manager)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
NMState best_state = NM_STATE_DISCONNECTED;
@@ -804,11 +780,10 @@ find_best_device_state (NMManager *manager, gboolean *force_connectivity_check)
case NM_ACTIVE_CONNECTION_STATE_ACTIVATED:
if ( nm_active_connection_get_default (ac)
|| nm_active_connection_get_default6 (ac)) {
- if (nm_connectivity_get_state (priv->connectivity) == NM_CONNECTIVITY_FULL)
+ if (priv->connectivity_state)
return NM_STATE_CONNECTED_GLOBAL;
best_state = NM_STATE_CONNECTED_SITE;
- NM_SET_OUT (force_connectivity_check, TRUE);
} else {
if (best_state < NM_STATE_CONNECTING)
best_state = NM_STATE_CONNECTED_LOCAL;
@@ -866,7 +841,6 @@ nm_manager_update_state (NMManager *manager)
{
NMManagerPrivate *priv;
NMState new_state = NM_STATE_DISCONNECTED;
- gboolean force_connectivity_check = FALSE;
g_return_if_fail (NM_IS_MANAGER (manager));
@@ -875,27 +849,11 @@ nm_manager_update_state (NMManager *manager)
if (manager_sleeping (manager))
new_state = NM_STATE_ASLEEP;
else
- new_state = find_best_device_state (manager, &force_connectivity_check);
-
- nm_connectivity_set_online (priv->connectivity, new_state >= NM_STATE_CONNECTED_LOCAL);
-
- if (new_state == NM_STATE_CONNECTED_SITE) {
- /* We have a default route, let's see if we can reach the Internet or a
- * captive portal. */
- force_connectivity_check = TRUE;
- }
-
- if (new_state == NM_STATE_CONNECTED_LOCAL) {
- /* If we just lost a default route, let's retrigger the connectivity check
- * so that the connectivity property would be updated to indicate we can't
- * reach the Internet anymore. */
- force_connectivity_check = TRUE;
- }
+ new_state = find_best_device_state (manager);
- if (force_connectivity_check) {
- nm_connectivity_check_async (priv->connectivity,
- checked_connectivity,
- g_object_ref (manager));
+ if ( new_state >= NM_STATE_CONNECTED_LOCAL
+ && priv->connectivity_state == NM_CONNECTIVITY_FULL) {
+ new_state = NM_STATE_CONNECTED_GLOBAL;
}
set_state (manager, new_state);
@@ -2008,6 +1966,41 @@ device_realized (NMDevice *device,
_notify (self, PROP_DEVICES);
}
+#if WITH_CONCHECK
+static void
+nm_manager_update_connectivity_state (NMManager *self)
+{
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+ NMConnectivityState state = NM_CONNECTIVITY_UNKNOWN;
+ NMDevice *device;
+
+ if (priv->primary_connection) {
+ device = nm_active_connection_get_device (priv->primary_connection);
+ if (device)
+ state = nm_device_get_connectivity_state (device);
+ }
+
+ if (state != priv->connectivity_state) {
+ priv->connectivity_state = state;
+
+ _LOGD (LOGD_CORE, "connectivity checking indicates %s",
+ nm_connectivity_state_to_string (priv->connectivity_state));
+
+ nm_manager_update_state (self);
+ _notify (self, PROP_CONNECTIVITY);
+ nm_dispatcher_call_connectivity (priv->connectivity_state, NULL, NULL, NULL);
+ }
+}
+
+static void
+device_connectivity_changed (NMDevice *device,
+ GParamSpec *pspec,
+ NMManager *self)
+{
+ nm_manager_update_connectivity_state (self);
+}
+#endif
+
static void
_device_realize_finish (NMManager *self,
NMDevice *device,
@@ -2112,6 +2105,12 @@ add_device (NMManager *self, NMDevice *device, GError **error)
G_CALLBACK (device_realized),
self);
+#if WITH_CONCHECK
+ g_signal_connect (device, "notify::" NM_DEVICE_CONNECTIVITY,
+ G_CALLBACK (device_connectivity_changed),
+ self);
+#endif
+
if (priv->startup) {
g_signal_connect (device, "notify::" NM_DEVICE_HAS_PENDING_ACTION,
G_CALLBACK (device_has_pending_action_changed),
@@ -4827,24 +4826,14 @@ impl_manager_get_logging (NMManager *manager,
}
static void
-connectivity_check_done (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
+device_connectivity_done (NMDevice *device, NMConnectivityState state, gpointer user_data)
{
GDBusMethodInvocation *context = user_data;
- NMConnectivityState state;
- GError *error = NULL;
- state = nm_connectivity_check_finish (NM_CONNECTIVITY (object), result, &error);
- if (error)
- g_dbus_method_invocation_take_error (context, error);
- else {
- g_dbus_method_invocation_return_value (context,
- g_variant_new ("(u)", state));
- }
+ g_dbus_method_invocation_return_value (context,
+ g_variant_new ("(u)", state));
}
-
static void
check_connectivity_auth_done_cb (NMAuthChain *chain,
GError *auth_error,
@@ -4872,9 +4861,14 @@ check_connectivity_auth_done_cb (NMAuthChain *chain,
"Not authorized to recheck connectivity");
} else {
/* it's allowed */
- nm_connectivity_check_async (priv->connectivity,
- connectivity_check_done,
- context);
+ if (priv->primary_connection) {
+ nm_device_check_connectivity (nm_active_connection_get_device (priv->primary_connection),
+ device_connectivity_done,
+ context);
+ } else {
+ g_dbus_method_invocation_return_value (context,
+ g_variant_new ("(u)", priv->connectivity_state));
+ }
}
if (error)
@@ -5086,20 +5080,6 @@ handle_firmware_changed (gpointer user_data)
}
static void
-connectivity_changed (NMConnectivity *connectivity,
- GParamSpec *pspec,
- gpointer user_data)
-{
- NMManager *self = NM_MANAGER (user_data);
-
- _LOGD (LOGD_CORE, "connectivity checking indicates %s",
- nm_connectivity_state_to_string (nm_connectivity_get_state (connectivity)));
-
- nm_manager_update_state (self);
- _notify (self, PROP_CONNECTIVITY);
-}
-
-static void
firmware_dir_changed (GFileMonitor *monitor,
GFile *file,
GFile *other_file,
@@ -5173,6 +5153,7 @@ policy_default_device_changed (GObject *object, GParamSpec *pspec, gpointer user
_notify (self, PROP_PRIMARY_CONNECTION);
_notify (self, PROP_PRIMARY_CONNECTION_TYPE);
nm_manager_update_metered (self);
+ nm_manager_update_connectivity_state (self);
}
}
@@ -5906,7 +5887,6 @@ constructed (GObject *object)
{
NMManager *self = NM_MANAGER (object);
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
- NMConfigData *config_data;
const NMConfigState *state;
G_OBJECT_CLASS (nm_manager_parent_class)->constructed (object);
@@ -5949,13 +5929,6 @@ constructed (GObject *object)
G_CALLBACK (_config_changed_cb),
self);
- config_data = nm_config_get_data (priv->config);
- priv->connectivity = nm_connectivity_new (nm_config_data_get_connectivity_uri (config_data),
- nm_config_data_get_connectivity_interval (config_data),
- nm_config_data_get_connectivity_response (config_data));
- g_signal_connect (priv->connectivity, "notify::" NM_CONNECTIVITY_STATE,
- G_CALLBACK (connectivity_changed), self);
-
state = nm_config_state_get (priv->config);
priv->net_enabled = state->net_enabled;
@@ -6111,7 +6084,7 @@ get_property (GObject *object, guint prop_id,
nm_utils_g_value_set_object_path_array (value, priv->active_connections, NULL, NULL);
break;
case PROP_CONNECTIVITY:
- g_value_set_uint (value, nm_connectivity_get_state (priv->connectivity));
+ g_value_set_uint (value, priv->connectivity_state);
break;
case PROP_PRIMARY_CONNECTION:
nm_utils_g_value_set_object_path (value, priv->primary_connection);
@@ -6240,10 +6213,6 @@ dispose (GObject *object)
g_signal_handlers_disconnect_by_func (priv->config, _config_changed_cb, manager);
g_clear_object (&priv->config);
}
- if (priv->connectivity) {
- g_signal_handlers_disconnect_by_func (priv->connectivity, connectivity_changed, manager);
- g_clear_object (&priv->connectivity);
- }
g_free (priv->hostname);