diff options
-rw-r--r-- | src/settings/plugins/ifcfg-rh/plugin.c | 278 | ||||
-rw-r--r-- | src/settings/plugins/ifcfg-rh/plugin.h | 4 |
2 files changed, 230 insertions, 52 deletions
diff --git a/src/settings/plugins/ifcfg-rh/plugin.c b/src/settings/plugins/ifcfg-rh/plugin.c index e7ce97a28d..15b3a33446 100644 --- a/src/settings/plugins/ifcfg-rh/plugin.c +++ b/src/settings/plugins/ifcfg-rh/plugin.c @@ -50,6 +50,7 @@ #include "writer.h" #include "utils.h" #include "nm-dbus-compat.h" +#include "nm-exported-object.h" #include "nmdbus-ifcfg-rh.h" @@ -78,14 +79,23 @@ static NMIfcfgConnection *update_connection (SettingsPluginIfcfg *plugin, static void settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface); -G_DEFINE_TYPE_EXTENDED (SettingsPluginIfcfg, settings_plugin_ifcfg, NM_TYPE_EXPORTED_OBJECT, 0, - G_IMPLEMENT_INTERFACE (NM_TYPE_SETTINGS_PLUGIN, - settings_plugin_interface_init)) +G_DEFINE_TYPE_EXTENDED (SettingsPluginIfcfg, settings_plugin_ifcfg, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (NM_TYPE_SETTINGS_PLUGIN, + settings_plugin_interface_init)) #define SETTINGS_PLUGIN_IFCFG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SETTINGS_TYPE_PLUGIN_IFCFG, SettingsPluginIfcfgPrivate)) typedef struct { + NMConfig *config; + + struct { + GDBusConnection *connection; + GDBusInterfaceSkeleton *interface; + GCancellable *cancellable; + guint signal_id; + } dbus; + GHashTable *connections; /* uuid::connection */ gboolean initialized; @@ -725,7 +735,7 @@ impl_ifcfgrh_get_ifcfg_details (SettingsPluginIfcfg *plugin, "unable to get the UUID"); return; } - + path = nm_connection_get_path (NM_CONNECTION (connection)); if (!path) { g_dbus_method_invocation_return_error (context, @@ -739,6 +749,202 @@ impl_ifcfgrh_get_ifcfg_details (SettingsPluginIfcfg *plugin, g_variant_new ("(so)", uuid, path)); } +/*****************************************************************************/ + +static void +_dbus_clear (SettingsPluginIfcfg *self) +{ + SettingsPluginIfcfgPrivate *priv = SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (self); + + nm_clear_g_signal_handler (priv->dbus.connection, &priv->dbus.signal_id); + + nm_clear_g_cancellable (&priv->dbus.cancellable); + + if (priv->dbus.interface) { + g_dbus_interface_skeleton_unexport (priv->dbus.interface); + nm_exported_object_skeleton_release (priv->dbus.interface); + priv->dbus.interface = NULL; + } + + g_clear_object (&priv->dbus.connection); +} + +static void +_dbus_connection_closed (GDBusConnection *connection, + gboolean remote_peer_vanished, + GError *error, + gpointer user_data) +{ + _LOGW ("dbus: %s bus closed", IFCFGRH1_DBUS_SERVICE_NAME); + _dbus_clear (SETTINGS_PLUGIN_IFCFG (user_data)); + + /* Retry or recover? */ +} + +static void +_dbus_request_name_done (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GDBusConnection *connection = G_DBUS_CONNECTION (source_object); + SettingsPluginIfcfg *self; + SettingsPluginIfcfgPrivate *priv; + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *ret = NULL; + guint32 result; + + ret = g_dbus_connection_call_finish (connection, res, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = SETTINGS_PLUGIN_IFCFG (user_data); + priv = SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (self); + + g_clear_object (&priv->dbus.cancellable); + + if (!ret) { + _LOGW ("dbus: couldn't acquire D-Bus service: %s", error->message); + _dbus_clear (self); + return; + } + + g_variant_get (ret, "(u)", &result); + + if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { + _LOGW ("dbus: couldn't acquire ifcfgrh1 D-Bus service (already taken)"); + _dbus_clear (self); + return; + } + + { + GType skeleton_type = NMDBUS_TYPE_IFCFGRH1_SKELETON; + gs_free char *method_name_get_ifcfg_details = NULL; + NMExportedObjectDBusMethodImpl methods[] = { + { + .method_name = (method_name_get_ifcfg_details = nm_exported_object_skeletonify_method_name ("GetIfcfgDetails")), + .impl = G_CALLBACK (impl_ifcfgrh_get_ifcfg_details), + }, + }; + + priv->dbus.interface = nm_exported_object_skeleton_create (skeleton_type, + g_type_class_peek (SETTINGS_TYPE_PLUGIN_IFCFG), + methods, + G_N_ELEMENTS (methods), + (GObject *) self); + + if (!g_dbus_interface_skeleton_export (priv->dbus.interface, + priv->dbus.connection, + IFCFGRH1_DBUS_OBJECT_PATH, + &error)) { + nm_exported_object_skeleton_release (priv->dbus.interface); + priv->dbus.interface = NULL; + _LOGW ("dbus: failed exporting interface: %s", error->message); + _dbus_clear (self); + return; + } + } + + _LOGD ("dbus: aquired D-Bus service %s and exported %s object", + IFCFGRH1_DBUS_SERVICE_NAME, + IFCFGRH1_DBUS_OBJECT_PATH); +} + +static void +_dbus_create_done (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + SettingsPluginIfcfg *self; + SettingsPluginIfcfgPrivate *priv; + gs_free_error GError *error = NULL; + GDBusConnection *connection; + + connection = g_dbus_connection_new_for_address_finish (res, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = SETTINGS_PLUGIN_IFCFG (user_data); + priv = SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (self); + + g_clear_object (&priv->dbus.cancellable); + + if (!connection) { + _LOGW ("dbus: couldn't initialize system bus: %s", error->message); + return; + } + + priv->dbus.connection = connection; + priv->dbus.cancellable = g_cancellable_new (); + + priv->dbus.signal_id = g_signal_connect (priv->dbus.connection, + "closed", + G_CALLBACK (_dbus_connection_closed), + self); + + g_dbus_connection_call (priv->dbus.connection, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "RequestName", + g_variant_new ("(su)", + IFCFGRH1_DBUS_SERVICE_NAME, + DBUS_NAME_FLAG_DO_NOT_QUEUE), + G_VARIANT_TYPE ("(u)"), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->dbus.cancellable, + _dbus_request_name_done, + self); +} + +static void +_dbus_setup (SettingsPluginIfcfg *self) +{ + SettingsPluginIfcfgPrivate *priv = SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (self); + gs_free char *address = NULL; + gs_free_error GError *error = NULL; + + g_return_if_fail (!priv->dbus.connection); + + address = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SYSTEM, NULL, &error); + if (address == NULL) { + _LOGW ("dbus: failed getting address for system bus: %s", error->message); + return; + } + + priv->dbus.cancellable = g_cancellable_new (); + + g_dbus_connection_new_for_address (address, + G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT + | G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION, + NULL, + priv->dbus.cancellable, + _dbus_create_done, + self); +} + +static void +config_changed_cb (NMConfig *config, + NMConfigData *config_data, + NMConfigChangeFlags changes, + NMConfigData *old_data, + SettingsPluginIfcfg *self) +{ + /* If the dbus connection for some reason is borked the D-Bus service + * won't be offered. + * + * On SIGHUP and SIGUSR1 try to re-connect to D-Bus. So in the unlikely + * event that the D-Bus conneciton is broken, that allows for recovery + * without need for restarting NetworkManager. */ + if ( NM_FLAGS_HAS (changes, NM_CONFIG_CHANGE_SIGHUP) + || NM_FLAGS_HAS (changes, NM_CONFIG_CHANGE_SIGUSR1)) { + if (!SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (self)->dbus.connection) + _dbus_setup (self); + } +} + +/*****************************************************************************/ + static void init (NMSettingsPlugin *config) { @@ -756,53 +962,33 @@ static void constructed (GObject *object) { SettingsPluginIfcfg *self = SETTINGS_PLUGIN_IFCFG (object); - GError *error = NULL; - GDBusConnection *bus; - GVariant *ret; - guint32 result; + SettingsPluginIfcfgPrivate *priv = SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (self); G_OBJECT_CLASS (settings_plugin_ifcfg_parent_class)->constructed (object); - bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); - if (!bus) { - _LOGW ("Couldn't connect to D-Bus: %s", error->message); - g_clear_error (&error); - return; - } + priv->config = nm_config_get (); + g_object_add_weak_pointer ((GObject *) priv->config, (gpointer *) &priv->config); + g_signal_connect (priv->config, + NM_CONFIG_SIGNAL_CONFIG_CHANGED, + G_CALLBACK (config_changed_cb), + self); - ret = g_dbus_connection_call_sync (bus, - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - "RequestName", - g_variant_new ("(su)", - IFCFGRH1_DBUS_SERVICE_NAME, - DBUS_NAME_FLAG_DO_NOT_QUEUE), - G_VARIANT_TYPE ("(u)"), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, &error); - g_object_unref (bus); - if (ret) { - g_variant_get (ret, "(u)", &result); - g_variant_unref (ret); - - if (result == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { - nm_exported_object_export (NM_EXPORTED_OBJECT (self)); - _LOGD ("Acquired D-Bus service %s", IFCFGRH1_DBUS_SERVICE_NAME); - } else - _LOGW ("Couldn't acquire ifcfgrh1 D-Bus service (already taken)"); - } else { - _LOGW ("Couldn't acquire D-Bus service: %s", error->message); - g_clear_error (&error); - } + _dbus_setup (self); } static void dispose (GObject *object) { - SettingsPluginIfcfg *plugin = SETTINGS_PLUGIN_IFCFG (object); - SettingsPluginIfcfgPrivate *priv = SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (plugin); + SettingsPluginIfcfg *self = SETTINGS_PLUGIN_IFCFG (object); + SettingsPluginIfcfgPrivate *priv = SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (self); + + if (priv->config) { + g_object_remove_weak_pointer ((GObject *) priv->config, (gpointer *) &priv->config); + g_signal_handlers_disconnect_by_func (priv->config, config_changed_cb, self); + priv->config = NULL; + } + + _dbus_clear (self); if (priv->connections) { g_hash_table_destroy (priv->connections); @@ -855,12 +1041,9 @@ static void settings_plugin_ifcfg_class_init (SettingsPluginIfcfgClass *req_class) { GObjectClass *object_class = G_OBJECT_CLASS (req_class); - NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (req_class); g_type_class_add_private (req_class, sizeof (SettingsPluginIfcfgPrivate)); - exported_object_class->export_path = IFCFGRH1_DBUS_OBJECT_PATH; - object_class->constructed = constructed; object_class->dispose = dispose; object_class->get_property = get_property; @@ -877,11 +1060,6 @@ settings_plugin_ifcfg_class_init (SettingsPluginIfcfgClass *req_class) g_object_class_override_property (object_class, NM_SETTINGS_PLUGIN_PROP_CAPABILITIES, NM_SETTINGS_PLUGIN_CAPABILITIES); - - nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (req_class), - NMDBUS_TYPE_IFCFGRH1_SKELETON, - "GetIfcfgDetails", impl_ifcfgrh_get_ifcfg_details, - NULL); } static void diff --git a/src/settings/plugins/ifcfg-rh/plugin.h b/src/settings/plugins/ifcfg-rh/plugin.h index e2020ce6c7..eba734cff8 100644 --- a/src/settings/plugins/ifcfg-rh/plugin.h +++ b/src/settings/plugins/ifcfg-rh/plugin.h @@ -37,11 +37,11 @@ typedef struct _SettingsPluginIfcfg SettingsPluginIfcfg; typedef struct _SettingsPluginIfcfgClass SettingsPluginIfcfgClass; struct _SettingsPluginIfcfg { - NMExportedObject parent; + GObject parent; }; struct _SettingsPluginIfcfgClass { - NMExportedObjectClass parent; + GObjectClass parent; }; GType settings_plugin_ifcfg_get_type (void); |