diff options
-rw-r--r-- | plugins/option/mm-broadband-bearer-hso.c | 152 |
1 files changed, 101 insertions, 51 deletions
diff --git a/plugins/option/mm-broadband-bearer-hso.c b/plugins/option/mm-broadband-bearer-hso.c index 8a12f645..0ea36b6f 100644 --- a/plugins/option/mm-broadband-bearer-hso.c +++ b/plugins/option/mm-broadband-bearer-hso.c @@ -241,6 +241,7 @@ typedef struct { GCancellable *cancellable; GSimpleAsyncResult *result; guint auth_idx; + GError *saved_error; } Dial3gppContext; static Dial3gppContext * @@ -319,6 +320,37 @@ dial_3gpp_finish (MMBroadbandBearer *self, return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error); } +static void +connect_reset_ready (MMBaseModem *modem, + GAsyncResult *res, + Dial3gppContext *ctx) +{ + mm_base_modem_at_command_full_finish (modem, res, NULL); + + /* error should have already been set in the simple async result */ + dial_3gpp_context_complete_and_free (ctx); +} + +static void +connect_reset (Dial3gppContext *ctx) +{ + gchar *command; + + /* Need to reset the connection attempt */ + command = g_strdup_printf ("AT_OWANCALL=%d,0,1", + ctx->cid); + mm_base_modem_at_command_full (ctx->modem, + ctx->primary, + command, + 3, + FALSE, + FALSE, /* raw */ + NULL, /* cancellable */ + (GAsyncReadyCallback)connect_reset_ready, + ctx); + g_free (command); +} + void mm_broadband_bearer_hso_report_connection_status (MMBroadbandBearerHso *self, MMBroadbandBearerHsoConnectionStatus status) @@ -342,13 +374,26 @@ mm_broadband_bearer_hso_report_connection_status (MMBroadbandBearerHso *self, switch (status) { case MM_BROADBAND_BEARER_HSO_CONNECTION_STATUS_UNKNOWN: - g_warn_if_reached (); break; case MM_BROADBAND_BEARER_HSO_CONNECTION_STATUS_CONNECTED: if (!ctx) + /* We may get this if the timeout for the connection attempt is + * reached before the unsolicited response. We should probably + * keep the CID around to request explicit disconnection in this + * case. */ break; + /* If we wanted to get cancelled before, do it now */ + if (ctx->saved_error) { + /* Keep error */ + g_simple_async_result_take_error (ctx->result, ctx->saved_error); + ctx->saved_error = NULL; + /* Cancel connection */ + connect_reset (ctx); + return; + } + g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE); dial_3gpp_context_complete_and_free (ctx); return; @@ -357,6 +402,15 @@ mm_broadband_bearer_hso_report_connection_status (MMBroadbandBearerHso *self, if (!ctx) break; + /* If we wanted to get cancelled before and now we couldn't connect, + * use the cancelled error and return */ + if (ctx->saved_error) { + g_simple_async_result_take_error (ctx->result, ctx->saved_error); + ctx->saved_error = NULL; + dial_3gpp_context_complete_and_free (ctx); + return; + } + g_simple_async_result_set_error (ctx->result, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, @@ -366,48 +420,29 @@ mm_broadband_bearer_hso_report_connection_status (MMBroadbandBearerHso *self, case MM_BROADBAND_BEARER_HSO_CONNECTION_STATUS_DISCONNECTED: if (ctx) { + /* If we wanted to get cancelled before and now we couldn't connect, + * use the cancelled error and return */ + if (ctx->saved_error) { + g_simple_async_result_take_error (ctx->result, ctx->saved_error); + ctx->saved_error = NULL; + dial_3gpp_context_complete_and_free (ctx); + return; + } + g_simple_async_result_set_error (ctx->result, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Call setup failed"); dial_3gpp_context_complete_and_free (ctx); - } else { - /* Just ensure we mark ourselves as being disconnected... */ - mm_bearer_report_disconnection (MM_BEARER (self)); + return; } - break; - } -} - -static void -connect_reset_ready (MMBaseModem *modem, - GAsyncResult *res, - Dial3gppContext *ctx) -{ - mm_base_modem_at_command_full_finish (modem, res, NULL); - - /* error should have already been set in the simple async result */ - dial_3gpp_context_complete_and_free (ctx); -} -static void -connect_reset (Dial3gppContext *ctx) -{ - gchar *command; + /* Just ensure we mark ourselves as being disconnected... */ + mm_bearer_report_disconnection (MM_BEARER (self)); + return; + } - /* Need to reset the connection attempt */ - command = g_strdup_printf ("AT_OWANCALL=%d,0,1", - ctx->cid); - mm_base_modem_at_command_full (ctx->modem, - ctx->primary, - command, - 3, - FALSE, - FALSE, /* raw */ - NULL, /* cancellable */ - (GAsyncReadyCallback)connect_reset_ready, - ctx); - g_free (command); + g_warn_if_reached (); } static gboolean @@ -415,20 +450,31 @@ connect_timed_out_cb (MMBroadbandBearerHso *self) { Dial3gppContext *ctx; - /* Recover context and remove cancellation */ + /* Recover context and remove it from the private info */ ctx = self->priv->connect_pending; + self->priv->connect_pending = NULL; - g_cancellable_disconnect (ctx->cancellable, - self->priv->connect_cancellable_id); + /* Remove cancellation, if found */ + if (self->priv->connect_cancellable_id) { + g_cancellable_disconnect (ctx->cancellable, + self->priv->connect_cancellable_id); + self->priv->connect_cancellable_id = 0; + } - self->priv->connect_pending = NULL; + /* Cleanup timeout ID */ self->priv->connect_pending_id = 0; - self->priv->connect_cancellable_id = 0; - g_simple_async_result_set_error (ctx->result, - MM_MOBILE_EQUIPMENT_ERROR, - MM_MOBILE_EQUIPMENT_ERROR_NETWORK_TIMEOUT, - "Connection attempt timed out"); + /* If we were cancelled, prefer that error */ + if (ctx->saved_error) { + g_simple_async_result_take_error (ctx->result, ctx->saved_error); + ctx->saved_error = NULL; + } else + g_simple_async_result_set_error (ctx->result, + MM_MOBILE_EQUIPMENT_ERROR, + MM_MOBILE_EQUIPMENT_ERROR_NETWORK_TIMEOUT, + "Connection attempt timed out"); + + /* It's probably pointless to try to reset this here, but anyway... */ connect_reset (ctx); return FALSE; @@ -438,22 +484,26 @@ static void connect_cancelled_cb (GCancellable *cancellable, MMBroadbandBearerHso *self) { - GError *error = NULL; Dial3gppContext *ctx; /* Recover context and remove timeout */ ctx = self->priv->connect_pending; - g_source_remove (self->priv->connect_pending_id); + /* Recover context but DON'T remove it from the private info */ + ctx = self->priv->connect_pending; - self->priv->connect_pending = NULL; - self->priv->connect_pending_id = 0; + /* Remove the cancellable + * NOTE: we shouldn't remove the timeout yet. We still need to wait + * to get connected before running the explicit connection reset */ + g_cancellable_disconnect (ctx->cancellable, + self->priv->connect_cancellable_id); self->priv->connect_cancellable_id = 0; - g_assert (dial_3gpp_context_set_error_if_cancelled (ctx, &error)); + /* Store cancelled error */ + g_assert (dial_3gpp_context_set_error_if_cancelled (ctx, &ctx->saved_error)); - g_simple_async_result_take_error (ctx->result, error); - connect_reset (ctx); + /* We cannot reset right here, we need to wait for the connection + * attempt to finish */ } static void |