summaryrefslogtreecommitdiff
path: root/libnm/nm-client.c
diff options
context:
space:
mode:
Diffstat (limited to 'libnm/nm-client.c')
-rw-r--r--libnm/nm-client.c695
1 files changed, 644 insertions, 51 deletions
diff --git a/libnm/nm-client.c b/libnm/nm-client.c
index e655dbd43b..d17b7a36dc 100644
--- a/libnm/nm-client.c
+++ b/libnm/nm-client.c
@@ -29,13 +29,72 @@
#include "nm-remote-settings.h"
#include "nm-device-ethernet.h"
#include "nm-device-wifi.h"
-#include "nm-device-private.h"
#include "nm-core-internal.h"
#include "nm-active-connection.h"
#include "nm-vpn-connection.h"
#include "nm-remote-connection.h"
-#include "nm-object-cache.h"
#include "nm-dbus-helpers.h"
+#include "nm-wimax-nsp.h"
+#include "nm-object-private.h"
+
+#include "nmdbus-manager.h"
+#include "nmdbus-settings.h"
+#include "nmdbus-access-point.h"
+#include "nmdbus-active-connection.h"
+#include "nmdbus-device-adsl.h"
+#include "nmdbus-device-bond.h"
+#include "nmdbus-device-bridge.h"
+#include "nmdbus-device-bt.h"
+#include "nmdbus-device-ethernet.h"
+#include "nmdbus-device-generic.h"
+#include "nmdbus-device-infiniband.h"
+#include "nmdbus-device-ip-tunnel.h"
+#include "nmdbus-device-macvlan.h"
+#include "nmdbus-device-modem.h"
+#include "nmdbus-device-olpc-mesh.h"
+#include "nmdbus-device-team.h"
+#include "nmdbus-device-tun.h"
+#include "nmdbus-device-vlan.h"
+#include "nmdbus-device-vxlan.h"
+#include "nmdbus-device-wifi.h"
+#include "nmdbus-device-wimax.h"
+#include "nmdbus-device.h"
+#include "nmdbus-dhcp4-config.h"
+#include "nmdbus-dhcp6-config.h"
+#include "nmdbus-ip4-config.h"
+#include "nmdbus-ip6-config.h"
+#include "nmdbus-settings-connection.h"
+#include "nmdbus-vpn-connection.h"
+#include "nmdbus-wimax-nsp.h"
+
+#include "nm-access-point.h"
+#include "nm-active-connection.h"
+#include "nm-device-adsl.h"
+#include "nm-device-bond.h"
+#include "nm-device-bridge.h"
+#include "nm-device-bt.h"
+#include "nm-device-ethernet.h"
+#include "nm-device-generic.h"
+#include "nm-device-infiniband.h"
+#include "nm-device-ip-tunnel.h"
+#include "nm-device-macvlan.h"
+#include "nm-device-modem.h"
+#include "nm-device-olpc-mesh.h"
+#include "nm-device-team.h"
+#include "nm-device-tun.h"
+#include "nm-device-vlan.h"
+#include "nm-device-vxlan.h"
+#include "nm-device-wifi.h"
+#include "nm-device-wimax.h"
+#include "nm-dhcp4-config.h"
+#include "nm-dhcp6-config.h"
+#include "nm-dhcp-config.h"
+#include "nm-ip4-config.h"
+#include "nm-ip6-config.h"
+#include "nm-manager.h"
+#include "nm-remote-connection.h"
+#include "nm-remote-settings.h"
+#include "nm-vpn-connection.h"
void _nm_device_wifi_set_wireless_enabled (NMDeviceWifi *device, gboolean enabled);
@@ -52,6 +111,8 @@ G_DEFINE_TYPE_WITH_CODE (NMClient, nm_client, G_TYPE_OBJECT,
typedef struct {
NMManager *manager;
NMRemoteSettings *settings;
+ GDBusObjectManager *object_manager;
+ GCancellable *new_object_manager_cancellable;
} NMClientPrivate;
enum {
@@ -97,6 +158,8 @@ enum {
static guint signals[LAST_SIGNAL] = { 0 };
+static const GPtrArray empty = { 0, };
+
/*****************************************************************************/
/**
@@ -150,6 +213,9 @@ nm_client_get_version (NMClient *client)
{
g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
+ if (!nm_client_get_nm_running (client))
+ return NULL;
+
return nm_manager_get_version (NM_CLIENT_GET_PRIVATE (client)->manager);
}
@@ -166,6 +232,9 @@ nm_client_get_state (NMClient *client)
{
g_return_val_if_fail (NM_IS_CLIENT (client), NM_STATE_UNKNOWN);
+ if (!nm_client_get_nm_running (client))
+ return NM_STATE_UNKNOWN;
+
return nm_manager_get_state (NM_CLIENT_GET_PRIVATE (client)->manager);
}
@@ -181,7 +250,10 @@ nm_client_get_state (NMClient *client)
gboolean
nm_client_get_startup (NMClient *client)
{
- g_return_val_if_fail (NM_IS_CLIENT (client), NM_STATE_UNKNOWN);
+ g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
+
+ if (!nm_client_get_nm_running (client))
+ return FALSE;
return nm_manager_get_startup (NM_CLIENT_GET_PRIVATE (client)->manager);
}
@@ -199,7 +271,7 @@ nm_client_get_nm_running (NMClient *client)
{
g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
- return nm_manager_get_nm_running (NM_CLIENT_GET_PRIVATE (client)->manager);
+ return NM_CLIENT_GET_PRIVATE (client)->manager != NULL;
}
/**
@@ -215,6 +287,9 @@ nm_client_networking_get_enabled (NMClient *client)
{
g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
+ if (!nm_client_get_nm_running (client))
+ return FALSE;
+
return nm_manager_networking_get_enabled (NM_CLIENT_GET_PRIVATE (client)->manager);
}
@@ -255,6 +330,9 @@ nm_client_wireless_get_enabled (NMClient *client)
{
g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
+ if (!nm_client_get_nm_running (client))
+ return FALSE;
+
return nm_manager_wireless_get_enabled (NM_CLIENT_GET_PRIVATE (client)->manager);
}
@@ -270,7 +348,7 @@ nm_client_wireless_set_enabled (NMClient *client, gboolean enabled)
{
g_return_if_fail (NM_IS_CLIENT (client));
- if (!_nm_client_check_nm_running (client, NULL))
+ if (!nm_client_get_nm_running (client))
return;
nm_manager_wireless_set_enabled (NM_CLIENT_GET_PRIVATE (client)->manager, enabled);
@@ -289,6 +367,9 @@ nm_client_wireless_hardware_get_enabled (NMClient *client)
{
g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
+ if (!nm_client_get_nm_running (client))
+ return FALSE;
+
return nm_manager_wireless_hardware_get_enabled (NM_CLIENT_GET_PRIVATE (client)->manager);
}
@@ -305,6 +386,9 @@ nm_client_wwan_get_enabled (NMClient *client)
{
g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
+ if (!nm_client_get_nm_running (client))
+ return FALSE;
+
return nm_manager_wwan_get_enabled (NM_CLIENT_GET_PRIVATE (client)->manager);
}
@@ -339,6 +423,9 @@ nm_client_wwan_hardware_get_enabled (NMClient *client)
{
g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
+ if (!nm_client_get_nm_running (client))
+ return FALSE;
+
return nm_manager_wwan_hardware_get_enabled (NM_CLIENT_GET_PRIVATE (client)->manager);
}
@@ -355,6 +442,9 @@ nm_client_wimax_get_enabled (NMClient *client)
{
g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
+ if (!nm_client_get_nm_running (client))
+ return FALSE;
+
return nm_manager_wimax_get_enabled (NM_CLIENT_GET_PRIVATE (client)->manager);
}
@@ -370,7 +460,7 @@ nm_client_wimax_set_enabled (NMClient *client, gboolean enabled)
{
g_return_if_fail (NM_IS_CLIENT (client));
- if (!_nm_client_check_nm_running (client, NULL))
+ if (!nm_client_get_nm_running (client))
return;
nm_manager_wimax_set_enabled (NM_CLIENT_GET_PRIVATE (client)->manager, enabled);
@@ -389,6 +479,9 @@ nm_client_wimax_hardware_get_enabled (NMClient *client)
{
g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
+ if (!nm_client_get_nm_running (client))
+ return FALSE;
+
return nm_manager_wimax_hardware_get_enabled (NM_CLIENT_GET_PRIVATE (client)->manager);
}
@@ -459,6 +552,9 @@ nm_client_get_permission_result (NMClient *client, NMClientPermission permission
{
g_return_val_if_fail (NM_IS_CLIENT (client), NM_CLIENT_PERMISSION_RESULT_UNKNOWN);
+ if (!nm_client_get_nm_running (client))
+ return NM_CLIENT_PERMISSION_RESULT_UNKNOWN;
+
return nm_manager_get_permission_result (NM_CLIENT_GET_PRIVATE (client)->manager, permission);
}
@@ -478,6 +574,9 @@ nm_client_get_connectivity (NMClient *client)
{
g_return_val_if_fail (NM_IS_CLIENT (client), NM_CONNECTIVITY_UNKNOWN);
+ if (!nm_client_get_nm_running (client))
+ return NM_CONNECTIVITY_UNKNOWN;
+
return nm_manager_get_connectivity (NM_CLIENT_GET_PRIVATE (client)->manager);
}
@@ -614,6 +713,9 @@ nm_client_save_hostname (NMClient *client,
{
g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
+ if (!_nm_client_check_nm_running (client, error))
+ return FALSE;
+
return nm_remote_settings_save_hostname (NM_CLIENT_GET_PRIVATE (client)->settings,
hostname, cancellable, error);
}
@@ -720,6 +822,9 @@ nm_client_get_devices (NMClient *client)
{
g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
+ if (!nm_client_get_nm_running (client))
+ return ∅
+
return nm_manager_get_devices (NM_CLIENT_GET_PRIVATE (client)->manager);
}
@@ -748,6 +853,9 @@ nm_client_get_all_devices (NMClient *client)
{
g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
+ if (!nm_client_get_nm_running (client))
+ return ∅
+
return nm_manager_get_all_devices (NM_CLIENT_GET_PRIVATE (client)->manager);
}
@@ -766,6 +874,9 @@ nm_client_get_device_by_path (NMClient *client, const char *object_path)
g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
g_return_val_if_fail (object_path, NULL);
+ if (!nm_client_get_nm_running (client))
+ return NULL;
+
return nm_manager_get_device_by_path (NM_CLIENT_GET_PRIVATE (client)->manager, object_path);
}
@@ -784,6 +895,9 @@ nm_client_get_device_by_iface (NMClient *client, const char *iface)
g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
g_return_val_if_fail (iface, NULL);
+ if (!nm_client_get_nm_running (client))
+ return NULL;
+
return nm_manager_get_device_by_iface (NM_CLIENT_GET_PRIVATE (client)->manager, iface);
}
@@ -806,6 +920,9 @@ nm_client_get_active_connections (NMClient *client)
{
g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
+ if (!nm_client_get_nm_running (client))
+ return ∅
+
return nm_manager_get_active_connections (NM_CLIENT_GET_PRIVATE (client)->manager);
}
@@ -833,6 +950,9 @@ nm_client_get_primary_connection (NMClient *client)
{
g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
+ if (!nm_client_get_nm_running (client))
+ return NULL;
+
return nm_manager_get_primary_connection (NM_CLIENT_GET_PRIVATE (client)->manager);
}
@@ -852,6 +972,9 @@ nm_client_get_activating_connection (NMClient *client)
{
g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
+ if (!nm_client_get_nm_running (client))
+ return NULL;
+
return nm_manager_get_activating_connection (NM_CLIENT_GET_PRIVATE (client)->manager);
}
@@ -1093,7 +1216,7 @@ nm_client_deactivate_connection (NMClient *client,
g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (active), FALSE);
- if (!_nm_client_check_nm_running (client, NULL))
+ if (!nm_client_get_nm_running (client))
return TRUE;
return nm_manager_deactivate_connection (NM_CLIENT_GET_PRIVATE (client)->manager,
@@ -1200,6 +1323,9 @@ nm_client_get_connections (NMClient *client)
{
g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
+ if (!nm_client_get_nm_running (client))
+ return ∅
+
return nm_remote_settings_get_connections (NM_CLIENT_GET_PRIVATE (client)->settings);
}
@@ -1222,6 +1348,9 @@ nm_client_get_connection_by_id (NMClient *client, const char *id)
g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
g_return_val_if_fail (id != NULL, NULL);
+ if (!nm_client_get_nm_running (client))
+ NULL;
+
return nm_remote_settings_get_connection_by_id (NM_CLIENT_GET_PRIVATE (client)->settings, id);
}
@@ -1244,6 +1373,9 @@ nm_client_get_connection_by_path (NMClient *client, const char *path)
g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
g_return_val_if_fail (path != NULL, NULL);
+ if (!nm_client_get_nm_running (client))
+ NULL;
+
return nm_remote_settings_get_connection_by_path (NM_CLIENT_GET_PRIVATE (client)->settings, path);
}
@@ -1266,6 +1398,9 @@ nm_client_get_connection_by_uuid (NMClient *client, const char *uuid)
g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
g_return_val_if_fail (uuid != NULL, NULL);
+ if (!nm_client_get_nm_running (client))
+ NULL;
+
return nm_remote_settings_get_connection_by_uuid (NM_CLIENT_GET_PRIVATE (client)->settings, uuid);
}
@@ -1769,15 +1904,200 @@ manager_active_connection_removed (NMManager *manager,
g_signal_emit (client, signals[ACTIVE_CONNECTION_REMOVED], 0, active_connection);
}
+/****************************************************************/
+/* Object Initialization */
+/****************************************************************/
+
+static GType
+proxy_type (GDBusObjectManagerClient *manager,
+ const gchar *object_path,
+ const gchar *interface_name,
+ gpointer user_data)
+{
+ /* ObjectManager asks us for an object proxy. Unfortunatelly, we can't
+ * decide that by interface name and GDBusObjectManager doesn't allow
+ * us to look at the known interface list. Thus we need to create a
+ * generic GDBusObject and only couple a NMObject subclass later. */
+ if (!interface_name)
+ return G_TYPE_DBUS_OBJECT_PROXY;
+
+ /* An interface proxy */
+ if (strcmp (interface_name, NM_DBUS_INTERFACE) == 0)
+ return NMDBUS_TYPE_MANAGER_PROXY;
+ else if (strcmp (interface_name, NM_DBUS_INTERFACE_DEVICE_WIRELESS) == 0)
+ return NMDBUS_TYPE_DEVICE_WIFI_PROXY;
+ else if (strcmp (interface_name, NM_DBUS_INTERFACE_DEVICE) == 0)
+ return NMDBUS_TYPE_DEVICE_PROXY;
+ else if (strcmp (interface_name, NM_DBUS_INTERFACE_SETTINGS_CONNECTION) == 0)
+ return NMDBUS_TYPE_SETTINGS_CONNECTION_PROXY;
+ else if (strcmp (interface_name, NM_DBUS_INTERFACE_SETTINGS) == 0)
+ return NMDBUS_TYPE_SETTINGS_PROXY;
+ else if (strcmp (interface_name, NM_DBUS_INTERFACE_VPN_CONNECTION) == 0)
+ return NMDBUS_TYPE_VPN_CONNECTION_PROXY;
+
+ /* Use a generic D-Bus Proxy whenever we can. The typed GDBusProxy
+ * subclasses actually use quite some memory, so they're better avoided. */
+ return G_TYPE_DBUS_PROXY;
+}
+
+static NMObject *
+obj_nm_for_gdbus_object (GDBusObject *object, GDBusObjectManager *object_manager)
+{
+ GList *interfaces;
+ GList *l;
+ GType type = G_TYPE_INVALID;
+ NMObject *obj_nm;
+
+ g_return_val_if_fail (G_IS_DBUS_OBJECT_PROXY (object), NULL);
+
+ interfaces = g_dbus_object_get_interfaces (object);
+ for (l = interfaces; l; l = l->next) {
+ GDBusProxy *proxy = G_DBUS_PROXY (l->data);
+ const char *ifname = g_dbus_proxy_get_interface_name (proxy);
+
+ /* This is a performance/scalability hack. It makes sense to call it
+ * from here, since this is in the common object creation path. */
+ _nm_dbus_proxy_replace_match (proxy);
+
+ if (strcmp (ifname, NM_DBUS_INTERFACE) == 0)
+ type = NM_TYPE_MANAGER;
+ else if (strcmp (ifname, NM_DBUS_INTERFACE_ACCESS_POINT) == 0)
+ type = NM_TYPE_ACCESS_POINT;
+ else if (strcmp (ifname, NM_DBUS_INTERFACE_ACTIVE_CONNECTION) == 0 && type != NM_TYPE_VPN_CONNECTION)
+ type = NM_TYPE_ACTIVE_CONNECTION;
+ else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_ADSL) == 0)
+ type = NM_TYPE_DEVICE_ADSL;
+ else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_BOND) == 0)
+ type = NM_TYPE_DEVICE_BOND;
+ else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_BRIDGE) == 0)
+ type = NM_TYPE_DEVICE_BRIDGE;
+ else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_BLUETOOTH) == 0)
+ type = NM_TYPE_DEVICE_BT;
+ else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_WIRED) == 0)
+ type = NM_TYPE_DEVICE_ETHERNET;
+ else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_GENERIC) == 0)
+ type = NM_TYPE_DEVICE_GENERIC;
+ else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_INFINIBAND) == 0)
+ type = NM_TYPE_DEVICE_INFINIBAND;
+ else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_IP_TUNNEL) == 0)
+ type = NM_TYPE_DEVICE_IP_TUNNEL;
+ else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_MACVLAN) == 0)
+ type = NM_TYPE_DEVICE_MACVLAN;
+ else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_MODEM) == 0)
+ type = NM_TYPE_DEVICE_MODEM;
+ else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_OLPC_MESH) == 0)
+ type = NM_TYPE_DEVICE_OLPC_MESH;
+ else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_TEAM) == 0)
+ type = NM_TYPE_DEVICE_TEAM;
+ else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_TUN) == 0)
+ type = NM_TYPE_DEVICE_TUN;
+ else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_VLAN) == 0)
+ type = NM_TYPE_DEVICE_VLAN;
+ else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_VXLAN) == 0)
+ type = NM_TYPE_DEVICE_VXLAN;
+ else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_WIRELESS) == 0)
+ type = NM_TYPE_DEVICE_WIFI;
+ else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_WIMAX) == 0)
+ type = NM_TYPE_DEVICE_WIMAX;
+ else if (strcmp (ifname, NM_DBUS_INTERFACE_DHCP4_CONFIG) == 0)
+ type = NM_TYPE_DHCP4_CONFIG;
+ else if (strcmp (ifname, NM_DBUS_INTERFACE_DHCP6_CONFIG) == 0)
+ type = NM_TYPE_DHCP6_CONFIG;
+ else if (strcmp (ifname, NM_DBUS_INTERFACE_IP4_CONFIG) == 0)
+ type = NM_TYPE_IP4_CONFIG;
+ else if (strcmp (ifname, NM_DBUS_INTERFACE_IP6_CONFIG) == 0)
+ type = NM_TYPE_IP6_CONFIG;
+ else if (strcmp (ifname, NM_DBUS_INTERFACE_SETTINGS_CONNECTION) == 0)
+ type = NM_TYPE_REMOTE_CONNECTION;
+ else if (strcmp (ifname, NM_DBUS_INTERFACE_SETTINGS) == 0)
+ type = NM_TYPE_REMOTE_SETTINGS;
+ else if (strcmp (ifname, NM_DBUS_INTERFACE_VPN_CONNECTION) == 0)
+ type = NM_TYPE_VPN_CONNECTION;
+ else if (strcmp (ifname, NM_DBUS_INTERFACE_WIMAX_NSP) == 0)
+ type = NM_TYPE_WIMAX_NSP;
+
+ if (type != G_TYPE_INVALID)
+ break;
+ }
+
+ g_list_free_full (interfaces, g_object_unref);
+ if (type == G_TYPE_INVALID)
+ return NULL;
+
+ obj_nm = g_object_new (type,
+ NM_OBJECT_DBUS_OBJECT, object,
+ NM_OBJECT_DBUS_OBJECT_MANAGER, object_manager,
+ NULL);
+ g_object_set_qdata_full (G_OBJECT (object), _nm_object_obj_nm_quark (),
+ obj_nm, g_object_unref);
+ return obj_nm;
+}
+
+static void
+obj_nm_inited (GObject *object, GAsyncResult *result, gpointer user_data)
+{
+ if (!g_async_initable_init_finish (G_ASYNC_INITABLE (object), result, NULL)) {
+ /* This is a can-not-happen situation, the NMObject subclasses are not
+ * supposed to fail initialization. */
+ g_warn_if_reached ();
+ }
+}
+
+
static void
-constructed (GObject *object)
+object_added (GDBusObjectManager *object_manager, GDBusObject *object, gpointer user_data)
+{
+ NMObject *obj_nm;
+
+ obj_nm = obj_nm_for_gdbus_object (object, object_manager);
+ if (obj_nm) {
+ g_async_initable_init_async (G_ASYNC_INITABLE (obj_nm),
+ G_PRIORITY_DEFAULT, NULL,
+ obj_nm_inited, NULL);
+ }
+}
+
+static void
+object_removed (GDBusObjectManager *object_manager, GDBusObject *object, gpointer user_data)
+{
+ g_object_set_qdata (G_OBJECT (object), _nm_object_obj_nm_quark (), NULL);
+}
+
+static gboolean
+objects_created (NMClient *client, GDBusObjectManager *object_manager, GError **error)
{
- NMClient *client = NM_CLIENT (object);
NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
+ gs_unref_object GDBusObject *manager = NULL;
+ gs_unref_object GDBusObject *settings = NULL;
+ NMObject *obj_nm;
+ GList *objects, *iter;
+
+ /* First just ensure all the NMObjects for known GDBusObjects exist. */
+ objects = g_dbus_object_manager_get_objects (object_manager);
+ for (iter = objects; iter; iter = iter->next)
+ obj_nm_for_gdbus_object (iter->data, object_manager);
+ g_list_free_full (objects, g_object_unref);
+
+ manager = g_dbus_object_manager_get_object (object_manager, NM_DBUS_PATH);
+ if (!manager) {
+ g_set_error_literal (error,
+ NM_CLIENT_ERROR,
+ NM_CLIENT_ERROR_MANAGER_NOT_RUNNING,
+ "Manager object not found");
+ return FALSE;
+ }
+
+ obj_nm = g_object_get_qdata (G_OBJECT (manager), _nm_object_obj_nm_quark ());
+ if (!obj_nm) {
+ g_set_error_literal (error,
+ NM_CLIENT_ERROR,
+ NM_CLIENT_ERROR_MANAGER_NOT_RUNNING,
+ "Manager object lacks the proper interface");
+ return FALSE;
+ }
+
+ priv->manager = NM_MANAGER (g_object_ref (obj_nm));
- priv->manager = g_object_new (NM_TYPE_MANAGER,
- NM_OBJECT_PATH, NM_DBUS_PATH,
- NULL);
g_signal_connect (priv->manager, "notify",
G_CALLBACK (subobject_notify), client);
g_signal_connect (priv->manager, "device-added",
@@ -1795,9 +2115,26 @@ constructed (GObject *object)
g_signal_connect (priv->manager, "active-connection-removed",
G_CALLBACK (manager_active_connection_removed), client);
- priv->settings = g_object_new (NM_TYPE_REMOTE_SETTINGS,
- NM_OBJECT_PATH, NM_DBUS_PATH_SETTINGS,
- NULL);
+ settings = g_dbus_object_manager_get_object (object_manager, NM_DBUS_PATH_SETTINGS);
+ if (!settings) {
+ g_set_error_literal (error,
+ NM_CLIENT_ERROR,
+ NM_CLIENT_ERROR_MANAGER_NOT_RUNNING,
+ "Settings object not found");
+ return FALSE;
+ }
+
+ obj_nm = g_object_get_qdata (G_OBJECT (settings), _nm_object_obj_nm_quark ());
+ if (!obj_nm) {
+ g_set_error_literal (error,
+ NM_CLIENT_ERROR,
+ NM_CLIENT_ERROR_MANAGER_NOT_RUNNING,
+ "Settings object lacks the proper interface");
+ return FALSE;
+ }
+
+ priv->settings = NM_REMOTE_SETTINGS (g_object_ref (obj_nm));
+
g_signal_connect (priv->settings, "notify",
G_CALLBACK (subobject_notify), client);
g_signal_connect (priv->settings, "connection-added",
@@ -1805,29 +2142,74 @@ constructed (GObject *object)
g_signal_connect (priv->settings, "connection-removed",
G_CALLBACK (settings_connection_removed), client);
- G_OBJECT_CLASS (nm_client_parent_class)->constructed (object);
+ /* The handlers don't really use the client instance. However
+ * it makes it convenient to unhook them by data. */
+ g_signal_connect (object_manager, "object-added",
+ G_CALLBACK (object_added), client);
+ g_signal_connect (object_manager, "object-removed",
+ G_CALLBACK (object_removed), client);
+
+ return TRUE;
}
+/* Synchronous initialization. */
+
+static void name_owner_changed (GObject *object, GParamSpec *pspec, gpointer user_data);
+
static gboolean
init_sync (GInitable *initable, GCancellable *cancellable, GError **error)
{
NMClient *client = NM_CLIENT (initable);
NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
+ GList *objects, *iter;
+ gchar *name_owner;
- if (!g_initable_init (G_INITABLE (priv->manager), cancellable, error))
- return FALSE;
- if (!g_initable_init (G_INITABLE (priv->settings), cancellable, error))
+ priv->object_manager = g_dbus_object_manager_client_new_for_bus_sync (_nm_dbus_bus_type (),
+ G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
+ "org.freedesktop.NetworkManager",
+ "/org/freedesktop",
+ proxy_type, NULL, NULL,
+ cancellable, error);
+
+ if (!priv->object_manager)
return FALSE;
+ name_owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (priv->object_manager));
+ if (name_owner) {
+ g_free (name_owner);
+ if (!objects_created (client, priv->object_manager, error))
+ return FALSE;
+
+ objects = g_dbus_object_manager_get_objects (priv->object_manager);
+ for (iter = objects; iter; iter = iter->next) {
+ NMObject *obj_nm;
+
+ obj_nm = g_object_get_qdata (iter->data, _nm_object_obj_nm_quark ());
+ if (!obj_nm)
+ continue;
+
+ if (!g_initable_init (G_INITABLE (obj_nm), cancellable, NULL)) {
+ /* This is a can-not-happen situation, the NMObject subclasses are not
+ * supposed to fail initialization. */
+ g_warn_if_reached ();
+ }
+ }
+ g_list_free_full (objects, g_object_unref);
+ }
+
+ g_signal_connect (priv->object_manager, "notify::name-owner",
+ G_CALLBACK (name_owner_changed), client);
+
return TRUE;
}
+/* Asynchronous initialization. */
+
typedef struct {
NMClient *client;
GCancellable *cancellable;
GSimpleAsyncResult *result;
- gboolean manager_inited;
- gboolean settings_inited;
+ int pending_init;
} NMClientInitData;
static void
@@ -1840,7 +2222,7 @@ init_async_complete (NMClientInitData *init_data)
}
static void
-init_async_inited_manager (GObject *object, GAsyncResult *result, gpointer user_data)
+async_inited_obj_nm (GObject *object, GAsyncResult *result, gpointer user_data)
{
NMClientInitData *init_data = user_data;
GError *error = NULL;
@@ -1848,46 +2230,181 @@ init_async_inited_manager (GObject *object, GAsyncResult *result, gpointer user_
if (!g_async_initable_init_finish (G_ASYNC_INITABLE (object), result, &error))
g_simple_async_result_take_error (init_data->result, error);
- init_data->manager_inited = TRUE;
- if (init_data->settings_inited)
- init_async_complete (init_data);
+ if (init_data) {
+ init_data->pending_init--;
+ if (init_data->pending_init == 0)
+ init_async_complete (init_data);
+ }
}
static void
-init_async_inited_settings (GObject *object, GAsyncResult *result, gpointer user_data)
+init_async (GAsyncInitable *initable, int io_priority,
+ GCancellable *cancellable, GAsyncReadyCallback callback,
+ gpointer user_data);
+
+static void
+unhook_om (NMClient *self)
+{
+ NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (self);
+ GList *objects, *iter;
+
+ if (priv->manager) {
+ const GPtrArray *active_connections;
+ const GPtrArray *devices;
+ int i;
+
+ active_connections = nm_manager_get_active_connections (priv->manager);
+ for (i = 0; i < active_connections->len; i++)
+ g_signal_emit (self, signals[ACTIVE_CONNECTION_REMOVED], 0, active_connections->pdata[i]);
+
+ devices = nm_manager_get_all_devices (priv->manager);
+ for (i = 0; i < devices->len; i++)
+ g_signal_emit (self, signals[DEVICE_REMOVED], 0, devices->pdata[i]);
+
+ g_signal_handlers_disconnect_by_data (priv->manager, self);
+ g_clear_object (&priv->manager);
+ g_object_notify (G_OBJECT (self), NM_CLIENT_ACTIVE_CONNECTIONS);
+ g_object_notify (G_OBJECT (self), NM_CLIENT_NM_RUNNING);
+ }
+ if (priv->settings) {
+ const GPtrArray *connections;
+ guint i;
+
+ connections = nm_remote_settings_get_connections (priv->settings);
+ for (i = 0; i < connections->len; i++)
+ g_signal_emit (self, signals[CONNECTION_REMOVED], 0, connections->pdata[i]);
+
+ g_signal_handlers_disconnect_by_data (priv->settings, self);
+ g_clear_object (&priv->settings);
+ g_object_notify (G_OBJECT (self), NM_CLIENT_CONNECTIONS);
+ g_object_notify (G_OBJECT (self), NM_CLIENT_HOSTNAME);
+ g_object_notify (G_OBJECT (self), NM_CLIENT_CAN_MODIFY);
+ }
+
+ objects = g_dbus_object_manager_get_objects (priv->object_manager);
+ for (iter = objects; iter; iter = iter->next)
+ g_object_set_qdata (iter->data, _nm_object_obj_nm_quark (), NULL);
+ g_list_free_full (objects, g_object_unref);
+}
+
+static void
+new_object_manager (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (source_object);
+
+ g_object_notify (G_OBJECT (user_data), NM_CLIENT_NM_RUNNING);
+ g_clear_object (&priv->new_object_manager_cancellable);
+}
+
+static void
+got_object_manager (GObject *object, GAsyncResult *result, gpointer user_data)
{
NMClientInitData *init_data = user_data;
+ NMClient *client;
+ NMClientPrivate *priv;
+ GList *objects, *iter;
+ gchar *name_owner;
GError *error = NULL;
+ GDBusObjectManager *object_manager;
+
+ object_manager = g_dbus_object_manager_client_new_for_bus_finish (result, &error);
+ if (object_manager == NULL) {
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ g_simple_async_result_take_error (init_data->result, error);
+ init_async_complete (init_data);
+ }
+ return;
+ }
- if (!g_async_initable_init_finish (G_ASYNC_INITABLE (object), result, &error))
- g_simple_async_result_take_error (init_data->result, error);
-
- init_data->settings_inited = TRUE;
- if (init_data->manager_inited)
+ client = init_data->client;
+ priv = NM_CLIENT_GET_PRIVATE (client);
+ priv->object_manager = object_manager;
+
+ name_owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (priv->object_manager));
+ if (name_owner) {
+ g_free (name_owner);
+ if (!objects_created (client, priv->object_manager, &error)) {
+ g_simple_async_result_take_error (init_data->result, error);
+ init_async_complete (init_data);
+ return;
+ }
+
+ objects = g_dbus_object_manager_get_objects (priv->object_manager);
+ for (iter = objects; iter; iter = iter->next) {
+ NMObject *obj_nm;
+
+ obj_nm = g_object_get_qdata (iter->data, _nm_object_obj_nm_quark ());
+ if (!obj_nm)
+ continue;
+
+ init_data->pending_init++;
+ g_async_initable_init_async (G_ASYNC_INITABLE (obj_nm),
+ G_PRIORITY_DEFAULT, init_data->cancellable,
+ async_inited_obj_nm, init_data);
+ }
+ g_list_free_full (objects, g_object_unref);
+
+ } else
init_async_complete (init_data);
+
+ g_signal_connect (priv->object_manager, "notify::name-owner",
+ G_CALLBACK (name_owner_changed), client);
}
static void
-init_async (GAsyncInitable *initable, int io_priority,
- GCancellable *cancellable, GAsyncReadyCallback callback,
- gpointer user_data)
+prepare_object_manager (NMClient *client,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
- NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (initable);
NMClientInitData *init_data;
init_data = g_slice_new0 (NMClientInitData);
- init_data->client = NM_CLIENT (initable);
+ init_data->client = client;
init_data->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
- init_data->result = g_simple_async_result_new (G_OBJECT (initable), callback,
+ init_data->result = g_simple_async_result_new (G_OBJECT (client), callback,
user_data, init_async);
g_simple_async_result_set_op_res_gboolean (init_data->result, TRUE);
- g_async_initable_init_async (G_ASYNC_INITABLE (priv->manager),
- G_PRIORITY_DEFAULT, init_data->cancellable,
- init_async_inited_manager, init_data);
- g_async_initable_init_async (G_ASYNC_INITABLE (priv->settings),
- G_PRIORITY_DEFAULT, init_data->cancellable,
- init_async_inited_settings, init_data);
+ g_dbus_object_manager_client_new_for_bus (_nm_dbus_bus_type (),
+ G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
+ "org.freedesktop.NetworkManager",
+ "/org/freedesktop",
+ proxy_type, NULL, NULL,
+ init_data->cancellable,
+ got_object_manager,
+ init_data);
+}
+
+static void
+name_owner_changed (GObject *object, GParamSpec *pspec, gpointer user_data)
+{
+ NMClient *self = user_data;
+ NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (self);
+ GDBusObjectManager *object_manager = G_DBUS_OBJECT_MANAGER (object);
+ gchar *name_owner;
+
+ name_owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (object));
+ if (name_owner) {
+ g_free (name_owner);
+ g_object_unref (object_manager);
+ if (priv->new_object_manager_cancellable)
+ g_cancellable_cancel (priv->new_object_manager_cancellable);
+ priv->new_object_manager_cancellable = g_cancellable_new ();
+ prepare_object_manager (self, priv->new_object_manager_cancellable,
+ new_object_manager, user_data);
+ } else {
+ g_signal_handlers_disconnect_by_func (object_manager, object_added, self);
+ unhook_om (self);
+ }
+}
+
+static void
+init_async (GAsyncInitable *initable, int io_priority,
+ GCancellable *cancellable, GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ prepare_object_manager (NM_CLIENT (initable), cancellable, callback, user_data);
}
static gboolean
@@ -1906,15 +2423,26 @@ dispose (GObject *object)
{
NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (object);
+ if (priv->new_object_manager_cancellable) {
+ g_cancellable_cancel (priv->new_object_manager_cancellable);
+ g_clear_object (&priv->new_object_manager_cancellable);
+ }
+
if (priv->manager) {
g_signal_handlers_disconnect_by_data (priv->manager, object);
g_clear_object (&priv->manager);
}
+
if (priv->settings) {
g_signal_handlers_disconnect_by_data (priv->settings, object);
g_clear_object (&priv->settings);
}
+ if (priv->object_manager) {
+ g_signal_handlers_disconnect_by_data (priv->object_manager, object);
+ g_clear_object (&priv->object_manager);
+ }
+
G_OBJECT_CLASS (nm_client_parent_class)->dispose (object);
}
@@ -1922,13 +2450,15 @@ static void
set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
+ NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (object);
+
switch (prop_id) {
case PROP_NETWORKING_ENABLED:
case PROP_WIRELESS_ENABLED:
case PROP_WWAN_ENABLED:
case PROP_WIMAX_ENABLED:
- g_object_set_property (G_OBJECT (NM_CLIENT_GET_PRIVATE (object)->manager),
- pspec->name, value);
+ if (priv->manager)
+ g_object_set_property (G_OBJECT (priv->manager), pspec->name, value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -1940,33 +2470,97 @@ static void
get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
+ NMClient *self = NM_CLIENT (object);
+ NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (object);
+
switch (prop_id) {
+ case PROP_NM_RUNNING:
+ g_value_set_boolean (value, nm_client_get_nm_running (self));
+ break;
+
+ /* Manager properties. */
case PROP_VERSION:
+ g_value_set_string (value, nm_client_get_version (self));
+ break;
case PROP_STATE:
+ g_value_set_enum (value, nm_client_get_state (self));
+ break;
case PROP_STARTUP:
- case PROP_NM_RUNNING:
+ g_value_set_boolean (value, nm_client_get_startup (self));
+ break;
case PROP_NETWORKING_ENABLED:
+ g_value_set_boolean (value, nm_client_networking_get_enabled (self));
+ break;
case PROP_WIRELESS_ENABLED:
+ g_value_set_boolean (value, nm_client_wireless_get_enabled (self));
+ break;
case PROP_WIRELESS_HARDWARE_ENABLED:
+ if (priv->manager)
+ g_object_get_property (G_OBJECT (priv->settings), pspec->name, value);
+ else
+ g_value_set_boolean (value, FALSE);
+ break;
case PROP_WWAN_ENABLED:
+ g_value_set_boolean (value, nm_client_wwan_get_enabled (self));
+ break;
case PROP_WWAN_HARDWARE_ENABLED:
+ if (priv->manager)
+ g_object_get_property (G_OBJECT (priv->settings), pspec->name, value);
+ else
+ g_value_set_boolean (value, FALSE);
+ break;
case PROP_WIMAX_ENABLED:
+ g_value_set_boolean (value, nm_client_wimax_get_enabled (self));
+ break;
case PROP_WIMAX_HARDWARE_ENABLED:
+ if (priv->manager)
+ g_object_get_property (G_OBJECT (priv->settings), pspec->name, value);
+ else
+ g_value_set_boolean (value, FALSE);
+ break;
case PROP_ACTIVE_CONNECTIONS:
+ g_value_take_boxed (value, _nm_utils_copy_object_array (nm_client_get_active_connections (self)));
+ break;
case PROP_CONNECTIVITY:
+ g_value_set_enum (value, nm_client_get_connectivity (self));
+ break;
case PROP_PRIMARY_CONNECTION:
+ g_value_set_object (value, nm_client_get_primary_connection (self));
+ break;
case PROP_ACTIVATING_CONNECTION:
+ g_value_set_object (value, nm_client_get_activating_connection (self));
+ break;
case PROP_DEVICES:
+ g_value_take_boxed (value, _nm_utils_copy_object_array (nm_client_get_devices (self)));
+ break;
case PROP_METERED:
+ if (priv->manager)
+ g_object_get_property (G_OBJECT (priv->settings), pspec->name, value);
+ else
+ g_value_set_uint (value, NM_METERED_UNKNOWN);
+ break;
case PROP_ALL_DEVICES:
- g_object_get_property (G_OBJECT (NM_CLIENT_GET_PRIVATE (object)->manager),
- pspec->name, value);
+ g_value_take_boxed (value, _nm_utils_copy_object_array (nm_client_get_all_devices (self)));
break;
+
+ /* Settings properties. */
case PROP_CONNECTIONS:
+ if (priv->settings)
+ g_object_get_property (G_OBJECT (priv->settings), pspec->name, value);
+ else
+ g_value_take_boxed (value, _nm_utils_copy_object_array (&empty));
+ break;
case PROP_HOSTNAME:
+ if (priv->settings)
+ g_object_get_property (G_OBJECT (priv->settings), pspec->name, value);
+ else
+ g_value_set_string (value, NULL);
+ break;
case PROP_CAN_MODIFY:
- g_object_get_property (G_OBJECT (NM_CLIENT_GET_PRIVATE (object)->settings),
- pspec->name, value);
+ if (priv->settings)
+ g_object_get_property (G_OBJECT (priv->settings), pspec->name, value);
+ else
+ g_value_set_boolean (value, FALSE);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -1982,7 +2576,6 @@ nm_client_class_init (NMClientClass *client_class)
g_type_class_add_private (client_class, sizeof (NMClientPrivate));
/* virtual methods */
- object_class->constructed = constructed;
object_class->set_property = set_property;
object_class->get_property = get_property;
object_class->dispose = dispose;