summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Winship <danw@gnome.org>2014-02-26 13:14:07 -0500
committerDan Winship <danw@gnome.org>2014-02-26 13:42:01 -0500
commit1a5c75fe56fddbc530f43ecfc50041f6caf3fa66 (patch)
tree482d5a07eb2228890e1b9cc314cdbef51c130d59
parentfbd3a3a7854bd38468692c99e5070661116c07cd (diff)
downloadNetworkManager-danw/trackdevice.tar.gz
core: add a framework for tracking devicesdanw/wip/trackdevicedanw/trackdevice
Some devices need to track the presence/creation/destruction of other devices. Add nm_manager_track_device() to simplify this, and port NMDeviceOlpcMesh to use it for tracking its companion wifi device.
-rw-r--r--src/devices/nm-device-olpc-mesh.c197
-rw-r--r--src/nm-manager.c116
-rw-r--r--src/nm-manager.h14
3 files changed, 196 insertions, 131 deletions
diff --git a/src/devices/nm-device-olpc-mesh.c b/src/devices/nm-device-olpc-mesh.c
index 6ac03bae6d..56437a533d 100644
--- a/src/devices/nm-device-olpc-mesh.c
+++ b/src/devices/nm-device-olpc-mesh.c
@@ -86,18 +86,28 @@ struct _NMDeviceOlpcMeshPrivate {
WifiData * wifi_data;
NMDevice * companion;
+ gpointer companion_track_tag;
+ gboolean waiting_for_companion;
+
gboolean stage1_waiting;
- guint device_added_id;
- guint device_removed_id;
- guint cmp_state_changed_id;
- guint cmp_scanning_id;
- guint cmp_scanning_allowed_id;
- guint cmp_autoconnect_allowed_id;
};
static void state_changed (NMDevice *device, NMDeviceState new_state,
NMDeviceState old_state, NMDeviceStateReason reason);
+static void companion_state_changed_cb (NMDeviceWifi *companion,
+ NMDeviceState state,
+ NMDeviceState old_state,
+ NMDeviceStateReason reason,
+ gpointer user_data);
+static void companion_notify_cb (NMDeviceWifi *companion, GParamSpec *pspec, gpointer user_data);
+static gboolean companion_scan_allowed_cb (NMDeviceWifi *companion, gpointer user_data);
+static gboolean companion_autoconnect_allowed_cb (NMDeviceWifi *companion, gpointer user_data);
+
+static gboolean match_companion (NMManager *manager, NMDevice *other, gpointer user_data);
+static void got_companion (NMManager *manager, NMDevice *companion, gpointer user_data);
+static void lost_companion (NMManager *manager, NMDevice *companion, gpointer user_data);
+
static GQuark
nm_olpc_mesh_error_quark (void)
{
@@ -110,11 +120,6 @@ nm_olpc_mesh_error_quark (void)
static void
nm_device_olpc_mesh_init (NMDeviceOlpcMesh * self)
{
- NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
-
- priv->dispose_has_run = FALSE;
- priv->companion = NULL;
- priv->stage1_waiting = FALSE;
}
static GObject*
@@ -158,6 +163,14 @@ constructor (GType type,
/* shorter timeout for mesh connectivity */
nm_device_set_dhcp_timeout (NM_DEVICE (self), 20);
+
+ /* Find companion */
+ priv->companion_track_tag = nm_manager_track_device (nm_manager_get (),
+ match_companion,
+ got_companion,
+ lost_companion,
+ self);
+
return object;
}
@@ -333,25 +346,10 @@ companion_cleanup (NMDeviceOlpcMesh *self)
if (priv->companion == NULL)
return;
- if (priv->cmp_state_changed_id) {
- g_signal_handler_disconnect (priv->companion, priv->cmp_state_changed_id);
- priv->cmp_state_changed_id = 0;
- }
-
- if (priv->cmp_scanning_id) {
- g_signal_handler_disconnect (priv->companion, priv->cmp_scanning_id);
- priv->cmp_scanning_id = 0;
- }
-
- if (priv->cmp_scanning_allowed_id) {
- g_signal_handler_disconnect (priv->companion, priv->cmp_scanning_allowed_id);
- priv->cmp_scanning_allowed_id = 0;
- }
-
- if (priv->cmp_autoconnect_allowed_id) {
- g_signal_handler_disconnect (priv->companion, priv->cmp_autoconnect_allowed_id);
- priv->cmp_autoconnect_allowed_id = 0;
- }
+ g_signal_handlers_disconnect_by_func (priv->companion, companion_state_changed_cb, self);
+ g_signal_handlers_disconnect_by_func (priv->companion, companion_notify_cb, self);
+ g_signal_handlers_disconnect_by_func (priv->companion, companion_scan_allowed_cb, self);
+ g_signal_handlers_disconnect_by_func (priv->companion, companion_autoconnect_allowed_cb, self);
priv->companion = NULL;
g_object_notify (G_OBJECT (self), NM_DEVICE_OLPC_MESH_COMPANION);
@@ -362,7 +360,6 @@ dispose (GObject *object)
{
NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (object);
NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
- NMManager *manager;
if (priv->dispose_has_run) {
G_OBJECT_CLASS (nm_device_olpc_mesh_parent_class)->dispose (object);
@@ -374,12 +371,7 @@ dispose (GObject *object)
wifi_utils_deinit (priv->wifi_data);
companion_cleanup (self);
-
- manager = nm_manager_get ();
- if (priv->device_added_id)
- g_signal_handler_disconnect (manager, priv->device_added_id);
- if (priv->device_removed_id)
- g_signal_handler_disconnect (manager, priv->device_removed_id);
+ nm_manager_untrack_device (nm_manager_get (), priv->companion_track_tag);
G_OBJECT_CLASS (nm_device_olpc_mesh_parent_class)->dispose (object);
}
@@ -530,12 +522,11 @@ companion_autoconnect_allowed_cb (NMDeviceWifi *companion, gpointer user_data)
}
static gboolean
-is_companion (NMDeviceOlpcMesh *self, NMDevice *other)
+match_companion (NMManager *manager, NMDevice *other, gpointer user_data)
{
- NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
+ NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data);
const guint8 *my_addr, *their_addr;
guint their_addr_len;
- NMManager *manager;
if (!NM_IS_DEVICE_WIFI (other))
return FALSE;
@@ -546,93 +537,47 @@ is_companion (NMDeviceOlpcMesh *self, NMDevice *other)
|| (memcmp (my_addr, their_addr, ETH_ALEN) != 0))
return FALSE;
- priv->companion = other;
+ return TRUE;
+}
- /* When we've found the companion, stop listening for other devices */
- manager = nm_manager_get ();
- if (priv->device_added_id) {
- g_signal_handler_disconnect (manager, priv->device_added_id);
- priv->device_added_id = 0;
- }
+static void
+got_companion (NMManager *manager, NMDevice *companion, gpointer user_data)
+{
+ NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data);
+ NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
- nm_device_state_changed (NM_DEVICE (self),
- NM_DEVICE_STATE_DISCONNECTED,
- NM_DEVICE_STATE_REASON_NONE);
+ priv->companion = companion;
nm_log_info (LOGD_OLPC_MESH, "(%s): found companion WiFi device %s",
nm_device_get_iface (NM_DEVICE (self)),
- nm_device_get_iface (other));
-
- priv->cmp_state_changed_id = g_signal_connect (G_OBJECT (other), "state-changed",
- G_CALLBACK (companion_state_changed_cb), self);
+ nm_device_get_iface (companion));
- priv->cmp_scanning_id = g_signal_connect (G_OBJECT (other), "notify::scanning",
- G_CALLBACK (companion_notify_cb), self);
-
- priv->cmp_scanning_allowed_id = g_signal_connect (G_OBJECT (other), "scanning-allowed",
- G_CALLBACK (companion_scan_allowed_cb), self);
-
- priv->cmp_autoconnect_allowed_id = g_signal_connect (G_OBJECT (other), "autoconnect-allowed",
- G_CALLBACK (companion_autoconnect_allowed_cb), self);
+ g_signal_connect (G_OBJECT (companion), "state-changed",
+ G_CALLBACK (companion_state_changed_cb), self);
+ g_signal_connect (G_OBJECT (companion), "notify::scanning",
+ G_CALLBACK (companion_notify_cb), self);
+ g_signal_connect (G_OBJECT (companion), "scanning-allowed",
+ G_CALLBACK (companion_scan_allowed_cb), self);
+ g_signal_connect (G_OBJECT (companion), "autoconnect-allowed",
+ G_CALLBACK (companion_autoconnect_allowed_cb), self);
g_object_notify (G_OBJECT (self), NM_DEVICE_OLPC_MESH_COMPANION);
- return TRUE;
-}
-
-static void
-device_added_cb (NMManager *manager, NMDevice *other, gpointer user_data)
-{
- NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data);
-
- is_companion (self, other);
+ if (priv->waiting_for_companion) {
+ priv->waiting_for_companion = FALSE;
+ nm_device_queue_state (NM_DEVICE (self),
+ NM_DEVICE_STATE_DISCONNECTED,
+ NM_DEVICE_STATE_REASON_NONE);
+ nm_device_remove_pending_action (NM_DEVICE (self), "waiting for companion");
+ }
}
static void
-device_removed_cb (NMManager *manager, NMDevice *other, gpointer user_data)
-{
- NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data);
-
- if (other == NM_DEVICE_OLPC_MESH_GET_PRIVATE (self)->companion)
- companion_cleanup (self);
-}
-
-static gboolean
-check_companion_cb (gpointer user_data)
+lost_companion (NMManager *manager, NMDevice *companion, gpointer user_data)
{
NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data);
- NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
- NMManager *manager;
- GSList *list;
-
- if (priv->companion != NULL) {
- nm_device_state_changed (NM_DEVICE (user_data),
- NM_DEVICE_STATE_DISCONNECTED,
- NM_DEVICE_STATE_REASON_NONE);
- goto done;
- }
- if (priv->device_added_id != 0)
- goto done;
-
- manager = nm_manager_get ();
-
- priv->device_added_id = g_signal_connect (manager, "device-added",
- G_CALLBACK (device_added_cb), self);
- if (!priv->device_removed_id) {
- priv->device_removed_id = g_signal_connect (manager, "device-removed",
- G_CALLBACK (device_removed_cb), self);
- }
-
- /* Try to find the companion if it's already known to the NMManager */
- for (list = nm_manager_get_devices (manager); list ; list = g_slist_next (list)) {
- if (is_companion (self, NM_DEVICE (list->data)))
- break;
- }
-
- done:
- nm_device_remove_pending_action (NM_DEVICE (self), "waiting for companion");
- return FALSE;
+ companion_cleanup (self);
}
static void
@@ -640,25 +585,17 @@ state_changed (NMDevice *device, NMDeviceState new_state,
NMDeviceState old_state, NMDeviceStateReason reason)
{
NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (device);
+ NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
- switch (new_state) {
- case NM_DEVICE_STATE_UNMANAGED:
- break;
- case NM_DEVICE_STATE_UNAVAILABLE:
- /* If transitioning to UNAVAILABLE and the companion device is known then
- * 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;
- case NM_DEVICE_STATE_FAILED:
- break;
- case NM_DEVICE_STATE_DISCONNECTED:
- break;
- default:
- break;
+ if (new_state == NM_DEVICE_STATE_UNAVAILABLE) {
+ if (priv->companion) {
+ nm_device_queue_state (device,
+ NM_DEVICE_STATE_DISCONNECTED,
+ NM_DEVICE_STATE_REASON_NONE);
+ } else {
+ priv->waiting_for_companion = TRUE;
+ nm_device_add_pending_action (device, "waiting for companion");
+ }
}
}
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 7677f2a824..8682361731 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -213,6 +213,7 @@ typedef struct {
NMActiveConnection *activating_connection;
GSList *devices;
+ GSList *device_trackers;
NMState state;
NMConnectivity *connectivity;
@@ -533,6 +534,93 @@ nm_manager_get_device_by_ifindex (NMManager *manager, int ifindex)
return NULL;
}
+typedef struct {
+ NMManager *manager;
+ NMDevice *device;
+ NMManagerDeviceMatchFunc match_func;
+ NMManagerDeviceCallback added_callback;
+ NMManagerDeviceCallback removed_callback;
+ gpointer user_data;
+} NMManagerTrackDeviceData;
+
+/**
+ * nm_manager_track_device:
+ * @manager: the #NMManager
+ * @match_func: the match function used to find the device
+ * @added_callback: the callback function when a matching device is found
+ * @removed_callback: the callback function when a matching device is removed
+ * @user_data: data for the #NMManagerDeviceFuncs
+ *
+ * Helper function for tracking to presence of a device matching
+ * certain criteria.
+ *
+ * If a device matching @match_func is already present, then
+ * @added_callback will be called immediately (from within
+ * nm_manager_track_device()) with the matching device.
+ *
+ * After nm_manager_track_device() returns, @added_callback will be
+ * called any time a device matching @match_func is added (if one has
+ * not already been found), and @removed_callback will be called when
+ * the matched device has been removed.
+ *
+ * Returns: an opaque pointer, which can be passed to
+ * nm_manager_untrack_device() to stop tracking.
+ */
+gpointer
+nm_manager_track_device (NMManager *manager,
+ NMManagerDeviceMatchFunc match_func,
+ NMManagerDeviceCallback added_callback,
+ NMManagerDeviceCallback removed_callback,
+ gpointer user_data)
+{
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+ NMManagerTrackDeviceData *track_data;
+ GSList *iter;
+
+ track_data = g_slice_new (NMManagerTrackDeviceData);
+ track_data->manager = manager;
+ track_data->device = NULL;
+ track_data->match_func = match_func;
+ track_data->added_callback = added_callback;
+ track_data->removed_callback = removed_callback;
+ track_data->user_data = user_data;
+
+ priv->device_trackers = g_slist_prepend (priv->device_trackers, track_data);
+
+ for (iter = priv->devices; iter; iter = iter->next) {
+ NMDevice *device = NM_DEVICE (iter->data);
+
+ if (match_func (manager, device, user_data)) {
+ track_data->device = device;
+ break;
+ }
+ }
+
+ if (track_data->device)
+ added_callback (manager, track_data->device, user_data);
+
+ return track_data;
+}
+
+/**
+ * nm_manager_untrack_device:
+ * @manager: the #NMManager
+ * @tag: a tag returned from nm_manager_track_device()
+ *
+ * Stops the device monitoring initiated by an nm_manager_track_device()
+ * call.
+ */
+void
+nm_manager_untrack_device (NMManager *manager,
+ gpointer tag)
+{
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+ NMManagerTrackDeviceData *track_data = tag;
+
+ priv->device_trackers = g_slist_remove (priv->device_trackers, track_data);
+ g_slice_free (NMManagerTrackDeviceData, track_data);
+}
+
static gboolean
manager_sleeping (NMManager *self)
{
@@ -806,6 +894,7 @@ static void
remove_device (NMManager *manager, NMDevice *device, gboolean quitting)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+ GSList *iter, *next;
if (nm_device_get_managed (device)) {
/* Leave configured interfaces up when quitting so they can be
@@ -829,8 +918,18 @@ remove_device (NMManager *manager, NMDevice *device, gboolean quitting)
nm_settings_device_removed (priv->settings, device, quitting);
g_signal_emit (manager, signals[DEVICE_REMOVED], 0, device);
g_object_notify (G_OBJECT (manager), NM_MANAGER_DEVICES);
- g_object_unref (device);
+ for (iter = priv->device_trackers; iter; iter = next) {
+ NMManagerTrackDeviceData *track_data = iter->data;
+
+ next = iter->next;
+ if (track_data->device == device) {
+ track_data->device = NULL;
+ track_data->removed_callback (manager, device, track_data->user_data);
+ }
+ }
+
+ g_object_unref (device);
priv->devices = g_slist_remove (priv->devices, device);
if (priv->startup)
@@ -1824,6 +1923,7 @@ add_device (NMManager *self, NMDevice *device, gboolean generate_con)
gboolean enabled = FALSE;
RfKillType rtype;
NMDeviceType devtype;
+ GSList *iter, *next;
iface = nm_device_get_ip_iface (device);
g_assert (iface);
@@ -1925,6 +2025,17 @@ add_device (NMManager *self, NMDevice *device, gboolean generate_con)
g_signal_emit (self, signals[DEVICE_ADDED], 0, device);
g_object_notify (G_OBJECT (self), NM_MANAGER_DEVICES);
+ for (iter = priv->device_trackers; iter; iter = next) {
+ NMManagerTrackDeviceData *track_data = iter->data;
+
+ next = iter->next;
+ if ( !track_data->device
+ && track_data->match_func (self, device, track_data->user_data)) {
+ track_data->device = device;
+ track_data->added_callback (self, device, track_data->user_data);
+ }
+ }
+
/* New devices might be master interfaces for virtual interfaces; so we may
* need to create new virtual interfaces now.
*/
@@ -5071,6 +5182,9 @@ dispose (GObject *object)
while (priv->devices)
remove_device (manager, NM_DEVICE (priv->devices->data), TRUE);
+ while (priv->device_trackers)
+ nm_manager_untrack_device (manager, priv->device_trackers->data);
+
if (priv->ac_cleanup_id) {
g_source_remove (priv->ac_cleanup_id);
priv->ac_cleanup_id = 0;
diff --git a/src/nm-manager.h b/src/nm-manager.h
index 1b0865fe0d..dfd62aef9b 100644
--- a/src/nm-manager.h
+++ b/src/nm-manager.h
@@ -118,6 +118,20 @@ NMDevice *nm_manager_get_device_by_master (NMManager *manager,
NMDevice *nm_manager_get_device_by_ifindex (NMManager *manager,
int ifindex);
+typedef gboolean (*NMManagerDeviceMatchFunc) (NMManager *manager,
+ NMDevice *device,
+ gpointer user_data);
+typedef void (*NMManagerDeviceCallback) (NMManager *manager,
+ NMDevice *device,
+ gpointer user_data);
+gpointer nm_manager_track_device (NMManager *manager,
+ NMManagerDeviceMatchFunc match_func,
+ NMManagerDeviceCallback added_callback,
+ NMManagerDeviceCallback removed_callback,
+ gpointer user_data);
+void nm_manager_untrack_device (NMManager *manager,
+ gpointer tag);
+
NMActiveConnection *nm_manager_activate_connection (NMManager *manager,
NMConnection *connection,
const char *specific_object,