Commit 9fd98ef9 authored by Dan Winship's avatar Dan Winship Committed by Dan Williams

libnm-glib: implement GInitable/GAsyncInitable in NMObject

Implement GInitable and GAsyncInitable in NMObject, with
implementations that synchronously or asynchonously load all
properties, and change _nm_object_ensure_inited() to run
g_initable_init().

Update the object/object-array property handling to initialize the
objects after creating them (synchronously or asynchronously,
according to the situation), so that they will have all of their
properties preloaded before they are ever visible to the caller.

Move the non-blocking/non-failable parts of various objects'
constructor() methods to constructed(), and move the blocking/failable
parts to init(), and implement init_async() methods with non-blocking
versions of the blocking methods.

Make nm_device_new() and nm_client_new() call
_nm_object_ensure_inited(), to preserve the behaviour formerly
enforced by their construct() methods, that properties are guaranteed
to be initialized before any signals involving them are emitted.
parent ad5daa09
......@@ -43,7 +43,7 @@ libdeprecated_HEADERS = libnm_glib.h
lib_LTLIBRARIES = libnm-glib.la libnm-glib-vpn.la
libnm_glib_la_CFLAGS = \
$(GLIB_CFLAGS) \
$(GIO_CFLAGS) \
$(DBUS_CFLAGS) \
$(GUDEV_CFLAGS)
......@@ -117,7 +117,7 @@ libnm_glib_la_LIBADD = \
$(top_builddir)/libnm-util/libnm-util.la \
$(top_builddir)/marshallers/libmarshallers.la \
$(builddir)/libdeprecated-nm-glib.la \
$(GLIB_LIBS) \
$(GIO_LIBS) \
$(DBUS_LIBS) \
$(GUDEV_LIBS)
......@@ -129,16 +129,16 @@ libnm_glib_la_LDFLAGS = -Wl,--version-script=$(SYMBOL_VIS_FILE) \
noinst_PROGRAMS = libnm-glib-test
libnm_glib_test_SOURCES = libnm-glib-test.c
libnm_glib_test_CFLAGS = $(GLIB_CFLAGS) $(DBUS_CFLAGS)
libnm_glib_test_LDADD = libnm-glib.la $(top_builddir)/libnm-util/libnm-util.la $(GLIB_LIBS) $(DBUS_LIBS)
libnm_glib_test_CFLAGS = $(GIO_CFLAGS) $(DBUS_CFLAGS)
libnm_glib_test_LDADD = libnm-glib.la $(top_builddir)/libnm-util/libnm-util.la $(GIO_LIBS) $(DBUS_LIBS)
libnm_glib_vpn_la_SOURCES = \
nm-vpn-plugin.c \
nm-vpn-plugin-ui-interface.c \
nm-vpn-plugin-utils.c
libnm_glib_vpn_la_CFLAGS = $(GLIB_CFLAGS) $(DBUS_CFLAGS)
libnm_glib_vpn_la_LIBADD = $(top_builddir)/libnm-util/libnm-util.la $(GLIB_LIBS) $(DBUS_LIBS)
libnm_glib_vpn_la_CFLAGS = $(GIO_CFLAGS) $(DBUS_CFLAGS)
libnm_glib_vpn_la_LIBADD = $(top_builddir)/libnm-util/libnm-util.la $(GIO_LIBS) $(DBUS_LIBS)
libnm_glib_vpn_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libnm-glib-vpn.ver \
-version-info "2:0:1"
......@@ -147,7 +147,7 @@ libnm_glib_vpn_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libnm-glib-vpn.ver \
#####################################################
libnm_glib_test_la_CFLAGS = \
$(GLIB_CFLAGS) \
$(GIO_CFLAGS) \
$(DBUS_CFLAGS) \
$(GUDEV_CFLAGS) \
-DLIBNM_GLIB_TEST
......@@ -159,7 +159,7 @@ libnm_glib_test_la_SOURCES = \
libnm_glib_test_la_LIBADD = \
$(top_builddir)/libnm-util/libnm-util.la \
$(top_builddir)/marshallers/libmarshallers.la \
$(GLIB_LIBS) \
$(GIO_LIBS) \
$(DBUS_LIBS) \
$(GUDEV_LIBS)
......
......@@ -533,30 +533,21 @@ register_properties (NMAccessPoint *ap)
property_info);
}
static GObject*
constructor (GType type,
guint n_construct_params,
GObjectConstructParam *construct_params)
static void
constructed (GObject *object)
{
NMObject *object;
NMAccessPointPrivate *priv;
object = (NMObject *) G_OBJECT_CLASS (nm_access_point_parent_class)->constructor (type,
n_construct_params,
construct_params);
if (!object)
return NULL;
G_OBJECT_CLASS (nm_access_point_parent_class)->constructed (object);
priv = NM_ACCESS_POINT_GET_PRIVATE (object);
priv->proxy = dbus_g_proxy_new_for_name (nm_object_get_connection (object),
priv->proxy = dbus_g_proxy_new_for_name (nm_object_get_connection (NM_OBJECT (object)),
NM_DBUS_SERVICE,
nm_object_get_path (object),
nm_object_get_path (NM_OBJECT (object)),
NM_DBUS_INTERFACE_ACCESS_POINT);
register_properties (NM_ACCESS_POINT (object));
return G_OBJECT (object);
}
......@@ -568,7 +559,7 @@ nm_access_point_class_init (NMAccessPointClass *ap_class)
g_type_class_add_private (ap_class, sizeof (NMAccessPointPrivate));
/* virtual methods */
object_class->constructor = constructor;
object_class->constructed = constructed;
object_class->get_property = get_property;
object_class->dispose = dispose;
object_class->finalize = finalize;
......
......@@ -445,30 +445,21 @@ register_properties (NMActiveConnection *connection)
property_info);
}
static GObject*
constructor (GType type,
guint n_construct_params,
GObjectConstructParam *construct_params)
static void
constructed (GObject *object)
{
NMObject *object;
NMActiveConnectionPrivate *priv;
object = (NMObject *) G_OBJECT_CLASS (nm_active_connection_parent_class)->constructor (type,
n_construct_params,
construct_params);
if (!object)
return NULL;
G_OBJECT_CLASS (nm_active_connection_parent_class)->constructed (object);
priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object);
priv->proxy = dbus_g_proxy_new_for_name (nm_object_get_connection (object),
priv->proxy = dbus_g_proxy_new_for_name (nm_object_get_connection (NM_OBJECT (object)),
NM_DBUS_SERVICE,
nm_object_get_path (object),
nm_object_get_path (NM_OBJECT (object)),
NM_DBUS_INTERFACE_ACTIVE_CONNECTION);
register_properties (NM_ACTIVE_CONNECTION (object));
return G_OBJECT (object);
}
......@@ -480,7 +471,7 @@ nm_active_connection_class_init (NMActiveConnectionClass *ap_class)
g_type_class_add_private (ap_class, sizeof (NMActiveConnectionPrivate));
/* virtual methods */
object_class->constructor = constructor;
object_class->constructed = constructed;
object_class->get_property = get_property;
object_class->dispose = dispose;
object_class->finalize = finalize;
......
......@@ -39,7 +39,15 @@
void _nm_device_wifi_set_wireless_enabled (NMDeviceWifi *device, gboolean enabled);
G_DEFINE_TYPE (NMClient, nm_client, NM_TYPE_OBJECT)
static void nm_client_initable_iface_init (GInitableIface *iface);
static void nm_client_async_initable_iface_init (GAsyncInitableIface *iface);
static GInitableIface *nm_client_parent_initable_iface;
static GAsyncInitableIface *nm_client_parent_async_initable_iface;
G_DEFINE_TYPE_WITH_CODE (NMClient, nm_client, NM_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, nm_client_initable_iface_init);
G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, nm_client_async_initable_iface_init);
)
#define NM_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_CLIENT, NMClientPrivate))
......@@ -372,19 +380,21 @@ update_permissions (NMClient *self, GHashTable *permissions)
g_list_free (keys);
}
static void
get_permissions_sync (NMClient *self)
static gboolean
get_permissions_sync (NMClient *self, GError **error)
{
gboolean success;
GHashTable *permissions = NULL;
success = dbus_g_proxy_call_with_timeout (NM_CLIENT_GET_PRIVATE (self)->client_proxy,
"GetPermissions", 3000, NULL,
"GetPermissions", 3000, error,
G_TYPE_INVALID,
DBUS_TYPE_G_MAP_OF_STRING, &permissions, G_TYPE_INVALID);
update_permissions (self, success ? permissions : NULL);
if (permissions)
g_hash_table_destroy (permissions);
return success;
}
static void
......@@ -1191,6 +1201,7 @@ nm_client_new (void)
{
DBusGConnection *connection;
GError *err = NULL;
NMClient *client;
#ifdef LIBNM_GLIB_TEST
connection = dbus_g_bus_get (DBUS_BUS_SESSION, &err);
......@@ -1203,34 +1214,28 @@ nm_client_new (void)
return NULL;
}
return (NMClient *) g_object_new (NM_TYPE_CLIENT,
NM_OBJECT_DBUS_CONNECTION, connection,
NM_OBJECT_DBUS_PATH, NM_DBUS_PATH,
NULL);
client = g_object_new (NM_TYPE_CLIENT,
NM_OBJECT_DBUS_CONNECTION, connection,
NM_OBJECT_DBUS_PATH, NM_DBUS_PATH,
NULL);
_nm_object_ensure_inited (NM_OBJECT (client));
return client;
}
static GObject*
constructor (GType type,
guint n_construct_params,
GObjectConstructParam *construct_params)
static void
constructed (GObject *object)
{
NMObject *object;
DBusGConnection *connection;
NMClientPrivate *priv;
GError *err = NULL;
object = (NMObject *) G_OBJECT_CLASS (nm_client_parent_class)->constructor (type,
n_construct_params,
construct_params);
if (!object)
return NULL;
G_OBJECT_CLASS (nm_client_parent_class)->constructed (object);
priv = NM_CLIENT_GET_PRIVATE (object);
connection = nm_object_get_connection (object);
connection = nm_object_get_connection (NM_OBJECT (object));
priv->client_proxy = dbus_g_proxy_new_for_name (connection,
NM_DBUS_SERVICE,
nm_object_get_path (object),
nm_object_get_path (NM_OBJECT (object)),
NM_DBUS_INTERFACE);
register_properties (NM_CLIENT (object));
......@@ -1242,7 +1247,6 @@ constructor (GType type,
G_CALLBACK (client_recheck_permissions),
object,
NULL);
get_permissions_sync (NM_CLIENT (object));
priv->bus_proxy = dbus_g_proxy_new_for_name (connection,
DBUS_SERVICE_DBUS,
......@@ -1257,38 +1261,136 @@ constructor (GType type,
G_CALLBACK (proxy_name_owner_changed),
object, NULL);
g_signal_connect (object, "notify::" NM_CLIENT_WIRELESS_ENABLED,
G_CALLBACK (wireless_enabled_cb), NULL);
g_signal_connect (object, "notify::" NM_CLIENT_ACTIVE_CONNECTIONS,
G_CALLBACK (active_connections_changed_cb), NULL);
}
static gboolean
init_sync (GInitable *initable, GCancellable *cancellable, GError **error)
{
NMClient *client = NM_CLIENT (initable);
NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
if (!nm_client_parent_initable_iface->init (initable, cancellable, error))
return FALSE;
if (!dbus_g_proxy_call (priv->bus_proxy,
"NameHasOwner", &err,
G_TYPE_STRING, NM_DBUS_SERVICE,
G_TYPE_INVALID,
G_TYPE_BOOLEAN, &priv->manager_running,
G_TYPE_INVALID)) {
g_warning ("Error on NameHasOwner DBUS call: %s", err->message);
g_error_free (err);
}
"NameHasOwner", error,
G_TYPE_STRING, NM_DBUS_SERVICE,
G_TYPE_INVALID,
G_TYPE_BOOLEAN, &priv->manager_running,
G_TYPE_INVALID))
return FALSE;
if (priv->manager_running && !get_permissions_sync (client, error))
return FALSE;
return TRUE;
}
typedef struct {
NMClient *client;
GSimpleAsyncResult *result;
gboolean properties_pending;
gboolean permissions_pending;
} NMClientInitData;
static void
init_async_complete (NMClientInitData *init_data)
{
if (init_data->properties_pending || init_data->permissions_pending)
return;
g_simple_async_result_complete (init_data->result);
g_object_unref (init_data->result);
g_slice_free (NMClientInitData, init_data);
}
static void
init_async_got_permissions (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
{
NMClientInitData *init_data = user_data;
GHashTable *permissions;
GError *error = NULL;
dbus_g_proxy_end_call (proxy, call, &error,
DBUS_TYPE_G_MAP_OF_STRING, &permissions,
G_TYPE_INVALID);
update_permissions (init_data->client, error ? NULL : permissions);
g_clear_error (&error);
init_data->permissions_pending = FALSE;
init_async_complete (init_data);
}
static void
init_async_got_properties (GObject *source, GAsyncResult *result, gpointer user_data)
{
NMClientInitData *init_data = user_data;
GError *error = NULL;
if (priv->manager_running) {
update_wireless_status (NM_CLIENT (object), FALSE);
update_wwan_status (NM_CLIENT (object), FALSE);
update_wimax_status (NM_CLIENT (object), FALSE);
nm_client_get_state (NM_CLIENT (object));
if (!nm_client_parent_async_initable_iface->init_finish (G_ASYNC_INITABLE (source), result, &error))
g_simple_async_result_take_error (init_data->result, error);
init_data->properties_pending = FALSE;
init_async_complete (init_data);
}
static void
init_async_got_manager_running (DBusGProxy *proxy, DBusGProxyCall *call,
gpointer user_data)
{
NMClientInitData *init_data = user_data;
NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (init_data->client);
GError *error = NULL;
if (!dbus_g_proxy_end_call (proxy, call, &error,
G_TYPE_BOOLEAN, &priv->manager_running,
G_TYPE_INVALID)) {
g_simple_async_result_take_error (init_data->result, error);
init_async_complete (init_data);
return;
}
g_signal_connect (G_OBJECT (object), "notify::" NM_CLIENT_WIRELESS_ENABLED,
G_CALLBACK (wireless_enabled_cb), NULL);
if (!priv->manager_running) {
g_simple_async_result_set_op_res_gboolean (init_data->result, TRUE);
init_async_complete (init_data);
return;
}
g_signal_connect (object, "notify::" NM_CLIENT_ACTIVE_CONNECTIONS,
G_CALLBACK (active_connections_changed_cb), NULL);
nm_client_parent_async_initable_iface->init_async (G_ASYNC_INITABLE (init_data->client),
G_PRIORITY_DEFAULT, NULL, /* FIXME cancellable */
init_async_got_properties, init_data);
init_data->properties_pending = TRUE;
/* Get initial devices from NM. It is important to do it early. Else,
* a 'lazy' call won't find removed device.
* Solves this case: DeviceRemoved signal is received, we get devices
* from NM, but the removed object path is not there any more, and
* NMClient doesn't have the device either.
*/
nm_client_get_devices (NM_CLIENT (object));
dbus_g_proxy_begin_call (priv->client_proxy, "GetPermissions",
init_async_got_permissions, init_data, NULL,
G_TYPE_INVALID);
init_data->permissions_pending = TRUE;
}
return G_OBJECT (object);
static void
init_async (GAsyncInitable *initable, int io_priority,
GCancellable *cancellable, GAsyncReadyCallback callback,
gpointer user_data)
{
NMClientInitData *init_data;
NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (initable);
init_data = g_slice_new0 (NMClientInitData);
init_data->client = NM_CLIENT (initable);
init_data->result = g_simple_async_result_new (G_OBJECT (initable), callback,
user_data, init_async);
/* Check if NM is running */
dbus_g_proxy_begin_call (priv->bus_proxy, "NameHasOwner",
init_async_got_manager_running,
init_data, NULL,
G_TYPE_STRING, NM_DBUS_SERVICE,
G_TYPE_INVALID);
}
static void
......@@ -1427,7 +1529,7 @@ nm_client_class_init (NMClientClass *client_class)
g_type_class_add_private (client_class, sizeof (NMClientPrivate));
/* virtual methods */
object_class->constructor = constructor;
object_class->constructed = constructed;
object_class->set_property = set_property;
object_class->get_property = get_property;
object_class->dispose = dispose;
......@@ -1631,3 +1733,18 @@ nm_client_class_init (NMClientClass *client_class)
G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
}
static void
nm_client_initable_iface_init (GInitableIface *iface)
{
nm_client_parent_initable_iface = g_type_interface_peek_parent (iface);
iface->init = init_sync;
}
static void
nm_client_async_initable_iface_init (GAsyncInitableIface *iface)
{
nm_client_parent_async_initable_iface = g_type_interface_peek_parent (iface);
iface->init_async = init_async;
}
......@@ -216,28 +216,19 @@ register_properties (NMDeviceBt *device)
property_info);
}
static GObject*
constructor (GType type,
guint n_construct_params,
GObjectConstructParam *construct_params)
static void
constructed (GObject *object)
{
GObject *object;
object = G_OBJECT_CLASS (nm_device_bt_parent_class)->constructor (type,
n_construct_params,
construct_params);
if (object) {
NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (object);
NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (object);
priv->proxy = dbus_g_proxy_new_for_name (nm_object_get_connection (NM_OBJECT (object)),
NM_DBUS_SERVICE,
nm_object_get_path (NM_OBJECT (object)),
NM_DBUS_INTERFACE_DEVICE_BLUETOOTH);
G_OBJECT_CLASS (nm_device_bt_parent_class)->constructed (object);
register_properties (NM_DEVICE_BT (object));
}
priv->proxy = dbus_g_proxy_new_for_name (nm_object_get_connection (NM_OBJECT (object)),
NM_DBUS_SERVICE,
nm_object_get_path (NM_OBJECT (object)),
NM_DBUS_INTERFACE_DEVICE_BLUETOOTH);
return object;
register_properties (NM_DEVICE_BT (object));
}
static void
......@@ -300,7 +291,7 @@ nm_device_bt_class_init (NMDeviceBtClass *bt_class)
g_type_class_add_private (bt_class, sizeof (NMDeviceBtPrivate));
/* virtual methods */
object_class->constructor = constructor;
object_class->constructed = constructed;
object_class->dispose = dispose;
object_class->finalize = finalize;
object_class->get_property = get_property;
......
......@@ -75,13 +75,17 @@ enum {
GObject *
nm_device_ethernet_new (DBusGConnection *connection, const char *path)
{
GObject *device;
g_return_val_if_fail (connection != NULL, NULL);
g_return_val_if_fail (path != NULL, NULL);
return g_object_new (NM_TYPE_DEVICE_ETHERNET,
NM_OBJECT_DBUS_CONNECTION, connection,
NM_OBJECT_DBUS_PATH, path,
NULL);
device = g_object_new (NM_TYPE_DEVICE_ETHERNET,
NM_OBJECT_DBUS_CONNECTION, connection,
NM_OBJECT_DBUS_PATH, path,
NULL);
_nm_object_ensure_inited (NM_OBJECT (device));
return device;
}
/**
......@@ -224,19 +228,12 @@ register_properties (NMDeviceEthernet *device)
property_info);
}
static GObject*
constructor (GType type,
guint n_construct_params,
GObjectConstructParam *construct_params)
static void
constructed (GObject *object)
{
GObject *object;
NMDeviceEthernetPrivate *priv;
object = G_OBJECT_CLASS (nm_device_ethernet_parent_class)->constructor (type,
n_construct_params,
construct_params);
if (!object)
return NULL;
G_OBJECT_CLASS (nm_device_ethernet_parent_class)->constructed (object);
priv = NM_DEVICE_ETHERNET_GET_PRIVATE (object);
......@@ -246,8 +243,6 @@ constructor (GType type,
NM_DBUS_INTERFACE_DEVICE_WIRED);
register_properties (NM_DEVICE_ETHERNET (object));
return object;
}
static void
......@@ -314,7 +309,7 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *eth_class)
g_type_class_add_private (eth_class, sizeof (NMDeviceEthernetPrivate));
/* virtual methods */
object_class->constructor = constructor;
object_class->constructed = constructed;
object_class->dispose = dispose;
object_class->finalize = finalize;
object_class->get_property = get_property;
......
......@@ -68,13 +68,17 @@ enum {
GObject *
nm_device_infiniband_new (DBusGConnection *connection, const char *path)
{
GObject *device;
g_return_val_if_fail (connection != NULL, NULL);
g_return_val_if_fail (path != NULL, NULL);
return g_object_new (NM_TYPE_DEVICE_INFINIBAND,
NM_OBJECT_DBUS_CONNECTION, connection,
NM_OBJECT_DBUS_PATH, path,
NULL);
device = g_object_new (NM_TYPE_DEVICE_INFINIBAND,
NM_OBJECT_DBUS_CONNECTION, connection,
NM_OBJECT_DBUS_PATH, path,
NULL);
_nm_object_ensure_inited (NM_OBJECT (device));
return device;
}
/**
......@@ -168,19 +172,12 @@ register_properties (NMDeviceInfiniband *device)
property_info);
}
static GObject*
constructor (GType type,
guint n_construct_params,
GObjectConstructParam *construct_params)
static void
constructed (GObject *object)
{
GObject *object;
NMDeviceInfinibandPrivate *priv;
object = G_OBJECT_CLASS (nm_device_infiniband_parent_class)->constructor (type,
n_construct_params,
construct_params);
if (!object)
return NULL;
G_OBJECT_CLASS (nm_device_infiniband_parent_class)->constructed (object);
priv = NM_DEVICE_INFINIBAND_GET_PRIVATE (object);
......@@ -190,8 +187,6 @@ constructor (GType type,
NM_DBUS_INTERFACE_DEVICE_INFINIBAND);
register_properties (NM_DEVICE_INFINIBAND (object));
return object;
}
static void
......@@ -247,7 +242,7 @@ nm_device_infiniband_class_init (NMDeviceInfinibandClass *eth_class)
g_type_class_add_private (eth_class, sizeof (NMDeviceInfinibandPrivate));
/* virtual methods */
object_class->constructor = constructor;
object_class->constructed = constructed;
object_class->dispose = dispose;
object_class->finalize = finalize;
object_class->get_property = get_property;
......
......@@ -147,29 +147,21 @@ register_properties (NMDeviceModem *device)
property_info);
}
static GObject*
constructor (GType type,
guint n_construct_params,
GObjectConstructParam *construct_params)