diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index cc3df54ae8..9b9584ce71 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -180,6 +180,7 @@ enum { REMOVED, RECHECK_AUTO_ACTIVATE, RECHECK_ASSUME, + CONNECTIVITY_CHANGED, LAST_SIGNAL, }; static guint signals[LAST_SIGNAL] = { 0 }; @@ -631,6 +632,8 @@ static void _set_mtu (NMDevice *self, guint32 mtu); static void _commit_mtu (NMDevice *self, const NMIP4Config *config); static void _cancel_activation (NMDevice *self); +static void concheck_update_state (NMDevice *self, NMConnectivityState state, gboolean is_periodic); + /*****************************************************************************/ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (queued_state_to_string, NMDeviceState, @@ -2389,6 +2392,9 @@ nm_device_check_connectivity_update_interval (NMDevice *self) if (!new_interval) { /* this will cancel any potentially pending timeout. */ concheck_periodic_schedule_do (self, 0); + + /* also update the fake connectivity state. */ + concheck_update_state (self, NM_CONNECTIVITY_FAKE, TRUE); return; } @@ -2418,6 +2424,10 @@ concheck_update_state (NMDevice *self, NMConnectivityState state, gboolean is_pe /* If the connectivity check is disabled and we obtain a fake * result, make an optimistic guess. */ if (priv->state == NM_DEVICE_STATE_ACTIVATED) { + /* FIXME: the fake connectivity state depends on the availablility of + * a default route. However, we have no mechanism that rechecks the + * value if a device route appears/disappears after the device + * was activated. */ if (nm_device_get_best_default_route (self, AF_UNSPEC)) state = NM_CONNECTIVITY_FULL; else @@ -2457,6 +2467,7 @@ concheck_update_state (NMDevice *self, NMConnectivityState state, gboolean is_pe priv->connectivity_state = state; _notify (self, PROP_CONNECTIVITY); + g_signal_emit (self, signals[CONNECTIVITY_CHANGED], 0); if ( priv->state == NM_DEVICE_STATE_ACTIVATED && !nm_device_sys_iface_state_is_external (self)) { @@ -2499,7 +2510,8 @@ concheck_cb (NMConnectivity *connectivity, GError *error, gpointer user_data) { - gs_unref_object NMDevice *self = NULL; + _nm_unused gs_unref_object NMDevice *self_keep_alive = NULL; + NMDevice *self; NMDevicePrivate *priv; NMDeviceConnectivityHandle *handle; NMDeviceConnectivityHandle *other_handle; @@ -2511,20 +2523,24 @@ concheck_cb (NMConnectivity *connectivity, 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, "", "")); + self = handle->self; 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, * nothing to do. */ + _LOGT (LOGD_CONCHECK, "connectivity: complete check (seq:%llu, obsoleted by later request returning)", + (long long unsigned) handle->seq); return; } + self_keep_alive = g_object_ref (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, "", "")); + /* we keep NMConnectivity instance alive. It cannot be disposing. */ nm_assert (!nm_utils_error_is_cancelled (error, TRUE)); @@ -15739,4 +15755,12 @@ nm_device_class_init (NMDeviceClass *klass) G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); + + signals[CONNECTIVITY_CHANGED] = + g_signal_new (NM_DEVICE_CONNECTIVITY_CHANGED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); } diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index fd266d69ab..66720f015c 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -135,6 +135,7 @@ nm_device_state_reason_check (NMDeviceStateReason reason) #define NM_DEVICE_STATE_CHANGED "state-changed" #define NM_DEVICE_LINK_INITIALIZED "link-initialized" #define NM_DEVICE_AUTOCONNECT_ALLOWED "autoconnect-allowed" +#define NM_DEVICE_CONNECTIVITY_CHANGED "connectivity-changed" #define NM_DEVICE_STATISTICS_REFRESH_RATE_MS "refresh-rate-ms" #define NM_DEVICE_STATISTICS_TX_BYTES "tx-bytes" diff --git a/src/nm-dispatcher.c b/src/nm-dispatcher.c index 29bf5c9748..2f88d468eb 100644 --- a/src/nm-dispatcher.c +++ b/src/nm-dispatcher.c @@ -631,9 +631,7 @@ _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) { diff --git a/src/nm-manager.c b/src/nm-manager.c index fcebcfd314..034675b9e8 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -1142,26 +1142,6 @@ _nm_state_to_string (NMState state) } } -static void -set_state (NMManager *self, NMState state) -{ - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - - if (priv->state == state) - return; - - priv->state = state; - - _LOGI (LOGD_CORE, "NetworkManager state is now %s", _nm_state_to_string (state)); - - _notify (self, PROP_STATE); - nm_dbus_object_emit_signal (NM_DBUS_OBJECT (self), - &interface_info_manager, - &signal_info_state_changed, - "(u)", - (guint32) priv->state); -} - static NMState find_best_device_state (NMManager *manager) { @@ -1232,26 +1212,38 @@ nm_manager_update_metered (NMManager *self) } static void -nm_manager_update_state (NMManager *manager) +nm_manager_update_state (NMManager *self) { NMManagerPrivate *priv; NMState new_state = NM_STATE_DISCONNECTED; - g_return_if_fail (NM_IS_MANAGER (manager)); + g_return_if_fail (NM_IS_MANAGER (self)); - priv = NM_MANAGER_GET_PRIVATE (manager); + priv = NM_MANAGER_GET_PRIVATE (self); - if (manager_sleeping (manager)) + if (manager_sleeping (self)) new_state = NM_STATE_ASLEEP; else - new_state = find_best_device_state (manager); + new_state = find_best_device_state (self); if ( new_state >= NM_STATE_CONNECTED_LOCAL && priv->connectivity_state == NM_CONNECTIVITY_FULL) { new_state = NM_STATE_CONNECTED_GLOBAL; } - set_state (manager, new_state); + if (priv->state == new_state) + return; + + priv->state = new_state; + + _LOGI (LOGD_CORE, "NetworkManager state is now %s", _nm_state_to_string (new_state)); + + _notify (self, PROP_STATE); + nm_dbus_object_emit_signal (NM_DBUS_OBJECT (self), + &interface_info_manager, + &signal_info_state_changed, + "(u)", + (guint32) priv->state); } static void @@ -2512,7 +2504,6 @@ device_realized (NMDevice *device, static void device_connectivity_changed (NMDevice *device, - GParamSpec *pspec, NMManager *self) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); @@ -2520,11 +2511,20 @@ device_connectivity_changed (NMDevice *device, NMConnectivityState state; NMDevice *dev; - c_list_for_each_entry (dev, &priv->devices_lst_head, devices_lst) { - state = nm_device_get_connectivity_state (dev); - if (state > best_state) + best_state = nm_device_get_connectivity_state (device); + if (best_state < NM_CONNECTIVITY_FULL) { + c_list_for_each_entry (dev, &priv->devices_lst_head, devices_lst) { + state = nm_device_get_connectivity_state (dev); + if (state <= best_state) + continue; best_state = state; + if (best_state >= NM_CONNECTIVITY_FULL) { + /* it doesn't get better than this. */ + break; + } + } } + nm_assert (best_state <= NM_CONNECTIVITY_FULL); if (best_state != priv->connectivity_state) { priv->connectivity_state = best_state; @@ -2646,7 +2646,7 @@ add_device (NMManager *self, NMDevice *device, GError **error) G_CALLBACK (device_realized), self); - g_signal_connect (device, "notify::" NM_DEVICE_CONNECTIVITY, + g_signal_connect (device, NM_DEVICE_CONNECTIVITY_CHANGED, G_CALLBACK (device_connectivity_changed), self);