Files
NetworkManager/libnm-glib/nm-dbus-settings.c
Tambet Ingo bbaf9e2bfc 2008-05-07 Tambet Ingo <tambet@gmail.com>
Patch from André Lemos.

	* libnm-glib/nm-dbus-settings.c (fetch_connections_done): Fix a memory
	corruption.


git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3638 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
2008-05-07 09:21:44 +00:00

354 lines
9.0 KiB
C

/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
#include <string.h>
#include <NetworkManager.h>
#include <nm-connection.h>
#include "nm-dbus-settings.h"
#include "nm-settings-bindings.h"
G_DEFINE_TYPE (NMDBusSettings, nm_dbus_settings, NM_TYPE_SETTINGS)
#define NM_DBUS_SETTINGS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DBUS_SETTINGS, NMDBusSettingsPrivate))
typedef struct {
DBusGConnection *dbus_connection;
NMConnectionScope scope;
DBusGProxy *settings_proxy;
DBusGProxy *dbus_proxy;
GHashTable *connections;
gboolean disposed;
} NMDBusSettingsPrivate;
enum {
PROP_0,
PROP_DBUS_CONNECTION,
PROP_SCOPE,
LAST_PROP
};
NMDBusSettings *
nm_dbus_settings_new (DBusGConnection *dbus_connection)
{
g_return_val_if_fail (dbus_connection != NULL, NULL);
return (NMDBusSettings *) g_object_new (NM_TYPE_DBUS_SETTINGS,
NM_DBUS_SETTINGS_DBUS_CONNECTION, dbus_connection,
NM_DBUS_SETTINGS_SCOPE, NM_CONNECTION_SCOPE_USER,
NULL);
}
NMDBusConnection *
nm_dbus_settings_get_connection_by_path (NMDBusSettings *self, const char *path)
{
g_return_val_if_fail (NM_IS_DBUS_SETTINGS (self), NULL);
g_return_val_if_fail (path != NULL, NULL);
return g_hash_table_lookup (NM_DBUS_SETTINGS_GET_PRIVATE (self)->connections, path);
}
static void
connection_removed_cb (NMExportedConnection *exported, gpointer user_data)
{
NMDBusSettingsPrivate *priv = NM_DBUS_SETTINGS_GET_PRIVATE (user_data);
NMConnection *connection;
connection = nm_exported_connection_get_connection (exported);
g_hash_table_remove (priv->connections, nm_connection_get_path (connection));
}
static void
new_connection_cb (DBusGProxy *proxy,
const char *path,
gpointer user_data)
{
NMDBusSettingsPrivate *priv = NM_DBUS_SETTINGS_GET_PRIVATE (user_data);
NMDBusConnection *connection;
connection = nm_dbus_connection_new (priv->dbus_connection, priv->scope, path);
if (connection) {
g_signal_connect (connection, "removed",
G_CALLBACK (connection_removed_cb),
user_data);
g_hash_table_insert (priv->connections, g_strdup (path), connection);
nm_settings_signal_new_connection (NM_SETTINGS (user_data),
NM_EXPORTED_CONNECTION (connection));
}
}
static void
fetch_connections_done (DBusGProxy *proxy,
GPtrArray *connections,
GError *err,
gpointer user_data)
{
if (!err) {
int i;
for (i = 0; i < connections->len; i++) {
char *path = g_ptr_array_index (connections, i);
new_connection_cb (proxy, path, user_data);
g_free (path);
}
g_ptr_array_free (connections, TRUE);
} else {
g_warning ("Could not retrieve dbus connections: %s.", err->message);
g_error_free (err);
}
}
static void
settings_proxy_destroyed (gpointer data, GObject *destroyed_object)
{
NM_DBUS_SETTINGS_GET_PRIVATE (data)->settings_proxy = NULL;
}
static gboolean
fetch_connections (gpointer data)
{
NMDBusSettingsPrivate *priv = NM_DBUS_SETTINGS_GET_PRIVATE (data);
DBusGProxyCall *call;
if (!priv->settings_proxy) {
const char *service = (priv->scope == NM_CONNECTION_SCOPE_SYSTEM) ?
NM_DBUS_SERVICE_SYSTEM_SETTINGS : NM_DBUS_SERVICE_USER_SETTINGS;
priv->settings_proxy = dbus_g_proxy_new_for_name (priv->dbus_connection,
service,
NM_DBUS_PATH_SETTINGS,
NM_DBUS_IFACE_SETTINGS);
g_object_weak_ref (G_OBJECT (priv->settings_proxy), settings_proxy_destroyed, data);
dbus_g_proxy_add_signal (priv->settings_proxy, "NewConnection",
DBUS_TYPE_G_OBJECT_PATH,
G_TYPE_INVALID);
dbus_g_proxy_connect_signal (priv->settings_proxy, "NewConnection",
G_CALLBACK (new_connection_cb),
data,
NULL);
}
call = org_freedesktop_NetworkManagerSettings_list_connections_async (priv->settings_proxy,
fetch_connections_done,
data);
return FALSE;
}
static void
hash_values_to_slist (gpointer key, gpointer data, gpointer user_data)
{
GSList **list = (GSList **) user_data;
*list = g_slist_prepend (*list, data);
}
static GSList *
list_connections (NMSettings *settings)
{
GSList *list = NULL;
g_return_val_if_fail (NM_IS_DBUS_SETTINGS (settings), NULL);
g_hash_table_foreach (NM_DBUS_SETTINGS_GET_PRIVATE (settings)->connections, hash_values_to_slist, &list);
return list;
}
static void
remove_one_connection (gpointer key, gpointer value, gpointer user_data)
{
nm_exported_connection_signal_removed (NM_EXPORTED_CONNECTION (value));
}
static gboolean
remove_connections (gpointer data)
{
NMDBusSettings *self = NM_DBUS_SETTINGS (data);
NMDBusSettingsPrivate *priv = NM_DBUS_SETTINGS_GET_PRIVATE (self);
g_hash_table_foreach (priv->connections, remove_one_connection, NULL);
return FALSE;
}
static void
name_owner_changed (DBusGProxy *proxy,
const char *name,
const char *old_owner,
const char *new_owner,
gpointer user_data)
{
if (!strcmp (name, NM_DBUS_SERVICE_SYSTEM_SETTINGS)) {
if (new_owner && strlen (new_owner) > 0)
g_idle_add (fetch_connections, user_data);
else
g_idle_add (remove_connections, user_data);
}
}
/* GObject stuff */
static void
nm_dbus_settings_init (NMDBusSettings *settings)
{
NMDBusSettingsPrivate *priv = NM_DBUS_SETTINGS_GET_PRIVATE (settings);
priv->connections = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
}
static GObject *
constructor (GType type,
guint n_construct_params,
GObjectConstructParam *construct_params)
{
GObject *object;
NMDBusSettingsPrivate *priv;
object = G_OBJECT_CLASS (nm_dbus_settings_parent_class)->constructor (type, n_construct_params, construct_params);
if (!object)
return NULL;
priv = NM_DBUS_SETTINGS_GET_PRIVATE (object);
if (!priv->dbus_connection) {
g_warning ("DBus connection not provided.");
goto err;
}
if (priv->scope == NM_CONNECTION_SCOPE_UNKNOWN) {
g_warning ("Connection scope not provided.");
goto err;
}
priv->dbus_proxy = dbus_g_proxy_new_for_name (priv->dbus_connection,
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus");
dbus_g_proxy_add_signal (priv->dbus_proxy, "NameOwnerChanged",
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
G_TYPE_INVALID);
dbus_g_proxy_connect_signal (priv->dbus_proxy,
"NameOwnerChanged",
G_CALLBACK (name_owner_changed),
object, NULL);
g_idle_add (fetch_connections, object);
return object;
err:
g_object_unref (object);
return NULL;
}
static void
dispose (GObject *object)
{
NMDBusSettingsPrivate *priv = NM_DBUS_SETTINGS_GET_PRIVATE (object);
if (priv->disposed)
return;
priv->disposed = TRUE;
if (priv->connections)
g_hash_table_destroy (priv->connections);
if (priv->dbus_proxy)
g_object_unref (priv->dbus_proxy);
if (priv->settings_proxy)
g_object_unref (priv->settings_proxy);
dbus_g_connection_unref (priv->dbus_connection);
G_OBJECT_CLASS (nm_dbus_settings_parent_class)->dispose (object);
}
static void
set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
NMDBusSettingsPrivate *priv = NM_DBUS_SETTINGS_GET_PRIVATE (object);
switch (prop_id) {
case PROP_DBUS_CONNECTION:
/* Construct only */
priv->dbus_connection = dbus_g_connection_ref ((DBusGConnection *) g_value_get_boxed (value));
break;
case PROP_SCOPE:
priv->scope = (NMConnectionScope) g_value_get_uint (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
NMDBusSettingsPrivate *priv = NM_DBUS_SETTINGS_GET_PRIVATE (object);
switch (prop_id) {
case PROP_DBUS_CONNECTION:
g_value_set_boxed (value, priv->dbus_connection);
break;
case PROP_SCOPE:
g_value_set_uint (value, priv->scope);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
nm_dbus_settings_class_init (NMDBusSettingsClass *dbus_settings_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (dbus_settings_class);
NMSettingsClass *settings_class = NM_SETTINGS_CLASS (dbus_settings_class);
g_type_class_add_private (dbus_settings_class, sizeof (NMDBusSettingsPrivate));
/* Virtual methods */
object_class->constructor = constructor;
object_class->set_property = set_property;
object_class->get_property = get_property;
object_class->dispose = dispose;
settings_class->list_connections = list_connections;
/* Properties */
g_object_class_install_property
(object_class, PROP_DBUS_CONNECTION,
g_param_spec_boxed (NM_DBUS_SETTINGS_DBUS_CONNECTION,
"DBusGConnection",
"DBusGConnection",
DBUS_TYPE_G_CONNECTION,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property
(object_class, PROP_SCOPE,
g_param_spec_uint (NM_DBUS_SETTINGS_SCOPE,
"Scope",
"NMConnection scope",
NM_CONNECTION_SCOPE_UNKNOWN,
NM_CONNECTION_SCOPE_USER,
NM_CONNECTION_SCOPE_USER,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
}