iface-modem-simple: clear ongoing connect cancellable on early errors

If the Simple.Connect() operation fails before the bearer connection
process starts (e.g. during the previous SIM-PIN checks or explicit
registration attempt), the ongoing connect cancellable is not being
properly cleared, and this would prevent additional new connection
attempts unless an explicit Simple.Disconnect() is called.

    $ sudo mmcli -m 1 --simple-connect="operator-id=21403,apn=internet"
    error: couldn't connect the modem: 'GDBus.Error:org.freedesktop.ModemManager1.Error.MobileEquipment.NetworkTimeout: Network timeout'
    $ sudo mmcli -m 1 --simple-connect="operator-id=21403,apn=internet"
    error: couldn't connect the modem: 'GDBus.Error:org.freedesktop.ModemManager1.Error.Core.InProgress: Connection request forbidden: operation already in progress'
    $ sudo mmcli -m 1 --simple-connect="operator-id=21403,apn=internet"
    error: couldn't connect the modem: 'GDBus.Error:org.freedesktop.ModemManager1.Error.Core.InProgress: Connection request forbidden: operation already in progress'

Fix this, by making sure the ongoing connect cancellable is always
cleared when completing the DBus method invocation that created it.

Fixes https://gitlab.freedesktop.org/mobile-broadband/ModemManager/issues/169
This commit is contained in:
Aleksander Morgado
2019-12-21 09:53:06 +01:00
parent d83c018f98
commit 7a398214f9
+20 -11
View File
@@ -237,10 +237,29 @@ typedef struct {
GCancellable *cancellable;
} ConnectionContext;
static void
cleanup_cancellation (ConnectionContext *ctx)
{
Private *priv;
/* The ongoing connect cancellable and the one in the connection context
* must be the same, as they're set together, so if the one in the
* context doesn't exist, do nothing. */
if (!ctx->cancellable)
return;
/* If the ongoing connect cancellable is cancelled via the Simple.Disconnect
* method, it won't exist in the private struct, so don't assume they
* both exist. */
priv = get_private (ctx->self);
g_clear_object (&priv->ongoing_connect);
g_clear_object (&ctx->cancellable);
}
static void
connection_context_free (ConnectionContext *ctx)
{
g_clear_object (&ctx->cancellable);
cleanup_cancellation (ctx);
g_clear_object (&ctx->properties);
g_clear_object (&ctx->bearer);
g_variant_unref (ctx->dictionary);
@@ -487,16 +506,6 @@ completed_if_cancelled (ConnectionContext *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)