summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Winship <danw@gnome.org>2013-08-13 17:45:34 -0400
committerDan Winship <danw@gnome.org>2013-08-16 17:27:34 -0400
commitbc091f2f3ea2ee27d012f2332c514516fd61441b (patch)
tree8fb8b00a6b51203564185ae674518cea99887f5b
parentcee676e7048313af32a31b18846f522fff3ec5d5 (diff)
downloadNetworkManager-bc091f2f3ea2ee27d012f2332c514516fd61441b.tar.gz
core: add NMManager:startup property
Add a property on NMManager indicating that it is currently starting up and activating startup-time/boot-time network connections. "startup" is initially TRUE, and becomes FALSE once all NMDevices report that they have no pending activity (eg, trying to activate, waiting for a wifi scan to complete, etc). This is tracked via a new NMDevice:has-pending-activity property, which is maintained partially by the device itself, and partially by other parts of the code.
-rw-r--r--introspection/nm-manager.xml8
-rw-r--r--src/devices/nm-device-olpc-mesh.c7
-rw-r--r--src/devices/nm-device-wifi.c21
-rw-r--r--src/devices/nm-device.c65
-rw-r--r--src/devices/nm-device.h5
-rw-r--r--src/nm-manager.c71
-rw-r--r--src/nm-manager.h1
-rw-r--r--src/nm-policy.c5
8 files changed, 179 insertions, 4 deletions
diff --git a/introspection/nm-manager.xml b/introspection/nm-manager.xml
index 6f3c8cac6a..d9f6a7c3d2 100644
--- a/introspection/nm-manager.xml
+++ b/introspection/nm-manager.xml
@@ -302,6 +302,14 @@
</tp:docstring>
</property>
+ <property name="Startup" type="b" access="read">
+ <tp:docstring>
+ Indicates whether NM is still starting up; this becomes FALSE
+ when NM has finished attempting to activate every connection
+ that it might be able to activate at startup.
+ </tp:docstring>
+ </property>
+
<property name="Version" type="s" access="read">
<tp:docstring>
NetworkManager version.
diff --git a/src/devices/nm-device-olpc-mesh.c b/src/devices/nm-device-olpc-mesh.c
index 4a5c5f949a..8a032e45f0 100644
--- a/src/devices/nm-device-olpc-mesh.c
+++ b/src/devices/nm-device-olpc-mesh.c
@@ -606,11 +606,11 @@ check_companion_cb (gpointer user_data)
nm_device_state_changed (NM_DEVICE (user_data),
NM_DEVICE_STATE_DISCONNECTED,
NM_DEVICE_STATE_REASON_NONE);
- return FALSE;
+ goto done;
}
if (priv->device_added_id != 0)
- return FALSE;
+ goto done;
manager = nm_manager_get ();
@@ -629,6 +629,8 @@ check_companion_cb (gpointer user_data)
g_object_unref (manager);
+ done:
+ nm_device_remove_pending_action (NM_DEVICE (self), "waiting for companion");
return FALSE;
}
@@ -646,6 +648,7 @@ state_changed (NMDevice *device, NMDeviceState new_state,
* transition to DISCONNECTED otherwise wait for our companion.
*/
g_idle_add (check_companion_cb, self);
+ nm_device_add_pending_action (device, "waiting for companion");
break;
case NM_DEVICE_STATE_ACTIVATED:
break;
diff --git a/src/devices/nm-device-wifi.c b/src/devices/nm-device-wifi.c
index cad045e6a5..cffc2c2939 100644
--- a/src/devices/nm-device-wifi.c
+++ b/src/devices/nm-device-wifi.c
@@ -139,6 +139,7 @@ struct _NMDeviceWifiPrivate {
guint8 scan_interval; /* seconds */
guint pending_scan_id;
guint scanlist_cull_id;
+ gboolean requested_scan;
Supplicant supplicant;
WifiData * wifi_data;
@@ -349,6 +350,9 @@ supplicant_interface_acquire (NMDeviceWifi *self)
return FALSE;
}
+ if (nm_supplicant_interface_get_state (priv->supplicant.iface) < NM_SUPPLICANT_INTERFACE_STATE_READY)
+ nm_device_add_pending_action (NM_DEVICE (self), "waiting for supplicant");
+
g_signal_connect (priv->supplicant.iface,
NM_SUPPLICANT_INTERFACE_STATE,
G_CALLBACK (supplicant_iface_state_cb),
@@ -1652,6 +1656,11 @@ request_wireless_scan (gpointer user_data)
gboolean backoff = FALSE;
GPtrArray *ssids = NULL;
+ if (priv->requested_scan) {
+ /* There's already a scan in progress */
+ return FALSE;
+ }
+
if (check_scanning_allowed (self)) {
nm_log_dbg (LOGD_WIFI_SCAN, "(%s): scanning requested",
nm_device_get_iface (NM_DEVICE (self)));
@@ -1679,6 +1688,8 @@ request_wireless_scan (gpointer user_data)
if (nm_supplicant_interface_request_scan (priv->supplicant.iface, ssids)) {
/* success */
backoff = TRUE;
+ priv->requested_scan = TRUE;
+ nm_device_add_pending_action (NM_DEVICE (self), "scan");
}
if (ssids) {
@@ -1764,6 +1775,8 @@ supplicant_iface_scan_done_cb (NMSupplicantInterface *iface,
gboolean success,
NMDeviceWifi *self)
{
+ NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+
nm_log_dbg (LOGD_WIFI_SCAN, "(%s): scan %s",
nm_device_get_iface (NM_DEVICE (self)),
success ? "successful" : "failed");
@@ -1774,6 +1787,11 @@ supplicant_iface_scan_done_cb (NMSupplicantInterface *iface,
* happens when there are new BSSes.
*/
schedule_scanlist_cull (self);
+
+ if (priv->requested_scan) {
+ priv->requested_scan = FALSE;
+ nm_device_remove_pending_action (NM_DEVICE (self), "scan");
+ }
}
@@ -2321,6 +2339,9 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface,
/* Request a scan to get latest results */
cancel_pending_scan (self);
request_wireless_scan (self);
+
+ if (old_state < NM_SUPPLICANT_INTERFACE_STATE_READY)
+ nm_device_remove_pending_action (device, "waiting for supplicant");
break;
case NM_SUPPLICANT_INTERFACE_STATE_COMPLETED:
remove_supplicant_interface_error_handler (self);
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 14ca2e1aab..a4c3ba2fea 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -130,6 +130,7 @@ enum {
PROP_AVAILABLE_CONNECTIONS,
PROP_IS_MASTER,
PROP_HW_ADDRESS,
+ PROP_HAS_PENDING_ACTION,
LAST_PROP
};
@@ -180,6 +181,7 @@ typedef struct {
NMDeviceStateReason state_reason;
QueuedState queued_state;
guint queued_ip_config_id;
+ guint pending_actions;
char * udi;
char * path;
@@ -5180,6 +5182,9 @@ get_property (GObject *object, guint prop_id,
else
g_value_set_string (value, NULL);
break;
+ case PROP_HAS_PENDING_ACTION:
+ g_value_set_boolean (value, nm_device_has_pending_action (self));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -5440,6 +5445,14 @@ nm_device_class_init (NMDeviceClass *klass)
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property
+ (object_class, PROP_HAS_PENDING_ACTION,
+ g_param_spec_boolean (NM_DEVICE_HAS_PENDING_ACTION,
+ "Has pending action",
+ "Has pending action",
+ FALSE,
+ G_PARAM_READABLE));
+
/* Signals */
signals[STATE_CHANGED] =
g_signal_new ("state-changed",
@@ -5666,6 +5679,13 @@ reason_to_string (NMDeviceStateReason reason)
return "unknown";
}
+static inline gboolean
+state_implies_pending_action (NMDeviceState state)
+{
+ return ( state >= NM_DEVICE_STATE_PREPARE
+ && state < NM_DEVICE_STATE_ACTIVATED);
+}
+
void
nm_device_state_changed (NMDevice *device,
NMDeviceState state,
@@ -5697,6 +5717,10 @@ nm_device_state_changed (NMDevice *device,
priv->state = state;
priv->state_reason = reason;
+ if ( state_implies_pending_action (state)
+ && !state_implies_pending_action (old_state))
+ nm_device_add_pending_action (device, "activation");
+
nm_log_info (LOGD_DEVICE, "(%s): device state change: %s -> %s (reason '%s') [%d %d %d]",
nm_device_get_iface (device),
state_to_string (old_state),
@@ -5838,6 +5862,10 @@ nm_device_state_changed (NMDevice *device,
if (req)
g_object_unref (req);
+ if ( state_implies_pending_action (old_state)
+ && !state_implies_pending_action (state))
+ nm_device_remove_pending_action (device, "activation");
+
priv->in_state_changed = FALSE;
}
@@ -5864,6 +5892,7 @@ queued_set_state (gpointer user_data)
nm_device_queued_state_clear (self);
nm_device_state_changed (self, new_state, new_reason);
+ nm_device_remove_pending_action (self, "queued state change");
} else {
g_warn_if_fail (priv->queued_state.state == NM_DEVICE_STATE_UNKNOWN);
g_warn_if_fail (priv->queued_state.reason == NM_DEVICE_STATE_REASON_NONE);
@@ -5896,6 +5925,7 @@ nm_device_queue_state (NMDevice *self,
priv->queued_state.state = state;
priv->queued_state.reason = reason;
priv->queued_state.id = g_idle_add (queued_set_state, self);
+ nm_device_add_pending_action (self, "queued state change");
nm_log_dbg (LOGD_DEVICE, "(%s): queued state change to %s due to %s (id %d)",
nm_device_get_iface (self), state_to_string (state), reason_to_string (reason),
@@ -5923,6 +5953,7 @@ nm_device_queued_state_clear (NMDevice *self)
nm_log_dbg (LOGD_DEVICE, "(%s): clearing queued state transition (id %d)",
nm_device_get_iface (self), priv->queued_state.id);
g_source_remove (priv->queued_state.id);
+ nm_device_remove_pending_action (self, "queued state change");
}
memset (&priv->queued_state, 0, sizeof (priv->queued_state));
}
@@ -6515,3 +6546,37 @@ nm_device_update_hw_address (NMDevice *dev)
return changed;
}
+
+void
+nm_device_add_pending_action (NMDevice *device, const char *action)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
+
+ priv->pending_actions++;
+ nm_log_dbg (LOGD_DEVICE, "(%s): add_pending_action (%d): %s",
+ nm_device_get_iface (device), priv->pending_actions, action);
+
+ if (priv->pending_actions == 1)
+ g_object_notify (G_OBJECT (device), NM_DEVICE_HAS_PENDING_ACTION);
+}
+
+void
+nm_device_remove_pending_action (NMDevice *device, const char *action)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
+
+ priv->pending_actions--;
+ nm_log_dbg (LOGD_DEVICE, "(%s): remove_pending_action (%d): %s",
+ nm_device_get_iface (device), priv->pending_actions, action);
+
+ if (priv->pending_actions == 0)
+ g_object_notify (G_OBJECT (device), NM_DEVICE_HAS_PENDING_ACTION);
+}
+
+gboolean
+nm_device_has_pending_action (NMDevice *device)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
+
+ return priv->pending_actions > 0;
+}
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index 9815d2d407..e3ac2ab659 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -65,6 +65,7 @@
#define NM_DEVICE_IFINDEX "ifindex" /* Internal only */
#define NM_DEVICE_IS_MASTER "is-master" /* Internal only */
#define NM_DEVICE_HW_ADDRESS "hw-address" /* Internal only */
+#define NM_DEVICE_HAS_PENDING_ACTION "has-pending-action" /* Internal only */
/* Internal signals */
#define NM_DEVICE_AUTH_REQUEST "auth-request"
@@ -315,6 +316,10 @@ void nm_device_set_connection_provider (NMDevice *device, NMConnectionProvider *
gboolean nm_device_supports_vlans (NMDevice *device);
+void nm_device_add_pending_action (NMDevice *device, const char *action);
+void nm_device_remove_pending_action (NMDevice *device, const char *action);
+gboolean nm_device_has_pending_action (NMDevice *device);
+
G_END_DECLS
/* For testing only */
diff --git a/src/nm-manager.c b/src/nm-manager.c
index d12db94aaf..2ed174e38e 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -258,6 +258,7 @@ typedef struct {
GHashTable *nm_bridges;
+ gboolean startup;
gboolean disposed;
} NMManagerPrivate;
@@ -285,6 +286,7 @@ enum {
PROP_0,
PROP_VERSION,
PROP_STATE,
+ PROP_STARTUP,
PROP_NETWORKING_ENABLED,
PROP_WIRELESS_ENABLED,
PROP_WIRELESS_HARDWARE_ENABLED,
@@ -582,9 +584,7 @@ manager_device_state_changed (NMDevice *device,
gpointer user_data)
{
NMManager *self = NM_MANAGER (user_data);
-#if WITH_CONCHECK
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-#endif
switch (new_state) {
case NM_DEVICE_STATE_UNMANAGED:
@@ -618,6 +618,50 @@ manager_device_state_changed (NMDevice *device,
#endif
}
+static void device_has_pending_action_changed (NMDevice *device,
+ GParamSpec *pspec,
+ NMManager *self);
+
+static void
+check_if_startup_complete (NMManager *self)
+{
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+ GSList *iter;
+
+ if (!priv->startup)
+ return;
+
+ for (iter = priv->devices; iter; iter = iter->next) {
+ NMDevice *dev = iter->data;
+
+ if (nm_device_has_pending_action (dev)) {
+ nm_log_dbg (LOGD_CORE, "check_if_startup_complete returns FALSE because of %s",
+ nm_device_get_iface (dev));
+ return;
+ }
+ }
+
+ nm_log_info (LOGD_CORE, "startup complete");
+
+ priv->startup = FALSE;
+ g_object_notify (G_OBJECT (self), "startup");
+
+ /* We don't have to watch notify::has-pending-action any more. */
+ for (iter = priv->devices; iter; iter = iter->next) {
+ NMDevice *dev = iter->data;
+
+ g_signal_handlers_disconnect_by_func (dev, G_CALLBACK (device_has_pending_action_changed), self);
+ }
+}
+
+static void
+device_has_pending_action_changed (NMDevice *device,
+ GParamSpec *pspec,
+ NMManager *self)
+{
+ check_if_startup_complete (self);
+}
+
static void
remove_device (NMManager *manager, NMDevice *device, gboolean quitting)
{
@@ -645,6 +689,9 @@ remove_device (NMManager *manager, NMDevice *device, gboolean quitting)
g_object_unref (device);
priv->devices = g_slist_remove (priv->devices, device);
+
+ if (priv->startup)
+ check_if_startup_complete (manager);
}
static void
@@ -1933,6 +1980,12 @@ add_device (NMManager *self, NMDevice *device)
G_CALLBACK (device_auth_request_cb),
self);
+ if (priv->startup) {
+ g_signal_connect (device, "notify::" NM_DEVICE_HAS_PENDING_ACTION,
+ G_CALLBACK (device_has_pending_action_changed),
+ self);
+ }
+
if (devtype == NM_DEVICE_TYPE_WIFI) {
/* Attach to the access-point-added signal so that the manager can fill
* non-SSID-broadcasting APs with an SSID.
@@ -3824,6 +3877,8 @@ nm_manager_start (NMManager *self)
/* FIXME: remove when we handle bridges non-destructively */
g_hash_table_unref (priv->nm_bridges);
priv->nm_bridges = NULL;
+
+ check_if_startup_complete (self);
}
static gboolean
@@ -4431,6 +4486,9 @@ get_property (GObject *object, guint prop_id,
nm_manager_update_state (self);
g_value_set_uint (value, priv->state);
break;
+ case PROP_STARTUP:
+ g_value_set_boolean (value, priv->startup);
+ break;
case PROP_NETWORKING_ENABLED:
g_value_set_boolean (value, priv->net_enabled);
break;
@@ -4548,6 +4606,7 @@ nm_manager_init (NMManager *manager)
priv->sleeping = FALSE;
priv->state = NM_STATE_DISCONNECTED;
+ priv->startup = TRUE;
priv->dbus_mgr = nm_dbus_manager_get ();
priv->dbus_connection_changed_id = g_signal_connect (priv->dbus_mgr,
@@ -4652,6 +4711,14 @@ nm_manager_class_init (NMManagerClass *manager_class)
G_PARAM_READABLE));
g_object_class_install_property
+ (object_class, PROP_STARTUP,
+ g_param_spec_boolean (NM_MANAGER_STARTUP,
+ "Startup",
+ "Is NetworkManager still starting up",
+ TRUE,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property
(object_class, PROP_NETWORKING_ENABLED,
g_param_spec_boolean (NM_MANAGER_NETWORKING_ENABLED,
"NetworkingEnabled",
diff --git a/src/nm-manager.h b/src/nm-manager.h
index 5aeeaab62a..6e376787e1 100644
--- a/src/nm-manager.h
+++ b/src/nm-manager.h
@@ -51,6 +51,7 @@ typedef enum {
#define NM_MANAGER_VERSION "version"
#define NM_MANAGER_STATE "state"
+#define NM_MANAGER_STARTUP "startup"
#define NM_MANAGER_NETWORKING_ENABLED "networking-enabled"
#define NM_MANAGER_WIRELESS_ENABLED "wireless-enabled"
#define NM_MANAGER_WIRELESS_HARDWARE_ENABLED "wireless-hardware-enabled"
diff --git a/src/nm-policy.c b/src/nm-policy.c
index 525fbc7741..cf94033537 100644
--- a/src/nm-policy.c
+++ b/src/nm-policy.c
@@ -860,6 +860,8 @@ typedef struct {
static void
activate_data_free (ActivateData *data)
{
+ nm_device_remove_pending_action (data->device, "autoactivate");
+
if (data->id)
g_source_remove (data->id);
g_object_unref (data->device);
@@ -958,6 +960,9 @@ activate_data_new (NMPolicy *policy, NMDevice *device, guint delay_seconds)
data->id = g_timeout_add_seconds (delay_seconds, auto_activate_device, data);
else
data->id = g_idle_add (auto_activate_device, data);
+
+ nm_device_add_pending_action (device, "autoactivate");
+
return data;
}