Commit 0a62a0e9 authored by Thomas Haller's avatar Thomas Haller
Browse files

connectivity: schedule connectivity timers per-device and probe for short outages

It might happen, that connectivitiy is lost only for a moment and
returns soon after. Based on that assumption, when we loose connectivity
we want to have a probe interval where we check for returning
connectivity more frequently.

For that, we handle tracking of the timeouts per-device.

The intervall shall start with 1 seconds, and double the interval time until
the full interval is reached. Actually, due to the implementation, it's unlikely
that we already perform the second check 1 second later. That is because commonly
the first check returns before the one second timeout is reached and bumps the
interval to 2 seconds right away.

Also, we go through extra lengths so that manual connectivity check
delay the periodic checks. By being more smart about that, we can reduce
the number of connectivity checks, but still keeping the promise to
check at least within the requested interval.

The complexity of book keeping the timeouts is remarkable. But I think
it is worth the effort and we should try hard to

 - have a connectivity state as accurate as possible. Clearly,
   connectivity checking means that we probing, so being more intelligent
   about timeout and backoff timers can result in a better connectivity
   state. The connectivity state is important because we use it for
   the default-route penaly and the GUI indicates bad connectivity.

 - be intelligent about avoiding redundant connectivity checks. While
   we want to check often to get an accurate connectivity state, we
   also want to minimize the number of HTTP requests, in case the
   connectivity is established and suppossedly stable.

Also, perform connectivity checks in every state of the device.
Even if a device is disconnected, it still might have connectivity,
for example if the user externally adds an IP address on an unmanaged
device.

