aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am4
-rw-r--r--src/meson.build3
-rw-r--r--src/mm-dispatcher-connection.c231
-rw-r--r--src/mm-dispatcher-connection.h49
4 files changed, 287 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 8686c74b..e4ca5f7a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -294,6 +294,8 @@ ModemManager_CPPFLAGS = \
-DPLUGINDIR=\"$(pkglibdir)\" \
-DFCCUNLOCKDIRPACKAGE=\"${pkglibdir}/fcc-unlock.d\" \
-DFCCUNLOCKDIRUSER=\"${pkgsysconfdir}/fcc-unlock.d\" \
+ -DCONNECTIONDIRPACKAGE=\"${pkglibdir}/connection.d\" \
+ -DCONNECTIONDIRUSER=\"${pkgsysconfdir}/connection.d\" \
-DMM_COMPILATION \
$(NULL)
@@ -315,6 +317,8 @@ ModemManager_SOURCES = \
mm-auth-provider.c \
mm-dispatcher.h \
mm-dispatcher.c \
+ mm-dispatcher-connection.h \
+ mm-dispatcher-connection.c \
mm-dispatcher-fcc-unlock.h \
mm-dispatcher-fcc-unlock.c \
mm-filter.h \
diff --git a/src/meson.build b/src/meson.build
index a26a82e3..fdf6b09c 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -201,6 +201,7 @@ sources = files(
'mm-context.c',
'mm-device.c',
'mm-dispatcher.c',
+ 'mm-dispatcher-connection.c',
'mm-dispatcher-fcc-unlock.c',
'mm-filter.c',
'mm-iface-modem-3gpp.c',
@@ -255,6 +256,8 @@ c_args = [
'-DPLUGINDIR="@0@"'.format(mm_prefix / mm_pkglibdir),
'-DFCCUNLOCKDIRPACKAGE="@0@"'.format(mm_prefix / mm_pkglibdir / 'fcc-unlock.d'),
'-DFCCUNLOCKDIRUSER="@0@"'.format(mm_prefix / mm_pkgsysconfdir / 'fcc-unlock.d'),
+ '-DCONNECTIONDIRPACKAGE="@0@"'.format(mm_prefix / mm_pkglibdir / 'connection.d'),
+ '-DCONNECTIONDIRUSER="@0@"'.format(mm_prefix / mm_pkgsysconfdir / 'connection.d'),
]
if enable_qrtr
diff --git a/src/mm-dispatcher-connection.c b/src/mm-dispatcher-connection.c
new file mode 100644
index 00000000..7f370a59
--- /dev/null
+++ b/src/mm-dispatcher-connection.c
@@ -0,0 +1,231 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2022 Aleksander Morgado <aleksander@aleksander.es>
+ */
+
+#include <config.h>
+#include <sys/stat.h>
+
+#include <ModemManager.h>
+#include "mm-errors-types.h"
+#include "mm-utils.h"
+#include "mm-log-object.h"
+#include "mm-dispatcher-connection.h"
+
+#if !defined CONNECTIONDIRPACKAGE
+# error CONNECTIONDIRPACKAGE must be defined at build time
+#endif
+
+#if !defined CONNECTIONDIRUSER
+# error CONNECTIONDIRUSER must be defined at build time
+#endif
+
+#define OPERATION_DESCRIPTION "connection status report"
+#define CONNECTED_STRING "connected"
+#define DISCONNECTED_STRING "disconnected"
+
+/* Maximum time a connection dispatcher command is allowed to run before
+ * us killing it */
+#define MAX_CONNECTION_EXEC_TIME_SECS 5
+
+struct _MMDispatcherConnection {
+ MMDispatcher parent;
+};
+
+struct _MMDispatcherConnectionClass {
+ MMDispatcherClass parent;
+};
+
+G_DEFINE_TYPE (MMDispatcherConnection, mm_dispatcher_connection, MM_TYPE_DISPATCHER)
+
+/*****************************************************************************/
+
+typedef struct {
+ gchar *modem_dbus_path;
+ gchar *bearer_dbus_path;
+ gchar *data_port;
+ gboolean connected;
+ GList *dispatcher_scripts;
+ GFile *current;
+ guint n_failures;
+} ConnectionRunContext;
+
+static void
+connection_run_context_free (ConnectionRunContext *ctx)
+{
+ g_assert (!ctx->current);
+ g_free (ctx->modem_dbus_path);
+ g_free (ctx->bearer_dbus_path);
+ g_free (ctx->data_port);
+ g_list_free_full (ctx->dispatcher_scripts, (GDestroyNotify)g_object_unref);
+ g_slice_free (ConnectionRunContext, ctx);
+}
+
+gboolean
+mm_dispatcher_connection_run_finish (MMDispatcherConnection *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void connection_run_next (GTask *task);
+
+static void
+dispatcher_run_ready (MMDispatcher *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ ConnectionRunContext *ctx;
+ g_autoptr(GError) error = NULL;
+
+ ctx = g_task_get_task_data (task);
+
+ if (!mm_dispatcher_run_finish (self, res, &error)) {
+ ctx->n_failures++;
+ mm_obj_warn (self, "Cannot run " OPERATION_DESCRIPTION " operation from %s: %s",
+ g_file_peek_path (ctx->current), error->message);
+ } else
+ mm_obj_dbg (self, OPERATION_DESCRIPTION " operation successfully from %s",
+ g_file_peek_path (ctx->current));
+
+ g_clear_object (&ctx->current);
+ connection_run_next (task);
+}
+
+static void
+connection_run_next (GTask *task)
+{
+ MMDispatcherConnection *self;
+ ConnectionRunContext *ctx;
+ g_autofree gchar *path = NULL;
+ GPtrArray *aux;
+ g_auto(GStrv) argv = NULL;
+
+ self = g_task_get_source_object (task);
+ ctx = g_task_get_task_data (task);
+
+ if (!ctx->dispatcher_scripts) {
+ if (ctx->n_failures)
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Failed %u " OPERATION_DESCRIPTION " operations",
+ ctx->n_failures);
+ else
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+ return;
+ }
+
+ /* store current file reference in context */
+ ctx->current = ctx->dispatcher_scripts->data;
+ ctx->dispatcher_scripts = g_list_delete_link (ctx->dispatcher_scripts, ctx->dispatcher_scripts);
+ path = g_file_get_path (ctx->current);
+
+ /* build argv */
+ aux = g_ptr_array_new ();
+ g_ptr_array_add (aux, g_steal_pointer (&path));
+ g_ptr_array_add (aux, g_strdup (ctx->modem_dbus_path));
+ g_ptr_array_add (aux, g_strdup (ctx->bearer_dbus_path));
+ g_ptr_array_add (aux, g_strdup (ctx->data_port));
+ g_ptr_array_add (aux, g_strdup (ctx->connected ? CONNECTED_STRING : DISCONNECTED_STRING));
+ g_ptr_array_add (aux, NULL);
+ argv = (GStrv) g_ptr_array_free (aux, FALSE);
+
+ /* run */
+ mm_dispatcher_run (MM_DISPATCHER (self),
+ argv,
+ MAX_CONNECTION_EXEC_TIME_SECS,
+ g_task_get_cancellable (task),
+ (GAsyncReadyCallback) dispatcher_run_ready,
+ task);
+}
+
+static gint
+dispatcher_script_cmp (GFile *a,
+ GFile *b)
+{
+ g_autofree gchar *a_name = NULL;
+ g_autofree gchar *b_name = NULL;
+
+ a_name = g_file_get_basename (a);
+ b_name = g_file_get_basename (b);
+
+ return g_strcmp0 (a_name, b_name);
+}
+
+void
+mm_dispatcher_connection_run (MMDispatcherConnection *self,
+ const gchar *modem_dbus_path,
+ const gchar *bearer_dbus_path,
+ const gchar *data_port,
+ gboolean connected,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ ConnectionRunContext *ctx;
+ guint i;
+ const gchar *enabled_dirs[] = {
+ CONNECTIONDIRUSER, /* sysconfdir */
+ CONNECTIONDIRPACKAGE, /* libdir */
+ };
+
+ task = g_task_new (self, cancellable, callback, user_data);
+
+ ctx = g_slice_new0 (ConnectionRunContext);
+ ctx->modem_dbus_path = g_strdup (modem_dbus_path);
+ ctx->bearer_dbus_path = g_strdup (bearer_dbus_path);
+ ctx->data_port = g_strdup (data_port);
+ ctx->connected = connected;
+ g_task_set_task_data (task, ctx, (GDestroyNotify)connection_run_context_free);
+
+ /* Iterate over all enabled dirs and collect all dispatcher script paths */
+ for (i = 0; i < G_N_ELEMENTS (enabled_dirs); i++) {
+ g_autoptr(GFile) dir_file = NULL;
+ g_autoptr(GFileEnumerator) enumerator = NULL;
+ GFile *child;
+
+ dir_file = g_file_new_for_path (enabled_dirs[i]);
+ enumerator = g_file_enumerate_children (dir_file,
+ G_FILE_ATTRIBUTE_STANDARD_NAME,
+ G_FILE_QUERY_INFO_NONE,
+ cancellable,
+ NULL);
+ if (!enumerator)
+ continue;
+
+ while (g_file_enumerator_iterate (enumerator, NULL, &child, cancellable, NULL) && child)
+ ctx->dispatcher_scripts = g_list_prepend (ctx->dispatcher_scripts, g_object_ref (child));
+ }
+
+ /* Sort all by filename, regardless of the directory where they're in */
+ ctx->dispatcher_scripts = g_list_sort (ctx->dispatcher_scripts, (GCompareFunc)dispatcher_script_cmp);
+
+ connection_run_next (task);
+}
+
+/*****************************************************************************/
+
+static void
+mm_dispatcher_connection_init (MMDispatcherConnection *self)
+{
+}
+
+static void
+mm_dispatcher_connection_class_init (MMDispatcherConnectionClass *class)
+{
+}
+
+MM_DEFINE_SINGLETON_GETTER (MMDispatcherConnection, mm_dispatcher_connection_get, MM_TYPE_DISPATCHER_CONNECTION,
+ MM_DISPATCHER_OPERATION_DESCRIPTION, OPERATION_DESCRIPTION)
diff --git a/src/mm-dispatcher-connection.h b/src/mm-dispatcher-connection.h
new file mode 100644
index 00000000..dfa21701
--- /dev/null
+++ b/src/mm-dispatcher-connection.h
@@ -0,0 +1,49 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2022 Aleksander Morgado <aleksander@aleksander.es>
+ */
+
+#ifndef MM_DISPATCHER_CONNECTION_H
+#define MM_DISPATCHER_CONNECTION_H
+
+#include <config.h>
+#include <gio/gio.h>
+
+#include "mm-dispatcher.h"
+
+#define MM_TYPE_DISPATCHER_CONNECTION (mm_dispatcher_connection_get_type ())
+#define MM_DISPATCHER_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_DISPATCHER_CONNECTION, MMDispatcherConnection))
+#define MM_DISPATCHER_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_DISPATCHER_CONNECTION, MMDispatcherConnectionClass))
+#define MM_IS_DISPATCHER_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_DISPATCHER_CONNECTION))
+#define MM_IS_DISPATCHER_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_DISPATCHER_CONNECTION))
+#define MM_DISPATCHER_CONNECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_DISPATCHER_CONNECTION, MMDispatcherConnectionClass))
+
+typedef struct _MMDispatcherConnection MMDispatcherConnection;
+typedef struct _MMDispatcherConnectionClass MMDispatcherConnectionClass;
+typedef struct _MMDispatcherConnectionPrivate MMDispatcherConnectionPrivate;
+
+GType mm_dispatcher_connection_get_type (void);
+MMDispatcherConnection *mm_dispatcher_connection_get (void);
+void mm_dispatcher_connection_run (MMDispatcherConnection *self,
+ const gchar *modem_dbus_path,
+ const gchar *bearer_dbus_path,
+ const gchar *data_port,
+ gboolean connected,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean mm_dispatcher_connection_run_finish (MMDispatcherConnection *self,
+ GAsyncResult *res,
+ GError **error);
+
+#endif /* MM_DISPATCHER_CONNECTION_H */