diff options
author | Thomas Haller <thaller@redhat.com> | 2017-05-12 17:41:12 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2017-05-12 17:41:12 +0200 |
commit | 36e7a1f8a0b6bbfe7fca5e681b3854fd601d8aed (patch) | |
tree | e8892b5e57da7dec0da8226a101baebf1c9beac2 | |
parent | 4efab710e481649213c049c4a6f8900378d7ca77 (diff) | |
parent | af5b86aa1ec59f9215604e55e2d3ee0026d718ff (diff) | |
download | NetworkManager-36e7a1f8a0b6bbfe7fca5e681b3854fd601d8aed.tar.gz |
core: merge branch 'th/async-bgo781643'
https://bugzilla.gnome.org/show_bug.cgi?id=781643
-rw-r--r-- | Makefile.am | 3 | ||||
-rw-r--r-- | src/devices/bluetooth/nm-bluez4-adapter.c | 118 | ||||
-rw-r--r-- | src/devices/bluetooth/nm-bluez4-manager.c | 145 | ||||
-rw-r--r-- | src/devices/bluetooth/nm-device-bt.c | 93 | ||||
-rw-r--r-- | src/devices/bluetooth/nm-device-bt.h | 6 | ||||
-rw-r--r-- | src/devices/wwan/libnm-wwan.ver | 4 | ||||
-rw-r--r-- | src/devices/wwan/nm-modem-manager.c | 813 | ||||
-rw-r--r-- | src/devices/wwan/nm-modem-manager.h | 13 | ||||
-rw-r--r-- | src/devices/wwan/nm-modem-ofono.c | 488 | ||||
-rw-r--r-- | src/devices/wwan/nm-modem.c | 39 | ||||
-rw-r--r-- | src/devices/wwan/nm-modem.h | 6 | ||||
-rw-r--r-- | src/devices/wwan/nm-wwan-factory.c | 4 | ||||
-rw-r--r-- | src/dns/nm-dns-manager.c | 1 | ||||
-rw-r--r-- | src/nm-hostname-manager.c | 661 | ||||
-rw-r--r-- | src/nm-hostname-manager.h | 63 | ||||
-rw-r--r-- | src/nm-manager.c | 64 | ||||
-rw-r--r-- | src/nm-manager.h | 1 | ||||
-rw-r--r-- | src/nm-policy.c | 160 | ||||
-rw-r--r-- | src/settings/nm-settings.c | 516 | ||||
-rw-r--r-- | src/settings/nm-settings.h | 10 |
20 files changed, 1996 insertions, 1212 deletions
diff --git a/Makefile.am b/Makefile.am index 96443196d4..32b6ba65f8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1391,6 +1391,9 @@ src_libNetworkManager_la_SOURCES = \ src/ppp/nm-ppp-manager.h \ src/ppp/nm-ppp-status.h \ \ + src/nm-hostname-manager.c \ + src/nm-hostname-manager.h \ + \ src/settings/nm-agent-manager.c \ src/settings/nm-agent-manager.h \ src/settings/nm-inotify-helper.c \ diff --git a/src/devices/bluetooth/nm-bluez4-adapter.c b/src/devices/bluetooth/nm-bluez4-adapter.c index c0c1be30b7..cd9eaed34a 100644 --- a/src/devices/bluetooth/nm-bluez4-adapter.c +++ b/src/devices/bluetooth/nm-bluez4-adapter.c @@ -49,6 +49,7 @@ static guint signals[LAST_SIGNAL] = { 0 }; typedef struct { char *path; GDBusProxy *proxy; + GCancellable *proxy_cancellable; gboolean initialized; char *address; @@ -73,6 +74,11 @@ G_DEFINE_TYPE (NMBluez4Adapter, nm_bluez4_adapter, G_TYPE_OBJECT) /*****************************************************************************/ +#define _NMLOG_DOMAIN LOGD_BT +#define _NMLOG(level, ...) __NMLOG_DEFAULT (level, _NMLOG_DOMAIN, "bluez4-adapter", __VA_ARGS__) + +/*****************************************************************************/ + static void device_do_remove (NMBluez4Adapter *self, NMBluezDevice *device); /*****************************************************************************/ @@ -119,8 +125,8 @@ nm_bluez4_adapter_get_devices (NMBluez4Adapter *self) static void emit_device_removed (NMBluez4Adapter *self, NMBluezDevice *device) { - nm_log_dbg (LOGD_BT, "(%s): bluez device now unusable", - nm_bluez_device_get_path (device)); + _LOGD ("(%s): bluez device now unusable", + nm_bluez_device_get_path (device)); g_signal_emit (self, signals[DEVICE_REMOVED], 0, device); } @@ -130,9 +136,9 @@ device_usable (NMBluezDevice *device, GParamSpec *pspec, gpointer user_data) NMBluez4Adapter *self = NM_BLUEZ4_ADAPTER (user_data); if (nm_bluez_device_get_usable (device)) { - nm_log_dbg (LOGD_BT, "(%s): bluez device now usable (device address is %s)", - nm_bluez_device_get_path (device), - nm_bluez_device_get_address (device)); + _LOGD ("(%s): bluez device now usable (device address is %s)", + nm_bluez_device_get_path (device), + nm_bluez_device_get_address (device)); g_signal_emit (self, signals[DEVICE_ADDED], 0, device); } else emit_device_removed (self, device); @@ -143,9 +149,9 @@ device_initialized (NMBluezDevice *device, gboolean success, gpointer user_data) { NMBluez4Adapter *self = NM_BLUEZ4_ADAPTER (user_data); - nm_log_dbg (LOGD_BT, "(%s): bluez device %s", - nm_bluez_device_get_path (device), - success ? "initialized" : "failed to initialize"); + _LOGD ("(%s): bluez device %s", + nm_bluez_device_get_path (device), + success ? "initialized" : "failed to initialize"); if (!success) device_do_remove (self, device); } @@ -178,7 +184,7 @@ device_created (GDBusProxy *proxy, const char *path, gpointer user_data) g_signal_connect (device, "notify::usable", G_CALLBACK (device_usable), self); g_hash_table_insert (priv->devices, (gpointer) nm_bluez_device_get_path (device), device); - nm_log_dbg (LOGD_BT, "(%s): new bluez device found", path); + _LOGD ("(%s): new bluez device found", path); } static void @@ -188,7 +194,7 @@ device_removed (GDBusProxy *proxy, const char *path, gpointer user_data) NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); NMBluezDevice *device; - nm_log_dbg (LOGD_BT, "(%s): bluez device removed", path); + _LOGD ("(%s): bluez device removed", path); device = g_hash_table_lookup (priv->devices, path); if (device) @@ -198,19 +204,28 @@ device_removed (GDBusProxy *proxy, const char *path, gpointer user_data) static void get_properties_cb (GObject *proxy, GAsyncResult *result, gpointer user_data) { - NMBluez4Adapter *self = NM_BLUEZ4_ADAPTER (user_data); - NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); - GError *err = NULL; + NMBluez4Adapter *self; + NMBluez4AdapterPrivate *priv; + gs_free_error GError *error = NULL; GVariant *ret, *properties; char **devices; int i; ret = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), result, - G_VARIANT_TYPE ("(a{sv})"), &err); + G_VARIANT_TYPE ("(a{sv})"), &error); + + if ( !ret + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = NM_BLUEZ4_ADAPTER (user_data); + priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); + + g_clear_object (&priv->proxy_cancellable); + if (!ret) { - g_dbus_error_strip_remote_error (err); - nm_log_warn (LOGD_BT, "bluez error getting adapter properties: %s", err->message); - g_error_free (err); + g_dbus_error_strip_remote_error (error); + _LOGW ("bluez error getting adapter properties: %s", error->message); goto done; } @@ -233,15 +248,43 @@ done: } static void -query_properties (NMBluez4Adapter *self) +_proxy_new_cb (GObject *source_object, + GAsyncResult *result, + gpointer user_data) { - NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); + NMBluez4Adapter *self; + NMBluez4AdapterPrivate *priv; + gs_free_error GError *error = NULL; + GDBusProxy *proxy; + + proxy = g_dbus_proxy_new_for_bus_finish (result, &error); + if ( !proxy + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = user_data; + priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); + + if (!proxy) { + _LOGW ("bluez error creating D-Bus proxy: %s", error->message); + g_clear_object (&priv->proxy_cancellable); + g_signal_emit (self, signals[INITIALIZED], 0, priv->initialized); + return; + } + + priv->proxy = proxy; + + _nm_dbus_signal_connect (priv->proxy, "DeviceCreated", G_VARIANT_TYPE ("(o)"), + G_CALLBACK (device_created), self); + _nm_dbus_signal_connect (priv->proxy, "DeviceRemoved", G_VARIANT_TYPE ("(o)"), + G_CALLBACK (device_removed), self); g_dbus_proxy_call (priv->proxy, "GetProperties", NULL, G_DBUS_CALL_FLAGS_NONE, -1, - NULL, - get_properties_cb, self); + priv->proxy_cancellable, + get_properties_cb, + self); } /*****************************************************************************/ @@ -316,19 +359,17 @@ nm_bluez4_adapter_new (const char *path, NMSettings *settings) priv->settings = g_object_ref (settings); - priv->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, - NULL, - BLUEZ_SERVICE, - priv->path, - BLUEZ4_ADAPTER_INTERFACE, - NULL, NULL); - _nm_dbus_signal_connect (priv->proxy, "DeviceCreated", G_VARIANT_TYPE ("(o)"), - G_CALLBACK (device_created), self); - _nm_dbus_signal_connect (priv->proxy, "DeviceRemoved", G_VARIANT_TYPE ("(o)"), - G_CALLBACK (device_removed), self); + priv->proxy_cancellable = g_cancellable_new (); - query_properties (self); + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, + NULL, + BLUEZ_SERVICE, + priv->path, + BLUEZ4_ADAPTER_INTERFACE, + priv->proxy_cancellable, + _proxy_new_cb, + self); return self; } @@ -339,21 +380,28 @@ dispose (GObject *object) NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); NMBluezDevice *device; + nm_clear_g_cancellable (&priv->proxy_cancellable); + while ((device = g_hash_table_find (priv->devices, _find_all, NULL))) device_do_remove (self, device); + if (priv->proxy) { + g_signal_handlers_disconnect_by_data (priv->proxy, self); + g_clear_object (&priv->proxy); + } + G_OBJECT_CLASS (nm_bluez4_adapter_parent_class)->dispose (object); } static void finalize (GObject *object) { - NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE ((NMBluez4Adapter *) object); + NMBluez4Adapter *self = NM_BLUEZ4_ADAPTER (object); + NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); g_hash_table_destroy (priv->devices); g_free (priv->address); g_free (priv->path); - g_object_unref (priv->proxy); G_OBJECT_CLASS (nm_bluez4_adapter_parent_class)->finalize (object); diff --git a/src/devices/bluetooth/nm-bluez4-manager.c b/src/devices/bluetooth/nm-bluez4-manager.c index a9079a2fc0..66ef83104d 100644 --- a/src/devices/bluetooth/nm-bluez4-manager.c +++ b/src/devices/bluetooth/nm-bluez4-manager.c @@ -47,6 +47,7 @@ typedef struct { NMSettings *settings; GDBusProxy *proxy; + GCancellable *proxy_cancellable; NMBluez4Adapter *adapter; } NMBluez4ManagerPrivate; @@ -66,6 +67,11 @@ G_DEFINE_TYPE (NMBluez4Manager, nm_bluez4_manager, G_TYPE_OBJECT) /*****************************************************************************/ +#define _NMLOG_DOMAIN LOGD_BT +#define _NMLOG(level, ...) __NMLOG_DEFAULT (level, _NMLOG_DOMAIN, "bluez4-manager", __VA_ARGS__) + +/*****************************************************************************/ + static void emit_bdaddr_added (NMBluez4Manager *self, NMBluezDevice *device) { @@ -176,42 +182,62 @@ default_adapter_changed (GDBusProxy *proxy, const char *path, NMBluez4Manager *s static void default_adapter_cb (GObject *proxy, GAsyncResult *result, gpointer user_data) { - NMBluez4Manager *self = NM_BLUEZ4_MANAGER (user_data); - NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); - GVariant *ret; - GError *err = NULL; + NMBluez4Manager *self; + NMBluez4ManagerPrivate *priv; + gs_unref_variant GVariant *ret = NULL; + gs_free_error GError *error = NULL; + const char *default_adapter; ret = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), result, - G_VARIANT_TYPE ("(o)"), &err); - if (ret) { - const char *default_adapter; + G_VARIANT_TYPE ("(o)"), &error); + if ( !ret + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; - g_variant_get (ret, "(&o)", &default_adapter); - default_adapter_changed (priv->proxy, default_adapter, self); - g_variant_unref (ret); - } else { + self = NM_BLUEZ4_MANAGER (user_data); + priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); + + g_clear_object (&priv->proxy_cancellable); + + if (!ret) { /* Ignore "No such adapter" errors; just means bluetooth isn't active */ - if ( !_nm_dbus_error_has_name (err, "org.bluez.Error.NoSuchAdapter") - && !_nm_dbus_error_has_name (err, "org.freedesktop.systemd1.LoadFailed") - && !g_error_matches (err, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)) { - g_dbus_error_strip_remote_error (err); - nm_log_warn (LOGD_BT, "bluez error getting default adapter: %s", - err->message); + if ( !_nm_dbus_error_has_name (error, "org.bluez.Error.NoSuchAdapter") + && !_nm_dbus_error_has_name (error, "org.freedesktop.systemd1.LoadFailed") + && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)) { + g_dbus_error_strip_remote_error (error); + _LOGW ("bluez error getting default adapter: %s", + error->message); } - g_error_free (err); + return; } + + g_variant_get (ret, "(&o)", &default_adapter); + default_adapter_changed (priv->proxy, default_adapter, self); } static void -query_default_adapter (NMBluez4Manager *self) +name_owner_changed (NMBluez4Manager *self) { NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); + gs_free char *owner = NULL; + + nm_clear_g_cancellable (&priv->proxy_cancellable); + + owner = g_dbus_proxy_get_name_owner (priv->proxy); + if (!owner) { + /* Throwing away the adapter removes all devices too */ + g_clear_object (&priv->adapter); + return; + } + + priv->proxy_cancellable = g_cancellable_new (); g_dbus_proxy_call (priv->proxy, "DefaultAdapter", NULL, G_DBUS_CALL_FLAGS_NONE, -1, - NULL, - default_adapter_cb, self); + priv->proxy_cancellable, + default_adapter_cb, + self); } static void @@ -219,34 +245,35 @@ name_owner_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_data) { - NMBluez4Manager *self = NM_BLUEZ4_MANAGER (user_data); - NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); - char *owner; - - owner = g_dbus_proxy_get_name_owner (priv->proxy); - if (owner) { - query_default_adapter (self); - g_free (owner); - } else { - /* Throwing away the adapter removes all devices too */ - g_clear_object (&priv->adapter); - } + name_owner_changed (user_data); } -/*****************************************************************************/ - static void -nm_bluez4_manager_init (NMBluez4Manager *self) +_proxy_new_cb (GObject *source_object, + GAsyncResult *result, + gpointer user_data) { - NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); + NMBluez4Manager *self; + NMBluez4ManagerPrivate *priv; + gs_free_error GError *error = NULL; + GDBusProxy *proxy; + + proxy = g_dbus_proxy_new_for_bus_finish (result, &error); + if ( !proxy + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = user_data; + priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); + + if (!proxy) { + _LOGW ("bluez error creating D-Bus proxy: %s", error->message); + g_clear_object (&priv->proxy_cancellable); + return; + } + + priv->proxy = proxy; - priv->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, - NULL, - BLUEZ_SERVICE, - BLUEZ_MANAGER_PATH, - BLUEZ4_MANAGER_INTERFACE, - NULL, NULL); _nm_dbus_signal_connect (priv->proxy, "AdapterRemoved", G_VARIANT_TYPE ("(o)"), G_CALLBACK (adapter_removed), self); _nm_dbus_signal_connect (priv->proxy, "DefaultAdapterChanged", G_VARIANT_TYPE ("(o)"), @@ -254,7 +281,27 @@ nm_bluez4_manager_init (NMBluez4Manager *self) g_signal_connect (priv->proxy, "notify::g-name-owner", G_CALLBACK (name_owner_changed_cb), self); - query_default_adapter (self); + name_owner_changed (self); +} + +/*****************************************************************************/ + +static void +nm_bluez4_manager_init (NMBluez4Manager *self) +{ + NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); + + priv->proxy_cancellable = g_cancellable_new (); + + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, + NULL, + BLUEZ_SERVICE, + BLUEZ_MANAGER_PATH, + BLUEZ4_MANAGER_INTERFACE, + priv->proxy_cancellable, + _proxy_new_cb, + self); } NMBluez4Manager * @@ -275,7 +322,13 @@ dispose (GObject *object) NMBluez4Manager *self = NM_BLUEZ4_MANAGER (object); NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); - g_clear_object (&priv->proxy); + nm_clear_g_cancellable (&priv->proxy_cancellable); + + if (priv->proxy) { + g_signal_handlers_disconnect_by_data (priv->proxy, self); + g_clear_object (&priv->proxy); + } + g_clear_object (&priv->adapter); G_OBJECT_CLASS (nm_bluez4_manager_parent_class)->dispose (object); diff --git a/src/devices/bluetooth/nm-device-bt.c b/src/devices/bluetooth/nm-device-bt.c index 4ee7148928..3402532fca 100644 --- a/src/devices/bluetooth/nm-device-bt.c +++ b/src/devices/bluetooth/nm-device-bt.c @@ -40,15 +40,14 @@ #include "nm-bt-error.h" #include "platform/nm-platform.h" +#include "devices/wwan/nm-modem-manager.h" +#include "devices/wwan/nm-modem.h" + #include "introspection/org.freedesktop.NetworkManager.Device.Bluetooth.h" #include "devices/nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceBt); -#define MM_DBUS_SERVICE "org.freedesktop.ModemManager1" -#define MM_DBUS_PATH "/org/freedesktop/ModemManager1" -#define MM_DBUS_INTERFACE "org.freedesktop.ModemManager1" - /*****************************************************************************/ NM_GOBJECT_PROPERTIES_DEFINE_BASE ( @@ -65,7 +64,8 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; typedef struct { - GDBusProxy *mm_proxy; + NMModemManager *modem_manager; + gboolean mm_running; NMBluezDevice *bt_device; @@ -967,9 +967,12 @@ is_available (NMDevice *dev, NMDeviceCheckDevAvailableFlags flags) } static void -set_mm_running (NMDeviceBt *self, gboolean running) +set_mm_running (NMDeviceBt *self) { NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); + gboolean running; + + running = (nm_modem_manager_name_owner_get (priv->modem_manager) != NULL); if (priv->mm_running != running) { _LOGD (LOGD_BT, "ModemManager now %s", @@ -983,18 +986,11 @@ set_mm_running (NMDeviceBt *self, gboolean running) } static void -mm_name_owner_changed (GObject *object, - GParamSpec *pspec, - NMDeviceBt *self) +mm_name_owner_changed_cb (GObject *object, + GParamSpec *pspec, + gpointer user_data) { - char *owner; - - owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (object)); - if (owner) { - set_mm_running (self, TRUE); - g_free (owner); - } else - set_mm_running (self, FALSE); + set_mm_running (user_data); } /*****************************************************************************/ @@ -1039,7 +1035,8 @@ set_property (GObject *object, guint prop_id, case PROP_BT_DEVICE: /* construct-only */ priv->bt_device = g_value_dup_object (value); - g_signal_connect (priv->bt_device, "removed", G_CALLBACK (bluez_device_removed), object); + if (!priv->bt_device) + g_return_if_reached (); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -1052,46 +1049,41 @@ set_property (GObject *object, guint prop_id, static void nm_device_bt_init (NMDeviceBt *self) { - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); - GError *error = NULL; - - priv->mm_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | - G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS | - G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, - NULL, - MM_DBUS_SERVICE, - MM_DBUS_PATH, - MM_DBUS_INTERFACE, - NULL, &error); - if (priv->mm_proxy) { - g_signal_connect (priv->mm_proxy, "notify::g-name-owner", - G_CALLBACK (mm_name_owner_changed), - self); - mm_name_owner_changed (G_OBJECT (priv->mm_proxy), NULL, self); - } else { - _LOGW (LOGD_MB, "Could not create proxy for '%s': %s", - MM_DBUS_SERVICE, error->message); - g_clear_error (&error); - } } static void constructed (GObject *object) { - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE ((NMDeviceBt *) object); + NMDeviceBt *self = NM_DEVICE_BT (object); + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); const char *my_hwaddr; G_OBJECT_CLASS (nm_device_bt_parent_class)->constructed (object); + priv->modem_manager = g_object_ref (nm_modem_manager_get ()); + + nm_modem_manager_name_owner_ref (priv->modem_manager); + + g_signal_connect (priv->modem_manager, + "notify::"NM_MODEM_MANAGER_NAME_OWNER, + G_CALLBACK (mm_name_owner_changed_cb), + self); + + if (priv->bt_device) { + /* Watch for BT device property changes */ + g_signal_connect (priv->bt_device, "notify::" NM_BLUEZ_DEVICE_CONNECTED, + G_CALLBACK (bluez_connected_changed), + object); + g_signal_connect (priv->bt_device, "removed", G_CALLBACK (bluez_device_removed), object); + } + my_hwaddr = nm_device_get_hw_address (NM_DEVICE (object)); - g_assert (my_hwaddr); - priv->bdaddr = g_strdup (my_hwaddr); + if (my_hwaddr) + priv->bdaddr = g_strdup (my_hwaddr); + else + g_warn_if_reached (); - /* Watch for BT device property changes */ - g_signal_connect (priv->bt_device, "notify::" NM_BLUEZ_DEVICE_CONNECTED, - G_CALLBACK (bluez_connected_changed), - object); + set_mm_running (self); } NMDevice * @@ -1129,9 +1121,10 @@ dispose (GObject *object) g_signal_handlers_disconnect_matched (priv->bt_device, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, object); - if (priv->mm_proxy) { - g_signal_handlers_disconnect_by_func (priv->mm_proxy, G_CALLBACK (mm_name_owner_changed), object); - g_clear_object (&priv->mm_proxy); + if (priv->modem_manager) { + g_signal_handlers_disconnect_by_func (priv->modem_manager, G_CALLBACK (mm_name_owner_changed_cb), object); + nm_modem_manager_name_owner_unref (priv->modem_manager); + g_clear_object (&priv->modem_manager); } modem_cleanup (NM_DEVICE_BT (object)); diff --git a/src/devices/bluetooth/nm-device-bt.h b/src/devices/bluetooth/nm-device-bt.h index 9bcf6ca861..b90dbd2aa9 100644 --- a/src/devices/bluetooth/nm-device-bt.h +++ b/src/devices/bluetooth/nm-device-bt.h @@ -24,8 +24,6 @@ #include "devices/nm-device.h" #include "nm-bluez-device.h" -#include "devices/wwan/nm-modem.h" - #define NM_TYPE_DEVICE_BT (nm_device_bt_get_type ()) #define NM_DEVICE_BT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_BT, NMDeviceBt)) #define NM_DEVICE_BT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_BT, NMDeviceBtClass)) @@ -52,8 +50,10 @@ NMDevice *nm_device_bt_new (NMBluezDevice *bt_device, guint32 nm_device_bt_get_capabilities (NMDeviceBt *device); +struct _NMModem; + gboolean nm_device_bt_modem_added (NMDeviceBt *device, - NMModem *modem, + struct _NMModem *modem, const char *driver); #endif /* __NETWORKMANAGER_DEVICE_BT_H__ */ diff --git a/src/devices/wwan/libnm-wwan.ver b/src/devices/wwan/libnm-wwan.ver index eb577aafb7..6efcb03fa7 100644 --- a/src/devices/wwan/libnm-wwan.ver +++ b/src/devices/wwan/libnm-wwan.ver @@ -20,7 +20,11 @@ global: nm_modem_get_type; nm_modem_get_uid; nm_modem_ip4_pre_commit; + nm_modem_manager_get; nm_modem_manager_get_type; + nm_modem_manager_name_owner_get; + nm_modem_manager_name_owner_ref; + nm_modem_manager_name_owner_unref; nm_modem_owns_port; nm_modem_set_mm_enabled; nm_modem_stage3_ip4_config_start; diff --git a/src/devices/wwan/nm-modem-manager.c b/src/devices/wwan/nm-modem-manager.c index b1f6d92e7f..3dd9377699 100644 --- a/src/devices/wwan/nm-modem-manager.c +++ b/src/devices/wwan/nm-modem-manager.c @@ -45,6 +45,10 @@ /*****************************************************************************/ +NM_GOBJECT_PROPERTIES_DEFINE (NMModemManager, + PROP_NAME_OWNER, +); + enum { MODEM_ADDED, LAST_SIGNAL, @@ -54,14 +58,38 @@ static guint signals[LAST_SIGNAL] = { 0 }; typedef struct { GDBusConnection *dbus_connection; - MMManager *modem_manager; - guint mm_launch_id; - gulong mm_name_owner_changed_id; - gulong mm_object_added_id; - gulong mm_object_removed_id; + + /* used during g_bus_get() and later during mm_manager_new(). */ + GCancellable *main_cancellable; + + struct { + MMManager *manager; + GCancellable *poke_cancellable; + gulong handle_name_owner_changed_id; + gulong handle_object_added_id; + gulong handle_object_removed_id; + guint relaunch_id; + + /* this only has one use: that the <info> logging line about + * ModemManager available distinguishes between first-time + * and later name-owner-changed. */ + enum { + LOG_AVAILABLE_NOT_INITIALIZED = 0, + LOG_AVAILABLE_YES, + LOG_AVAILABLE_NO, + } log_available:3; + + GDBusProxy *proxy; + GCancellable *proxy_cancellable; + guint proxy_ref_count; + char *proxy_name_owner; + } modm; #if WITH_OFONO - GDBusProxy *ofono_proxy; + struct { + GDBusProxy *proxy; + GCancellable *cancellable; + } ofono; #endif GHashTable *modems; @@ -82,19 +110,35 @@ G_DEFINE_TYPE (NMModemManager, nm_modem_manager, G_TYPE_OBJECT) /*****************************************************************************/ +#define _NMLOG_DOMAIN LOGD_MB +#define _NMLOG(level, ...) __NMLOG_DEFAULT (level, _NMLOG_DOMAIN, "modem-manager", __VA_ARGS__) + +/*****************************************************************************/ + +NM_DEFINE_SINGLETON_GETTER (NMModemManager, nm_modem_manager_get, NM_TYPE_MODEM_MANAGER); + +/*****************************************************************************/ + +static void modm_schedule_manager_relaunch (NMModemManager *self, + guint n_seconds); +static void modm_ensure_manager (NMModemManager *self); + +/*****************************************************************************/ + static void handle_new_modem (NMModemManager *self, NMModem *modem) { + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); const char *path; path = nm_modem_get_path (modem); - if (g_hash_table_lookup (self->_priv.modems, path)) { + if (g_hash_table_lookup (priv->modems, path)) { g_warn_if_reached (); return; } /* Track the new modem */ - g_hash_table_insert (self->_priv.modems, g_strdup (path), modem); + g_hash_table_insert (priv->modems, g_strdup (path), modem); g_signal_emit (self, signals[MODEM_ADDED], 0, modem); } @@ -105,22 +149,27 @@ remove_one_modem (gpointer key, gpointer value, gpointer user_data) return TRUE; } +/*****************************************************************************/ + static void -clear_modem_manager (NMModemManager *self) +modm_clear_manager (NMModemManager *self) { - if (!self->_priv.modem_manager) + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + + if (!priv->modm.manager) return; - nm_clear_g_signal_handler (self->_priv.modem_manager, &self->_priv.mm_name_owner_changed_id); - nm_clear_g_signal_handler (self->_priv.modem_manager, &self->_priv.mm_object_added_id); - nm_clear_g_signal_handler (self->_priv.modem_manager, &self->_priv.mm_object_removed_id); - g_clear_object (&self->_priv.modem_manager); + nm_clear_g_signal_handler (priv->modm.manager, &priv->modm.handle_name_owner_changed_id); + nm_clear_g_signal_handler (priv->modm.manager, &priv->modm.handle_object_added_id); + nm_clear_g_signal_handler (priv->modm.manager, &priv->modm.handle_object_removed_id); + g_clear_object (&priv->modm.manager); } static void -modem_object_added (MMManager *modem_manager, - MMObject *modem_object, - NMModemManager *self) +modm_handle_object_added (MMManager *modem_manager, + MMObject *modem_object, + NMModemManager *self) { + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); const gchar *path; MMModem *modem_iface; NMModem *modem; @@ -128,21 +177,21 @@ modem_object_added (MMManager *modem_manager, /* Ensure we don't have the same modem already */ path = mm_object_get_path (modem_object); - if (g_hash_table_lookup (self->_priv.modems, path)) { - nm_log_warn (LOGD_MB, "modem with path %s already exists, ignoring", path); + if (g_hash_table_lookup (priv->modems, path)) { + _LOGW ("modem with path %s already exists, ignoring", path); return; } /* Ensure we have the 'Modem' interface at least */ modem_iface = mm_object_peek_modem (modem_object); if (!modem_iface) { - nm_log_warn (LOGD_MB, "modem with path %s doesn't have the Modem interface, ignoring", path); + _LOGW ("modem with path %s doesn't have the Modem interface, ignoring", path); return; } /* Ensure we have a primary port reported */ if (!mm_modem_get_primary_port (modem_iface)) { - nm_log_warn (LOGD_MB, "modem with path %s has unknown primary port, ignoring", path); + _LOGW ("modem with path %s has unknown primary port, ignoring", path); return; } @@ -150,65 +199,68 @@ modem_object_added (MMManager *modem_manager, modem = nm_modem_broadband_new (G_OBJECT (modem_object), &error); if (modem) handle_new_modem (self, modem); - else { - nm_log_warn (LOGD_MB, "failed to create modem: %s", - error->message); - } + else + _LOGW ("failed to create modem: %s", error->message); g_clear_error (&error); } static void -modem_object_removed (MMManager *manager, - MMObject *modem_object, - NMModemManager *self) +modm_handle_object_removed (MMManager *manager, + MMObject *modem_object, + NMModemManager *self) { + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); NMModem *modem; const gchar *path; path = mm_object_get_path (modem_object); - modem = (NMModem *) g_hash_table_lookup (self->_priv.modems, path); + modem = (NMModem *) g_hash_table_lookup (priv->modems, path); if (!modem) return; nm_modem_emit_removed (modem); - g_hash_table_remove (self->_priv.modems, path); + g_hash_table_remove (priv->modems, path); } static void -modem_manager_available (NMModemManager *self) +modm_manager_available (NMModemManager *self) { + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); GList *modems, *l; - nm_log_info (LOGD_MB, "ModemManager available in the bus"); + if (priv->modm.log_available != LOG_AVAILABLE_YES) { + _LOGI ("ModemManager %savailable", priv->modm.log_available ? "now " : ""); + priv->modm.log_available = LOG_AVAILABLE_YES; + } /* Update initial modems list */ - modems = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (self->_priv.modem_manager)); + modems = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (priv->modm.manager)); for (l = modems; l; l = g_list_next (l)) - modem_object_added (self->_priv.modem_manager, MM_OBJECT (l->data), self); + modm_handle_object_added (priv->modm.manager, MM_OBJECT (l->data), self); g_list_free_full (modems, (GDestroyNotify) g_object_unref); } -static void schedule_modem_manager_relaunch (NMModemManager *self, - guint n_seconds); -static void ensure_modem_manager (NMModemManager *self); - static void -modem_manager_name_owner_changed (MMManager *modem_manager, - GParamSpec *pspec, - NMModemManager *self) +modm_handle_name_owner_changed (MMManager *modem_manager, + GParamSpec *pspec, + NMModemManager *self) { + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); gchar *name_owner; /* Quit poking, if any */ - nm_clear_g_source (&self->_priv.mm_launch_id); + nm_clear_g_source (&priv->modm.relaunch_id); name_owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (modem_manager)); if (!name_owner) { - nm_log_info (LOGD_MB, "ModemManager disappeared from bus"); + if (priv->modm.log_available != LOG_AVAILABLE_NO) { + _LOGI ("ModemManager %savailable", priv->modm.log_available ? "no longer " : "not "); + priv->modm.log_available = LOG_AVAILABLE_NO; + } /* If not managed by systemd, schedule relaunch */ if (!sd_booted ()) - schedule_modem_manager_relaunch (self, 0); + modm_schedule_manager_relaunch (self, 0); return; } @@ -220,18 +272,322 @@ modem_manager_name_owner_changed (MMManager *modem_manager, * nor 'object-removed' if it was created while there was no ModemManager in * the bus. This hack avoids this issue until we get a GIO with the fix * included... */ - clear_modem_manager (self); - ensure_modem_manager (self); + modm_clear_manager (self); + modm_ensure_manager (self); /* Whenever GDBusObjectManagerClient is fixed, we can just do the following: - * modem_manager_available (self); + * modm_manager_available (self); */ } +static void +modm_manager_poke_cb (GObject *connection, + GAsyncResult *res, + gpointer user_data) +{ + NMModemManager *self; + NMModemManagerPrivate *priv; + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *result = NULL; + + result = g_dbus_connection_call_finish (G_DBUS_CONNECTION (connection), res, &error); + + if ( !result + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = user_data; + priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + + g_clear_object (&priv->modm.poke_cancellable); + + if (error) { + _LOGW ("error poking ModemManager: %s", error->message); + + /* Don't reschedule poke is MM service doesn't exist. */ + if ( !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN) + && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND)) { + + /* Setup timeout to relaunch */ + modm_schedule_manager_relaunch (self, MODEM_POKE_INTERVAL); + } + } +} + +static void +modm_manager_poke (NMModemManager *self) +{ + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + + nm_clear_g_cancellable (&priv->modm.poke_cancellable); + priv->modm.poke_cancellable = g_cancellable_new (); + + /* If there is no current owner right away, ensure we poke to get one */ + g_dbus_connection_call (priv->dbus_connection, + NM_MODEM_MANAGER_MM_DBUS_SERVICE, + NM_MODEM_MANAGER_MM_DBUS_PATH, + DBUS_INTERFACE_PEER, + "Ping", + NULL, + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->modm.poke_cancellable, + modm_manager_poke_cb, + self); +} + +static void +modm_manager_check_name_owner (NMModemManager *self) +{ + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + gs_free gchar *name_owner = NULL; + + name_owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (priv->modm.manager)); + if (name_owner) { + modm_manager_available (self); + return; + } + + /* If the lifecycle is not managed by systemd, poke */ + if (!sd_booted ()) + modm_manager_poke (self); +} + +static void +modm_manager_new_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + NMModemManager *self; + NMModemManagerPrivate *priv; + gs_free_error GError *error = NULL; + MMManager *modem_manager; + + modem_manager = mm_manager_new_finish (res, &error); + if ( !modem_manager + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = user_data; + priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + + nm_assert (!priv->modm.manager); + + g_clear_object (&priv->main_cancellable); + + if (!modem_manager) { + /* We're not really supposed to get any error here. If we do get one, + * though, just re-schedule the MMManager creation after some time. + * During this period, name-owner changes won't be followed. */ + _LOGW ("error creating ModemManager client: %s", error->message); + /* Setup timeout to relaunch */ + modm_schedule_manager_relaunch (self, MODEM_POKE_INTERVAL); + return; + } + + priv->modm.manager = modem_manager; + + /* Setup signals in the GDBusObjectManagerClient */ + priv->modm.handle_name_owner_changed_id = + g_signal_connect (priv->modm.manager, + "notify::name-owner", + G_CALLBACK (modm_handle_name_owner_changed), + self); + priv->modm.handle_object_added_id = + g_signal_connect (priv->modm.manager, + "object-added", + G_CALLBACK (modm_handle_object_added), + self); + priv->modm.handle_object_removed_id = + g_signal_connect (priv->modm.manager, + "object-removed", + G_CALLBACK (modm_handle_object_removed), + self); + + modm_manager_check_name_owner (self); +} + +static void +modm_ensure_manager (NMModemManager *self) +{ + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + + g_assert (priv->dbus_connection); + + /* Create the GDBusObjectManagerClient. We do not request to autostart, as + * we don't really want the MMManager creation to fail. We can always poke + * later on if we want to request the autostart */ + if (!priv->modm.manager) { + if (!priv->main_cancellable) + priv->main_cancellable = g_cancellable_new (); + mm_manager_new (priv->dbus_connection, + G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START, + priv->main_cancellable, + modm_manager_new_cb, + self); + return; + } + + /* If already available, recheck name owner! */ + modm_manager_check_name_owner (self); +} + +static gboolean +modm_schedule_manager_relaunch_cb (NMModemManager *self) +{ + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + + priv->modm.relaunch_id = 0; + modm_ensure_manager (self); + return G_SOURCE_REMOVE; +} + +static void +modm_schedule_manager_relaunch (NMModemManager *self, + guint n_seconds) +{ + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + + /* No need to pass an extra reference to self; timeout/idle will be + * cancelled if the object gets disposed. */ + if (n_seconds) + priv->modm.relaunch_id = g_timeout_add_seconds (n_seconds, (GSourceFunc)modm_schedule_manager_relaunch_cb, self); + else + priv->modm.relaunch_id = g_idle_add ((GSourceFunc)modm_schedule_manager_relaunch_cb, self); +} + +/*****************************************************************************/ + +static void +modm_proxy_name_owner_reset (NMModemManager *self) +{ + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + char *name = NULL; + + if (priv->modm.proxy) + name = g_dbus_proxy_get_name_owner (priv->modm.proxy); + + if (nm_streq0 (priv->modm.proxy_name_owner, name)) { + g_free (name); + return; + } + g_free (priv->modm.proxy_name_owner); + priv->modm.proxy_name_owner = name; + + _notify (self, PROP_NAME_OWNER); +} + +static void +modm_proxy_name_owner_changed_cb (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + modm_proxy_name_owner_reset (user_data); +} + +static void +modm_proxy_new_cb (GObject *source_object, + GAsyncResult *result, + gpointer user_data) +{ + NMModemManager *self; + NMModemManagerPrivate *priv; + GDBusProxy *proxy; + gs_free_error GError *error = NULL; + + proxy = g_dbus_proxy_new_for_bus_finish (result, &error); + if ( !proxy + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = user_data; + priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + + g_clear_object (&priv->modm.proxy_cancellable); + + if (!proxy) { + _LOGW ("could not obtain D-Bus proxy for ModemManager: %s", error->message); + return; + } + + priv->modm.proxy = proxy; + g_signal_connect (priv->modm.proxy, "notify::g-name-owner", + G_CALLBACK (modm_proxy_name_owner_changed_cb), self); + + modm_proxy_name_owner_reset (self); +} + +void +nm_modem_manager_name_owner_ref (NMModemManager *self) +{ + NMModemManagerPrivate *priv; + + g_return_if_fail (NM_IS_MODEM_MANAGER (self)); + + priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + + if (priv->modm.proxy_ref_count++ > 0) { + /* only try once to create the proxy. If proxy creation + * for the first "ref" failed, it's unclear what to do. + * The proxy is hosed. */ + return; + } + + nm_assert (!priv->modm.proxy && !priv->modm.proxy_cancellable); + + priv->modm.proxy_cancellable = g_cancellable_new (); + + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES + | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS + | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + NULL, + NM_MODEM_MANAGER_MM_DBUS_SERVICE, + NM_MODEM_MANAGER_MM_DBUS_PATH, + NM_MODEM_MANAGER_MM_DBUS_INTERFACE, + priv->modm.proxy_cancellable, + modm_proxy_new_cb, + self); +} + +void +nm_modem_manager_name_owner_unref (NMModemManager *self) +{ + NMModemManagerPrivate *priv; + + g_return_if_fail (NM_IS_MODEM_MANAGER (self)); + + priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + + g_return_if_fail (priv->modm.proxy_ref_count > 0); + + if (--priv->modm.proxy_ref_count > 0) + return; + + nm_clear_g_cancellable (&priv->modm.proxy_cancellable); + g_clear_object (&priv->modm.proxy); + + modm_proxy_name_owner_reset (self); +} + +const char * +nm_modem_manager_name_owner_get (NMModemManager *self) +{ + g_return_val_if_fail (NM_IS_MODEM_MANAGER (self), NULL); + nm_assert (NM_MODEM_MANAGER_GET_PRIVATE (self)->modm.proxy_ref_count > 0); + + return NM_MODEM_MANAGER_GET_PRIVATE (self)->modm.proxy_name_owner; +} + +/*****************************************************************************/ + #if WITH_OFONO + static void ofono_create_modem (NMModemManager *self, const char *path) { + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); NMModem *modem = NULL; /* Ensure duplicate modems aren't created. Because we're not using the @@ -239,12 +595,12 @@ ofono_create_modem (NMModemManager *self, const char *path) * receive ModemAdded signals before GetModems() returns, so some of the * modems returned from GetModems() may already have been created. */ - if (!g_hash_table_lookup (self->_priv.modems, path)) { + if (!g_hash_table_lookup (priv->modems, path)) { modem = nm_modem_ofono_new (path); if (modem) handle_new_modem (self, modem); else - nm_log_warn (LOGD_MB, "Failed to create oFono modem for %s", path); + _LOGW ("Failed to create oFono modem for %s", path); } } @@ -256,80 +612,96 @@ ofono_signal_cb (GDBusProxy *proxy, gpointer user_data) { NMModemManager *self = NM_MODEM_MANAGER (user_data); + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); gchar *object_path; NMModem *modem; if (g_strcmp0 (signal_name, "ModemAdded") == 0) { g_variant_get (parameters, "(oa{sv})", &object_path, NULL); - nm_log_info (LOGD_MB, "oFono modem appeared: %s", object_path); + _LOGI ("oFono modem appeared: %s", object_path); ofono_create_modem (NM_MODEM_MANAGER (user_data), object_path); g_free (object_path); } else if (g_strcmp0 (signal_name, "ModemRemoved") == 0) { g_variant_get (parameters, "(o)", &object_path); - nm_log_info (LOGD_MB, "oFono modem removed: %s", object_path); + _LOGI ("oFono modem removed: %s", object_path); - modem = (NMModem *) g_hash_table_lookup (self->_priv.modems, object_path); + modem = (NMModem *) g_hash_table_lookup (priv->modems, object_path); if (modem) { nm_modem_emit_removed (modem); - g_hash_table_remove (self->_priv.modems, object_path); + g_hash_table_remove (priv->modems, object_path); } else { - nm_log_warn (LOGD_MB, "could not remove modem %s, not found in table", - object_path); + _LOGW ("could not remove modem %s, not found in table", + object_path); } g_free (object_path); } } static void -ofono_enumerate_devices_done (GDBusProxy *proxy, GAsyncResult *res, gpointer user_data) +ofono_enumerate_devices_done (GObject *proxy, + GAsyncResult *res, + gpointer user_data) { - NMModemManager *manager = NM_MODEM_MANAGER (user_data); + NMModemManager *self; + NMModemManagerPrivate *priv; gs_free_error GError *error = NULL; GVariant *results; GVariantIter *iter; const char *path; - results = g_dbus_proxy_call_finish (proxy, res, &error); - if (results) { - g_variant_get (results, "(a(oa{sv}))", &iter); - while (g_variant_iter_loop (iter, "(&oa{sv})", &path, NULL)) - ofono_create_modem (manager, path); - g_variant_iter_free (iter); - g_variant_unref (results); - } + results = g_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), res, &error); + if ( !results + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; - if (error) { - nm_log_warn (LOGD_MB, "failed to enumerate oFono devices: %s", - error->message); + self = NM_MODEM_MANAGER (user_data); + priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + + g_clear_object (&priv->ofono.cancellable); + + if (!results) { + _LOGW ("failed to enumerate oFono devices: %s", + error->message); + return; } + + g_variant_get (results, "(a(oa{sv}))", &iter); + while (g_variant_iter_loop (iter, "(&oa{sv})", &path, NULL)) + ofono_create_modem (self, path); + g_variant_iter_free (iter); + g_variant_unref (results); } static void -ofono_check_name_owner (NMModemManager *self) +ofono_check_name_owner (NMModemManager *self, gboolean first_invocation) { + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); gs_free char *name_owner = NULL; - name_owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (self->_priv.ofono_proxy)); + name_owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (priv->ofono.proxy)); if (name_owner) { - nm_log_info (LOGD_MB, "oFono is now available"); + _LOGI ("oFono is %savailable", first_invocation ? "" : "now "); + + nm_clear_g_cancellable (&priv->ofono.cancellable); + priv->ofono.cancellable = g_cancellable_new (); - g_dbus_proxy_call (self->_priv.ofono_proxy, + g_dbus_proxy_call (priv->ofono.proxy, "GetModems", NULL, G_DBUS_CALL_FLAGS_NONE, -1, - NULL, - (GAsyncReadyCallback) ofono_enumerate_devices_done, - g_object_ref (self)); + priv->ofono.cancellable, + ofono_enumerate_devices_done, + self); } else { GHashTableIter iter; NMModem *modem; - nm_log_info (LOGD_MB, "oFono disappeared from bus"); + _LOGI ("oFono is %savailable", first_invocation ? "not " : "no longer "); /* Remove any oFono modems that might be left around */ - g_hash_table_iter_init (&iter, self->_priv.modems); + g_hash_table_iter_init (&iter, priv->modems); while (g_hash_table_iter_next (&iter, NULL, (gpointer) &modem)) { if (NM_IS_MODEM_OFONO (modem)) { nm_modem_emit_removed (modem); @@ -344,219 +716,121 @@ ofono_name_owner_changed (GDBusProxy *ofono_proxy, GParamSpec *pspec, NMModemManager *self) { - ofono_check_name_owner (self); + ofono_check_name_owner (self, FALSE); } static void -ofono_proxy_new_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +ofono_proxy_new_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) { - gs_unref_object NMModemManager *self = NM_MODEM_MANAGER (user_data); + NMModemManager *self; + NMModemManagerPrivate *priv; gs_free_error GError *error = NULL; + GDBusProxy *proxy; - self->_priv.ofono_proxy = g_dbus_proxy_new_finish (res, &error); - if (error) { - nm_log_warn (LOGD_MB, "error getting oFono bus proxy: %s", error->message); + proxy = g_dbus_proxy_new_finish (res, &error); + if ( !proxy + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = NM_MODEM_MANAGER (user_data); + priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + + g_clear_object (&priv->ofono.cancellable); + + if (!proxy) { + _LOGW ("error getting oFono bus proxy: %s", error->message); return; } - g_signal_connect (self->_priv.ofono_proxy, + priv->ofono.proxy = proxy; + + g_signal_connect (priv->ofono.proxy, "notify::g-name-owner", G_CALLBACK (ofono_name_owner_changed), self); - g_signal_connect (self->_priv.ofono_proxy, + g_signal_connect (priv->ofono.proxy, "g-signal", G_CALLBACK (ofono_signal_cb), self); - ofono_check_name_owner (self); + ofono_check_name_owner (self, TRUE); } static void -ensure_ofono_client (NMModemManager *self) +ofono_init_proxy (NMModemManager *self) { - g_assert (self->_priv.dbus_connection); - g_dbus_proxy_new (self->_priv.dbus_connection, + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + + nm_assert (priv->dbus_connection); + nm_assert (!priv->ofono.cancellable); + + priv->ofono.cancellable = g_cancellable_new (); + + g_dbus_proxy_new (priv->dbus_connection, G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, NULL, OFONO_DBUS_SERVICE, OFONO_DBUS_PATH, OFONO_DBUS_INTERFACE, - NULL, - (GAsyncReadyCallback) ofono_proxy_new_cb, - g_object_ref (self)); + priv->ofono.cancellable, + ofono_proxy_new_cb, + self); } #endif -static void -modem_manager_poke_cb (GDBusConnection *connection, - GAsyncResult *res, - NMModemManager *self) -{ - GError *error = NULL; - GVariant *result; - - result = g_dbus_connection_call_finish (connection, res, &error); - if (error) { - nm_log_warn (LOGD_MB, "error poking ModemManager: %s", - error ? error->message : ""); - - /* Don't reschedule poke is MM service doesn't exist. */ - if (!g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN) - && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND)) { - - /* Setup timeout to relaunch */ - schedule_modem_manager_relaunch (self, MODEM_POKE_INTERVAL); - } - - g_error_free (error); - } else - g_variant_unref (result); - - /* Balance refcount */ - g_object_unref (self); -} - -static void -modem_manager_poke (NMModemManager *self) -{ - /* If there is no current owner right away, ensure we poke to get one */ - g_dbus_connection_call (self->_priv.dbus_connection, - "org.freedesktop.ModemManager1", - "/org/freedesktop/ModemManager1", - DBUS_INTERFACE_PEER, - "Ping", - NULL, /* inputs */ - NULL, /* outputs */ - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, /* cancellable */ - (GAsyncReadyCallback)modem_manager_poke_cb, /* callback */ - g_object_ref (self)); /* user_data */ -} +/*****************************************************************************/ static void -modem_manager_check_name_owner (NMModemManager *self) +bus_get_ready (GObject *source, + GAsyncResult *res, + gpointer user_data) { - gs_free gchar *name_owner = NULL; + NMModemManager *self; + NMModemManagerPrivate *priv; + gs_free_error GError *error = NULL; + GDBusConnection *connection; - name_owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (self->_priv.modem_manager)); - if (name_owner) { - /* Available! */ - modem_manager_available (self); + connection = g_bus_get_finish (res, &error); + if ( !connection + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; - } - - /* If the lifecycle is not managed by systemd, poke */ - if (!sd_booted ()) - modem_manager_poke (self); -} - -static void -manager_new_ready (GObject *source, - GAsyncResult *res, - NMModemManager *self) -{ - /* Note we always get an extra reference to self here */ - GError *error = NULL; + self = NM_MODEM_MANAGER (user_data); + priv = NM_MODEM_MANAGER_GET_PRIVATE (self); - g_return_if_fail (!self->_priv.modem_manager); - - self->_priv.modem_manager = mm_manager_new_finish (res, &error); - if (!self->_priv.modem_manager) { - /* We're not really supposed to get any error here. If we do get one, - * though, just re-schedule the MMManager creation after some time. - * During this period, name-owner changes won't be followed. */ - nm_log_warn (LOGD_MB, "error creating ModemManager client: %s", error->message); - g_error_free (error); - /* Setup timeout to relaunch */ - schedule_modem_manager_relaunch (self, MODEM_POKE_INTERVAL); - } else { - /* Setup signals in the GDBusObjectManagerClient */ - self->_priv.mm_name_owner_changed_id = - g_signal_connect (self->_priv.modem_manager, - "notify::name-owner", - G_CALLBACK (modem_manager_name_owner_changed), - self); - self->_priv.mm_object_added_id = - g_signal_connect (self->_priv.modem_manager, - "object-added", - G_CALLBACK (modem_object_added), - self); - self->_priv.mm_object_removed_id = - g_signal_connect (self->_priv.modem_manager, - "object-removed", - G_CALLBACK (modem_object_removed), - self); - - modem_manager_check_name_owner (self); - } - - /* Balance refcount */ - g_object_unref (self); -} - -static void -ensure_modem_manager (NMModemManager *self) -{ - g_assert (self->_priv.dbus_connection); - - /* Create the GDBusObjectManagerClient. We do not request to autostart, as - * we don't really want the MMManager creation to fail. We can always poke - * later on if we want to request the autostart */ - if (!self->_priv.modem_manager) { - mm_manager_new (self->_priv.dbus_connection, - G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START, - NULL, - (GAsyncReadyCallback)manager_new_ready, - g_object_ref (self)); + if (!connection) { + _LOGW ("error getting bus connection: %s", error->message); return; } - /* If already available, recheck name owner! */ - modem_manager_check_name_owner (self); -} + priv->dbus_connection = connection; -static gboolean -mm_launch_cb (NMModemManager *self) -{ - self->_priv.mm_launch_id = 0; - ensure_modem_manager (self); - return G_SOURCE_REMOVE; + modm_ensure_manager (self); +#if WITH_OFONO + ofono_init_proxy (self); +#endif } -static void -schedule_modem_manager_relaunch (NMModemManager *self, - guint n_seconds) -{ - /* No need to pass an extra reference to self; timeout/idle will be - * cancelled if the object gets disposed. */ - if (n_seconds) - self->_priv.mm_launch_id = g_timeout_add_seconds (n_seconds, (GSourceFunc)mm_launch_cb, self); - else - self->_priv.mm_launch_id = g_idle_add ((GSourceFunc)mm_launch_cb, self); -} +/*****************************************************************************/ static void -bus_get_ready (GObject *source, - GAsyncResult *res, - gpointer user_data) +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) { - gs_unref_object NMModemManager *self = NM_MODEM_MANAGER (user_data); - gs_free_error GError *error = NULL; - - self->_priv.dbus_connection = g_bus_get_finish (res, &error); - if (!self->_priv.dbus_connection) { - nm_log_warn (LOGD_MB, "error getting bus connection: %s", error->message); - return; + NMModemManager *self = NM_MODEM_MANAGER (object); + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + + switch (prop_id) { + case PROP_NAME_OWNER: + g_value_set_string (value, priv->modm.proxy_name_owner); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; } - - /* Got the bus, ensure clients */ - ensure_modem_manager (self); -#if WITH_OFONO - ensure_ofono_client (self); -#endif } /*****************************************************************************/ @@ -564,36 +838,50 @@ bus_get_ready (GObject *source, static void nm_modem_manager_init (NMModemManager *self) { - self->_priv.modems = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); + + priv->modems = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + + priv->main_cancellable = g_cancellable_new (); g_bus_get (G_BUS_TYPE_SYSTEM, - NULL, - (GAsyncReadyCallback)bus_get_ready, - g_object_ref (self)); + priv->main_cancellable, + bus_get_ready, + self); } static void dispose (GObject *object) { NMModemManager *self = NM_MODEM_MANAGER (object); + NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); - nm_clear_g_source (&self->_priv.mm_launch_id); + nm_clear_g_cancellable (&priv->main_cancellable); + nm_clear_g_cancellable (&priv->modm.poke_cancellable); - clear_modem_manager (self); + nm_clear_g_source (&priv->modm.relaunch_id); + + nm_clear_g_cancellable (&priv->modm.proxy_cancellable); + g_clear_object (&priv->modm.proxy); + nm_clear_g_free (&priv->modm.proxy_name_owner); + + modm_clear_manager (self); #if WITH_OFONO - if (self->_priv.ofono_proxy) { - g_signal_handlers_disconnect_by_func (self->_priv.ofono_proxy, ofono_name_owner_changed, self); - g_signal_handlers_disconnect_by_func (self->_priv.ofono_proxy, ofono_signal_cb, self); - g_clear_object (&self->_priv.ofono_proxy); + if (priv->ofono.proxy) { + g_signal_handlers_disconnect_by_func (priv->ofono.proxy, ofono_name_owner_changed, self); + g_signal_handlers_disconnect_by_func (priv->ofono.proxy, ofono_signal_cb, self); + g_clear_object (&priv->ofono.proxy); } + nm_clear_g_cancellable (&priv->ofono.cancellable); #endif - g_clear_object (&self->_priv.dbus_connection); + g_clear_object (&priv->dbus_connection); - if (self->_priv.modems) { - g_hash_table_foreach_remove (self->_priv.modems, remove_one_modem, object); - g_hash_table_destroy (self->_priv.modems); + if (priv->modems) { + g_hash_table_foreach_remove (priv->modems, remove_one_modem, object); + g_hash_table_destroy (priv->modems); + priv->modems = NULL; } G_OBJECT_CLASS (nm_modem_manager_parent_class)->dispose (object); @@ -605,6 +893,15 @@ nm_modem_manager_class_init (NMModemManagerClass *klass) GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = dispose; + object_class->get_property = get_property; + + obj_properties[PROP_NAME_OWNER] = + g_param_spec_string (NM_MODEM_MANAGER_NAME_OWNER, "", "", + NULL, + G_PARAM_READABLE + | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); signals[MODEM_ADDED] = g_signal_new (NM_MODEM_MANAGER_MODEM_ADDED, diff --git a/src/devices/wwan/nm-modem-manager.h b/src/devices/wwan/nm-modem-manager.h index 65594dfa56..5f913083a9 100644 --- a/src/devices/wwan/nm-modem-manager.h +++ b/src/devices/wwan/nm-modem-manager.h @@ -34,9 +34,22 @@ #define NM_MODEM_MANAGER_MODEM_ADDED "modem-added" +#define NM_MODEM_MANAGER_NAME_OWNER "name-owner" + +#define NM_MODEM_MANAGER_MM_DBUS_SERVICE "org.freedesktop.ModemManager1" +#define NM_MODEM_MANAGER_MM_DBUS_PATH "/org/freedesktop/ModemManager1" +#define NM_MODEM_MANAGER_MM_DBUS_INTERFACE "org.freedesktop.ModemManager1" + typedef struct _NMModemManager NMModemManager; typedef struct _NMModemManagerClass NMModemManagerClass; GType nm_modem_manager_get_type (void); +NMModemManager *nm_modem_manager_get (void); + +void nm_modem_manager_name_owner_ref (NMModemManager *self); +void nm_modem_manager_name_owner_unref (NMModemManager *self); + +const char *nm_modem_manager_name_owner_get (NMModemManager *self); + #endif /* __NETWORKMANAGER_MODEM_MANAGER_H__ */ diff --git a/src/devices/wwan/nm-modem-ofono.c b/src/devices/wwan/nm-modem-ofono.c index 52b335c7bc..d1ad016a91 100644 --- a/src/devices/wwan/nm-modem-ofono.c +++ b/src/devices/wwan/nm-modem-ofono.c @@ -46,6 +46,11 @@ typedef struct { GDBusProxy *context_proxy; GDBusProxy *sim_proxy; + GCancellable *modem_proxy_cancellable; + GCancellable *connman_proxy_cancellable; + GCancellable *context_proxy_cancellable; + GCancellable *sim_proxy_cancellable; + GError *property_error; char *context_path; @@ -165,29 +170,17 @@ typedef struct { static void disconnect_context_complete (DisconnectContext *ctx) { - g_simple_async_result_complete_in_idle (ctx->result); if (ctx->cancellable) g_object_unref (ctx->cancellable); - g_object_unref (ctx->result); + if (ctx->result) { + g_simple_async_result_complete_in_idle (ctx->result); + g_object_unref (ctx->result); + } g_object_unref (ctx->self); g_slice_free (DisconnectContext, ctx); } static gboolean -disconnect_context_complete_if_cancelled (DisconnectContext *ctx) -{ - GError *error = NULL; - - if (g_cancellable_set_error_if_cancelled (ctx->cancellable, &error)) { - g_simple_async_result_take_error (ctx->result, error); - disconnect_context_complete (ctx); - return TRUE; - } - - return FALSE; -} - -static gboolean disconnect_finish (NMModem *self, GAsyncResult *result, GError **error) @@ -196,25 +189,25 @@ disconnect_finish (NMModem *self, } static void -disconnect_done (GDBusProxy *proxy, - GAsyncResult *result, - gpointer user_data) +disconnect_done (GObject *source, + GAsyncResult *result, + gpointer user_data) { DisconnectContext *ctx = (DisconnectContext*) user_data; NMModemOfono *self = ctx->self; - GError *error = NULL; + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *v = NULL; - g_dbus_proxy_call_finish (proxy, result, &error); + v = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error); if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - _LOGD ("disconnect cancelled"); + if (ctx->result) + g_simple_async_result_take_error (ctx->result, g_steal_pointer (&error)); + disconnect_context_complete (ctx); return; } - if (error) { - if (ctx->warn) - _LOGW ("failed to disconnect modem: %s", error->message); - g_clear_error (&error); - } + if (error && ctx->warn) + _LOGW ("failed to disconnect modem: %s", error->message); _LOGD ("modem disconnected"); @@ -233,18 +226,15 @@ disconnect (NMModem *modem, NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE (self); DisconnectContext *ctx; NMModemState state = nm_modem_get_state (NM_MODEM (self)); + GError *error = NULL; _LOGD ("warn: %s modem_state: %s", warn ? "TRUE" : "FALSE", nm_modem_state_to_string (state)); - if (state != NM_MODEM_STATE_CONNECTED) - return; - - ctx = g_slice_new (DisconnectContext); + ctx = g_slice_new0 (DisconnectContext); ctx->self = g_object_ref (self); ctx->warn = warn; - if (callback) { ctx->result = g_simple_async_result_new (G_OBJECT (self), callback, @@ -252,9 +242,28 @@ disconnect (NMModem *modem, disconnect); } - ctx->cancellable = cancellable ? g_object_ref (cancellable) : NULL; - if (disconnect_context_complete_if_cancelled (ctx)) + if (state != NM_MODEM_STATE_CONNECTED) { + if (ctx->result) { + g_set_error_literal (&error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + ("modem is currently not connected")); + g_simple_async_result_take_error (ctx->result, error); + } + disconnect_context_complete (ctx); return; + } + + if (g_cancellable_set_error_if_cancelled (cancellable, &error)) { + if (ctx->result) + g_simple_async_result_take_error (ctx->result, error); + else + g_clear_error (&error); + disconnect_context_complete (ctx); + return; + } + + ctx->cancellable = nm_g_object_ref (cancellable); nm_modem_set_state (NM_MODEM (self), NM_MODEM_STATE_DISCONNECTING, @@ -267,8 +276,8 @@ disconnect (NMModem *modem, g_variant_new ("b", warn)), G_DBUS_CALL_FLAGS_NONE, 20000, - NULL, - (GAsyncReadyCallback) disconnect_done, + ctx->cancellable, + disconnect_done, ctx); } @@ -375,22 +384,35 @@ sim_property_changed (GDBusProxy *proxy, } static void -sim_get_properties_done (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +sim_get_properties_done (GObject *source, + GAsyncResult *result, + gpointer user_data) { - gs_unref_object NMModemOfono *self = NM_MODEM_OFONO (user_data); - GError *error = NULL; - GVariant *v_properties, *v_dict, *v; + NMModemOfono *self; + NMModemOfonoPrivate *priv; + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *v_properties = NULL; + gs_unref_variant GVariant *v_dict = NULL; + GVariant *v; GVariantIter i; const char *property; - v_properties = _nm_dbus_proxy_call_finish (proxy, + v_properties = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, G_VARIANT_TYPE ("(a{sv})"), &error); + if ( !v_properties + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = NM_MODEM_OFONO (user_data); + priv = NM_MODEM_OFONO_GET_PRIVATE (self); + + g_clear_object (&priv->sim_proxy_cancellable); + if (!v_properties) { g_dbus_error_strip_remote_error (error); _LOGW ("error getting sim properties: %s", error->message); - g_error_free (error); return; } @@ -418,9 +440,49 @@ sim_get_properties_done (GDBusProxy *proxy, GAsyncResult *result, gpointer user_ handle_sim_property (NULL, property, v, self); g_variant_unref (v); } +} + +static void +_sim_proxy_new_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + NMModemOfono *self; + NMModemOfonoPrivate *priv; + gs_free_error GError *error = NULL; + GDBusProxy *proxy; + + proxy = g_dbus_proxy_new_for_bus_finish (result, &error); + if ( !proxy + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = user_data; + priv = NM_MODEM_OFONO_GET_PRIVATE (self); + + if (!proxy) { + _LOGW ("failed to create SimManager proxy: %s", error->message); + g_clear_object (&priv->sim_proxy_cancellable); + return; + } - g_variant_unref (v_dict); - g_variant_unref (v_properties); + priv->sim_proxy = proxy; + + /* Watch for custom ofono PropertyChanged signals */ + _nm_dbus_signal_connect (priv->sim_proxy, + "PropertyChanged", + G_VARIANT_TYPE ("(sv)"), + G_CALLBACK (sim_property_changed), + self); + + g_dbus_proxy_call (priv->sim_proxy, + "GetProperties", + NULL, + G_DBUS_CALL_FLAGS_NONE, + 20000, + priv->sim_proxy_cancellable, + sim_get_properties_done, + self); } static void @@ -430,47 +492,30 @@ handle_sim_iface (NMModemOfono *self, gboolean found) _LOGD ("SimManager interface %sfound", found ? "" : "not "); - if (!found && priv->sim_proxy) { + if (!found && (priv->sim_proxy || priv->sim_proxy_cancellable)) { _LOGI ("SimManager interface disappeared"); - g_signal_handlers_disconnect_by_data (priv->sim_proxy, NM_MODEM_OFONO (self)); - g_clear_object (&priv->sim_proxy); + nm_clear_g_cancellable (&priv->sim_proxy_cancellable); + if (priv->sim_proxy) { + g_signal_handlers_disconnect_by_data (priv->sim_proxy, self); + g_clear_object (&priv->sim_proxy); + } g_clear_pointer (&priv->imsi, g_free); update_modem_state (self); - } else if (found && !priv->sim_proxy) { - GError *error = NULL; - + } else if (found && (!priv->sim_proxy && !priv->sim_proxy_cancellable)) { _LOGI ("found new SimManager interface"); - priv->sim_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES - | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, - NULL, /* GDBusInterfaceInfo */ - OFONO_DBUS_SERVICE, - nm_modem_get_path (NM_MODEM (self)), - OFONO_DBUS_INTERFACE_SIM_MANAGER, - NULL, /* GCancellable */ - &error); - if (priv->sim_proxy == NULL) { - _LOGW ("failed to create SimManager proxy: %s", error->message); - g_error_free (error); - return; - } - - /* Watch for custom ofono PropertyChanged signals */ - _nm_dbus_signal_connect (priv->sim_proxy, - "PropertyChanged", - G_VARIANT_TYPE ("(sv)"), - G_CALLBACK (sim_property_changed), - self); - - g_dbus_proxy_call (priv->sim_proxy, - "GetProperties", - NULL, - G_DBUS_CALL_FLAGS_NONE, - 20000, - NULL, - (GAsyncReadyCallback) sim_get_properties_done, - g_object_ref (self)); + priv->sim_proxy_cancellable = g_cancellable_new (); + + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES + | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + NULL, /* GDBusInterfaceInfo */ + OFONO_DBUS_SERVICE, + nm_modem_get_path (NM_MODEM (self)), + OFONO_DBUS_INTERFACE_SIM_MANAGER, + priv->sim_proxy_cancellable, /* GCancellable */ + _sim_proxy_new_cb, + self); } } @@ -514,22 +559,35 @@ connman_property_changed (GDBusProxy *proxy, } static void -connman_get_properties_done (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +connman_get_properties_done (GObject *source, + GAsyncResult *result, + gpointer user_data) { - gs_unref_object NMModemOfono *self = NM_MODEM_OFONO (user_data); - GError *error = NULL; - GVariant *v_properties, *v_dict, *v; + NMModemOfono *self; + NMModemOfonoPrivate *priv; + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *v_properties = NULL; + gs_unref_variant GVariant *v_dict = NULL; + GVariant *v; GVariantIter i; const char *property; - v_properties = _nm_dbus_proxy_call_finish (proxy, - result, - G_VARIANT_TYPE ("(a{sv})"), - &error); + v_properties = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (source), + result, + G_VARIANT_TYPE ("(a{sv})"), + &error); + if ( !v_properties + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = NM_MODEM_OFONO (user_data); + priv = NM_MODEM_OFONO_GET_PRIVATE (self); + + g_clear_object (&priv->connman_proxy_cancellable); + if (!v_properties) { g_dbus_error_strip_remote_error (error); _LOGW ("error getting connman properties: %s", error->message); - g_error_free (error); return; } @@ -549,9 +607,48 @@ connman_get_properties_done (GDBusProxy *proxy, GAsyncResult *result, gpointer u handle_connman_property (NULL, property, v, self); g_variant_unref (v); } +} - g_variant_unref (v_dict); - g_variant_unref (v_properties); +static void +_connman_proxy_new_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + NMModemOfono *self; + NMModemOfonoPrivate *priv; + gs_free_error GError *error = NULL; + GDBusProxy *proxy; + + proxy = g_dbus_proxy_new_for_bus_finish (result, &error); + if ( !proxy + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = user_data; + priv = NM_MODEM_OFONO_GET_PRIVATE (self); + + if (!proxy) { + _LOGW ("failed to create ConnectionManager proxy: %s", error->message); + g_clear_object (&priv->connman_proxy_cancellable); + return; + } + + priv->connman_proxy = proxy; + + _nm_dbus_signal_connect (priv->connman_proxy, + "PropertyChanged", + G_VARIANT_TYPE ("(sv)"), + G_CALLBACK (connman_property_changed), + self); + + g_dbus_proxy_call (priv->connman_proxy, + "GetProperties", + NULL, + G_DBUS_CALL_FLAGS_NONE, + 20000, + priv->connman_proxy_cancellable, + connman_get_properties_done, + self); } static void @@ -561,11 +658,13 @@ handle_connman_iface (NMModemOfono *self, gboolean found) _LOGD ("ConnectionManager interface %sfound", found ? "" : "not "); - if (!found && priv->connman_proxy) { + if (!found && (priv->connman_proxy || priv->connman_proxy_cancellable)) { _LOGI ("ConnectionManager interface disappeared"); - - g_signal_handlers_disconnect_by_data (priv->connman_proxy, NM_MODEM_OFONO (self)); - g_clear_object (&priv->connman_proxy); + nm_clear_g_cancellable (&priv->connman_proxy_cancellable); + if (priv->connman_proxy) { + g_signal_handlers_disconnect_by_data (priv->connman_proxy, self); + g_clear_object (&priv->connman_proxy); + } /* The connection manager proxy disappeared, we should * consider the modem disabled. @@ -573,41 +672,21 @@ handle_connman_iface (NMModemOfono *self, gboolean found) priv->gprs_attached = FALSE; update_modem_state (self); - } else if (found && !priv->connman_proxy) { - GError *error = NULL; - + } else if (found && (!priv->connman_proxy && !priv->connman_proxy_cancellable)) { _LOGI ("found new ConnectionManager interface"); - priv->connman_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES - | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, - NULL, /* GDBusInterfaceInfo */ - OFONO_DBUS_SERVICE, - nm_modem_get_path (NM_MODEM (self)), - OFONO_DBUS_INTERFACE_CONNECTION_MANAGER, - NULL, /* GCancellable */ - &error); - if (priv->connman_proxy == NULL) { - _LOGW ("failed to create ConnectionManager proxy: %s", error->message); - g_error_free (error); - return; - } - - /* Watch for custom ofono PropertyChanged signals */ - _nm_dbus_signal_connect (priv->connman_proxy, - "PropertyChanged", - G_VARIANT_TYPE ("(sv)"), - G_CALLBACK (connman_property_changed), - self); - - g_dbus_proxy_call (priv->connman_proxy, - "GetProperties", - NULL, - G_DBUS_CALL_FLAGS_NONE, - 20000, - NULL, - (GAsyncReadyCallback) connman_get_properties_done, - g_object_ref (self)); + priv->connman_proxy_cancellable = g_cancellable_new (); + + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES + | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + NULL, /* GDBusInterfaceInfo */ + OFONO_DBUS_SERVICE, + nm_modem_get_path (NM_MODEM (self)), + OFONO_DBUS_INTERFACE_CONNECTION_MANAGER, + priv->connman_proxy_cancellable, + _connman_proxy_new_cb, + NULL); } } @@ -667,22 +746,35 @@ modem_property_changed (GDBusProxy *proxy, } static void -modem_get_properties_done (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +modem_get_properties_done (GObject *source, + GAsyncResult *result, + gpointer user_data) { - gs_unref_object NMModemOfono *self = NM_MODEM_OFONO (user_data); - GError *error = NULL; - GVariant *v_properties, *v_dict, *v; + NMModemOfono *self; + NMModemOfonoPrivate *priv; + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *v_properties = NULL; + gs_unref_variant GVariant *v_dict = NULL; + GVariant *v; GVariantIter i; const char *property; - v_properties = _nm_dbus_proxy_call_finish (proxy, + v_properties = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, G_VARIANT_TYPE ("(a{sv})"), &error); + if ( !v_properties + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = NM_MODEM_OFONO (user_data); + priv = NM_MODEM_OFONO_GET_PRIVATE (self); + + g_clear_object (&priv->modem_proxy_cancellable); + if (!v_properties) { g_dbus_error_strip_remote_error (error); _LOGW ("error getting modem properties: %s", error->message); - g_error_free (error); return; } @@ -706,21 +798,29 @@ modem_get_properties_done (GDBusProxy *proxy, GAsyncResult *result, gpointer use handle_modem_property (NULL, property, v, self); g_variant_unref (v); } - - g_variant_unref (v_dict); - g_variant_unref (v_properties); } static void -stage1_prepare_done (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +stage1_prepare_done (GObject *source, + GAsyncResult *result, + gpointer user_data) { - gs_unref_object NMModemOfono *self = NM_MODEM_OFONO (user_data); - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE (self); - GError *error = NULL; + NMModemOfono *self; + NMModemOfonoPrivate *priv; + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *v = NULL; + + v = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = NM_MODEM_OFONO (user_data); + priv = NM_MODEM_OFONO_GET_PRIVATE (self); + + g_clear_object (&priv->context_proxy_cancellable); g_clear_pointer (&priv->connect_properties, g_hash_table_destroy); - g_dbus_proxy_call_finish (proxy, result, &error); if (error) { _LOGW ("connection failed: %s", error->message); @@ -732,8 +832,6 @@ stage1_prepare_done (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data * leading to the connection being disabled, and a 5m * timeout... */ - - g_clear_error (&error); } } @@ -946,21 +1044,33 @@ static_stage3_ip4_config_start (NMModem *modem, } static void -context_proxy_new_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +context_proxy_new_cb (GObject *source, GAsyncResult *result, gpointer user_data) { - gs_unref_object NMModemOfono *self = NM_MODEM_OFONO (user_data); - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE (self); - GError *error = NULL; + NMModemOfono *self; + NMModemOfonoPrivate *priv; + gs_free_error GError *error = NULL; + GDBusProxy *proxy; - priv->context_proxy = g_dbus_proxy_new_for_bus_finish (result, &error); - if (error) { + proxy = g_dbus_proxy_new_for_bus_finish (result, &error); + if ( !proxy + || g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = NM_MODEM_OFONO (user_data); + priv = NM_MODEM_OFONO_GET_PRIVATE (self); + + if (!proxy) { _LOGE ("failed to create ofono ConnectionContext DBus proxy: %s", error->message); + g_clear_object (&priv->context_proxy_cancellable); nm_modem_emit_prepare_result (NM_MODEM (self), FALSE, NM_DEVICE_STATE_REASON_MODEM_BUSY); return; } + priv->context_proxy = proxy; + if (!priv->gprs_attached) { + g_clear_object (&priv->context_proxy_cancellable); nm_modem_emit_prepare_result (NM_MODEM (self), FALSE, NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER); return; @@ -972,7 +1082,6 @@ context_proxy_new_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_dat */ g_clear_object (&priv->ip4_config); - /* Watch for custom ofono PropertyChanged signals */ _nm_dbus_signal_connect (priv->context_proxy, "PropertyChanged", G_VARIANT_TYPE ("(sv)"), @@ -986,9 +1095,9 @@ context_proxy_new_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_dat g_variant_new ("b", TRUE)), G_DBUS_CALL_FLAGS_NONE, 20000, - NULL, - (GAsyncReadyCallback) stage1_prepare_done, - g_object_ref (self)); + priv->context_proxy_cancellable, + stage1_prepare_done, + self); } static void @@ -998,16 +1107,20 @@ do_context_activate (NMModemOfono *self) g_return_if_fail (NM_IS_MODEM_OFONO (self)); + nm_clear_g_cancellable (&priv->context_proxy_cancellable); g_clear_object (&priv->context_proxy); + + priv->context_proxy_cancellable = g_cancellable_new (); + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, NULL, OFONO_DBUS_SERVICE, priv->context_path, OFONO_DBUS_INTERFACE_CONNECTION_CONTEXT, - NULL, - (GAsyncReadyCallback) context_proxy_new_cb, - g_object_ref (self)); + priv->context_proxy_cancellable, + context_proxy_new_cb, + self); } static GHashTable * @@ -1081,19 +1194,29 @@ act_stage1_prepare (NMModem *modem, } static void -modem_proxy_new_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +modem_proxy_new_cb (GObject *source, GAsyncResult *result, gpointer user_data) { - gs_unref_object NMModemOfono *self = NM_MODEM_OFONO (user_data); - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE (self); - GError *error = NULL; + NMModemOfono *self; + NMModemOfonoPrivate *priv; + gs_free_error GError *error = NULL; + GDBusProxy *proxy; - priv->modem_proxy = g_dbus_proxy_new_for_bus_finish (result, &error); - if (error) { + proxy = g_dbus_proxy_new_for_bus_finish (result, &error); + if ( !proxy + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = NM_MODEM_OFONO (user_data); + priv = NM_MODEM_OFONO_GET_PRIVATE (self); + + if (!proxy) { _LOGE ("failed to create ofono modem DBus proxy: %s", error->message); + g_clear_object (&priv->modem_proxy_cancellable); return; } - /* Watch for custom ofono PropertyChanged signals */ + priv->modem_proxy = proxy; + _nm_dbus_signal_connect (priv->modem_proxy, "PropertyChanged", G_VARIANT_TYPE ("(sv)"), @@ -1105,9 +1228,9 @@ modem_proxy_new_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) NULL, G_DBUS_CALL_FLAGS_NONE, 20000, - NULL, - (GAsyncReadyCallback) modem_get_properties_done, - g_object_ref (self)); + priv->modem_proxy_cancellable, + modem_get_properties_done, + self); } /*****************************************************************************/ @@ -1121,6 +1244,9 @@ static void constructed (GObject *object) { NMModemOfono *self = NM_MODEM_OFONO (object); + NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE (self); + + priv->modem_proxy_cancellable = g_cancellable_new (); g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, @@ -1128,9 +1254,11 @@ constructed (GObject *object) OFONO_DBUS_SERVICE, nm_modem_get_path (NM_MODEM (self)), OFONO_DBUS_INTERFACE_MODEM, - NULL, - (GAsyncReadyCallback) modem_proxy_new_cb, - g_object_ref (self)); + priv->modem_proxy_cancellable, + modem_proxy_new_cb, + self); + + G_OBJECT_CLASS (nm_modem_ofono_parent_class)->constructed (object); } NMModem * @@ -1163,6 +1291,11 @@ dispose (GObject *object) NMModemOfono *self = NM_MODEM_OFONO (object); NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE (self); + nm_clear_g_cancellable (&priv->modem_proxy_cancellable); + nm_clear_g_cancellable (&priv->connman_proxy_cancellable); + nm_clear_g_cancellable (&priv->context_proxy_cancellable); + nm_clear_g_cancellable (&priv->sim_proxy_cancellable); + if (priv->connect_properties) { g_hash_table_destroy (priv->connect_properties); priv->connect_properties = NULL; @@ -1171,15 +1304,22 @@ dispose (GObject *object) g_clear_object (&priv->ip4_config); if (priv->modem_proxy) { - g_signal_handlers_disconnect_by_data (priv->modem_proxy, NM_MODEM_OFONO (self)); + g_signal_handlers_disconnect_by_data (priv->modem_proxy, self); g_clear_object (&priv->modem_proxy); } - g_clear_object (&priv->connman_proxy); - g_clear_object (&priv->context_proxy); + if (priv->connman_proxy) { + g_signal_handlers_disconnect_by_data (priv->connman_proxy, self); + g_clear_object (&priv->connman_proxy); + } + + if (priv->context_proxy) { + g_signal_handlers_disconnect_by_data (priv->context_proxy, self); + g_clear_object (&priv->context_proxy); + } if (priv->sim_proxy) { - g_signal_handlers_disconnect_by_data (priv->sim_proxy, NM_MODEM_OFONO (self)); + g_signal_handlers_disconnect_by_data (priv->sim_proxy, self); g_clear_object (&priv->sim_proxy); } diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c index 6494b84995..c6885cef7d 100644 --- a/src/devices/wwan/nm-modem.c +++ b/src/devices/wwan/nm-modem.c @@ -1451,6 +1451,7 @@ set_property (GObject *object, guint prop_id, case PROP_PATH: /* construct-only */ priv->path = g_value_dup_string (value); + g_return_if_fail (priv->path); break; case PROP_DRIVER: /* construct-only */ @@ -1512,37 +1513,16 @@ nm_modem_init (NMModem *self) self->_priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_MODEM, NMModemPrivate); } -static GObject* -constructor (GType type, - guint n_construct_params, - GObjectConstructParam *construct_params) +static void +constructed (GObject *object) { - GObject *object; NMModemPrivate *priv; - object = G_OBJECT_CLASS (nm_modem_parent_class)->constructor (type, - n_construct_params, - construct_params); - if (!object) - return NULL; - - priv = NM_MODEM_GET_PRIVATE ((NMModem *) object); - - if (!priv->data_port && !priv->control_port) { - nm_log_err (LOGD_PLATFORM, "neither modem command nor data interface provided"); - goto err; - } - - if (!priv->path) { - nm_log_err (LOGD_PLATFORM, "D-Bus path not provided"); - goto err; - } + G_OBJECT_CLASS (nm_modem_parent_class)->constructed (object); - return object; + priv = NM_MODEM_GET_PRIVATE (NM_MODEM (object)); -err: - g_object_unref (object); - return NULL; + g_return_if_fail (priv->data_port || priv->control_port); } /*****************************************************************************/ @@ -1552,10 +1532,7 @@ dispose (GObject *object) { NMModemPrivate *priv = NM_MODEM_GET_PRIVATE ((NMModem *) object); - if (priv->act_request) { - g_object_unref (priv->act_request); - priv->act_request = NULL; - } + g_clear_object (&priv->act_request); G_OBJECT_CLASS (nm_modem_parent_class)->dispose (object); } @@ -1584,7 +1561,7 @@ nm_modem_class_init (NMModemClass *klass) g_type_class_add_private (object_class, sizeof (NMModemPrivate)); - object_class->constructor = constructor; + object_class->constructed = constructed; object_class->set_property = set_property; object_class->get_property = get_property; object_class->dispose = dispose; diff --git a/src/devices/wwan/nm-modem.h b/src/devices/wwan/nm-modem.h index a50727a96a..c6efda951d 100644 --- a/src/devices/wwan/nm-modem.h +++ b/src/devices/wwan/nm-modem.h @@ -105,10 +105,12 @@ typedef enum { /*< underscore_name=nm_modem_state >*/ struct _NMModemPrivate; -typedef struct { +struct _NMModem { GObject parent; struct _NMModemPrivate *_priv; -} NMModem; +}; + +typedef struct _NMModem NMModem; typedef struct { GObjectClass parent; diff --git a/src/devices/wwan/nm-wwan-factory.c b/src/devices/wwan/nm-wwan-factory.c index fa4c8dbbf6..663102de4d 100644 --- a/src/devices/wwan/nm-wwan-factory.c +++ b/src/devices/wwan/nm-wwan-factory.c @@ -127,8 +127,8 @@ start (NMDeviceFactory *factory) NMWwanFactory *self = NM_WWAN_FACTORY (factory); NMWwanFactoryPrivate *priv = NM_WWAN_FACTORY_GET_PRIVATE (self); - priv->mm = g_object_new (NM_TYPE_MODEM_MANAGER, NULL); - g_assert (priv->mm); + priv->mm = g_object_ref (nm_modem_manager_get ()); + g_signal_connect (priv->mm, NM_MODEM_MANAGER_MODEM_ADDED, G_CALLBACK (modem_added_cb), diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c index 1f6c2eede4..cc9be29e7f 100644 --- a/src/dns/nm-dns-manager.c +++ b/src/dns/nm-dns-manager.c @@ -1435,6 +1435,7 @@ nm_dns_manager_set_initial_hostname (NMDnsManager *self, { NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self); + g_free (priv->hostname); priv->hostname = g_strdup (hostname); } diff --git a/src/nm-hostname-manager.c b/src/nm-hostname-manager.c new file mode 100644 index 0000000000..40f3351a69 --- /dev/null +++ b/src/nm-hostname-manager.c @@ -0,0 +1,661 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * (C) Copyright 2017 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-hostname-manager.h" + +#include <sys/stat.h> +#include <errno.h> +#include <string.h> + +#if HAVE_SELINUX +#include <selinux/selinux.h> +#endif + +#include "nm-common-macros.h" +#include "nm-dbus-interface.h" +#include "nm-connection.h" +#include "nm-utils.h" +#include "nm-core-internal.h" + +#include "NetworkManagerUtils.h" + +/*****************************************************************************/ + +#define HOSTNAMED_SERVICE_NAME "org.freedesktop.hostname1" +#define HOSTNAMED_SERVICE_PATH "/org/freedesktop/hostname1" +#define HOSTNAMED_SERVICE_INTERFACE "org.freedesktop.hostname1" + +#define HOSTNAME_FILE_DEFAULT "/etc/hostname" +#define HOSTNAME_FILE_UCASE_HOSTNAME "/etc/HOSTNAME" +#define HOSTNAME_FILE_GENTOO "/etc/conf.d/hostname" + +#if (defined(HOSTNAME_PERSIST_SUSE) + defined(HOSTNAME_PERSIST_SLACKWARE) + defined(HOSTNAME_PERSIST_GENTOO)) > 1 +#error "Can only define one of HOSTNAME_PERSIST_*" +#endif + +#if defined(HOSTNAME_PERSIST_SUSE) +#define HOSTNAME_FILE HOSTNAME_FILE_UCASE_HOSTNAME +#elif defined(HOSTNAME_PERSIST_SLACKWARE) +#define HOSTNAME_FILE HOSTNAME_FILE_UCASE_HOSTNAME +#elif defined(HOSTNAME_PERSIST_GENTOO) +#define HOSTNAME_FILE HOSTNAME_FILE_GENTOO +#else +#define HOSTNAME_FILE HOSTNAME_FILE_DEFAULT +#endif + +/*****************************************************************************/ + +NM_GOBJECT_PROPERTIES_DEFINE (NMHostnameManager, + PROP_HOSTNAME, +); + +typedef struct { + char *current_hostname; + GFileMonitor *monitor; + GFileMonitor *dhcp_monitor; + gulong monitor_id; + gulong dhcp_monitor_id; + GDBusProxy *hostnamed_proxy; +} NMHostnameManagerPrivate; + +struct _NMHostnameManager { + GObject parent; + NMHostnameManagerPrivate _priv; +}; + +struct _NMHostnameManagerClass { + GObjectClass parent; +}; + +G_DEFINE_TYPE (NMHostnameManager, nm_hostname_manager, G_TYPE_OBJECT); + +#define NM_HOSTNAME_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMHostnameManager, NM_IS_HOSTNAME_MANAGER) + +NM_DEFINE_SINGLETON_GETTER (NMHostnameManager, nm_hostname_manager_get, NM_TYPE_HOSTNAME_MANAGER); + +/*****************************************************************************/ + +#define _NMLOG_DOMAIN LOGD_CORE +#define _NMLOG(level, ...) __NMLOG_DEFAULT (level, _NMLOG_DOMAIN, "hostname", __VA_ARGS__) + +/*****************************************************************************/ + +#if defined(HOSTNAME_PERSIST_GENTOO) +static gchar * +read_hostname_gentoo (const char *path) +{ + gs_free char *contents = NULL; + gs_strfreev char **all_lines = NULL; + const char *tmp; + guint i; + + if (!g_file_get_contents (path, &contents, NULL, NULL)) + return NULL; + + all_lines = g_strsplit (contents, "\n", 0); + for (i = 0; all_lines[i]; i++) { + g_strstrip (all_lines[i]); + if (all_lines[i][0] == '#' || all_lines[i][0] == '\0') + continue; + if (g_str_has_prefix (all_lines[i], "hostname=")) { + tmp = &all_lines[i][NM_STRLEN ("hostname=")]; + return g_shell_unquote (tmp, NULL); + } + } + return NULL; +} +#endif + +#if defined(HOSTNAME_PERSIST_SLACKWARE) +static gchar * +read_hostname_slackware (const char *path) +{ + gs_free char *contents = NULL; + gs_strfreev char **all_lines = NULL; + char *tmp; + guint i, j = 0; + + if (!g_file_get_contents (path, &contents, NULL, NULL)) + return NULL; + + all_lines = g_strsplit (contents, "\n", 0); + for (i = 0; all_lines[i]; i++) { + g_strstrip (all_lines[i]); + if (all_lines[i][0] == '#' || all_lines[i][0] == '\0') + continue; + tmp = &all_lines[i][0]; + /* We only want up to the first '.' -- the rest of the */ + /* fqdn is defined in /etc/hosts */ + while (tmp[j] != '\0') { + if (tmp[j] == '.') { + tmp[j] = '\0'; + break; + } + j++; + } + return g_shell_unquote (tmp, NULL); + } + return NULL; +} +#endif + +#if defined(HOSTNAME_PERSIST_SUSE) +static gboolean +hostname_is_dynamic (void) +{ + GIOChannel *channel; + char *str = NULL; + gboolean dynamic = FALSE; + + channel = g_io_channel_new_file (CONF_DHCP, "r", NULL); + if (!channel) + return dynamic; + + while (g_io_channel_read_line (channel, &str, NULL, NULL, NULL) != G_IO_STATUS_EOF) { + if (str) { + g_strstrip (str); + if (g_str_has_prefix (str, "DHCLIENT_SET_HOSTNAME=")) + dynamic = strcmp (&str[NM_STRLEN ("DHCLIENT_SET_HOSTNAME=")], "\"yes\"") == 0; + g_free (str); + } + } + + g_io_channel_shutdown (channel, FALSE, NULL); + g_io_channel_unref (channel); + + return dynamic; +} +#endif + +/* Returns an allocated string which the caller owns and must eventually free */ +char * +nm_hostname_manager_read_hostname (NMHostnameManager *self) +{ + NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE (self); + char *hostname = NULL; + + if (priv->hostnamed_proxy) { + hostname = g_strdup (priv->current_hostname); + goto out; + } + +#if defined(HOSTNAME_PERSIST_SUSE) + if (priv->dhcp_monitor_id && hostname_is_dynamic ()) + return NULL; +#endif + +#if defined(HOSTNAME_PERSIST_GENTOO) + hostname = read_hostname_gentoo (HOSTNAME_FILE); +#elif defined(HOSTNAME_PERSIST_SLACKWARE) + hostname = read_hostname_slackware (HOSTNAME_FILE); +#else + if (g_file_get_contents (HOSTNAME_FILE, &hostname, NULL, NULL)) + g_strchomp (hostname); +#endif + +out: + if (hostname && !hostname[0]) { + g_free (hostname); + return NULL; + } + + return hostname; +} + +/*****************************************************************************/ + +const char * +nm_hostname_manager_get_hostname (NMHostnameManager *self) +{ + g_return_val_if_fail (NM_IS_HOSTNAME_MANAGER (self), NULL); + return NM_HOSTNAME_MANAGER_GET_PRIVATE (self)->current_hostname; +} + +static void +_set_hostname_take (NMHostnameManager *self, char *hostname) +{ + NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE (self); + + _LOGI ("hostname changed from %s%s%s to %s%s%s", + NM_PRINT_FMT_QUOTED (priv->current_hostname, "\"", priv->current_hostname, "\"", "(none)"), + NM_PRINT_FMT_QUOTED (hostname, "\"", hostname, "\"", "(none)")); + + g_free (priv->current_hostname); + priv->current_hostname = hostname; + _notify (self, PROP_HOSTNAME); +} + +static void +_set_hostname (NMHostnameManager *self, const char *hostname) +{ + NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE (self); + + hostname = nm_str_not_empty (hostname); + if (!nm_streq0 (hostname, priv->current_hostname)) + _set_hostname_take (self, g_strdup (hostname)); +} + +static void +_set_hostname_read (NMHostnameManager *self) +{ + NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE (self); + char *hostname; + + if (priv->hostnamed_proxy) { + /* read-hostname returns the current hostname with hostnamed. */ + return; + } + + hostname = nm_hostname_manager_read_hostname (self); + + if (nm_streq0 (hostname, priv->current_hostname)) { + g_free (hostname); + return; + } + + _set_hostname_take (self, hostname); +} + +/*****************************************************************************/ + +typedef struct { + char *hostname; + NMHostnameManagerSetHostnameCb cb; + gpointer user_data; +} SetHostnameInfo; + +static void +set_transient_hostname_done (GObject *object, + GAsyncResult *res, + gpointer user_data) +{ + GDBusProxy *proxy = G_DBUS_PROXY (object); + gs_free SetHostnameInfo *info = user_data; + gs_unref_variant GVariant *result = NULL; + gs_free_error GError *error = NULL; + + result = g_dbus_proxy_call_finish (proxy, res, &error); + + if (error) { + _LOGW ("couldn't set the system hostname to '%s' using hostnamed: %s", + info->hostname, error->message); + } + + info->cb (info->hostname, !error, info->user_data); + g_free (info->hostname); +} + +void +nm_hostname_manager_set_transient_hostname (NMHostnameManager *self, + const char *hostname, + NMHostnameManagerSetHostnameCb cb, + gpointer user_data) +{ + NMHostnameManagerPrivate *priv; + SetHostnameInfo *info; + + g_return_if_fail (NM_IS_HOSTNAME_MANAGER (self)); + + priv = NM_HOSTNAME_MANAGER_GET_PRIVATE (self); + + if (!priv->hostnamed_proxy) { + cb (hostname, FALSE, user_data); + return; + } + + info = g_new0 (SetHostnameInfo, 1); + info->hostname = g_strdup (hostname); + info->cb = cb; + info->user_data = user_data; + + g_dbus_proxy_call (priv->hostnamed_proxy, + "SetHostname", + g_variant_new ("(sb)", hostname, FALSE), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + set_transient_hostname_done, + info); +} + +gboolean +nm_hostname_manager_get_transient_hostname (NMHostnameManager *self, char **hostname) +{ + NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE (self); + GVariant *v_hostname; + + if (!priv->hostnamed_proxy) + return FALSE; + + v_hostname = g_dbus_proxy_get_cached_property (priv->hostnamed_proxy, + "Hostname"); + if (!v_hostname) { + _LOGT ("transient hostname retrieval failed"); + return FALSE; + } + + *hostname = g_variant_dup_string (v_hostname, NULL); + g_variant_unref (v_hostname); + + return TRUE; +} + +gboolean +nm_hostname_manager_write_hostname (NMHostnameManager *self, const char *hostname) +{ + NMHostnameManagerPrivate *priv; + char *hostname_eol; + gboolean ret; + gs_free_error GError *error = NULL; + const char *file = HOSTNAME_FILE; + gs_free char *link_path = NULL; + gs_unref_variant GVariant *var = NULL; + struct stat file_stat; +#if HAVE_SELINUX + security_context_t se_ctx_prev = NULL, se_ctx = NULL; + mode_t st_mode = 0; +#endif + + g_return_val_if_fail (NM_IS_HOSTNAME_MANAGER (self), FALSE); + + priv = NM_HOSTNAME_MANAGER_GET_PRIVATE (self); + + if (priv->hostnamed_proxy) { + var = g_dbus_proxy_call_sync (priv->hostnamed_proxy, + "SetStaticHostname", + g_variant_new ("(sb)", hostname, FALSE), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + if (error) + _LOGW ("could not set hostname: %s", error->message); + + return !error; + } + + /* If the hostname file is a symbolic link, follow it to find where the + * real file is located, otherwise g_file_set_contents will attempt to + * replace the link with a plain file. + */ + if ( lstat (file, &file_stat) == 0 + && S_ISLNK (file_stat.st_mode) + && (link_path = nm_utils_read_link_absolute (file, NULL))) + file = link_path; + +#if HAVE_SELINUX + /* Get default context for hostname file and set it for fscreate */ + if (stat (file, &file_stat) == 0) + st_mode = file_stat.st_mode; + matchpathcon (file, st_mode, &se_ctx); + matchpathcon_fini (); + getfscreatecon (&se_ctx_prev); + setfscreatecon (se_ctx); +#endif + +#if defined (HOSTNAME_PERSIST_GENTOO) + hostname_eol = g_strdup_printf ("#Generated by NetworkManager\n" + "hostname=\"%s\"\n", hostname); +#else + hostname_eol = g_strdup_printf ("%s\n", hostname); +#endif + + ret = g_file_set_contents (file, hostname_eol, -1, &error); + +#if HAVE_SELINUX + /* Restore previous context and cleanup */ + setfscreatecon (se_ctx_prev); + freecon (se_ctx); + freecon (se_ctx_prev); +#endif + + g_free (hostname_eol); + + if (!ret) { + _LOGW ("could not save hostname to %s: %s", file, error->message); + return FALSE; + } + + return TRUE; +} + +gboolean +nm_hostname_manager_validate_hostname (const char *hostname) +{ + const char *p; + gboolean dot = TRUE; + + if (!hostname || !hostname[0]) + return FALSE; + + for (p = hostname; *p; p++) { + if (*p == '.') { + if (dot) + return FALSE; + dot = TRUE; + } else { + if (!g_ascii_isalnum (*p) && (*p != '-') && (*p != '_')) + return FALSE; + dot = FALSE; + } + } + + if (dot) + return FALSE; + + return (p - hostname <= HOST_NAME_MAX); +} + +static void +hostname_file_changed_cb (GFileMonitor *monitor, + GFile *file, + GFile *other_file, + GFileMonitorEvent event_type, + gpointer user_data) +{ + _set_hostname_read (user_data); +} + +/*****************************************************************************/ + +static void +hostnamed_properties_changed (GDBusProxy *proxy, + GVariant *changed_properties, + char **invalidated_properties, + gpointer user_data) +{ + NMHostnameManager *self = user_data; + NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE (self); + GVariant *v_hostname; + + v_hostname = g_dbus_proxy_get_cached_property (priv->hostnamed_proxy, + "StaticHostname"); + if (v_hostname) { + _set_hostname (self, g_variant_get_string (v_hostname, NULL)); + g_variant_unref (v_hostname); + } +} + +static void +setup_hostname_file_monitors (NMHostnameManager *self) +{ + NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE (self); + GFileMonitor *monitor; + const char *path = HOSTNAME_FILE; + char *link_path = NULL; + struct stat file_stat; + GFile *file; + + /* resolve the path to the hostname file if it is a symbolic link */ + if ( lstat(path, &file_stat) == 0 + && S_ISLNK (file_stat.st_mode) + && (link_path = nm_utils_read_link_absolute (path, NULL))) { + path = link_path; + if ( lstat(link_path, &file_stat) == 0 + && S_ISLNK (file_stat.st_mode)) { + _LOGW ("only one level of symbolic link indirection is allowed when monitoring " + HOSTNAME_FILE); + } + } + + /* monitor changes to hostname file */ + file = g_file_new_for_path (path); + monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL); + g_object_unref (file); + g_free(link_path); + if (monitor) { + priv->monitor_id = g_signal_connect (monitor, "changed", + G_CALLBACK (hostname_file_changed_cb), + self); + priv->monitor = monitor; + } + +#if defined (HOSTNAME_PERSIST_SUSE) + /* monitor changes to dhcp file to know whether the hostname is valid */ + file = g_file_new_for_path (CONF_DHCP); + monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL); + g_object_unref (file); + if (monitor) { + priv->dhcp_monitor_id = g_signal_connect (monitor, "changed", + G_CALLBACK (hostname_file_changed_cb), + self); + priv->dhcp_monitor = monitor; + } +#endif + + _set_hostname_read (self); +} + +/*****************************************************************************/ + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMHostnameManager *self = NM_HOSTNAME_MANAGER (object); + + switch (prop_id) { + case PROP_HOSTNAME: + g_value_set_string (value, nm_hostname_manager_get_hostname (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/*****************************************************************************/ + +static void +nm_hostname_manager_init (NMHostnameManager *self) +{ +} + +static void +constructed (GObject *object) +{ + NMHostnameManager *self = NM_HOSTNAME_MANAGER (object); + NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE (self); + GDBusProxy *proxy; + GVariant *variant; + gs_free GError *error = NULL; + + proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, 0, NULL, + HOSTNAMED_SERVICE_NAME, HOSTNAMED_SERVICE_PATH, + HOSTNAMED_SERVICE_INTERFACE, NULL, &error); + if (proxy) { + variant = g_dbus_proxy_get_cached_property (proxy, "StaticHostname"); + if (variant) { + _LOGI ("hostname: using hostnamed"); + priv->hostnamed_proxy = proxy; + g_signal_connect (proxy, "g-properties-changed", + G_CALLBACK (hostnamed_properties_changed), self); + hostnamed_properties_changed (proxy, NULL, NULL, self); + g_variant_unref (variant); + } else { + _LOGI ("hostname: couldn't get property from hostnamed"); + g_object_unref (proxy); + } + } else { + _LOGI ("hostname: hostnamed not used as proxy creation failed with: %s", + error->message); + g_clear_error (&error); + } + + if (!priv->hostnamed_proxy) + setup_hostname_file_monitors (self); + + G_OBJECT_CLASS (nm_hostname_manager_parent_class)->constructed (object); +} + +static void +dispose (GObject *object) +{ + NMHostnameManager *self = NM_HOSTNAME_MANAGER (object); + NMHostnameManagerPrivate *priv = NM_HOSTNAME_MANAGER_GET_PRIVATE (self); + + if (priv->hostnamed_proxy) { + g_signal_handlers_disconnect_by_func (priv->hostnamed_proxy, + G_CALLBACK (hostnamed_properties_changed), + self); + g_clear_object (&priv->hostnamed_proxy); + } + + if (priv->monitor) { + if (priv->monitor_id) + g_signal_handler_disconnect (priv->monitor, priv->monitor_id); + + g_file_monitor_cancel (priv->monitor); + g_clear_object (&priv->monitor); + } + + if (priv->dhcp_monitor) { + if (priv->dhcp_monitor_id) + g_signal_handler_disconnect (priv->dhcp_monitor, + priv->dhcp_monitor_id); + + g_file_monitor_cancel (priv->dhcp_monitor); + g_clear_object (&priv->dhcp_monitor); + } + + nm_clear_g_free (&priv->current_hostname); + + G_OBJECT_CLASS (nm_hostname_manager_parent_class)->dispose (object); +} + +static void +nm_hostname_manager_class_init (NMHostnameManagerClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->constructed = constructed; + object_class->get_property = get_property; + object_class->dispose = dispose; + + obj_properties[PROP_HOSTNAME] = + g_param_spec_string (NM_HOSTNAME_MANAGER_HOSTNAME, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); +} diff --git a/src/nm-hostname-manager.h b/src/nm-hostname-manager.h new file mode 100644 index 0000000000..a837e9b92d --- /dev/null +++ b/src/nm-hostname-manager.h @@ -0,0 +1,63 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager + * + * Søren Sandmann <sandmann@daimi.au.dk> + * Dan Williams <dcbw@redhat.com> + * Tambet Ingo <tambet@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * (C) Copyright 2007 - 2011, 2017 Red Hat, Inc. + * (C) Copyright 2008 Novell, Inc. + */ + +#ifndef __NM_HOSTNAME_MANAGER_H__ +#define __NM_HOSTNAME_MANAGER_H__ + +#define NM_TYPE_HOSTNAME_MANAGER (nm_hostname_manager_get_type ()) +#define NM_HOSTNAME_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_HOSTNAME_MANAGER, NMHostnameManager)) +#define NM_HOSTNAME_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_HOSTNAME_MANAGER, NMHostnameManagerClass)) +#define NM_IS_HOSTNAME_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_HOSTNAME_MANAGER)) +#define NM_IS_HOSTNAME_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_HOSTNAME_MANAGER)) +#define NM_HOSTNAME_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_HOSTNAME_MANAGER, NMHostnameManagerClass)) + +#define NM_HOSTNAME_MANAGER_HOSTNAME "hostname" + +typedef struct _NMHostnameManager NMHostnameManager; +typedef struct _NMHostnameManagerClass NMHostnameManagerClass; + +typedef void (*NMHostnameManagerSetHostnameCb) (const char *name, gboolean result, gpointer user_data); + +GType nm_hostname_manager_get_type (void); + +NMHostnameManager *nm_hostname_manager_get (void); + +const char *nm_hostname_manager_get_hostname (NMHostnameManager *self); + +char *nm_hostname_manager_read_hostname (NMHostnameManager *self); + +gboolean nm_hostname_manager_write_hostname (NMHostnameManager *self, const char *hostname); + +void nm_hostname_manager_set_transient_hostname (NMHostnameManager *self, + const char *hostname, + NMHostnameManagerSetHostnameCb cb, + gpointer user_data); + +gboolean nm_hostname_manager_get_transient_hostname (NMHostnameManager *self, + char **hostname); + +gboolean nm_hostname_manager_validate_hostname (const char *hostname); + +#endif /* __NM_HOSTNAME_MANAGER_H__ */ diff --git a/src/nm-manager.c b/src/nm-manager.c index a74021951a..a845321ab7 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -35,6 +35,7 @@ #include "devices/nm-device.h" #include "devices/nm-device-generic.h" #include "platform/nm-platform.h" +#include "nm-hostname-manager.h" #include "nm-rfkill-manager.h" #include "dhcp/nm-dhcp-manager.h" #include "settings/nm-settings.h" @@ -122,6 +123,8 @@ typedef struct { NMPolicy *policy; + NMHostnameManager *hostname_manager; + NMBusManager *dbus_mgr; struct { GDBusConnection *connection; @@ -132,7 +135,6 @@ typedef struct { NMCheckpointManager *checkpoint_mgr; NMSettings *settings; - char *hostname; RadioState radio_states[RFKILL_TYPE_MAX]; NMVpnManager *vpn_manager; @@ -211,7 +213,6 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMManager, PROP_ALL_DEVICES, /* Not exported */ - PROP_HOSTNAME, PROP_SLEEPING, ); @@ -1404,35 +1405,17 @@ system_unmanaged_devices_changed_cb (NMSettings *settings, } static void -system_hostname_changed_cb (NMSettings *settings, - GParamSpec *pspec, - gpointer user_data) +hostname_changed_cb (NMHostnameManager *hostname_manager, + GParamSpec *pspec, + NMManager *self) { - NMManager *self = NM_MANAGER (user_data); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - char *hostname; - - hostname = nm_settings_get_hostname (priv->settings); - - /* nm_settings_get_hostname() does not return an empty hostname. */ - nm_assert (!hostname || *hostname); - - if (!hostname && !priv->hostname) - return; - if (hostname && priv->hostname && !strcmp (hostname, priv->hostname)) { - g_free (hostname); - return; - } - - /* realloc, to free possibly trailing data after NUL. */ - if (hostname) - hostname = g_realloc (hostname, strlen (hostname) + 1); + const char *hostname; - g_free (priv->hostname); - priv->hostname = hostname; - _notify (self, PROP_HOSTNAME); + hostname = nm_hostname_manager_get_hostname (priv->hostname_manager); - nm_dhcp_manager_set_default_hostname (nm_dhcp_manager_get (), priv->hostname); + nm_dispatcher_call_hostname (NULL, NULL, NULL); + nm_dhcp_manager_set_default_hostname (nm_dhcp_manager_get (), hostname); } /*****************************************************************************/ @@ -5087,7 +5070,7 @@ nm_manager_start (NMManager *self, GError **error) priv->net_enabled ? "enabled" : "disabled"); system_unmanaged_devices_changed_cb (priv->settings, NULL, self); - system_hostname_changed_cb (priv->settings, NULL, self); + hostname_changed_cb (priv->hostname_manager, NULL, self); /* Start device factories */ nm_device_factory_manager_load_factories (_register_device_factory, self); @@ -5983,12 +5966,15 @@ constructed (GObject *object) G_CALLBACK (settings_startup_complete_changed), self); g_signal_connect (priv->settings, "notify::" NM_SETTINGS_UNMANAGED_SPECS, G_CALLBACK (system_unmanaged_devices_changed_cb), self); - g_signal_connect (priv->settings, "notify::" NM_SETTINGS_HOSTNAME, - G_CALLBACK (system_hostname_changed_cb), self); g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_ADDED, G_CALLBACK (connection_added_cb), self); g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED, G_CALLBACK (connection_updated_cb), self); + + priv->hostname_manager = g_object_ref (nm_hostname_manager_get ()); + g_signal_connect (priv->hostname_manager, "notify::" NM_HOSTNAME_MANAGER_HOSTNAME, + G_CALLBACK (hostname_changed_cb), self); + /* * Do not delete existing virtual devices to keep connectivity up. * Virtual devices are reused when NetworkManager is restarted. @@ -6185,9 +6171,6 @@ get_property (GObject *object, guint prop_id, case PROP_ACTIVATING_CONNECTION: nm_utils_g_value_set_object_path (value, priv->activating_connection); break; - case PROP_HOSTNAME: - g_value_set_string (value, priv->hostname); - break; case PROP_SLEEPING: g_value_set_boolean (value, priv->sleeping); break; @@ -6296,8 +6279,6 @@ dispose (GObject *object) g_clear_object (&priv->config); } - g_free (priv->hostname); - if (priv->policy) { g_signal_handlers_disconnect_by_func (priv->policy, policy_default_device_changed, manager); g_signal_handlers_disconnect_by_func (priv->policy, policy_activating_device_changed, manager); @@ -6307,12 +6288,16 @@ dispose (GObject *object) if (priv->settings) { g_signal_handlers_disconnect_by_func (priv->settings, settings_startup_complete_changed, manager); g_signal_handlers_disconnect_by_func (priv->settings, system_unmanaged_devices_changed_cb, manager); - g_signal_handlers_disconnect_by_func (priv->settings, system_hostname_changed_cb, manager); g_signal_handlers_disconnect_by_func (priv->settings, connection_added_cb, manager); g_signal_handlers_disconnect_by_func (priv->settings, connection_updated_cb, manager); g_clear_object (&priv->settings); } + if (priv->hostname_manager) { + g_signal_handlers_disconnect_by_func (priv->hostname_manager, hostname_changed_cb, manager); + g_clear_object (&priv->hostname_manager); + } + g_clear_object (&priv->vpn_manager); /* Unregister property filter */ @@ -6474,13 +6459,6 @@ nm_manager_class_init (NMManagerClass *manager_class) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - /* Hostname is not exported over D-Bus */ - obj_properties[PROP_HOSTNAME] = - g_param_spec_string (NM_MANAGER_HOSTNAME, "", "", - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - /* Sleeping is not exported over D-Bus */ obj_properties[PROP_SLEEPING] = g_param_spec_boolean (NM_MANAGER_SLEEPING, "", "", diff --git a/src/nm-manager.h b/src/nm-manager.h index 676fa995b6..fbbaffc314 100644 --- a/src/nm-manager.h +++ b/src/nm-manager.h @@ -54,7 +54,6 @@ #define NM_MANAGER_ALL_DEVICES "all-devices" /* Not exported */ -#define NM_MANAGER_HOSTNAME "hostname" #define NM_MANAGER_SLEEPING "sleeping" /* signals */ diff --git a/src/nm-policy.c b/src/nm-policy.c index 7c74a6b412..2d17bf3af0 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -49,6 +49,7 @@ #include "nm-dhcp6-config.h" #include "nm-config.h" #include "nm-netns.h" +#include "nm-hostname-manager.h" /*****************************************************************************/ @@ -73,12 +74,17 @@ typedef struct { NMSettings *settings; + NMHostnameManager *hostname_manager; + NMDevice *default_device4, *activating_device4; NMDevice *default_device6, *activating_device6; - GResolver *resolver; - GInetAddress *lookup_addr; - GCancellable *lookup_cancellable; + struct { + GInetAddress *addr; + GResolver *resolver; + GCancellable *cancellable; + } lookup; + NMDnsManager *dns_manager; gulong config_changed_id; @@ -443,50 +449,46 @@ settings_set_hostname_cb (const char *hostname, #define HOST_NAME_BUFSIZE (HOST_NAME_MAX + 2) static char * -_get_hostname (NMPolicy *self, char **hostname) +_get_hostname (NMPolicy *self) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - char *buf; - - g_assert (hostname && *hostname == NULL); + char *hostname = NULL; /* If there is an in-progress hostname change, return * the last hostname set as would be set soon... */ if (priv->changing_hostname) { _LOGT (LOGD_DNS, "get-hostname: \"%s\" (last on set)", priv->last_hostname); - *hostname = g_strdup (priv->last_hostname); - return *hostname; + return g_strdup (priv->last_hostname); } /* try to get the hostname via dbus... */ - if (nm_settings_get_transient_hostname (priv->settings, hostname)) { - _LOGT (LOGD_DNS, "get-hostname: \"%s\" (from dbus)", *hostname); - return *hostname; + if (nm_hostname_manager_get_transient_hostname (priv->hostname_manager, &hostname)) { + _LOGT (LOGD_DNS, "get-hostname: \"%s\" (from dbus)", hostname); + return hostname; } /* ...or retrieve it by yourself */ - buf = g_malloc (HOST_NAME_BUFSIZE); - if (gethostname (buf, HOST_NAME_BUFSIZE -1) != 0) { + hostname = g_malloc (HOST_NAME_BUFSIZE); + if (gethostname (hostname, HOST_NAME_BUFSIZE -1) != 0) { int errsv = errno; _LOGT (LOGD_DNS, "get-hostname: couldn't get the system hostname: (%d) %s", errsv, g_strerror (errsv)); - g_free (buf); + g_free (hostname); return NULL; } /* the name may be truncated... */ - buf[HOST_NAME_BUFSIZE - 1] = '\0'; - if (strlen (buf) >= HOST_NAME_BUFSIZE -1) { - _LOGT (LOGD_DNS, "get-hostname: system hostname too long: \"%s\"", buf); - g_free (buf); + hostname[HOST_NAME_BUFSIZE - 1] = '\0'; + if (strlen (hostname) >= HOST_NAME_BUFSIZE -1) { + _LOGT (LOGD_DNS, "get-hostname: system hostname too long: \"%s\"", hostname); + g_free (hostname); return NULL; } - _LOGT (LOGD_DNS, "get-hostname: \"%s\"", buf); - *hostname = buf; - return *hostname; + _LOGT (LOGD_DNS, "get-hostname: \"%s\"", hostname); + return hostname; } static void @@ -508,7 +510,7 @@ _set_hostname (NMPolicy *self, * restart the reverse lookup thread later. */ if (new_hostname) - g_clear_object (&priv->lookup_addr); + g_clear_object (&priv->lookup.addr); /* Update the DNS only if the hostname is actually * going to change. @@ -534,7 +536,7 @@ _set_hostname (NMPolicy *self, name = new_hostname; /* Don't set the hostname if it isn't actually changing */ - if ( _get_hostname (self, &old_hostname) + if ( (old_hostname = _get_hostname (self)) && (nm_streq (name, old_hostname))) { _LOGT (LOGD_DNS, "set-hostname: hostname already set to '%s' (%s)", name, msg); return; @@ -549,10 +551,10 @@ _set_hostname (NMPolicy *self, /* Ask NMSettings to update the transient hostname using its * systemd-hostnamed proxy */ - nm_settings_set_transient_hostname (priv->settings, - name, - settings_set_hostname_cb, - g_object_ref (self)); + nm_hostname_manager_set_transient_hostname (priv->hostname_manager, + name, + settings_set_hostname_cb, + g_object_ref (self)); } static void @@ -572,7 +574,7 @@ lookup_callback (GObject *source, self = user_data; priv = NM_POLICY_GET_PRIVATE (self); - g_clear_object (&priv->lookup_cancellable); + g_clear_object (&priv->lookup.cancellable); if (hostname) _set_hostname (self, hostname, "from address lookup"); @@ -581,10 +583,23 @@ lookup_callback (GObject *source, } static void +lookup_by_address (NMPolicy *self) +{ + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); + + nm_clear_g_cancellable (&priv->lookup.cancellable); + priv->lookup.cancellable = g_cancellable_new (); + g_resolver_lookup_by_address_async (priv->lookup.resolver, + priv->lookup.addr, + priv->lookup.cancellable, + lookup_callback, self); +} + +static void update_system_hostname (NMPolicy *self, NMDevice *best4, NMDevice *best6, const char *msg) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - char *configured_hostname = NULL; + const char *configured_hostname; gs_free char *temp_hostname = NULL; const char *dhcp_hostname, *p; NMIP4Config *ip4_config; @@ -600,12 +615,12 @@ update_system_hostname (NMPolicy *self, NMDevice *best4, NMDevice *best6, const _LOGT (LOGD_DNS, "set-hostname: updating hostname (%s)", msg); - nm_clear_g_cancellable (&priv->lookup_cancellable); + nm_clear_g_cancellable (&priv->lookup.cancellable); /* Check if the hostname was set externally to NM, so that in that case * we can avoid to fallback to the one we got when we started. * Consider "not specific" hostnames as equal. */ - if ( _get_hostname (self, &temp_hostname) + if ( (temp_hostname = _get_hostname (self)) && !nm_streq0 (temp_hostname, priv->last_hostname) && ( nm_utils_is_specific_hostname (temp_hostname) || nm_utils_is_specific_hostname (priv->last_hostname))) { @@ -614,14 +629,14 @@ update_system_hostname (NMPolicy *self, NMDevice *best4, NMDevice *best6, const temp_hostname); priv->dhcp_hostname = FALSE; + if (!nm_utils_is_specific_hostname (temp_hostname)) + nm_clear_g_free (&temp_hostname); if (!nm_streq0 (temp_hostname, priv->orig_hostname)) { /* Update original (fallback) hostname */ g_free (priv->orig_hostname); - if (nm_utils_is_specific_hostname (temp_hostname)) { - priv->orig_hostname = temp_hostname; - temp_hostname = NULL; - } else - priv->orig_hostname = NULL; + priv->orig_hostname = g_steal_pointer (&temp_hostname); + _LOGT (LOGD_DNS, "hostname-original: update to %s%s%s", + NM_PRINT_FMT_QUOTE_STRING (priv->orig_hostname)); } } @@ -635,14 +650,12 @@ update_system_hostname (NMPolicy *self, NMDevice *best4, NMDevice *best6, const */ /* Try a persistent hostname first */ - g_object_get (G_OBJECT (priv->manager), NM_MANAGER_HOSTNAME, &configured_hostname, NULL); + configured_hostname = nm_hostname_manager_get_hostname (priv->hostname_manager); if (configured_hostname && nm_utils_is_specific_hostname (configured_hostname)) { _set_hostname (self, configured_hostname, "from system configuration"); priv->dhcp_hostname = FALSE; - g_free (configured_hostname); return; } - g_free (configured_hostname); /* Try automatically determined hostname from the best device's IP config */ if (!best4) @@ -737,15 +750,15 @@ update_system_hostname (NMPolicy *self, NMDevice *best4, NMDevice *best6, const const NMPlatformIP4Address *addr4; addr4 = nm_ip4_config_get_address (ip4_config, 0); - g_clear_object (&priv->lookup_addr); - priv->lookup_addr = g_inet_address_new_from_bytes ((guint8 *) &addr4->address, + g_clear_object (&priv->lookup.addr); + priv->lookup.addr = g_inet_address_new_from_bytes ((guint8 *) &addr4->address, G_SOCKET_FAMILY_IPV4); } else if (ip6_config && nm_ip6_config_get_num_addresses (ip6_config) > 0) { const NMPlatformIP6Address *addr6; addr6 = nm_ip6_config_get_address (ip6_config, 0); - g_clear_object (&priv->lookup_addr); - priv->lookup_addr = g_inet_address_new_from_bytes ((guint8 *) &addr6->address, + g_clear_object (&priv->lookup.addr); + priv->lookup.addr = g_inet_address_new_from_bytes ((guint8 *) &addr6->address, G_SOCKET_FAMILY_IPV6); } else { /* No valid IP config; fall back to localhost.localdomain */ @@ -753,11 +766,7 @@ update_system_hostname (NMPolicy *self, NMDevice *best4, NMDevice *best6, const return; } - priv->lookup_cancellable = g_cancellable_new (); - g_resolver_lookup_by_address_async (priv->resolver, - priv->lookup_addr, - priv->lookup_cancellable, - lookup_callback, self); + lookup_by_address (self); } static void @@ -1248,7 +1257,7 @@ process_secondaries (NMPolicy *self, } static void -hostname_changed (NMManager *manager, GParamSpec *pspec, gpointer user_data) +hostname_changed (NMHostnameManager *hostname_manager, GParamSpec *pspec, gpointer user_data) { NMPolicyPrivate *priv = user_data; NMPolicy *self = _PRIV_TO_SELF (priv); @@ -2088,30 +2097,26 @@ dns_config_changed (NMDnsManager *dns_manager, gpointer user_data) * (race in updating DNS and doing the reverse lookup). */ - nm_clear_g_cancellable (&priv->lookup_cancellable); + nm_clear_g_cancellable (&priv->lookup.cancellable); /* Re-start the hostname lookup thread if we don't have hostname yet. */ - if (priv->lookup_addr) { + if (priv->lookup.addr) { char *str = NULL; gs_free char *hostname = NULL; /* Check if the hostname was externally set */ - if ( _get_hostname (self, &hostname) + if ( (hostname = _get_hostname (self)) && nm_utils_is_specific_hostname (hostname) && !nm_streq0 (hostname, priv->last_hostname)) { - g_clear_object (&priv->lookup_addr); + g_clear_object (&priv->lookup.addr); return; } _LOGD (LOGD_DNS, "restarting reverse-lookup thread for address %s", - (str = g_inet_address_to_string (priv->lookup_addr))); + (str = g_inet_address_to_string (priv->lookup.addr))); g_free (str); - priv->lookup_cancellable = g_cancellable_new (); - g_resolver_lookup_by_address_async (priv->resolver, - priv->lookup_addr, - priv->lookup_cancellable, - lookup_callback, self); + lookup_by_address (self); } } @@ -2240,6 +2245,15 @@ nm_policy_get_activating_ip6_device (NMPolicy *self) /*****************************************************************************/ +NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_hostname_mode_to_string, NMPolicyHostnameMode, + NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT ("unknown"), + NM_UTILS_LOOKUP_STR_ITEM (NM_POLICY_HOSTNAME_MODE_NONE, "none"), + NM_UTILS_LOOKUP_STR_ITEM (NM_POLICY_HOSTNAME_MODE_DHCP, "dhcp"), + NM_UTILS_LOOKUP_STR_ITEM (NM_POLICY_HOSTNAME_MODE_FULL, "full"), +); + +/*****************************************************************************/ + static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) @@ -2300,6 +2314,8 @@ nm_policy_init (NMPolicy *self) priv->netns = g_object_ref (nm_netns_get ()); + priv->hostname_manager = g_object_ref (nm_hostname_manager_get ()); + hostname_mode = nm_config_data_get_value (NM_CONFIG_GET_DATA_ORIG, NM_CONFIG_KEYFILE_GROUP_MAIN, NM_CONFIG_KEYFILE_KEY_MAIN_HOSTNAME_MODE, @@ -2311,7 +2327,6 @@ nm_policy_init (NMPolicy *self) else /* default - full mode */ priv->hostname_mode = NM_POLICY_HOSTNAME_MODE_FULL; - _LOGI (LOGD_DNS, "hostname management mode: %s", hostname_mode ? hostname_mode : "default"); priv->devices = g_hash_table_new (NULL, NULL); priv->ip6_prefix_delegations = g_array_new (FALSE, FALSE, sizeof (IP6PrefixDelegation)); g_array_set_clear_func (priv->ip6_prefix_delegations, clear_ip6_prefix_delegation); @@ -2325,7 +2340,7 @@ constructed (GObject *object) char *hostname = NULL; /* Grab hostname on startup and use that if nothing provides one */ - if (_get_hostname (self, &hostname)) { + if ((hostname = _get_hostname (self))) { /* init last_hostname */ priv->last_hostname = hostname; @@ -2333,6 +2348,8 @@ constructed (GObject *object) if (nm_utils_is_specific_hostname (hostname)) priv->orig_hostname = g_strdup (hostname); } + _LOGT (LOGD_DNS, "hostname-original: set to %s%s%s", + NM_PRINT_FMT_QUOTE_STRING (priv->orig_hostname)); priv->firewall_manager = g_object_ref (nm_firewall_manager_get ()); g_signal_connect (priv->firewall_manager, NM_FIREWALL_MANAGER_STATE_CHANGED, @@ -2343,9 +2360,10 @@ constructed (GObject *object) priv->config_changed_id = g_signal_connect (priv->dns_manager, NM_DNS_MANAGER_CONFIG_CHANGED, G_CALLBACK (dns_config_changed), self); - priv->resolver = g_resolver_get_default (); + priv->lookup.resolver = g_resolver_get_default (); + + g_signal_connect (priv->hostname_manager, "notify::" NM_HOSTNAME_MANAGER_HOSTNAME, (GCallback) hostname_changed, priv); - g_signal_connect (priv->manager, "notify::" NM_MANAGER_HOSTNAME, (GCallback) hostname_changed, priv); g_signal_connect (priv->manager, "notify::" NM_MANAGER_SLEEPING, (GCallback) sleeping_changed, priv); g_signal_connect (priv->manager, "notify::" NM_MANAGER_NETWORKING_ENABLED, (GCallback) sleeping_changed, priv); g_signal_connect (priv->manager, NM_MANAGER_INTERNAL_DEVICE_ADDED, (GCallback) device_added, priv); @@ -2360,6 +2378,8 @@ constructed (GObject *object) g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_AGENT_REGISTERED, (GCallback) secret_agent_registered, priv); G_OBJECT_CLASS (nm_policy_parent_class)->constructed (object); + + _LOGD (LOGD_DNS, "hostname-mode: %s", _hostname_mode_to_string (priv->hostname_mode)); } NMPolicy * @@ -2383,10 +2403,9 @@ dispose (GObject *object) GHashTableIter h_iter; NMDevice *device; - nm_clear_g_cancellable (&priv->lookup_cancellable); - - g_clear_object (&priv->lookup_addr); - g_clear_object (&priv->resolver); + nm_clear_g_cancellable (&priv->lookup.cancellable); + g_clear_object (&priv->lookup.addr); + g_clear_object (&priv->lookup.resolver); while (priv->pending_activation_checks) activate_data_free (priv->pending_activation_checks->data); @@ -2424,6 +2443,11 @@ dispose (GObject *object) g_clear_pointer (&priv->cur_hostname, g_free); g_clear_pointer (&priv->last_hostname, g_free); + if (priv->hostname_manager) { + g_signal_handlers_disconnect_by_data (priv->hostname_manager, priv); + g_clear_object (&priv->hostname_manager); + } + if (priv->settings) { g_signal_handlers_disconnect_by_data (priv->settings, priv); g_clear_object (&priv->settings); diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index afd1b0849c..8db58c8d3a 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -76,6 +76,7 @@ #include "NetworkManagerUtils.h" #include "nm-dispatcher.h" #include "nm-inotify-helper.h" +#include "nm-hostname-manager.h" #include "introspection/org.freedesktop.NetworkManager.Settings.h" @@ -94,13 +95,6 @@ EXPORT(nm_settings_connection_replace_and_commit) /*****************************************************************************/ -#define HOSTNAMED_SERVICE_NAME "org.freedesktop.hostname1" -#define HOSTNAMED_SERVICE_PATH "/org/freedesktop/hostname1" -#define HOSTNAMED_SERVICE_INTERFACE "org.freedesktop.hostname1" - -#define HOSTNAME_FILE_DEFAULT "/etc/hostname" -#define HOSTNAME_FILE_UCASE_HOSTNAME "/etc/HOSTNAME" -#define HOSTNAME_FILE_GENTOO "/etc/conf.d/hostname" #define IFCFG_DIR SYSCONFDIR "/sysconfig/network" #define CONF_DHCP IFCFG_DIR "/dhcp" @@ -162,14 +156,8 @@ typedef struct { gboolean started; gboolean startup_complete; - struct { - char *value; - GFileMonitor *monitor; - GFileMonitor *dhcp_monitor; - gulong monitor_id; - gulong dhcp_monitor_id; - GDBusProxy *hostnamed_proxy; - } hostname; + NMHostnameManager *hostname_manager; + } NMSettingsPrivate; struct _NMSettings { @@ -568,131 +556,6 @@ get_plugin (NMSettings *self, guint32 capability) return NULL; } -#if defined(HOSTNAME_PERSIST_GENTOO) -static gchar * -read_hostname_gentoo (const char *path) -{ - gs_free char *contents = NULL; - gs_strfreev char **all_lines = NULL; - const char *tmp; - guint i; - - if (!g_file_get_contents (path, &contents, NULL, NULL)) - return NULL; - - all_lines = g_strsplit (contents, "\n", 0); - for (i = 0; all_lines[i]; i++) { - g_strstrip (all_lines[i]); - if (all_lines[i][0] == '#' || all_lines[i][0] == '\0') - continue; - if (g_str_has_prefix (all_lines[i], "hostname=")) { - tmp = &all_lines[i][NM_STRLEN ("hostname=")]; - return g_shell_unquote (tmp, NULL); - } - } - return NULL; -} -#endif - -#if defined(HOSTNAME_PERSIST_SLACKWARE) -static gchar * -read_hostname_slackware (const char *path) -{ - gs_free char *contents = NULL; - gs_strfreev char **all_lines = NULL; - char *tmp; - guint i, j = 0; - - if (!g_file_get_contents (path, &contents, NULL, NULL)) - return NULL; - - all_lines = g_strsplit (contents, "\n", 0); - for (i = 0; all_lines[i]; i++) { - g_strstrip (all_lines[i]); - if (all_lines[i][0] == '#' || all_lines[i][0] == '\0') - continue; - tmp = &all_lines[i][0]; - /* We only want up to the first '.' -- the rest of the */ - /* fqdn is defined in /etc/hosts */ - while (tmp[j] != '\0') { - if (tmp[j] == '.') { - tmp[j] = '\0'; - break; - } - j++; - } - return g_shell_unquote (tmp, NULL); - } - return NULL; -} -#endif - -#if defined(HOSTNAME_PERSIST_SUSE) -static gboolean -hostname_is_dynamic (void) -{ - GIOChannel *channel; - char *str = NULL; - gboolean dynamic = FALSE; - - channel = g_io_channel_new_file (CONF_DHCP, "r", NULL); - if (!channel) - return dynamic; - - while (g_io_channel_read_line (channel, &str, NULL, NULL, NULL) != G_IO_STATUS_EOF) { - if (str) { - g_strstrip (str); - if (g_str_has_prefix (str, "DHCLIENT_SET_HOSTNAME=")) - dynamic = strcmp (&str[NM_STRLEN ("DHCLIENT_SET_HOSTNAME=")], "\"yes\"") == 0; - g_free (str); - } - } - - g_io_channel_shutdown (channel, FALSE, NULL); - g_io_channel_unref (channel); - - return dynamic; -} -#endif - -/* Returns an allocated string which the caller owns and must eventually free */ -char * -nm_settings_get_hostname (NMSettings *self) -{ - NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); - char *hostname = NULL; - - if (!priv->started) - return NULL; - - if (priv->hostname.hostnamed_proxy) { - hostname = g_strdup (priv->hostname.value); - goto out; - } - -#if defined(HOSTNAME_PERSIST_SUSE) - if (priv->hostname.dhcp_monitor_id && hostname_is_dynamic ()) - return NULL; -#endif - -#if defined(HOSTNAME_PERSIST_GENTOO) - hostname = read_hostname_gentoo (HOSTNAME_FILE); -#elif defined(HOSTNAME_PERSIST_SLACKWARE) - hostname = read_hostname_slackware (HOSTNAME_FILE); -#else - if (g_file_get_contents (HOSTNAME_FILE, &hostname, NULL, NULL)) - g_strchomp (hostname); -#endif - -out: - if (hostname && !hostname[0]) { - g_free (hostname); - hostname = NULL; - } - - return hostname; -} - static gboolean find_spec (GSList *spec_list, const char *spec) { @@ -1626,160 +1489,7 @@ impl_settings_reload_connections (NMSettings *self, g_dbus_method_invocation_return_value (context, g_variant_new ("(b)", TRUE)); } -typedef struct { - char *hostname; - NMSettingsSetHostnameCb cb; - gpointer user_data; -} SetHostnameInfo; - -static void -set_transient_hostname_done (GObject *object, - GAsyncResult *res, - gpointer user_data) -{ - GDBusProxy *proxy = G_DBUS_PROXY (object); - gs_free SetHostnameInfo *info = user_data; - gs_unref_variant GVariant *result = NULL; - gs_free_error GError *error = NULL; - - result = g_dbus_proxy_call_finish (proxy, res, &error); - - if (error) { - _LOGW ("couldn't set the system hostname to '%s' using hostnamed: %s", - info->hostname, error->message); - } - - info->cb (info->hostname, !error, info->user_data); - g_free (info->hostname); -} - -void -nm_settings_set_transient_hostname (NMSettings *self, - const char *hostname, - NMSettingsSetHostnameCb cb, - gpointer user_data) -{ - NMSettingsPrivate *priv; - SetHostnameInfo *info; - - g_return_if_fail (NM_IS_SETTINGS (self)); - priv = NM_SETTINGS_GET_PRIVATE (self); - - if (!priv->hostname.hostnamed_proxy) { - cb (hostname, FALSE, user_data); - return; - } - - info = g_new0 (SetHostnameInfo, 1); - info->hostname = g_strdup (hostname); - info->cb = cb; - info->user_data = user_data; - - g_dbus_proxy_call (priv->hostname.hostnamed_proxy, - "SetHostname", - g_variant_new ("(sb)", hostname, FALSE), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - set_transient_hostname_done, - info); -} - -gboolean -nm_settings_get_transient_hostname (NMSettings *self, char **hostname) -{ - NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); - GVariant *v_hostname; - - if (!priv->hostname.hostnamed_proxy) - return FALSE; - - v_hostname = g_dbus_proxy_get_cached_property (priv->hostname.hostnamed_proxy, - "Hostname"); - if (!v_hostname) { - _LOGT ("transient hostname retrieval failed"); - return FALSE; - } - - *hostname = g_variant_dup_string (v_hostname, NULL); - g_variant_unref (v_hostname); - - return TRUE; -} - -static gboolean -write_hostname (NMSettingsPrivate *priv, const char *hostname) -{ - char *hostname_eol; - gboolean ret; - gs_free_error GError *error = NULL; - const char *file = HOSTNAME_FILE; - gs_free char *link_path = NULL; - gs_unref_variant GVariant *var = NULL; - struct stat file_stat; -#if HAVE_SELINUX - security_context_t se_ctx_prev = NULL, se_ctx = NULL; - mode_t st_mode = 0; -#endif - - if (priv->hostname.hostnamed_proxy) { - var = g_dbus_proxy_call_sync (priv->hostname.hostnamed_proxy, - "SetStaticHostname", - g_variant_new ("(sb)", hostname, FALSE), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - &error); - if (error) - _LOGW ("could not set hostname: %s", error->message); - - return !error; - } - - /* If the hostname file is a symbolic link, follow it to find where the - * real file is located, otherwise g_file_set_contents will attempt to - * replace the link with a plain file. - */ - if ( lstat (file, &file_stat) == 0 - && S_ISLNK (file_stat.st_mode) - && (link_path = nm_utils_read_link_absolute (file, NULL))) - file = link_path; - -#if HAVE_SELINUX - /* Get default context for hostname file and set it for fscreate */ - if (stat (file, &file_stat) == 0) - st_mode = file_stat.st_mode; - matchpathcon (file, st_mode, &se_ctx); - matchpathcon_fini (); - getfscreatecon (&se_ctx_prev); - setfscreatecon (se_ctx); -#endif - -#if defined (HOSTNAME_PERSIST_GENTOO) - hostname_eol = g_strdup_printf ("#Generated by NetworkManager\n" - "hostname=\"%s\"\n", hostname); -#else - hostname_eol = g_strdup_printf ("%s\n", hostname); -#endif - - ret = g_file_set_contents (file, hostname_eol, -1, &error); - -#if HAVE_SELINUX - /* Restore previous context and cleanup */ - setfscreatecon (se_ctx_prev); - freecon (se_ctx); - freecon (se_ctx_prev); -#endif - - g_free (hostname_eol); - - if (!ret) { - _LOGW ("could not save hostname to %s: %s", file, error->message); - return FALSE; - } - - return TRUE; -} +/*****************************************************************************/ static void pk_hostname_cb (NMAuthChain *chain, @@ -1812,7 +1522,7 @@ pk_hostname_cb (NMAuthChain *chain, } else { hostname = nm_auth_chain_get_data (chain, "hostname"); - if (!write_hostname (priv, hostname)) { + if (!nm_hostname_manager_write_hostname (priv->hostname_manager, hostname)) { error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "Saving the hostname failed."); @@ -1827,33 +1537,6 @@ pk_hostname_cb (NMAuthChain *chain, nm_auth_chain_unref (chain); } -static gboolean -validate_hostname (const char *hostname) -{ - const char *p; - gboolean dot = TRUE; - - if (!hostname || !hostname[0]) - return FALSE; - - for (p = hostname; *p; p++) { - if (*p == '.') { - if (dot) - return FALSE; - dot = TRUE; - } else { - if (!g_ascii_isalnum (*p) && (*p != '-') && (*p != '_')) - return FALSE; - dot = FALSE; - } - } - - if (dot) - return FALSE; - - return (p - hostname <= HOST_NAME_MAX); -} - static void impl_settings_save_hostname (NMSettings *self, GDBusMethodInvocation *context, @@ -1864,7 +1547,7 @@ impl_settings_save_hostname (NMSettings *self, GError *error = NULL; /* Minimal validation of the hostname */ - if (!validate_hostname (hostname)) { + if (!nm_hostname_manager_validate_hostname (hostname)) { error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_HOSTNAME, "The hostname was too long or contained invalid characters."); @@ -1888,37 +1571,7 @@ done: g_dbus_method_invocation_take_error (context, error); } -static void -hostname_maybe_changed (NMSettings *settings) -{ - NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (settings); - char *new_hostname; - - new_hostname = nm_settings_get_hostname (settings); - - if ( (new_hostname && !priv->hostname.value) - || (!new_hostname && priv->hostname.value) - || (priv->hostname.value && new_hostname && strcmp (priv->hostname.value, new_hostname))) { - - _LOGI ("hostname changed from %s%s%s to %s%s%s", - NM_PRINT_FMT_QUOTED (priv->hostname.value, "\"", priv->hostname.value, "\"", "(none)"), - NM_PRINT_FMT_QUOTED (new_hostname, "\"", new_hostname, "\"", "(none)")); - g_free (priv->hostname.value); - priv->hostname.value = new_hostname; - _notify (settings, PROP_HOSTNAME); - } else - g_free (new_hostname); -} - -static void -hostname_file_changed_cb (GFileMonitor *monitor, - GFile *file, - GFile *other_file, - GFileMonitorEvent event_type, - gpointer user_data) -{ - hostname_maybe_changed (user_data); -} +/*****************************************************************************/ static gboolean have_connection_for_device (NMSettings *self, NMDevice *device) @@ -2141,95 +1794,19 @@ nm_settings_get_startup_complete (NMSettings *self) /*****************************************************************************/ static void -hostnamed_properties_changed (GDBusProxy *proxy, - GVariant *changed_properties, - char **invalidated_properties, - gpointer user_data) +_hostname_changed_cb (NMHostnameManager *hostname_manager, + GParamSpec *pspec, + gpointer user_data) { - NMSettings *self = user_data; - NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); - GVariant *v_hostname; - const char *hostname; - - v_hostname = g_dbus_proxy_get_cached_property (priv->hostname.hostnamed_proxy, - "StaticHostname"); - if (!v_hostname) - return; - - hostname = g_variant_get_string (v_hostname, NULL); - - if (g_strcmp0 (priv->hostname.value, hostname) != 0) { - _LOGI ("hostname changed from %s%s%s to %s%s%s", - NM_PRINT_FMT_QUOTED (priv->hostname.value, "\"", priv->hostname.value, "\"", "(none)"), - NM_PRINT_FMT_QUOTED (hostname, "\"", hostname, "\"", "(none)")); - g_free (priv->hostname.value); - priv->hostname.value = g_strdup (hostname); - _notify (self, PROP_HOSTNAME); - nm_dispatcher_call_hostname (NULL, NULL, NULL); - } - - g_variant_unref (v_hostname); + _notify (user_data, PROP_HOSTNAME); } -static void -setup_hostname_file_monitors (NMSettings *self) -{ - NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); - GFileMonitor *monitor; - const char *path = HOSTNAME_FILE; - char *link_path = NULL; - struct stat file_stat; - GFile *file; - - priv->hostname.value = nm_settings_get_hostname (self); - - /* resolve the path to the hostname file if it is a symbolic link */ - if ( lstat(path, &file_stat) == 0 - && S_ISLNK (file_stat.st_mode) - && (link_path = nm_utils_read_link_absolute (path, NULL))) { - path = link_path; - if ( lstat(link_path, &file_stat) == 0 - && S_ISLNK (file_stat.st_mode)) { - _LOGW ("only one level of symbolic link indirection is allowed when monitoring " - HOSTNAME_FILE); - } - } - - /* monitor changes to hostname file */ - file = g_file_new_for_path (path); - monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL); - g_object_unref (file); - g_free(link_path); - if (monitor) { - priv->hostname.monitor_id = g_signal_connect (monitor, "changed", - G_CALLBACK (hostname_file_changed_cb), - self); - priv->hostname.monitor = monitor; - } - -#if defined (HOSTNAME_PERSIST_SUSE) - /* monitor changes to dhcp file to know whether the hostname is valid */ - file = g_file_new_for_path (CONF_DHCP); - monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL); - g_object_unref (file); - if (monitor) { - priv->hostname.dhcp_monitor_id = g_signal_connect (monitor, "changed", - G_CALLBACK (hostname_file_changed_cb), - self); - priv->hostname.dhcp_monitor = monitor; - } -#endif - - hostname_maybe_changed (self); -} +/*****************************************************************************/ gboolean nm_settings_start (NMSettings *self, GError **error) { NMSettingsPrivate *priv; - GDBusProxy *proxy; - GVariant *variant; - GError *local_error = NULL; gs_strfreev char **plugins = NULL; priv = NM_SETTINGS_GET_PRIVATE (self); @@ -2245,33 +1822,14 @@ nm_settings_start (NMSettings *self, GError **error) load_connections (self); check_startup_complete (self); - proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, 0, NULL, - HOSTNAMED_SERVICE_NAME, HOSTNAMED_SERVICE_PATH, - HOSTNAMED_SERVICE_INTERFACE, NULL, &local_error); - if (proxy) { - variant = g_dbus_proxy_get_cached_property (proxy, "StaticHostname"); - if (variant) { - _LOGI ("hostname: using hostnamed"); - priv->hostname.hostnamed_proxy = proxy; - g_signal_connect (proxy, "g-properties-changed", - G_CALLBACK (hostnamed_properties_changed), self); - hostnamed_properties_changed (proxy, NULL, NULL, self); - g_variant_unref (variant); - } else { - _LOGI ("hostname: couldn't get property from hostnamed"); - g_object_unref (proxy); - } - } else { - _LOGI ("hostname: hostnamed not used as proxy creation failed with: %s", - local_error->message); - g_clear_error (&local_error); - } - - if (!priv->hostname.hostnamed_proxy) - setup_hostname_file_monitors (self); + priv->hostname_manager = g_object_ref (nm_hostname_manager_get ()); + g_signal_connect (priv->hostname_manager, + "notify::"NM_HOSTNAME_MANAGER_HOSTNAME, + G_CALLBACK (_hostname_changed_cb), + self); + if (nm_hostname_manager_get_hostname (priv->hostname_manager)) + _notify (self, PROP_HOSTNAME); - priv->started = TRUE; - _notify (self, PROP_HOSTNAME); return TRUE; } @@ -2298,11 +1856,10 @@ get_property (GObject *object, guint prop_id, g_value_take_boxed (value, (char **) g_ptr_array_free (array, FALSE)); break; case PROP_HOSTNAME: - g_value_take_string (value, nm_settings_get_hostname (self)); - - /* Don't ever pass NULL through D-Bus */ - if (!g_value_get_string (value)) - g_value_set_static_string (value, ""); + g_value_set_string (value, + priv->hostname_manager + ? nm_hostname_manager_get_hostname (priv->hostname_manager) + : NULL); break; case PROP_CAN_MODIFY: g_value_set_boolean (value, !!get_plugin (self, NM_SETTINGS_PLUGIN_CAP_MODIFY_CONNECTIONS)); @@ -2362,32 +1919,13 @@ dispose (GObject *object) g_object_unref (priv->agent_mgr); - if (priv->hostname.hostnamed_proxy) { - g_signal_handlers_disconnect_by_func (priv->hostname.hostnamed_proxy, - G_CALLBACK (hostnamed_properties_changed), + if (priv->hostname_manager) { + g_signal_handlers_disconnect_by_func (priv->hostname_manager, + G_CALLBACK (_hostname_changed_cb), self); - g_clear_object (&priv->hostname.hostnamed_proxy); - } - - if (priv->hostname.monitor) { - if (priv->hostname.monitor_id) - g_signal_handler_disconnect (priv->hostname.monitor, priv->hostname.monitor_id); - - g_file_monitor_cancel (priv->hostname.monitor); - g_clear_object (&priv->hostname.monitor); + g_clear_object (&priv->hostname_manager); } - if (priv->hostname.dhcp_monitor) { - if (priv->hostname.dhcp_monitor_id) - g_signal_handler_disconnect (priv->hostname.dhcp_monitor, - priv->hostname.dhcp_monitor_id); - - g_file_monitor_cancel (priv->hostname.dhcp_monitor); - g_clear_object (&priv->hostname.dhcp_monitor); - } - - g_clear_pointer (&priv->hostname.value, g_free); - G_OBJECT_CLASS (nm_settings_parent_class)->dispose (object); } diff --git a/src/settings/nm-settings.h b/src/settings/nm-settings.h index 7110a12ba8..eede76b029 100644 --- a/src/settings/nm-settings.h +++ b/src/settings/nm-settings.h @@ -119,20 +119,10 @@ gboolean nm_settings_has_connection (NMSettings *self, NMSettingsConnection *con const GSList *nm_settings_get_unmanaged_specs (NMSettings *self); -char *nm_settings_get_hostname (NMSettings *self); - void nm_settings_device_added (NMSettings *self, NMDevice *device); void nm_settings_device_removed (NMSettings *self, NMDevice *device, gboolean quitting); gboolean nm_settings_get_startup_complete (NMSettings *self); -void nm_settings_set_transient_hostname (NMSettings *self, - const char *hostname, - NMSettingsSetHostnameCb cb, - gpointer user_data); - -gboolean nm_settings_get_transient_hostname (NMSettings *self, - char **hostname); - #endif /* __NM_SETTINGS_H__ */ |