aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mm-iface-modem-simple.c112
1 files changed, 108 insertions, 4 deletions
diff --git a/src/mm-iface-modem-simple.c b/src/mm-iface-modem-simple.c
index f39e2df1..893c470c 100644
--- a/src/mm-iface-modem-simple.c
+++ b/src/mm-iface-modem-simple.c
@@ -29,6 +29,40 @@
#include "mm-log.h"
/*****************************************************************************/
+/* Private data context */
+
+#define PRIVATE_TAG "iface-modem-simple-private-tag"
+static GQuark private_quark;
+
+typedef struct {
+ GCancellable *ongoing_connect;
+} Private;
+
+static void
+private_free (Private *priv)
+{
+ g_assert (!priv->ongoing_connect);
+ g_slice_free (Private, priv);
+}
+
+static Private *
+get_private (MMIfaceModemSimple *self)
+{
+ Private *priv;
+
+ if (G_UNLIKELY (!private_quark))
+ private_quark = g_quark_from_static_string (PRIVATE_TAG);
+
+ priv = g_object_get_qdata (G_OBJECT (self), private_quark);
+ if (!priv) {
+ priv = g_slice_new0 (Private);
+ g_object_set_qdata_full (G_OBJECT (self), private_quark, priv, (GDestroyNotify)private_free);
+ }
+
+ return priv;
+}
+
+/*****************************************************************************/
/* Register in either a CDMA or a 3GPP network (or both) */
typedef struct {
@@ -198,16 +232,18 @@ typedef struct {
/* Results to set */
MMBaseBearer *bearer;
+
+ /* Cancellation */
+ GCancellable *cancellable;
} ConnectionContext;
static void
connection_context_free (ConnectionContext *ctx)
{
+ g_clear_object (&ctx->cancellable);
+ g_clear_object (&ctx->properties);
+ g_clear_object (&ctx->bearer);
g_variant_unref (ctx->dictionary);
- if (ctx->properties)
- g_object_unref (ctx->properties);
- if (ctx->bearer)
- g_object_unref (ctx->bearer);
g_object_unref (ctx->skeleton);
g_object_unref (ctx->invocation);
g_object_unref (ctx->self);
@@ -436,9 +472,58 @@ bearer_list_find_disconnected (MMBaseBearer *bearer,
ctx->found = g_object_ref (bearer);
}
+static gboolean
+completed_if_cancelled (ConnectionContext *ctx)
+{
+ /* Do nothing if not cancelled */
+ if (!g_cancellable_is_cancelled (ctx->cancellable))
+ return FALSE;
+
+ /* Otherwise cancellable is valid and it's cancelled */
+ g_dbus_method_invocation_return_error (
+ ctx->invocation, G_IO_ERROR, G_IO_ERROR_CANCELLED,
+ "Connection attempt cancelled");
+ connection_context_free (ctx);
+ return TRUE;
+}
+
+static void
+cleanup_cancellation (ConnectionContext *ctx)
+{
+ Private *priv;
+
+ priv = get_private (ctx->self);
+ g_clear_object (&priv->ongoing_connect);
+ g_clear_object (&ctx->cancellable);
+}
+
+static gboolean
+setup_cancellation (ConnectionContext *ctx,
+ GError **error)
+{
+ Private *priv;
+
+ /* Only one connection attempt by Simple.Connect() may be handled at a time */
+ priv = get_private (ctx->self);
+ if (priv->ongoing_connect) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_IN_PROGRESS,
+ "Connection request forbidden: operation already in progress");
+ return FALSE;
+ }
+
+ g_assert (!ctx->cancellable);
+ ctx->cancellable = g_cancellable_new ();
+ priv->ongoing_connect = g_object_ref (ctx->cancellable);
+ return TRUE;
+}
+
static void
connection_step (ConnectionContext *ctx)
{
+ /* Early abort if operation is cancelled */
+ if (completed_if_cancelled (ctx))
+ return;
+
switch (ctx->step) {
case CONNECTION_STEP_FIRST:
/* Fall down to next step */
@@ -588,6 +673,10 @@ connection_step (ConnectionContext *ctx)
mm_info ("Simple connect state (%d/%d): Connect",
ctx->step, CONNECTION_STEP_LAST);
+ /* At this point, we can cleanup the cancellation point in the Simple interface,
+ * because the bearer connection has its own cancellation setup. */
+ cleanup_cancellation (ctx);
+
/* Wait... if we're already using an existing bearer, we need to check if it is
* already connected; and if so, just don't do anything else */
if (mm_base_bearer_get_status (ctx->bearer) != MM_BEARER_STATUS_CONNECTED) {
@@ -639,6 +728,12 @@ connect_auth_ready (MMBaseModem *self,
return;
}
+ if (!setup_cancellation (ctx, &error)) {
+ g_dbus_method_invocation_take_error (ctx->invocation, error);
+ connection_context_free (ctx);
+ return;
+ }
+
/* We may be able to skip some steps, so check that before doing anything */
g_object_get (self,
MM_IFACE_MODEM_STATE, &current,
@@ -826,6 +921,7 @@ disconnect_auth_ready (MMBaseModem *self,
{
GError *error = NULL;
MMBearerList *list = NULL;
+ Private *priv;
if (!mm_base_modem_authorize_finish (self, res, &error)) {
g_dbus_method_invocation_take_error (ctx->invocation, error);
@@ -833,6 +929,14 @@ disconnect_auth_ready (MMBaseModem *self,
return;
}
+ /* If not disconnecting a specific bearer, also cancel any ongoing
+ * connection attempt. */
+ priv = get_private (MM_IFACE_MODEM_SIMPLE (self));
+ if (!ctx->bearer_path && priv->ongoing_connect) {
+ g_cancellable_cancel (priv->ongoing_connect);
+ g_clear_object (&priv->ongoing_connect);
+ }
+
g_object_get (self,
MM_IFACE_MODEM_BEARER_LIST, &list,
NULL);