diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/mm-iface-modem-simple.c | 112 |
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, ¤t, @@ -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); |