summaryrefslogtreecommitdiff
path: root/src/devices/wwan/nm-modem-manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/wwan/nm-modem-manager.c')
-rw-r--r--src/devices/wwan/nm-modem-manager.c813
1 files changed, 555 insertions, 258 deletions
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,