diff --git a/libnm-glib/nm-active-connection.c b/libnm-glib/nm-active-connection.c index a68da56b6..0c922b7b4 100644 --- a/libnm-glib/nm-active-connection.c +++ b/libnm-glib/nm-active-connection.c @@ -28,15 +28,25 @@ #include "nm-object-private.h" #include "nm-types-private.h" #include "nm-device.h" +#include "nm-device-private.h" #include "nm-connection.h" +#include "nm-vpn-connection.h" -G_DEFINE_TYPE (NMActiveConnection, nm_active_connection, NM_TYPE_OBJECT) +static GType nm_active_connection_type_for_path (DBusGConnection *connection, + const char *path); +static void nm_active_connection_type_for_path_async (DBusGConnection *connection, + const char *path, + NMObjectTypeCallbackFunc callback, + gpointer user_data); + +G_DEFINE_TYPE_WITH_CODE (NMActiveConnection, nm_active_connection, NM_TYPE_OBJECT, + _nm_object_register_type_func (g_define_type_id, + nm_active_connection_type_for_path, + nm_active_connection_type_for_path_async); + ) #define NM_ACTIVE_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_ACTIVE_CONNECTION, NMActiveConnectionPrivate)) -static gboolean demarshal_devices (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field); - - typedef struct { gboolean disposed; DBusGProxy *proxy; @@ -95,6 +105,104 @@ nm_active_connection_new (DBusGConnection *connection, const char *path) NULL); } +static GType +nm_active_connection_type_for_path (DBusGConnection *connection, + const char *path) +{ + DBusGProxy *proxy; + GError *error = NULL; + GValue value = {0,}; + GType type; + + proxy = dbus_g_proxy_new_for_name (connection, + NM_DBUS_SERVICE, + path, + "org.freedesktop.DBus.Properties"); + if (!proxy) { + g_warning ("%s: couldn't create D-Bus object proxy.", __func__); + return G_TYPE_INVALID; + } + + /* Have to create an NMVPNConnection if it's a VPN connection, otherwise + * a plain NMActiveConnection. + */ + if (dbus_g_proxy_call (proxy, + "Get", &error, + G_TYPE_STRING, NM_DBUS_INTERFACE_ACTIVE_CONNECTION, + G_TYPE_STRING, "Vpn", + G_TYPE_INVALID, + G_TYPE_VALUE, &value, G_TYPE_INVALID)) { + if (g_value_get_boolean (&value)) + type = NM_TYPE_VPN_CONNECTION; + else + type = NM_TYPE_ACTIVE_CONNECTION; + } else { + g_warning ("Error in getting active connection 'Vpn' property: (%d) %s", + error->code, error->message); + g_error_free (error); + type = G_TYPE_INVALID; + } + + g_object_unref (proxy); + return type; +} + +typedef struct { + DBusGConnection *connection; + NMObjectTypeCallbackFunc callback; + gpointer user_data; +} NMActiveConnectionAsyncData; + +static void +async_got_type (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data) +{ + NMActiveConnectionAsyncData *async_data = user_data; + GValue value = G_VALUE_INIT; + const char *path = dbus_g_proxy_get_path (proxy); + GError *error = NULL; + GType type; + + if (dbus_g_proxy_end_call (proxy, call, &error, + G_TYPE_VALUE, &value, + G_TYPE_INVALID)) { + if (g_value_get_boolean (&value)) + type = NM_TYPE_VPN_CONNECTION; + else + type = NM_TYPE_ACTIVE_CONNECTION; + } else { + g_warning ("%s: could not read properties for %s: %s", __func__, path, error->message); + type = G_TYPE_INVALID; + } + + async_data->callback (type, async_data->user_data); + + g_object_unref (proxy); + g_slice_free (NMActiveConnectionAsyncData, async_data); +} + +static void +nm_active_connection_type_for_path_async (DBusGConnection *connection, + const char *path, + NMObjectTypeCallbackFunc callback, + gpointer user_data) +{ + NMActiveConnectionAsyncData *async_data; + DBusGProxy *proxy; + + async_data = g_slice_new (NMActiveConnectionAsyncData); + async_data->connection = connection; + async_data->callback = callback; + async_data->user_data = user_data; + + proxy = dbus_g_proxy_new_for_name (connection, NM_DBUS_SERVICE, path, + "org.freedesktop.DBus.Properties"); + dbus_g_proxy_begin_call (proxy, "Get", + async_got_type, async_data, NULL, + G_TYPE_STRING, NM_DBUS_INTERFACE_ACTIVE_CONNECTION, + G_TYPE_STRING, "Vpn", + G_TYPE_INVALID); +} + /** * nm_active_connection_get_connection: * @connection: a #NMActiveConnection @@ -316,19 +424,6 @@ get_property (GObject *object, } } -static gboolean -demarshal_devices (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field) -{ - DBusGConnection *connection; - - connection = nm_object_get_connection (object); - if (!_nm_object_array_demarshal (value, (GPtrArray **) field, connection, nm_device_new)) - return FALSE; - - _nm_object_queue_notify (object, NM_ACTIVE_CONNECTION_DEVICES); - return TRUE; -} - static void register_properties (NMActiveConnection *connection) { @@ -337,7 +432,7 @@ register_properties (NMActiveConnection *connection) { NM_ACTIVE_CONNECTION_CONNECTION, &priv->connection }, { NM_ACTIVE_CONNECTION_UUID, &priv->uuid }, { NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, &priv->specific_object }, - { NM_ACTIVE_CONNECTION_DEVICES, &priv->devices, demarshal_devices }, + { NM_ACTIVE_CONNECTION_DEVICES, &priv->devices, NULL, NM_TYPE_DEVICE }, { NM_ACTIVE_CONNECTION_STATE, &priv->state }, { NM_ACTIVE_CONNECTION_DEFAULT, &priv->is_default }, { NM_ACTIVE_CONNECTION_DEFAULT6, &priv->is_default6 }, diff --git a/libnm-glib/nm-client.c b/libnm-glib/nm-client.c index 9bf8bcb3e..a0f6214f3 100644 --- a/libnm-glib/nm-client.c +++ b/libnm-glib/nm-client.c @@ -235,62 +235,6 @@ update_wimax_status (NMClient *client, gboolean notify) } } -static GObject * -new_active_connection (DBusGConnection *connection, const char *path) -{ - DBusGProxy *proxy; - GError *error = NULL; - GValue value = {0,}; - GObject *object = NULL; - - proxy = dbus_g_proxy_new_for_name (connection, - NM_DBUS_SERVICE, - path, - "org.freedesktop.DBus.Properties"); - if (!proxy) { - g_warning ("%s: couldn't create D-Bus object proxy.", __func__); - return NULL; - } - - /* Have to create an NMVPNConnection if it's a VPN connection, otherwise - * a plain NMActiveConnection. - */ - if (dbus_g_proxy_call (proxy, - "Get", &error, - G_TYPE_STRING, NM_DBUS_INTERFACE_ACTIVE_CONNECTION, - G_TYPE_STRING, "Vpn", - G_TYPE_INVALID, - G_TYPE_VALUE, &value, G_TYPE_INVALID)) { - if (g_value_get_boolean (&value)) - object = nm_vpn_connection_new (connection, path); - else - object = nm_active_connection_new (connection, path); - } else { - g_warning ("Error in getting active connection 'Vpn' property: (%d) %s", - error->code, error->message); - g_error_free (error); - } - - g_object_unref (proxy); - return object; -} - -static gboolean -demarshal_active_connections (NMObject *object, - GParamSpec *pspec, - GValue *value, - gpointer field) -{ - DBusGConnection *connection; - - connection = nm_object_get_connection (object); - if (!_nm_object_array_demarshal (value, (GPtrArray **) field, connection, new_active_connection)) - return FALSE; - - _nm_object_queue_notify (object, NM_CLIENT_ACTIVE_CONNECTIONS); - return TRUE; -} - static void register_properties (NMClient *client) { @@ -305,7 +249,7 @@ register_properties (NMClient *client) { NM_CLIENT_WWAN_HARDWARE_ENABLED, &priv->wwan_hw_enabled }, { NM_CLIENT_WIMAX_ENABLED, &priv->wimax_enabled }, { NM_CLIENT_WIMAX_HARDWARE_ENABLED, &priv->wimax_hw_enabled }, - { NM_CLIENT_ACTIVE_CONNECTIONS, &priv->active_connections, demarshal_active_connections }, + { NM_CLIENT_ACTIVE_CONNECTIONS, &priv->active_connections, NULL, NM_TYPE_ACTIVE_CONNECTION }, { NULL }, }; diff --git a/libnm-glib/nm-device-private.h b/libnm-glib/nm-device-private.h index 2c56a0e64..5abf03f30 100644 --- a/libnm-glib/nm-device-private.h +++ b/libnm-glib/nm-device-private.h @@ -29,8 +29,4 @@ DBusGConnection *nm_device_get_connection (NMDevice *device); const char *nm_device_get_path (NMDevice *device); DBusGProxy *nm_device_get_properties_proxy (NMDevice *device); -/* static methods */ -NMDeviceType nm_device_type_for_path (DBusGConnection *connection, - const char *path); - #endif /* NM_DEVICE_PRIVATE_H */ diff --git a/libnm-glib/nm-device-wifi.c b/libnm-glib/nm-device-wifi.c index 91106d3ee..ca0dfba0e 100644 --- a/libnm-glib/nm-device-wifi.c +++ b/libnm-glib/nm-device-wifi.c @@ -40,8 +40,6 @@ G_DEFINE_TYPE (NMDeviceWifi, nm_device_wifi, NM_TYPE_DEVICE) #define NM_DEVICE_WIFI_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_WIFI, NMDeviceWifiPrivate)) -static gboolean demarshal_active_ap (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field); - void _nm_device_wifi_set_wireless_enabled (NMDeviceWifi *device, gboolean enabled); typedef struct { @@ -566,40 +564,6 @@ state_changed_cb (NMDevice *device, GParamSpec *pspec, gpointer user_data) } } -static gboolean -demarshal_active_ap (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (object); - const char *path; - NMAccessPoint *ap = NULL; - DBusGConnection *connection; - - if (value) { - if (!G_VALUE_HOLDS (value, DBUS_TYPE_G_OBJECT_PATH)) - return FALSE; - - path = g_value_get_boxed (value); - if (path) { - ap = NM_ACCESS_POINT (_nm_object_cache_get (path)); - if (!ap) { - connection = nm_object_get_connection (object); - ap = NM_ACCESS_POINT (nm_access_point_new (connection, path)); - } - } - } - - if (priv->active_ap) { - g_object_unref (priv->active_ap); - priv->active_ap = NULL; - } - - if (ap) - priv->active_ap = ap; - - _nm_object_queue_notify (object, NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT); - return TRUE; -} - static void register_properties (NMDeviceWifi *device) { @@ -609,7 +573,7 @@ register_properties (NMDeviceWifi *device) { NM_DEVICE_WIFI_PERMANENT_HW_ADDRESS, &priv->perm_hw_address }, { NM_DEVICE_WIFI_MODE, &priv->mode }, { NM_DEVICE_WIFI_BITRATE, &priv->rate }, - { NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT, &priv->active_ap, demarshal_active_ap }, + { NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT, &priv->active_ap, NULL, NM_TYPE_ACCESS_POINT }, { NM_DEVICE_WIFI_CAPABILITIES, &priv->wireless_caps }, { NULL }, }; diff --git a/libnm-glib/nm-device-wimax.c b/libnm-glib/nm-device-wimax.c index d9555a329..e464dd99f 100644 --- a/libnm-glib/nm-device-wimax.c +++ b/libnm-glib/nm-device-wimax.c @@ -38,8 +38,6 @@ G_DEFINE_TYPE (NMDeviceWimax, nm_device_wimax, NM_TYPE_DEVICE) #define NM_DEVICE_WIMAX_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_WIMAX, NMDeviceWimaxPrivate)) -static gboolean demarshal_active_nsp (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field); - void _nm_device_wimax_set_wireless_enabled (NMDeviceWimax *wimax, gboolean enabled); typedef struct { @@ -552,47 +550,13 @@ state_changed_cb (NMDevice *device, GParamSpec *pspec, gpointer user_data) } } -static gboolean -demarshal_active_nsp (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field) -{ - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (object); - const char *path; - NMWimaxNsp *nsp = NULL; - DBusGConnection *connection; - - if (value) { - if (!G_VALUE_HOLDS (value, DBUS_TYPE_G_OBJECT_PATH)) - return FALSE; - - path = g_value_get_boxed (value); - if (path) { - nsp = NM_WIMAX_NSP (_nm_object_cache_get (path)); - if (!nsp) { - connection = nm_object_get_connection (object); - nsp = NM_WIMAX_NSP (nm_wimax_nsp_new (connection, path)); - } - } - } - - if (priv->active_nsp) { - g_object_unref (priv->active_nsp); - priv->active_nsp = NULL; - } - - if (nsp) - priv->active_nsp = nsp; - - _nm_object_queue_notify (object, NM_DEVICE_WIMAX_ACTIVE_NSP); - return TRUE; -} - static void register_properties (NMDeviceWimax *wimax) { NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (wimax); const NMPropertiesInfo property_info[] = { { NM_DEVICE_WIMAX_HW_ADDRESS, &priv->hw_address }, - { NM_DEVICE_WIMAX_ACTIVE_NSP, &priv->active_nsp, demarshal_active_nsp }, + { NM_DEVICE_WIMAX_ACTIVE_NSP, &priv->active_nsp, NULL, NM_TYPE_WIMAX_NSP }, { NM_DEVICE_WIMAX_CENTER_FREQUENCY, &priv->center_freq }, { NM_DEVICE_WIMAX_RSSI, &priv->rssi }, { NM_DEVICE_WIMAX_CINR, &priv->cinr }, diff --git a/libnm-glib/nm-device.c b/libnm-glib/nm-device.c index 208f41507..616f110c1 100644 --- a/libnm-glib/nm-device.c +++ b/libnm-glib/nm-device.c @@ -39,7 +39,17 @@ #include "nm-marshal.h" #include "nm-dbus-glib-types.h" -G_DEFINE_TYPE (NMDevice, nm_device, NM_TYPE_OBJECT) +static GType nm_device_type_for_path (DBusGConnection *connection, + const char *path); +static void nm_device_type_for_path_async (DBusGConnection *connection, + const char *path, + NMObjectTypeCallbackFunc callback, + gpointer user_data); + +G_DEFINE_TYPE_WITH_CODE (NMDevice, nm_device, NM_TYPE_OBJECT, + _nm_object_register_type_func (g_define_type_id, nm_device_type_for_path, + nm_device_type_for_path_async); + ) #define NM_DEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE, NMDevicePrivate)) @@ -107,176 +117,6 @@ nm_device_init (NMDevice *device) priv->state = NM_DEVICE_STATE_UNKNOWN; } -static gboolean -demarshal_ip4_config (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (object); - const char *path; - NMIP4Config *config = NULL; - DBusGConnection *connection; - - if (value) { - if (!G_VALUE_HOLDS (value, DBUS_TYPE_G_OBJECT_PATH)) - return FALSE; - - path = g_value_get_boxed (value); - if (path) { - config = NM_IP4_CONFIG (_nm_object_cache_get (path)); - if (!config) { - connection = nm_object_get_connection (object); - config = NM_IP4_CONFIG (nm_ip4_config_new (connection, path)); - } - } - } - - if (priv->ip4_config) { - g_object_unref (priv->ip4_config); - priv->ip4_config = NULL; - } - - if (config) - priv->ip4_config = config; - - _nm_object_queue_notify (object, NM_DEVICE_IP4_CONFIG); - return TRUE; -} - -static gboolean -demarshal_dhcp4_config (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (object); - const char *path; - NMDHCP4Config *config = NULL; - DBusGConnection *connection; - - if (value) { - if (!G_VALUE_HOLDS (value, DBUS_TYPE_G_OBJECT_PATH)) - return FALSE; - - path = g_value_get_boxed (value); - if (path) { - config = NM_DHCP4_CONFIG (_nm_object_cache_get (path)); - if (!config) { - connection = nm_object_get_connection (object); - config = NM_DHCP4_CONFIG (nm_dhcp4_config_new (connection, path)); - } - } - } - - if (priv->dhcp4_config) { - g_object_unref (priv->dhcp4_config); - priv->dhcp4_config = NULL; - } - - if (config) - priv->dhcp4_config = config; - - _nm_object_queue_notify (object, NM_DEVICE_DHCP4_CONFIG); - return TRUE; -} - -static gboolean -demarshal_ip6_config (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (object); - const char *path; - NMIP6Config *config = NULL; - DBusGConnection *connection; - - if (value) { - if (!G_VALUE_HOLDS (value, DBUS_TYPE_G_OBJECT_PATH)) - return FALSE; - - path = g_value_get_boxed (value); - if (path) { - config = NM_IP6_CONFIG (_nm_object_cache_get (path)); - if (!config) { - connection = nm_object_get_connection (object); - config = NM_IP6_CONFIG (nm_ip6_config_new (connection, path)); - } - } - } - - if (priv->ip6_config) { - g_object_unref (priv->ip6_config); - priv->ip6_config = NULL; - } - - if (config) - priv->ip6_config = config; - - _nm_object_queue_notify (object, NM_DEVICE_IP6_CONFIG); - return TRUE; -} - -static gboolean -demarshal_dhcp6_config (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (object); - const char *path; - NMDHCP6Config *config = NULL; - DBusGConnection *connection; - - if (value) { - if (!G_VALUE_HOLDS (value, DBUS_TYPE_G_OBJECT_PATH)) - return FALSE; - - path = g_value_get_boxed (value); - if (path) { - config = NM_DHCP6_CONFIG (_nm_object_cache_get (path)); - if (!config) { - connection = nm_object_get_connection (object); - config = NM_DHCP6_CONFIG (nm_dhcp6_config_new (connection, path)); - } - } - } - - if (priv->dhcp6_config) { - g_object_unref (priv->dhcp6_config); - priv->dhcp6_config = NULL; - } - - if (config) - priv->dhcp6_config = config; - - _nm_object_queue_notify (object, NM_DEVICE_DHCP6_CONFIG); - return TRUE; -} - -static gboolean -demarshal_active_connection (NMObject *object, GParamSpec *pspec, GValue *value, gpointer field) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (object); - const char *path; - NMActiveConnection *active = NULL; - DBusGConnection *connection; - - if (value) { - if (!G_VALUE_HOLDS (value, DBUS_TYPE_G_OBJECT_PATH)) - return FALSE; - - path = g_value_get_boxed (value); - if (path) { - active = NM_ACTIVE_CONNECTION (_nm_object_cache_get (path)); - if (!active) { - connection = nm_object_get_connection (object); - active = NM_ACTIVE_CONNECTION (nm_active_connection_new (connection, path)); - } - } - } - - if (priv->active_connection) { - g_object_unref (priv->active_connection); - priv->active_connection = NULL; - } - - if (active) - priv->active_connection = active; - - _nm_object_queue_notify (object, NM_DEVICE_ACTIVE_CONNECTION); - return TRUE; -} - static void register_properties (NMDevice *device) { @@ -289,12 +129,12 @@ register_properties (NMDevice *device) { NM_DEVICE_CAPABILITIES, &priv->capabilities }, { NM_DEVICE_MANAGED, &priv->managed }, { NM_DEVICE_FIRMWARE_MISSING, &priv->firmware_missing }, - { NM_DEVICE_IP4_CONFIG, &priv->ip4_config, demarshal_ip4_config }, - { NM_DEVICE_DHCP4_CONFIG, &priv->dhcp4_config, demarshal_dhcp4_config }, - { NM_DEVICE_IP6_CONFIG, &priv->ip6_config, demarshal_ip6_config }, - { NM_DEVICE_DHCP6_CONFIG, &priv->dhcp6_config, demarshal_dhcp6_config }, + { NM_DEVICE_IP4_CONFIG, &priv->ip4_config, NULL, NM_TYPE_IP4_CONFIG }, + { NM_DEVICE_DHCP4_CONFIG, &priv->dhcp4_config, NULL, NM_TYPE_DHCP4_CONFIG }, + { NM_DEVICE_IP6_CONFIG, &priv->ip6_config, NULL, NM_TYPE_IP6_CONFIG }, + { NM_DEVICE_DHCP6_CONFIG, &priv->dhcp6_config, NULL, NM_TYPE_DHCP6_CONFIG }, { NM_DEVICE_STATE, &priv->state }, - { NM_DEVICE_ACTIVE_CONNECTION, &priv->active_connection, demarshal_active_connection }, + { NM_DEVICE_ACTIVE_CONNECTION, &priv->active_connection, NULL, NM_TYPE_ACTIVE_CONNECTION }, /* The D-Bus interface has this property, but we don't; register * it so that handle_property_changed() doesn't complain. @@ -795,6 +635,62 @@ nm_device_class_init (NMDeviceClass *device_class) G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT); } +static GType +nm_device_gtype_from_dtype (NMDeviceType dtype) +{ + switch (dtype) { + case NM_DEVICE_TYPE_ETHERNET: + return NM_TYPE_DEVICE_ETHERNET; + case NM_DEVICE_TYPE_WIFI: + return NM_TYPE_DEVICE_WIFI; + case NM_DEVICE_TYPE_MODEM: + return NM_TYPE_DEVICE_MODEM; + case NM_DEVICE_TYPE_BT: + return NM_TYPE_DEVICE_BT; + case NM_DEVICE_TYPE_WIMAX: + return NM_TYPE_DEVICE_WIMAX; + case NM_DEVICE_TYPE_INFINIBAND: + return NM_TYPE_DEVICE_INFINIBAND; + default: + g_warning ("Unknown device type %d", dtype); + return G_TYPE_INVALID; + } +} + +static GType +nm_device_type_for_path (DBusGConnection *connection, + const char *path) +{ + DBusGProxy *proxy; + GError *err = NULL; + GValue value = {0,}; + NMDeviceType nm_dtype; + + proxy = dbus_g_proxy_new_for_name (connection, + NM_DBUS_SERVICE, + path, + "org.freedesktop.DBus.Properties"); + if (!proxy) { + g_warning ("%s: couldn't create D-Bus object proxy.", __func__); + return G_TYPE_INVALID; + } + + if (!dbus_g_proxy_call (proxy, + "Get", &err, + G_TYPE_STRING, NM_DBUS_INTERFACE_DEVICE, + G_TYPE_STRING, "DeviceType", + G_TYPE_INVALID, + G_TYPE_VALUE, &value, G_TYPE_INVALID)) { + g_object_unref (proxy); + g_warning ("Error in get_property: %s\n", err->message); + g_error_free (err); + } + g_object_unref (proxy); + + nm_dtype = g_value_get_uint (&value); + return nm_device_gtype_from_dtype (nm_dtype); +} + /** * nm_device_new: * @connection: the #DBusGConnection @@ -807,72 +703,75 @@ nm_device_class_init (NMDeviceClass *device_class) GObject * nm_device_new (DBusGConnection *connection, const char *path) { - DBusGProxy *proxy; - GError *err = NULL; - GValue value = {0,}; - GType dtype = 0; - NMDevice *device = NULL; - NMDeviceType nm_dtype; + GType dtype; g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (path != NULL, NULL); - proxy = dbus_g_proxy_new_for_name (connection, - NM_DBUS_SERVICE, - path, - "org.freedesktop.DBus.Properties"); - if (!proxy) { - g_warning ("%s: couldn't create D-Bus object proxy.", __func__); + dtype = nm_device_type_for_path (connection, path); + if (dtype == G_TYPE_INVALID) return NULL; + + return g_object_new (dtype, + NM_OBJECT_DBUS_CONNECTION, connection, + NM_OBJECT_DBUS_PATH, path, + NULL); +} + +typedef struct { + DBusGConnection *connection; + NMObjectTypeCallbackFunc callback; + gpointer user_data; +} NMDeviceAsyncData; + +static void +async_got_type (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data) +{ + NMDeviceAsyncData *async_data = user_data; + GValue value = G_VALUE_INIT; + const char *path = dbus_g_proxy_get_path (proxy); + GError *error = NULL; + GType type; + + if (dbus_g_proxy_end_call (proxy, call, &error, + G_TYPE_VALUE, &value, + G_TYPE_INVALID)) { + NMDeviceType dtype; + + dtype = g_value_get_uint (&value); + type = nm_device_gtype_from_dtype (dtype); + } else { + g_warning ("%s: could not read properties for %s: %s", __func__, path, error->message); + g_error_free (error); + type = G_TYPE_INVALID; } - if (!dbus_g_proxy_call (proxy, - "Get", &err, - G_TYPE_STRING, NM_DBUS_INTERFACE_DEVICE, - G_TYPE_STRING, "DeviceType", - G_TYPE_INVALID, - G_TYPE_VALUE, &value, G_TYPE_INVALID)) { - g_warning ("Error in get_property: %s\n", err->message); - g_error_free (err); - goto out; - } - - nm_dtype = g_value_get_uint (&value); - switch (nm_dtype) { - case NM_DEVICE_TYPE_ETHERNET: - dtype = NM_TYPE_DEVICE_ETHERNET; - break; - case NM_DEVICE_TYPE_WIFI: - dtype = NM_TYPE_DEVICE_WIFI; - break; - case NM_DEVICE_TYPE_MODEM: - dtype = NM_TYPE_DEVICE_MODEM; - break; - case NM_DEVICE_TYPE_BT: - dtype = NM_TYPE_DEVICE_BT; - break; - case NM_DEVICE_TYPE_WIMAX: - dtype = NM_TYPE_DEVICE_WIMAX; - break; - case NM_DEVICE_TYPE_INFINIBAND: - dtype = NM_TYPE_DEVICE_INFINIBAND; - break; - default: - g_warning ("Unknown device type %d", g_value_get_uint (&value)); - break; - } - - if (dtype) { - device = (NMDevice *) g_object_new (dtype, - NM_OBJECT_DBUS_CONNECTION, connection, - NM_OBJECT_DBUS_PATH, path, - NM_DEVICE_DEVICE_TYPE, nm_dtype, - NULL); - } - -out: + async_data->callback (type, async_data->user_data); g_object_unref (proxy); - return G_OBJECT (device); + g_slice_free (NMDeviceAsyncData, async_data); +} + +static void +nm_device_type_for_path_async (DBusGConnection *connection, + const char *path, + NMObjectTypeCallbackFunc callback, + gpointer user_data) +{ + NMDeviceAsyncData *async_data; + DBusGProxy *proxy; + + async_data = g_slice_new (NMDeviceAsyncData); + async_data->connection = connection; + async_data->callback = callback; + async_data->user_data = user_data; + + proxy = dbus_g_proxy_new_for_name (connection, NM_DBUS_SERVICE, path, + "org.freedesktop.DBus.Properties"); + dbus_g_proxy_begin_call (proxy, "Get", + async_got_type, async_data, NULL, + G_TYPE_STRING, NM_DBUS_INTERFACE_DEVICE, + G_TYPE_STRING, "DeviceType", + G_TYPE_INVALID); } /** @@ -923,9 +822,31 @@ nm_device_get_ip_iface (NMDevice *device) NMDeviceType nm_device_get_device_type (NMDevice *self) { + NMDevicePrivate *priv; + g_return_val_if_fail (NM_IS_DEVICE (self), NM_DEVICE_TYPE_UNKNOWN); - return NM_DEVICE_GET_PRIVATE (self)->device_type; + priv = NM_DEVICE_GET_PRIVATE (self); + + /* Fill this in if it wasn't set at construct time */ + if (priv->device_type == NM_DEVICE_TYPE_UNKNOWN) { + if (NM_IS_DEVICE_ETHERNET (self)) + priv->device_type = NM_DEVICE_TYPE_ETHERNET; + else if (NM_IS_DEVICE_WIFI (self)) + priv->device_type = NM_DEVICE_TYPE_WIFI; + else if (NM_IS_DEVICE_MODEM (self)) + priv->device_type = NM_DEVICE_TYPE_MODEM; + else if (NM_IS_DEVICE_BT (self)) + priv->device_type = NM_DEVICE_TYPE_BT; + else if (NM_IS_DEVICE_WIMAX (self)) + priv->device_type = NM_DEVICE_TYPE_WIMAX; + else if (NM_IS_DEVICE_INFINIBAND (self)) + priv->device_type = NM_DEVICE_TYPE_INFINIBAND; + else + g_warn_if_reached (); + } + + return priv->device_type; } /** diff --git a/libnm-glib/nm-object-private.h b/libnm-glib/nm-object-private.h index 7b14ad694..08aa525e5 100644 --- a/libnm-glib/nm-object-private.h +++ b/libnm-glib/nm-object-private.h @@ -30,12 +30,14 @@ void _nm_object_ensure_inited (NMObject *object); typedef gboolean (*PropertyMarshalFunc) (NMObject *, GParamSpec *, GValue *, gpointer); + typedef GObject * (*NMObjectCreatorFunc) (DBusGConnection *, const char *); typedef struct { const char *name; gpointer field; PropertyMarshalFunc func; + GType object_type; } NMPropertiesInfo; @@ -69,4 +71,12 @@ handle_ptr_array_return (GPtrArray *array) return array; } +/* object demarshalling support */ +typedef GType (*NMObjectTypeFunc) (DBusGConnection *, const char *); +typedef void (*NMObjectTypeCallbackFunc) (GType, gpointer); +typedef void (*NMObjectTypeAsyncFunc) (DBusGConnection *, const char *, NMObjectTypeCallbackFunc, gpointer); + +void _nm_object_register_type_func (GType base_type, NMObjectTypeFunc type_func, + NMObjectTypeAsyncFunc type_async_func); + #endif /* NM_OBJECT_PRIVATE_H */ diff --git a/libnm-glib/nm-object.c b/libnm-glib/nm-object.c index 5eb7a0a6f..dfcb33f35 100644 --- a/libnm-glib/nm-object.c +++ b/libnm-glib/nm-object.c @@ -30,6 +30,7 @@ #include "nm-object-private.h" #include "nm-dbus-glib-types.h" #include "nm-glib-compat.h" +#include "nm-types.h" #define DEBUG 0 @@ -37,8 +38,12 @@ G_DEFINE_ABSTRACT_TYPE (NMObject, nm_object, G_TYPE_OBJECT) #define NM_OBJECT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_OBJECT, NMObjectPrivate)) +static GHashTable *type_funcs, *type_async_funcs; + typedef struct { PropertyMarshalFunc func; + GType object_type; + gpointer field; } PropertyInfo; @@ -192,6 +197,11 @@ nm_object_class_init (NMObjectClass *nm_object_class) g_type_class_add_private (nm_object_class, sizeof (NMObjectPrivate)); + if (!type_funcs) { + type_funcs = g_hash_table_new (NULL, NULL); + type_async_funcs = g_hash_table_new (NULL, NULL); + } + /* virtual methods */ object_class->constructor = constructor; object_class->set_property = set_property; @@ -311,6 +321,81 @@ _nm_object_queue_notify (NMObject *object, const char *property) priv->notify_props = g_slist_prepend (priv->notify_props, g_strdup (property)); } +void +_nm_object_register_type_func (GType base_type, NMObjectTypeFunc type_func, + NMObjectTypeAsyncFunc type_async_func) +{ + g_hash_table_insert (type_funcs, + GSIZE_TO_POINTER (base_type), + type_func); + g_hash_table_insert (type_async_funcs, + GSIZE_TO_POINTER (base_type), + type_async_func); +} + +static GObject * +_nm_object_create (GType type, DBusGConnection *connection, const char *path) +{ + NMObjectTypeFunc type_func; + + type_func = g_hash_table_lookup (type_funcs, GSIZE_TO_POINTER (type)); + if (type_func) + type = type_func (connection, path); + + return g_object_new (type, + NM_OBJECT_DBUS_CONNECTION, connection, + NM_OBJECT_DBUS_PATH, path, + NULL); +} + +typedef void (*NMObjectCreateCallbackFunc) (GObject *, gpointer); +typedef struct { + DBusGConnection *connection; + char *path; + NMObjectCreateCallbackFunc callback; + gpointer user_data; +} NMObjectTypeAsyncData; + +static void +async_got_type (GType type, gpointer user_data) +{ + NMObjectTypeAsyncData *async_data = user_data; + GObject *object; + + if (type != G_TYPE_INVALID) { + object = g_object_new (type, + NM_OBJECT_DBUS_CONNECTION, async_data->connection, + NM_OBJECT_DBUS_PATH, async_data->path, + NULL); + } else + object = NULL; + + async_data->callback (object, async_data->user_data); + + g_free (async_data->path); + g_slice_free (NMObjectTypeAsyncData, async_data); +} + +static void +_nm_object_create_async (GType type, DBusGConnection *connection, const char *path, + NMObjectCreateCallbackFunc callback, gpointer user_data) +{ + NMObjectTypeAsyncFunc type_async_func; + NMObjectTypeAsyncData *async_data; + + async_data = g_slice_new (NMObjectTypeAsyncData); + async_data->connection = connection; + async_data->path = g_strdup (path); + async_data->callback = callback; + async_data->user_data = user_data; + + type_async_func = g_hash_table_lookup (type_async_funcs, GSIZE_TO_POINTER (type)); + if (type_async_func) + type_async_func (connection, path, async_got_type, async_data); + else + async_got_type (type, async_data); +} + /* Stolen from dbus-glib */ static char* wincaps_to_dash (const char *caps) @@ -333,19 +418,155 @@ wincaps_to_dash (const char *caps) return g_string_free (str, FALSE); } +typedef struct { + NMObject *self; + PropertyInfo *pi; + + GObject **objects; + int length, remaining; + + gboolean array; + const char *property_name; +} ObjectCreatedData; + static void -handle_property_changed (gpointer key, gpointer data, gpointer user_data) +object_created (GObject *obj, gpointer user_data) +{ + ObjectCreatedData *odata = user_data; + NMObject *self = odata->self; + PropertyInfo *pi = odata->pi; + + /* We assume that on error, the creator_func printed something */ + + odata->objects[--odata->remaining] = obj; + if (odata->remaining) + return; + + if (odata->array) { + GPtrArray **array = pi->field; + int i; + + if (*array) + g_boxed_free (NM_TYPE_OBJECT_ARRAY, *array); + *array = g_ptr_array_sized_new (odata->length); + for (i = 0; i < odata->length; i++) { + if (odata->objects[i]) + g_ptr_array_add (*array, odata->objects[i]); + } + } else { + GObject **obj_p = pi->field; + + g_clear_object (obj_p); + *obj_p = odata->objects[0]; + } + + if (odata->property_name) + _nm_object_queue_notify (self, odata->property_name); + + g_object_unref (self); + g_free (odata->objects); + g_slice_free (ObjectCreatedData, odata); +} + +static gboolean +handle_object_property (NMObject *self, const char *property_name, GValue *value, + PropertyInfo *pi, gboolean synchronously) +{ + NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (self); + GObject *obj; + const char *path; + ObjectCreatedData *odata; + + odata = g_slice_new (ObjectCreatedData); + odata->self = g_object_ref (self); + odata->pi = pi; + odata->objects = g_new (GObject *, 1); + odata->length = odata->remaining = 1; + odata->array = FALSE; + odata->property_name = property_name; + + path = g_value_get_boxed (value); + if (!strcmp (path, "/")) { + object_created (NULL, odata); + return TRUE; + } + + obj = G_OBJECT (_nm_object_cache_get (path)); + if (obj) { + object_created (obj, odata); + return TRUE; + } else if (synchronously) { + obj = _nm_object_create (pi->object_type, priv->connection, path); + object_created (obj, odata); + return obj != NULL; + } else { + _nm_object_create_async (pi->object_type, priv->connection, path, + object_created, odata); + /* Assume success */ + return TRUE; + } +} + +static gboolean +handle_object_array_property (NMObject *self, const char *property_name, GValue *value, + PropertyInfo *pi, gboolean synchronously) +{ + NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (self); + GObject *obj; + GPtrArray *paths; + GPtrArray **array = pi->field; + const char *path; + ObjectCreatedData *odata; + int i; + + paths = g_value_get_boxed (value); + + odata = g_slice_new (ObjectCreatedData); + odata->self = g_object_ref (self); + odata->pi = pi; + odata->objects = g_new0 (GObject *, paths->len); + odata->length = odata->remaining = paths->len; + odata->array = TRUE; + odata->property_name = property_name; + + for (i = 0; i < paths->len; i++) { + path = paths->pdata[i]; + if (!strcmp (path, "/")) { + /* FIXME: can't happen? */ + continue; + } + + obj = G_OBJECT (_nm_object_cache_get (path)); + if (obj) { + object_created (obj, odata); + } else if (synchronously) { + obj = _nm_object_create (pi->object_type, priv->connection, path); + object_created (obj, odata); + } else { + _nm_object_create_async (pi->object_type, priv->connection, path, + object_created, odata); + } + } + + if (!synchronously) { + /* Assume success */ + return TRUE; + } + + return *array && ((*array)->len == paths->len); +} + +static void +handle_property_changed (NMObject *self, const char *dbus_name, GValue *value, gboolean synchronously) { - NMObject *self = NM_OBJECT (user_data); NMObjectPrivate *priv = NM_OBJECT_GET_PRIVATE (self); char *prop_name; PropertyInfo *pi; GParamSpec *pspec; gboolean success = FALSE, found = FALSE; GSList *iter; - GValue *value = data; - prop_name = wincaps_to_dash ((char *) key); + prop_name = wincaps_to_dash (dbus_name); /* Iterate through the object and its parents to find the property */ for (iter = priv->property_tables; iter; iter = g_slist_next (iter)) { @@ -377,13 +598,18 @@ handle_property_changed (gpointer key, gpointer data, gpointer user_data) goto out; } - /* Handle NULL object paths */ - if (G_VALUE_HOLDS (value, DBUS_TYPE_G_OBJECT_PATH)) { - if (g_strcmp0 (g_value_get_boxed (value), "/") == 0) - value = NULL; - } + if (pi->object_type) { + if (G_VALUE_HOLDS (value, DBUS_TYPE_G_OBJECT_PATH)) + success = handle_object_property (self, pspec->name, value, pi, synchronously); + else if (G_VALUE_HOLDS (value, DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH)) + success = handle_object_array_property (self, pspec->name, value, pi, synchronously); + else { + g_warn_if_reached (); + goto out; + } + } else + success = (*(pi->func)) (self, pspec, value, pi->field); - success = (*(pi->func)) (self, pspec, value, pi->field); if (!success) { g_warning ("%s: failed to update property '%s' of object type %s.", __func__, @@ -398,7 +624,12 @@ out: void _nm_object_process_properties_changed (NMObject *self, GHashTable *properties) { - g_hash_table_foreach (properties, handle_property_changed, self); + GHashTableIter iter; + gpointer name, value; + + g_hash_table_iter_init (&iter, properties); + while (g_hash_table_iter_next (&iter, &name, &value)) + handle_property_changed (self, name, value, FALSE); } static void @@ -509,6 +740,7 @@ _nm_object_register_properties (NMObject *object, pi = g_malloc0 (sizeof (PropertyInfo)); pi->func = tmp->func ? tmp->func : demarshal_generic; + pi->object_type = tmp->object_type; pi->field = tmp->field; g_hash_table_insert (instance, g_strdup (tmp->name), pi); } @@ -591,7 +823,7 @@ _nm_object_reload_property (NMObject *object, return; } - handle_property_changed ((gpointer)prop_name, &value, object); + handle_property_changed (object, prop_name, &value, TRUE); g_value_unset (&value); }