diff options
author | Dan Winship <danw@gnome.org> | 2014-02-26 13:14:07 -0500 |
---|---|---|
committer | Dan Winship <danw@gnome.org> | 2014-02-26 13:42:01 -0500 |
commit | 1a5c75fe56fddbc530f43ecfc50041f6caf3fa66 (patch) | |
tree | 482d5a07eb2228890e1b9cc314cdbef51c130d59 | |
parent | fbd3a3a7854bd38468692c99e5070661116c07cd (diff) | |
download | NetworkManager-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.c | 197 | ||||
-rw-r--r-- | src/nm-manager.c | 116 | ||||
-rw-r--r-- | src/nm-manager.h | 14 |
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, |