https://bugzilla.gnome.org/show_bug.cgi?id=792240
parent e8e0ef63
......@@ -164,6 +164,7 @@ struct _NMDeviceConnectivityHandle {
gpointer user_data;
NMConnectivityCheckHandle *c_handle;
guint64 seq;
bool is_periodic:1;
};
/*****************************************************************************/
......@@ -543,7 +544,19 @@ typedef struct _NMDevicePrivate {
NMConnectivity *concheck_mgr;
gulong concheck_periodic_id;
/* if periodic checks are enabled, this is the source id for the next check. */
guint concheck_p_cur_id;
/* the currently configured max periodic interval. */
guint concheck_p_max_interval;
/* the current interval. If we are probing, the interval might be lower
* then the configured max interval. */
guint concheck_p_cur_interval;
/* the timestamp, when we last scheduled the timer concheck_p_cur_id with current interval
* concheck_p_cur_interval. */
gint64 concheck_p_cur_basetime_ns;
NMConnectivityState connectivity_state;
......@@ -2185,17 +2198,225 @@ nm_device_get_physical_port_id (NMDevice *self)
/*****************************************************************************/
typedef enum {
CONCHECK_SCHEDULE_UPDATE_INTERVAL,
CONCHECK_SCHEDULE_CHECK_EXTERNAL,
CONCHECK_SCHEDULE_CHECK_PERIODIC,
CONCHECK_SCHEDULE_RETURNED_MIN,
CONCHECK_SCHEDULE_RETURNED_BUMP,
CONCHECK_SCHEDULE_RETURNED_MAX,
} ConcheckScheduleMode;
static NMDeviceConnectivityHandle *concheck_start (NMDevice *self,
NMDeviceConnectivityCallback callback,
gpointer user_data,
gboolean is_periodic);
static void concheck_periodic_schedule_set (NMDevice *self,
ConcheckScheduleMode mode);
static gboolean
concheck_periodic_timeout_cb (gpointer user_data)
{
NMDevice *self = user_data;
concheck_periodic_schedule_set (self, CONCHECK_SCHEDULE_CHECK_PERIODIC);
concheck_start (self, NULL, NULL, TRUE);
return G_SOURCE_CONTINUE;
}
static gboolean
concheck_is_possible (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if ( !nm_device_is_real (self)
|| NM_FLAGS_HAS (priv->unmanaged_flags, NM_UNMANAGED_LOOPBACK))
return FALSE;
/* we enable periodic checks for every device state (except UNKNOWN). Especially with
* unmanaged devices, it is interesting to know whether we have connectivity on that device. */
if (priv->state == NM_DEVICE_STATE_UNKNOWN)
return FALSE;
return TRUE;
}
static gboolean
concheck_periodic_schedule_do (NMDevice *self, gint64 interval_ns)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
gboolean periodic_check_disabled = FALSE;
/* we always cancel whatever was pending. */
if (nm_clear_g_source (&priv->concheck_p_cur_id))
periodic_check_disabled = TRUE;
if (priv->concheck_p_max_interval == 0) {
/* periodic checks are disabled */
goto out;
}
nm_assert (interval_ns >= 0);
if (!concheck_is_possible (self))
goto out;
_LOGT (LOGD_CONCHECK, "connectivity: periodic-check: %sscheduled in %u milliseconds (%u seconds interval)",
periodic_check_disabled ? "re-" : "",
(guint) (interval_ns / NM_UTILS_NS_PER_MSEC),
priv->concheck_p_cur_interval);
nm_assert (priv->concheck_p_cur_interval > 0);
priv->concheck_p_cur_id = g_timeout_add (interval_ns / NM_UTILS_NS_PER_MSEC,
concheck_periodic_timeout_cb,
self);
return TRUE;
out:
if (periodic_check_disabled)
_LOGT (LOGD_CONCHECK, "connectivity: periodic-check: unscheduled");
return FALSE;
}
#define CONCHECK_P_PROBE_INTERVAL 1
static void
concheck_update_state (NMDevice *self, NMConnectivityState state)
concheck_periodic_schedule_set (NMDevice *self,
ConcheckScheduleMode mode)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
gint64 new_expiry, cur_expiry, tdiff;
gint64 now_ns = 0;
if (state == NM_CONNECTIVITY_ERROR)
if (priv->concheck_p_max_interval == 0) {
/* periodic check is disabled. Nothing to do. */
return;
}
/* If the connectivity check is disabled and we obtain a fake
* result, make an optimistic guess. */
if (state == NM_CONNECTIVITY_FAKE) {
if (!priv->concheck_p_cur_id) {
/* we currently don't have a timeout scheduled. No need to reschedule
* another one... */
if (mode == CONCHECK_SCHEDULE_UPDATE_INTERVAL) {
/* ... unless, we are initalizing. In this case, setup the current current
* interval and schedule a perform a check right away. */
priv->concheck_p_cur_interval = NM_MIN (priv->concheck_p_max_interval, CONCHECK_P_PROBE_INTERVAL);
priv->concheck_p_cur_basetime_ns = nm_utils_get_monotonic_timestamp_ns_cached (&now_ns);
if (concheck_periodic_schedule_do (self, priv->concheck_p_cur_interval * NM_UTILS_NS_PER_SECOND))
concheck_start (self, NULL, NULL, TRUE);
}
return;
}
switch (mode) {
case CONCHECK_SCHEDULE_UPDATE_INTERVAL:
/* called with "UPDATE_INTERVAL" and already have a concheck_p_cur_id scheduled. */
if (priv->concheck_p_cur_interval <= priv->concheck_p_max_interval) {
/* we currently have a shorter interval set, then what we now have. Either,
* because we are probing, or because the previous max interval was shorter.
*
* Either way, the current timer is set just fine. Nothing to do. */
return;
}
cur_expiry = priv->concheck_p_cur_basetime_ns + (priv->concheck_p_max_interval * NM_UTILS_NS_PER_SECOND);
priv->concheck_p_cur_interval = priv->concheck_p_max_interval;
priv->concheck_p_cur_basetime_ns = nm_utils_get_monotonic_timestamp_ns_cached (&now_ns);
if (cur_expiry <= now_ns) {
/* the last timer was scheduled longer ago then the new desired interval. It means,
* we must schedule a timer right away */
if (concheck_periodic_schedule_do (self, priv->concheck_p_cur_interval * NM_UTILS_NS_PER_SECOND)) {
concheck_start (self, NULL, NULL, TRUE);
}
} else {
/* we only need to reset the timer. */
concheck_periodic_schedule_do (self, (cur_expiry - now_ns) / NM_UTILS_NS_PER_MSEC);
}
return;
case CONCHECK_SCHEDULE_CHECK_EXTERNAL:
/* a external connectivity check delays our periodic check. We reset the counter. */
priv->concheck_p_cur_basetime_ns = nm_utils_get_monotonic_timestamp_ns_cached (&now_ns);
concheck_periodic_schedule_do (self, priv->concheck_p_cur_interval * NM_UTILS_NS_PER_SECOND);
return;
case CONCHECK_SCHEDULE_CHECK_PERIODIC:
/* we schedule a periodic connectivity check now. We just remember the time when
* we did it. There is nothing to reschedule, it's fine already. */
priv->concheck_p_cur_basetime_ns = nm_utils_get_monotonic_timestamp_ns_cached (&now_ns);
return;
/* we just got an event that we lost connectivity (that is, concheck returned). We reset
* the interval to min/max or increase the probe interval (bump). */
case CONCHECK_SCHEDULE_RETURNED_MIN:
priv->concheck_p_cur_interval = NM_MIN (priv->concheck_p_max_interval, CONCHECK_P_PROBE_INTERVAL);
break;
case CONCHECK_SCHEDULE_RETURNED_MAX:
priv->concheck_p_cur_interval = priv->concheck_p_max_interval;
break;
case CONCHECK_SCHEDULE_RETURNED_BUMP:
priv->concheck_p_cur_interval = NM_MIN (priv->concheck_p_cur_interval * 2, priv->concheck_p_max_interval);
break;
}
/* we are here, because we returned from a connectivity check and adjust the current interval.
*
* But note that we calculate the new timeout based on the time when we scheduled the
* last check, instead of counting from now. The reaons is, that we want that the times
* when we schedule checks be at precise intervals, without including the time it took for
* the connectivity check. */
new_expiry = priv->concheck_p_cur_basetime_ns + (priv->concheck_p_cur_interval * NM_UTILS_NS_PER_SECOND);
tdiff = NM_MAX (new_expiry - nm_utils_get_monotonic_timestamp_ns_cached (&now_ns), 0);
priv->concheck_p_cur_basetime_ns = now_ns - tdiff;
concheck_periodic_schedule_do (self, tdiff);
}
void
nm_device_check_connectivity_update_interval (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
guint new_interval;
new_interval = nm_connectivity_get_interval (concheck_get_mgr (self));
new_interval = NM_MIN (new_interval, 7 *24 * 3600);
if (new_interval != priv->concheck_p_max_interval) {
_LOGT (LOGD_CONCHECK, "connectivity: periodic-check: set interval to %u seconds", new_interval);
priv->concheck_p_max_interval = new_interval;
}
if (!new_interval) {
/* this will cancel any potentially pending timeout. */
concheck_periodic_schedule_do (self, 0);
return;
}
concheck_periodic_schedule_set (self, CONCHECK_SCHEDULE_UPDATE_INTERVAL);
}
static void
concheck_update_state (NMDevice *self, NMConnectivityState state, gboolean is_periodic)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
/* @state is a result of the connectivity check. We only expect a precise
* number of possible values. */
nm_assert (NM_IN_SET (state, NM_CONNECTIVITY_LIMITED,
NM_CONNECTIVITY_PORTAL,
NM_CONNECTIVITY_FULL,
NM_CONNECTIVITY_FAKE,
NM_CONNECTIVITY_ERROR));
if (state == NM_CONNECTIVITY_ERROR) {
/* on error, we don't change the current connectivity state,
* except making UNKNOWN to NONE. */
state = priv->connectivity_state;
if (state == NM_CONNECTIVITY_UNKNOWN)
state = NM_CONNECTIVITY_NONE;
} else if (state == NM_CONNECTIVITY_FAKE) {
/* If the connectivity check is disabled and we obtain a fake
* result, make an optimistic guess. */
if (priv->state == NM_DEVICE_STATE_ACTIVATED) {
if (nm_device_get_best_default_route (self, AF_UNSPEC))
state = NM_CONNECTIVITY_FULL;
......@@ -2205,10 +2426,32 @@ concheck_update_state (NMDevice *self, NMConnectivityState state)
state = NM_CONNECTIVITY_NONE;
}
if (priv->connectivity_state == state)
if (priv->connectivity_state == state) {
/* we got a connectivty update, but the state didn't change. If we were probing,
* we bump the probe frequency. */
if ( is_periodic
&& priv->concheck_p_cur_id)
concheck_periodic_schedule_set (self, CONCHECK_SCHEDULE_RETURNED_BUMP);
return;
}
/* we need to update the probe interval before emitting signals. Emitting
* a signal might call back into NMDevice and change the probe settings.
* So, do that first. */
if (state == NM_CONNECTIVITY_FULL) {
/* we reached full connectivity state. Stop probing by setting the
* interval to the max. */
concheck_periodic_schedule_set (self, CONCHECK_SCHEDULE_RETURNED_MAX);
} else if (priv->connectivity_state == NM_CONNECTIVITY_FULL) {
/* we are about to loose connectivity. (re)start probing by setting
* the timeout interval to the min. */
concheck_periodic_schedule_set (self, CONCHECK_SCHEDULE_RETURNED_MIN);
} else {
if ( is_periodic
&& priv->concheck_p_cur_id)
concheck_periodic_schedule_set (self, CONCHECK_SCHEDULE_RETURNED_BUMP);
}
_LOGD (LOGD_CONCHECK, "state changed from %s to %s",
_LOGD (LOGD_CONCHECK, "connectivity state changed from %s to %s",
nm_connectivity_state_to_string (priv->connectivity_state),
nm_connectivity_state_to_string (state));
priv->connectivity_state = state;
......@@ -2226,34 +2469,6 @@ concheck_update_state (NMDevice *self, NMConnectivityState state)
}
}
static void
concheck_periodic (NMConnectivity *connectivity, NMDevice *self)
{
nm_device_check_connectivity (self, NULL, NULL);
}
static void
concheck_periodic_update (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if ( priv->state == NM_DEVICE_STATE_ACTIVATED
&& nm_device_get_best_default_route (self, AF_UNSPEC)) {
if (!priv->concheck_periodic_id) {
priv->concheck_periodic_id = g_signal_connect (concheck_get_mgr (self),
NM_CONNECTIVITY_PERIODIC_CHECK,
G_CALLBACK (concheck_periodic), self);
nm_device_check_connectivity (self, NULL, NULL);
}
} else {
if (priv->concheck_periodic_id) {
/* The default route has gone off, trigger a final connectivity check. */
nm_clear_g_signal_handler (priv->concheck_mgr, &priv->concheck_periodic_id);
nm_device_check_connectivity (self, NULL, NULL);
}
}
}
static void
concheck_handle_complete (NMDeviceConnectivityHandle *handle,
GError *error)
......@@ -2264,7 +2479,7 @@ concheck_handle_complete (NMDeviceConnectivityHandle *handle,
c_list_unlink (&handle->concheck_lst);
if (handle->c_handle)
nm_connectivity_check_cancel (g_steal_pointer (&handle->c_handle));
nm_connectivity_check_cancel (handle->c_handle);
if (handle->callback) {
handle->callback (handle->self,
......@@ -2291,6 +2506,18 @@ concheck_cb (NMConnectivity *connectivity,
gboolean handle_is_alive;
guint64 seq;
handle = user_data;
nm_assert (handle->c_handle == c_handle);
nm_assert (NM_IS_DEVICE (handle->self));
handle->c_handle = NULL;
self = g_object_ref (handle->self);
_LOGT (LOGD_CONCHECK, "connectivity: complete check (seq:%llu, state:%s%s%s%s)",
(long long unsigned) handle->seq,
nm_connectivity_state_to_string (state),
NM_PRINT_FMT_QUOTED (error, ", error: ", error->message, "", ""));
if (nm_utils_error_is_cancelled (error, FALSE)) {
/* the only place where we nm_connectivity_check_cancel(@c_handle), is
* from inside concheck_handle_event(). This is a recursive call,
......@@ -2301,12 +2528,7 @@ concheck_cb (NMConnectivity *connectivity,
/* we keep NMConnectivity instance alive. It cannot be disposing. */
nm_assert (!nm_utils_error_is_cancelled (error, TRUE));
handle = user_data;
nm_assert (handle->c_handle == c_handle);
handle->c_handle = NULL;
/* keep @self alive, while we invoke callbacks. */
self = g_object_ref (handle->self);
priv = NM_DEVICE_GET_PRIVATE (self);
nm_assert (!handle || c_list_contains (&priv->concheck_lst_head, &handle->concheck_lst));
......@@ -2314,7 +2536,7 @@ concheck_cb (NMConnectivity *connectivity,
seq = handle->seq;
/* first update the new state, and emit signals. */
concheck_update_state (self, state);
concheck_update_state (self, state, handle->is_periodic);
handle_is_alive = FALSE;
......@@ -2361,10 +2583,11 @@ check_handles:
concheck_handle_complete (handle, NULL);
}
NMDeviceConnectivityHandle *
nm_device_check_connectivity (NMDevice *self,
NMDeviceConnectivityCallback callback,
gpointer user_data)
static NMDeviceConnectivityHandle *
concheck_start (NMDevice *self,
NMDeviceConnectivityCallback callback,
gpointer user_data,
gboolean is_periodic)
{
static guint64 seq_counter = 0;
NMDevicePrivate *priv;
......@@ -2379,8 +2602,14 @@ nm_device_check_connectivity (NMDevice *self,
handle->self = self;
handle->callback = callback;
handle->user_data = user_data;
handle->is_periodic = is_periodic;
c_list_link_tail (&priv->concheck_lst_head, &handle->concheck_lst);
_LOGT (LOGD_CONCHECK, "connectivity: start check (seq:%llu%s)",
(long long unsigned) handle->seq,
is_periodic ? ", periodic-check" : "");
handle->c_handle = nm_connectivity_check_start (concheck_get_mgr (self),
nm_device_get_ip_iface (self),
concheck_cb,
......@@ -2388,6 +2617,21 @@ nm_device_check_connectivity (NMDevice *self,
return handle;
}
NMDeviceConnectivityHandle *
nm_device_check_connectivity (NMDevice *self,
NMDeviceConnectivityCallback callback,
gpointer user_data)
{
NMDeviceConnectivityHandle *handle;
if (!concheck_is_possible (self))
return NULL;
concheck_periodic_schedule_set (self, CONCHECK_SCHEDULE_CHECK_EXTERNAL);
handle = concheck_start (self, callback, user_data, FALSE);
return handle;
}
void
nm_device_check_connectivity_cancel (NMDeviceConnectivityHandle *handle)
{
......@@ -10688,8 +10932,6 @@ nm_device_set_ip_config (NMDevice *self,
}
if (IS_IPv4) {
concheck_periodic_update (self);
if (!nm_device_sys_iface_state_is_external_or_assume (self))
ip4_rp_filter_update (self);
}
......@@ -13544,7 +13786,7 @@ _set_state_full (NMDevice *self,
if (ip_config_valid (old_state) && !ip_config_valid (state))
notify_ip_properties (self);
concheck_periodic_update (self);
nm_device_check_connectivity_update_interval (self);
/* Dispose of the cached activation request */
if (req)
......@@ -14711,7 +14953,7 @@ dispose (GObject *object)
g_clear_object (&priv->lldp_listener);
}
nm_clear_g_signal_handler (priv->concheck_mgr, &priv->concheck_periodic_id);
nm_clear_g_source (&priv->concheck_p_cur_id);
G_OBJECT_CLASS (nm_device_parent_class)->dispose (object);
......
......@@ -783,6 +783,8 @@ typedef void (*NMDeviceConnectivityCallback) (NMDevice *self,
GError *error,
gpointer user_data);
void nm_device_check_connectivity_update_interval (NMDevice *self);
NMDeviceConnectivityHandle *nm_device_check_connectivity (NMDevice *self,
NMDeviceConnectivityCallback callback,
gpointer user_data);
......
......@@ -402,8 +402,6 @@ main (int argc, char *argv[])
manager))
goto done;
NM_UTILS_KEEP_ALIVE (manager, nm_connectivity_get (), "NMManager-depends-on-NMConnectivity");
nm_dispatcher_init ();
g_signal_connect (manager, NM_MANAGER_CONFIGURE_QUIT, G_CALLBACK (manager_configure_quit), config);
......
......@@ -81,7 +81,7 @@ struct _NMConnectivityCheckHandle {
};
enum {
PERIODIC_CHECK,
CONFIG_CHANGED,
LAST_SIGNAL
};
......@@ -99,7 +99,6 @@ typedef struct {
struct {
CURLM *curl_mhandle;
guint curl_timer;
guint periodic_check_id;
} concheck;
#endif
} NMConnectivityPrivate;
......@@ -539,21 +538,20 @@ nm_connectivity_check_cancel (NMConnectivityCheckHandle *cb_data)
gboolean
nm_connectivity_check_enabled (NMConnectivity *self)
{
NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
g_return_val_if_fail (NM_IS_CONNECTIVITY (self), FALSE);
return priv->enabled;
return NM_CONNECTIVITY_GET_PRIVATE (self)->enabled;
}
/*****************************************************************************/
#if WITH_CONCHECK
static gboolean
periodic_check (gpointer user_data)
guint
nm_connectivity_get_interval (NMConnectivity *self)
{
g_signal_emit (NM_CONNECTIVITY (user_data), signals[PERIODIC_CHECK], 0);
return G_SOURCE_CONTINUE;
return nm_connectivity_check_enabled (self)
? NM_CONNECTIVITY_GET_PRIVATE (self)->interval
: 0;
}
#endif
static void
update_config (NMConnectivity *self, NMConfigData *config_data)
......@@ -592,6 +590,7 @@ update_config (NMConnectivity *self, NMConfigData *config_data)
/* Set the interval. */
interval = nm_config_data_get_connectivity_interval (config_data);
interval = MIN (interval, (7 * 24 * 3600));
if (priv->interval != interval) {
priv->interval = interval;
changed = TRUE;
......@@ -622,13 +621,8 @@ update_config (NMConnectivity *self, NMConfigData *config_data)
changed = TRUE;
}
#if WITH_CONCHECK
if (changed) {
nm_clear_g_source (&priv->concheck.periodic_check_id);
if (nm_connectivity_check_enabled (self))
priv->concheck.periodic_check_id = g_timeout_add_seconds (priv->interval, periodic_check, self);
}
#endif
if (changed)
g_signal_emit (self, signals[CONFIG_CHANGED], 0);
}
static void
......@@ -699,7 +693,6 @@ again:
curl_multi_cleanup (priv->concheck.curl_mhandle);
curl_global_cleanup ();
nm_clear_g_source (&priv->concheck.periodic_check_id);
#endif
if (priv->config) {
......@@ -715,8 +708,8 @@ nm_connectivity_class_init (NMConnectivityClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
signals[PERIODIC_CHECK] =
g_signal_new (NM_CONNECTIVITY_PERIODIC_CHECK,
signals[CONFIG_CHANGED] =
g_signal_new (NM_CONNECTIVITY_CONFIG_CHANGED,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL,
......
......@@ -34,7 +34,7 @@
#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_PERIODIC_CHECK "nm-connectivity-periodic-check"
#define NM_CONNECTIVITY_CONFIG_CHANGED "config-changed"
typedef struct _NMConnectivityClass NMConnectivityClass;
......@@ -46,6 +46,8 @@ const char *nm_connectivity_state_to_string (NMConnectivityState state);
gboolean nm_connectivity_check_enabled (NMConnectivity *self);
guint nm_connectivity_get_interval (NMConnectivity *self);
typedef struct _NMConnectivityCheckHandle NMConnectivityCheckHandle;
typedef void (*NMConnectivityCheckCallback) (NMConnectivity *self,
......
......@@ -132,10 +132,8 @@ typedef struct {
NMState state;
NMConfig *config;
NMConnectivityState connectivity_state;
NMConnectivity *concheck_mgr;
NMPolicy *policy;
NMHostnameManager *hostname_manager;
struct {
......@@ -170,6 +168,8 @@ typedef struct {
guint devices_inited_id;
NMConnectivityState connectivity_state;
bool startup:1;
bool devices_inited:1;
......@@ -334,6 +334,34 @@ static NM_CACHED_QUARK_FCN ("autoconnect-root", autoconnect_root_quark)
/*****************************************************************************/
static void
concheck_config_changed_cb (NMConnectivity *connectivity,
NMManager *self)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
NMDevice *device;
c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst)
nm_device_check_connectivity_update_interval (device);
}
static NMConnectivity *
concheck_get_mgr (NMManager *self)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
if (G_UNLIKELY (!priv->concheck_mgr)) {
priv->concheck_mgr = g_object_ref (nm_connectivity_get ());
g_signal_connect (priv->concheck_mgr,
NM_CONNECTIVITY_CONFIG_CHANGED,
G_CALLBACK (concheck_config_changed_cb),
self);
}
return priv->concheck_mgr;
}
/*****************************************************************************/
typedef struct {
int ifindex;
guint32 aspired_metric;
......@@ -5527,10 +5555,10 @@ check_connectivity_auth_done_cb (NMAuthChain *chain,
data->remaining = 0;
c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) {
data->remaining++;
nm_device_check_connectivity (device,
device_connectivity_done,
data);
if (nm_device_check_connectivity (device,
device_connectivity_done,
data))
data->remaining++;
}