Refactor: Make SendMessage async
authorDenis Kenzior <denkenz@gmail.com>
Thu, 5 Nov 2009 22:44:22 +0000 (16:44 -0600)
committerDenis Kenzior <denkenz@gmail.com>
Thu, 5 Nov 2009 22:44:22 +0000 (16:44 -0600)
This commit does two things.  First it makes SendMessage an async
method, which returns only when the SMS message has been successfully
sent or failed.

This also adds a set number of tries that oFono will resubmit the PDU to
the SMSC.  If any fragment fails to be submitted, the entire send
message attempt is deemed a failure and an error is returned to the caller.

src/sms.c

index d9cea8a..cb59667 100644 (file)
--- a/src/sms.c
+++ b/src/sms.c
@@ -42,6 +42,8 @@
 
 #define SMS_MANAGER_FLAG_CACHED 0x1
 
+#define TXQ_MAX_RETRIES 4
+
 static gboolean tx_next(gpointer user_data);
 
 static GSList *g_drivers = NULL;
@@ -51,6 +53,7 @@ struct ofono_sms {
        DBusMessage *pending;
        struct ofono_phone_number sca;
        struct sms_assembly *assembly;
+       unsigned int next_msg_id;
        guint ref;
        GQueue *txq;
        time_t last_mms;
@@ -69,6 +72,15 @@ struct pending_pdu {
        int pdu_len;
 };
 
+struct tx_queue_entry {
+       struct pending_pdu *pdus;
+       unsigned char num_pdus;
+       unsigned char cur_pdu;
+       unsigned int msg_id;
+       unsigned int retry;
+       DBusMessage *msg;
+};
+
 static void set_sca(struct ofono_sms *sms,
                        const struct ofono_phone_number *sca)
 {
@@ -251,20 +263,53 @@ static DBusMessage *sms_set_property(DBusConnection *conn, DBusMessage *msg,
 static void tx_finished(const struct ofono_error *error, int mr, void *data)
 {
        struct ofono_sms *sms = data;
-       struct pending_pdu *pdu;
+       struct ofono_modem *modem = __ofono_atom_get_modem(sms->atom);
+       struct tx_queue_entry *entry = g_queue_peek_head(sms->txq);
 
        ofono_debug("tx_finished");
 
        if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
-               ofono_debug("Sending failed, retrying in 5 seconds...");
-               sms->tx_source = g_timeout_add_seconds(5, tx_next, sms);
+               entry->retry += 1;
+
+               if (entry->retry != TXQ_MAX_RETRIES) {
+                       ofono_debug("Sending failed, retry in %d secs",
+                                       entry->retry * 5);
+                       sms->tx_source = g_timeout_add_seconds(entry->retry * 5,
+                                                               tx_next, sms);
+                       return;
+               }
+
+               ofono_debug("Max retries reached, giving up");
+
+               entry = g_queue_pop_head(sms->txq);
+               __ofono_dbus_pending_reply(&entry->msg,
+                                       __ofono_error_failed(entry->msg));
+
+               g_free(entry->pdus);
+               g_free(entry);
+
+               if (g_queue_peek_head(sms->txq)) {
+                       ofono_debug("Previous send failed, scheduling next");
+                       sms->tx_source = g_timeout_add(0, tx_next, sms);
+               }
+
+               return;
+       }
+
+       entry->cur_pdu += 1;
+       entry->retry = 0;
+
+       if (entry->cur_pdu < entry->num_pdus) {
+               sms->tx_source = g_timeout_add(0, tx_next, sms);
                return;
        }
 
-       pdu = g_queue_pop_head(sms->txq);
-       g_free(pdu);
+       entry = g_queue_pop_head(sms->txq);
+       __ofono_dbus_pending_reply(&entry->msg,
+                               dbus_message_new_method_return(entry->msg));
 
-       ofono_debug("Peeking in the queue");
+       g_free(entry->pdus);
+       g_free(entry);
 
        if (g_queue_peek_head(sms->txq)) {
                ofono_debug("Scheduling next");
@@ -277,16 +322,17 @@ static gboolean tx_next(gpointer user_data)
        struct ofono_sms *sms = user_data;
        time_t ts;
        int send_mms = 0;
-       struct pending_pdu *pdu = g_queue_peek_head(sms->txq);
+       struct tx_queue_entry *entry = g_queue_peek_head(sms->txq);
+       struct pending_pdu *pdu = &entry->pdus[entry->cur_pdu];
        struct ofono_error error;
 
        error.type = OFONO_ERROR_TYPE_NO_ERROR;
 
-       ofono_debug("tx_next: %p", pdu);
+       ofono_debug("tx_next: %p", entry);
 
        sms->tx_source = 0;
 
-       if (!pdu)
+       if (!entry)
                return FALSE;
 
        ts = time(NULL);
@@ -319,31 +365,26 @@ static void set_ref_and_to(GSList *msg_list, guint16 ref, int offset,
        }
 }
 
-static void append_tx_queue(struct ofono_sms *sms, GSList *msg_list)
+static struct tx_queue_entry *create_tx_queue_entry(GSList *msg_list)
 {
-       struct sms *s;
+       struct tx_queue_entry *entry = g_new0(struct tx_queue_entry, 1);
+       int i = 0;
        GSList *l;
-       struct pending_pdu *pdu;
-       gboolean start = FALSE;
 
-       if (g_queue_peek_head(sms->txq) == NULL)
-               start = TRUE;
+       entry->num_pdus = g_slist_length(msg_list);
+       entry->pdus = g_new0(struct pending_pdu, entry->num_pdus);
 
        for (l = msg_list; l; l = l->next) {
-               s = l->data;
-
-               pdu = g_new(struct pending_pdu, 1);
+               struct pending_pdu *pdu = &entry->pdus[i];
+               struct sms *s = l->data;
 
                sms_encode(s, &pdu->pdu_len, &pdu->tpdu_len, pdu->pdu);
 
                ofono_debug("pdu_len: %d, tpdu_len: %d",
                                pdu->pdu_len, pdu->tpdu_len);
-
-               g_queue_push_tail(sms->txq, pdu);
        }
 
-       if (start)
-               sms->tx_source = g_timeout_add(0, tx_next, sms);
+       return entry;
 }
 
 static DBusMessage *sms_send_message(DBusConnection *conn, DBusMessage *msg,
@@ -354,6 +395,8 @@ static DBusMessage *sms_send_message(DBusConnection *conn, DBusMessage *msg,
        const char *text;
        GSList *msg_list;
        int ref_offset;
+       struct tx_queue_entry *entry;
+       struct ofono_modem *modem;
 
        if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &to,
                                        DBUS_TYPE_STRING, &text,
@@ -371,7 +414,10 @@ static DBusMessage *sms_send_message(DBusConnection *conn, DBusMessage *msg,
        ofono_debug("ref: %d, offset: %d", sms->ref, ref_offset);
 
        set_ref_and_to(msg_list, sms->ref, ref_offset, to);
-       append_tx_queue(sms, msg_list);
+       entry = create_tx_queue_entry(msg_list);
+
+       g_slist_foreach(msg_list, (GFunc)g_free, NULL);
+       g_slist_free(msg_list);
 
        if (ref_offset != 0) {
                if (sms->ref == 65536)
@@ -380,10 +426,15 @@ static DBusMessage *sms_send_message(DBusConnection *conn, DBusMessage *msg,
                        sms->ref = sms->ref + 1;
        }
 
-       g_slist_foreach(msg_list, (GFunc)g_free, NULL);
-       g_slist_free(msg_list);
+       entry->msg = dbus_message_ref(msg);
+       entry->msg_id = sms->next_msg_id++;
+
+       g_queue_push_tail(sms->txq, entry);
 
-       return dbus_message_new_method_return(msg);
+       if (g_queue_get_length(sms->txq) == 1)
+               sms->tx_source = g_timeout_add(0, tx_next, sms);
+
+       return NULL;
 }
 
 static GDBusMethodTable sms_manager_methods[] = {
@@ -391,7 +442,8 @@ static GDBusMethodTable sms_manager_methods[] = {
                                                        G_DBUS_METHOD_FLAG_ASYNC },
        { "SetProperty",        "sv",   "",             sms_set_property,
                                                        G_DBUS_METHOD_FLAG_ASYNC },
-       { "SendMessage",        "ss",   "",             sms_send_message },
+       { "SendMessage",        "ss",   "",             sms_send_message,
+                                                       G_DBUS_METHOD_FLAG_ASYNC },
        { }
 };