libnm-glib: simplify handling of object and object array properties

Add an "object_type" field to NMPropertiesInfo, and use that with
DBUS_TYPE_G_OBJECT_PATH and DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH
properties so that we don't need custom marshallers for each one.

When creating an NMDevice or NMActiveConnection, we need to fetch an
extra property first to figure out the exact subclass to use, so add a
bit of infrastructure for that as well. Also, do that preprocessing
asynchronously when processing a property change notification, so that
it doesn't block the main loop.
This commit is contained in:
Dan Winship 2012-01-11 07:56:04 -05:00 committed by Dan Williams
parent 5afcee4693
commit cc90f1010e
8 changed files with 526 additions and 400 deletions

View file

@ -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 },

View file

@ -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 },
};

View file

@ -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 */

View file

@ -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 },
};

View file

@ -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 },

View file

@ -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;
}
/**

View file

@ -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 */

View file

@ -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);
}