From 9d318e9fae475fb010030704bfb22dd0a514e0fe Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sun, 7 Oct 2007 23:33:28 +0000 Subject: [PATCH] 2007-10-07 Dan Williams * src/nm-manager.c src/nm-manager.h - Add a 'connections-added' signal to batch together updates of large numbers of connections, like when reading from a settings service the first time. Otherwise, the policy would just activate the first suitable connection it saw rather than waiting for the full list to arrive. - (nm_manager_class_init): register new signal - (get_type_for_proxy, connection_get_settings_cb, get_connection_for_proxy): centralize places where a proxy's setting service is determined - (free_get_settings_info): if the call being freed is the last call in a pending call group, fire off the connections-added signal - (internal_new_connection_cb): add call to a pending call group if requested - (list_connections_cb): always create a call group here, because this call results in a batch of new connections - (initial_get_connections): start getting system connections first - (nm_manager_connections_destroy, emit_removed): actually emit the removed signal when destroying connections * src/NetworkManagerPolicy.c - (nm_policy_new, connections_added): handle connections-added signal from the manager git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@2951 4912f4e0-d625-0410-9fb7-b9a5a253dbdc --- ChangeLog | 27 ++++++ src/NetworkManagerPolicy.c | 17 ++++ src/nm-manager.c | 168 ++++++++++++++++++++++++++++--------- src/nm-manager.h | 3 + 4 files changed, 177 insertions(+), 38 deletions(-) diff --git a/ChangeLog b/ChangeLog index b4aa35b61d..44ddcacc06 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,30 @@ +2007-10-07 Dan Williams + + * src/nm-manager.c + src/nm-manager.h + - Add a 'connections-added' signal to batch together updates of large + numbers of connections, like when reading from a settings service + the first time. Otherwise, the policy would just activate the first + suitable connection it saw rather than waiting for the full list + to arrive. + - (nm_manager_class_init): register new signal + - (get_type_for_proxy, connection_get_settings_cb, + get_connection_for_proxy): centralize places where a proxy's setting + service is determined + - (free_get_settings_info): if the call being freed is the last call + in a pending call group, fire off the connections-added signal + - (internal_new_connection_cb): add call to a pending call group if + requested + - (list_connections_cb): always create a call group here, because this + call results in a batch of new connections + - (initial_get_connections): start getting system connections first + - (nm_manager_connections_destroy, emit_removed): actually emit the + removed signal when destroying connections + + * src/NetworkManagerPolicy.c + - (nm_policy_new, connections_added): handle connections-added signal + from the manager + 2007-10-06 Dan Williams * src/nm-device-802-11-wireless.c diff --git a/src/NetworkManagerPolicy.c b/src/NetworkManagerPolicy.c index dc3601b1b9..3b7ae68724 100644 --- a/src/NetworkManagerPolicy.c +++ b/src/NetworkManagerPolicy.c @@ -475,6 +475,16 @@ state_changed (NMManager *manager, NMState state, gpointer user_data) } } +static void +connections_added (NMManager *manager, + NMConnectionType connection_type, + gpointer user_data) +{ + NMPolicy *policy = (NMPolicy *) user_data; + + schedule_change_check (policy); +} + static void connection_added (NMManager *manager, NMConnection *connection, @@ -544,6 +554,13 @@ nm_policy_new (NMManager *manager) g_signal_connect (manager, "state-change", G_CALLBACK (state_changed), policy); + /* Large batch of connections added, manager doesn't want us to + * process each one individually. + */ + g_signal_connect (manager, "connections-added", + G_CALLBACK (connections_added), policy); + + /* Single connection added */ g_signal_connect (manager, "connection-added", G_CALLBACK (connection_added), policy); diff --git a/src/nm-manager.c b/src/nm-manager.c index bd12453da6..59a78d20f9 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -75,6 +75,7 @@ enum { DEVICE_ADDED, DEVICE_REMOVED, STATE_CHANGE, + CONNECTIONS_ADDED, CONNECTION_ADDED, CONNECTION_UPDATED, CONNECTION_REMOVED, @@ -291,6 +292,16 @@ nm_manager_class_init (NMManagerClass *manager_class) G_TYPE_NONE, 1, G_TYPE_UINT); + signals[CONNECTIONS_ADDED] = + g_signal_new ("connections-added", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMManagerClass, connections_added), + NULL, NULL, + g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, 1, + G_TYPE_UINT); + signals[CONNECTION_ADDED] = g_signal_new ("connection-added", G_OBJECT_CLASS_TYPE (object_class), @@ -328,9 +339,25 @@ nm_manager_class_init (NMManagerClass *manager_class) #define DBUS_TYPE_G_STRING_VARIANT_HASHTABLE (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE)) #define DBUS_TYPE_G_DICT_OF_DICTS (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, DBUS_TYPE_G_STRING_VARIANT_HASHTABLE)) +static NMConnectionType +get_type_for_proxy (DBusGProxy *proxy) +{ + const char *bus_name = dbus_g_proxy_get_bus_name (proxy); + + if (strcmp (bus_name, NM_DBUS_SERVICE_USER_SETTINGS) == 0) + return NM_CONNECTION_TYPE_USER; + else if (strcmp (bus_name, NM_DBUS_SERVICE_SYSTEM_SETTINGS) == 0) + return NM_CONNECTION_TYPE_SYSTEM; + + return NM_CONNECTION_TYPE_UNKNOWN; +} + typedef struct GetSettingsInfo { NMManager *manager; NMConnection *connection; + DBusGProxy *proxy; + DBusGProxyCall *call; + GSList **calls; } GetSettingsInfo; static void @@ -338,6 +365,20 @@ free_get_settings_info (gpointer data) { GetSettingsInfo *info = (GetSettingsInfo *) data; + /* If this was the last pending call for a batch of GetSettings calls, + * send out the connections-added signal. + */ + if (info->calls) { + *(info->calls) = g_slist_remove (*(info->calls), info->call); + if (g_slist_length (*(info->calls)) == 0) { + g_slist_free (*(info->calls)); + g_signal_emit (info->manager, + signals[CONNECTIONS_ADDED], + 0, + get_type_for_proxy (info->proxy)); + } + } + if (info->manager) { g_object_unref (info->manager); info->manager = NULL; @@ -359,7 +400,7 @@ connection_get_settings_cb (DBusGProxy *proxy, GError *err = NULL; GHashTable *settings = NULL; NMConnection *connection; - NMConnectionType connection_type; + NMConnectionType type; NMManager *manager; g_return_if_fail (info != NULL); @@ -376,7 +417,6 @@ connection_get_settings_cb (DBusGProxy *proxy, connection = info->connection; if (connection == NULL) { const char *path = dbus_g_proxy_get_path (proxy); - const char *bus_name = dbus_g_proxy_get_bus_name (proxy); NMManagerPrivate *priv; connection = nm_connection_new_from_hash (settings); @@ -389,26 +429,33 @@ connection_get_settings_cb (DBusGProxy *proxy, (GDestroyNotify) g_object_unref); priv = NM_MANAGER_GET_PRIVATE (manager); - if (strcmp (bus_name, NM_DBUS_SERVICE_USER_SETTINGS) == 0) { - connection_type = NM_CONNECTION_TYPE_USER; - g_hash_table_insert (priv->user_connections, - g_strdup (path), - connection); - } else if (strcmp (bus_name, NM_DBUS_SERVICE_SYSTEM_SETTINGS) == 0) { - connection_type = NM_CONNECTION_TYPE_SYSTEM; - g_hash_table_insert (priv->system_connections, - g_strdup (path), - connection); - } else { - nm_warning ("Connection wasn't a user connection or a system connection."); - g_assert_not_reached (); + type = get_type_for_proxy (proxy); + switch (type) { + case NM_CONNECTION_TYPE_USER: + g_hash_table_insert (priv->user_connections, + g_strdup (path), + connection); + break; + case NM_CONNECTION_TYPE_SYSTEM: + g_hash_table_insert (priv->system_connections, + g_strdup (path), + connection); + break; + default: + nm_warning ("Connection wasn't a user connection or a system connection."); + g_assert_not_reached (); + break; } g_object_set_data (G_OBJECT (connection), NM_MANAGER_CONNECTION_TYPE_TAG, - GUINT_TO_POINTER (connection_type)); + GUINT_TO_POINTER (type)); - g_signal_emit (manager, signals[CONNECTION_ADDED], 0, connection, connection_type); + /* If the connection-added signal is supposed to be batched, don't + * emit the single connection-added here. + */ + if (!info->calls) + g_signal_emit (manager, signals[CONNECTION_ADDED], 0, connection, type); } else { // FIXME: merge settings? or just replace? nm_warning ("%s (#%d): implement merge settings", __func__, __LINE__); @@ -427,20 +474,27 @@ get_connection_for_proxy (NMManager *manager, const char **out_path) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); + NMConnection *connection = NULL; const char *path = dbus_g_proxy_get_path (proxy); - const char *bus_name = dbus_g_proxy_get_bus_name (proxy); if (out_path) *out_path = path; - if (strcmp (bus_name, NM_DBUS_SERVICE_USER_SETTINGS) == 0) { - *out_hash = priv->user_connections; - return g_hash_table_lookup (priv->user_connections, path); - } else if (strcmp (bus_name, NM_DBUS_SERVICE_SYSTEM_SETTINGS) == 0) { - *out_hash = priv->system_connections; - return g_hash_table_lookup (priv->system_connections, path); + switch (get_type_for_proxy (proxy)) { + case NM_CONNECTION_TYPE_USER: + *out_hash = priv->user_connections; + connection = g_hash_table_lookup (priv->user_connections, path); + break; + case NM_CONNECTION_TYPE_SYSTEM: + *out_hash = priv->system_connections; + connection = g_hash_table_lookup (priv->system_connections, path); + break; + default: + nm_warning ("Connection wasn't a user connection or a system connection."); + g_assert_not_reached (); + break; } - return NULL; + return connection; } static void @@ -449,7 +503,7 @@ remove_connection (NMManager *manager, GHashTable *hash, const char *path) { - NMConnectionType type = NM_CONNECTION_TYPE_UNKNOWN; + NMConnectionType type; /* Destroys the connection, then associated DBusGProxy due to the * weak reference notify function placed on the connection when it @@ -510,19 +564,21 @@ connection_updated_cb (DBusGProxy *proxy, GHashTable *settings, gpointer user_da } static void -new_connection_cb (DBusGProxy *proxy, const char *path, gpointer user_data) +internal_new_connection_cb (DBusGProxy *proxy, + const char *path, + NMManager *manager, + GSList **calls) { - NMManager * manager = NM_MANAGER (user_data); + struct GetSettingsInfo *info; DBusGProxy *con_proxy; NMDBusManager * dbus_mgr; DBusGConnection * g_connection; DBusGProxyCall *call; - struct GetSettingsInfo *info; dbus_mgr = nm_dbus_manager_get (); g_connection = nm_dbus_manager_get_connection (dbus_mgr); con_proxy = dbus_g_proxy_new_for_name (g_connection, - NM_DBUS_SERVICE_USER_SETTINGS, + dbus_g_proxy_get_bus_name (proxy), path, NM_DBUS_IFACE_SETTINGS_CONNECTION); g_object_unref (dbus_mgr); @@ -547,11 +603,16 @@ new_connection_cb (DBusGProxy *proxy, const char *path, gpointer user_data) info = g_slice_new0 (GetSettingsInfo); info->manager = g_object_ref (manager); + info->calls = calls; call = dbus_g_proxy_begin_call (con_proxy, "GetSettings", connection_get_settings_cb, info, free_get_settings_info, G_TYPE_INVALID); + info->call = call; + info->proxy = con_proxy; + if (info->calls) + *(info->calls) = g_slist_prepend (*(info->calls), call); } #define DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH (dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH)) @@ -564,6 +625,7 @@ list_connections_cb (DBusGProxy *proxy, NMManager *manager = NM_MANAGER (user_data); GError *err = NULL; GPtrArray *ops; + GSList **calls = NULL; int i; if (!dbus_g_proxy_end_call (proxy, call_id, &err, @@ -574,8 +636,17 @@ list_connections_cb (DBusGProxy *proxy, goto out; } - for (i = 0; i < ops->len; i++) - new_connection_cb (proxy, g_ptr_array_index (ops, i), manager); + /* Keep track of all calls made here; don't want to emit connection-added for + * each one, but emit connections-added when they are all done. + */ + calls = g_slice_new0 (GSList *); + + for (i = 0; i < ops->len; i++) { + internal_new_connection_cb (proxy, + g_ptr_array_index (ops, i), + manager, + calls); + } g_ptr_array_free (ops, TRUE); @@ -583,6 +654,12 @@ out: return; } +static void +new_connection_cb (DBusGProxy *proxy, const char *path, gpointer user_data) +{ + internal_new_connection_cb (proxy, path, NM_MANAGER (user_data), NULL); +} + static void query_connections (NMManager *manager, NMConnectionType type) @@ -676,14 +753,14 @@ initial_get_connections (gpointer user_data) { NMManager * manager = NM_MANAGER (user_data); - if (nm_dbus_manager_name_has_owner (nm_dbus_manager_get (), - NM_DBUS_SERVICE_USER_SETTINGS)) - query_connections (manager, NM_CONNECTION_TYPE_USER); - if (nm_dbus_manager_name_has_owner (nm_dbus_manager_get (), NM_DBUS_SERVICE_SYSTEM_SETTINGS)) query_connections (manager, NM_CONNECTION_TYPE_SYSTEM); + if (nm_dbus_manager_name_has_owner (nm_dbus_manager_get (), + NM_DBUS_SERVICE_USER_SETTINGS)) + query_connections (manager, NM_CONNECTION_TYPE_USER); + return FALSE; } @@ -713,6 +790,17 @@ nm_manager_new (void) return NM_MANAGER (object); } +static void +emit_removed (gpointer key, gpointer value, gpointer user_data) +{ + NMManager *manager = NM_MANAGER (user_data); + NMConnection *connection = NM_CONNECTION (value); + NMConnectionType type; + + type = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (connection), NM_MANAGER_CONNECTION_TYPE_TAG)); + g_signal_emit (manager, signals[CONNECTION_REMOVED], 0, connection, type); +} + static void nm_manager_connections_destroy (NMManager *manager, NMConnectionType type) @@ -720,16 +808,20 @@ nm_manager_connections_destroy (NMManager *manager, NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); if (type == NM_CONNECTION_TYPE_USER) { - if (priv->user_connections) + if (priv->user_connections) { + g_hash_table_foreach (priv->user_connections, emit_removed, manager); g_hash_table_remove_all (priv->user_connections); + } if (priv->user_proxy) { g_object_unref (priv->user_proxy); priv->user_proxy = NULL; } } else if (type == NM_CONNECTION_TYPE_SYSTEM) { - if (priv->system_connections) + if (priv->system_connections) { + g_hash_table_foreach (priv->system_connections, emit_removed, manager); g_hash_table_remove_all (priv->system_connections); + } if (priv->system_proxy) { g_object_unref (priv->system_proxy); diff --git a/src/nm-manager.h b/src/nm-manager.h index 8c2544e029..cfcbf1868c 100644 --- a/src/nm-manager.h +++ b/src/nm-manager.h @@ -37,6 +37,9 @@ typedef struct { void (*device_added) (NMManager *manager, NMDevice *device); void (*device_removed) (NMManager *manager, NMDevice *device); void (*state_change) (NMManager *manager, guint state); + + void (*connections_added) (NMManager *manager, NMConnectionType type); + void (*connection_added) (NMManager *manager, NMConnection *connection, NMConnectionType connection_type);