iface-modem-simple: allow single ongoing Connect() attempt
We only allow one single Simple.Connect() attempt at a time. If more than one arrives, the second and next ones will be forbidden. The ongoing connection attempt can now always be cancelled via Simple.Disconnect(), not only *after* the bearer object connection has started. i.e. if Simple.Disconnect() is called e.g. while waiting to be registered, we would also be cancelled properly.
This commit is contained in:
@@ -28,6 +28,40 @@
|
||||
#include "mm-iface-modem-simple.h"
|
||||
#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) */
|
||||
|
||||
@@ -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);
|
||||
|
Reference in New Issue
Block a user