All of lore.kernel.org
 help / color / mirror / Atom feed
* SMS status report
@ 2010-06-17 13:14 Pasi Miettinen
  2010-06-17 13:14 ` [RFC PATCH 1/5] smsutil: Status report assembly Pasi Miettinen
  0 siblings, 1 reply; 10+ messages in thread
From: Pasi Miettinen @ 2010-06-17 13:14 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 482 bytes --]


Hi,

Here are the latest modifications for the status report.

Most common use cases are tested in practise. For example:
-Send concatenated message from ofono to phone that is
 powered off.
-Reboot ofono and ofono reads the persistent data from imsi file.
-Power on the phone.
-Ofono receives the status reports and handles them correctly.

Ofono was run under the supervision of valgrind during these tests
and no memory leaks were detected.

Br,
Pasi






^ permalink raw reply	[flat|nested] 10+ messages in thread
* [RFC PATCH 1/5] smsutil: Status report assembly
@ 2010-06-16 14:08 Pasi Miettinen
  2010-06-16 14:08 ` [RFC PATCH 2/5] history: print SMS status Pasi Miettinen
  0 siblings, 1 reply; 10+ messages in thread
From: Pasi Miettinen @ 2010-06-16 14:08 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 7495 bytes --]

---
 src/smsutil.c |  183 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/smsutil.h |   31 ++++++++++
 2 files changed, 214 insertions(+), 0 deletions(-)

diff --git a/src/smsutil.c b/src/smsutil.c
index 95eca06..3db3d28 100644
--- a/src/smsutil.c
+++ b/src/smsutil.c
@@ -2625,6 +2625,189 @@ void sms_assembly_expire(struct sms_assembly *assembly, time_t before)
 	}
 }
 
+struct status_report_assembly *status_report_assembly_new(const char *imsi)
+{
+	struct status_report_assembly *ret =
+				g_new0(struct status_report_assembly, 1);
+
+	ret->assembly_table = g_hash_table_new_full(g_str_hash, g_str_equal,
+				g_free, (GDestroyNotify)g_hash_table_destroy);
+
+	if (imsi)
+		ret->imsi = imsi;
+
+	return ret;
+}
+
+void status_report_assembly_free(struct status_report_assembly *assembly)
+{
+	g_hash_table_destroy(assembly->assembly_table);
+	g_free(assembly);
+}
+
+gboolean status_report_assembly_report(struct status_report_assembly *assembly,
+					const struct sms *status_report,
+					unsigned int *msg_id,
+					gboolean *msg_delivered)
+{
+	unsigned int offset = status_report->status_report.mr / 32;
+	unsigned int bit = 1 << (status_report->status_report.mr % 32);
+	GHashTable *id_table;
+	struct id_table_node *node;
+	unsigned int *key;
+	gpointer value;
+	GHashTableIter iter;
+	int i;
+	gboolean pending = FALSE;
+	gboolean update_history = FALSE;
+
+	id_table = g_hash_table_lookup(assembly->assembly_table,
+				status_report->status_report.raddr.address);
+
+	/* ERROR, key (receiver address) does not exist in assembly */
+	if (!id_table) {
+		*msg_delivered = FALSE;
+		return FALSE;
+	}
+
+	g_hash_table_iter_init(&iter, id_table);
+	while (g_hash_table_iter_next(&iter, (gpointer)&key, &value)) {
+		node = value;
+
+		if (!(node->mrs[offset] & bit))
+			continue;
+
+		/* Mr belongs to this node. */
+		node->mrs[offset] ^= bit;
+		*msg_id = *key;
+
+		for (i = 0; i < 8; i++) {
+				/* There are still pending mr(s). */
+				if (node->mrs[i] != 0 ||
+					(node->sent_mrs < node->total_mrs)) {
+					pending = TRUE;
+					break;
+				}
+		}
+		/* Mr is not delivered. */
+		if (status_report->status_report.st !=
+				SMS_ST_COMPLETED_RECEIVED) {
+			/* First mr which is not delivered. Update ofono history
+			 * and mark the whole message as undeliverable. Upcoming
+			 * mrs can not change the status to deliverable even if
+			 * they are considered as delivered.
+			 */
+			if (node->deliverable) {
+				node->deliverable = FALSE;
+				update_history = TRUE;
+			}
+		}
+
+		/* If there are pending mrs that relate to this message, we do
+		 * not delete the node yet.
+		 */
+		if (pending) {
+			*msg_delivered = FALSE;
+			return update_history;
+		} else {
+			*msg_delivered = node->deliverable;
+
+			g_hash_table_iter_remove(&iter);
+
+			if (g_hash_table_size(id_table) == 0)
+				g_hash_table_remove(assembly->assembly_table,
+				status_report->status_report.raddr.address);
+			/* If there has not been undelivered mrs, message is
+			 * delivered and the ofono history needs to be updated.
+			 * If the message is concidered as undelivered, the
+			 * ofono history has already been updated when the first
+			 * undelivered mr arrived, unless this one is the only
+			 * related mr and was marked undelivered.
+			 */
+			return *msg_delivered || update_history;
+		}
+	}
+	/* ERROR, mr not found. */
+	*msg_delivered = FALSE;
+	return FALSE;
+}
+
+void status_report_assembly_add_fragment(
+					struct status_report_assembly *assembly,
+					unsigned int msg_id,
+					const struct sms_address *to,
+					unsigned char mr, time_t expiration,
+					unsigned char total_mrs)
+{
+	unsigned int offset = mr / 32;
+	unsigned int bit = 1 << (mr % 32);
+	GHashTable *id_table;
+	struct id_table_node *node;
+	char *assembly_table_key;
+	unsigned int *id_table_key;
+
+	id_table = g_hash_table_lookup(assembly->assembly_table, to->address);
+	/* Create id_table and node */
+	if (id_table == NULL) {
+		id_table = g_hash_table_new_full(g_int_hash, g_int_equal,
+								g_free, g_free);
+		id_table_key = g_new0(unsigned int, 1);
+
+		node = g_new0(struct id_table_node, 1);
+		node->to = *to;
+		node->mrs[offset] |= bit;
+		node->expiration = expiration;
+		node->total_mrs = total_mrs;
+		node->sent_mrs = 1;
+		node->deliverable = TRUE;
+
+		*id_table_key = msg_id;
+		g_hash_table_insert(id_table, id_table_key, node);
+
+		assembly_table_key = g_try_malloc(sizeof(to->address));
+
+		if (assembly_table_key == NULL) {
+			g_free(node);
+			return;
+		}
+
+		g_strlcpy(assembly_table_key, to->address, sizeof(to->address));
+
+		g_hash_table_insert(assembly->assembly_table,
+					assembly_table_key, id_table);
+		return;
+	}
+
+	node = g_hash_table_lookup(id_table, &msg_id);
+	/* id_table exists, create new node */
+	if (node == NULL) {
+		id_table_key = g_new0(unsigned int, 1);
+		node = g_new0(struct id_table_node, 1);
+		node->to = *to;
+		node->mrs[offset] |= bit;
+		node->expiration = expiration;
+		node->total_mrs = total_mrs;
+		node->sent_mrs = 1;
+		node->deliverable = TRUE;
+
+		*id_table_key = msg_id;
+		g_hash_table_insert(id_table, id_table_key, node);
+
+		return;
+	}
+	/* id_table and node both exists */
+	node->mrs[offset] |= bit;
+	node->expiration = expiration;
+	node->sent_mrs++;
+}
+
+void status_report_assembly_expire(struct status_report_assembly *assembly,
+					time_t before, GFunc foreach_func,
+					gpointer data)
+{
+	/*TODO*/
+}
+
 static inline GSList *sms_list_append(GSList *l, const struct sms *in)
 {
 	struct sms *sms;
diff --git a/src/smsutil.h b/src/smsutil.h
index 1bd42bb..5fb187b 100644
--- a/src/smsutil.h
+++ b/src/smsutil.h
@@ -19,6 +19,8 @@
  *
  */
 
+#include "history.h"
+
 #define CBS_MAX_GSM_CHARS 93
 
 enum sms_type {
@@ -364,6 +366,20 @@ struct sms_assembly {
 	GSList *assembly_list;
 };
 
+struct id_table_node {
+	struct sms_address to;
+	unsigned int mrs[8];
+	time_t expiration;
+	unsigned char total_mrs;
+	unsigned char sent_mrs;
+	gboolean deliverable;
+};
+
+struct status_report_assembly {
+	const char *imsi;
+	GHashTable *assembly_table;
+};
+
 struct cbs {
 	enum cbs_geo_scope gs;			/* 2 bits */
 	guint16 message_code;			/* 10 bits */
@@ -481,6 +497,21 @@ GSList *sms_assembly_add_fragment(struct sms_assembly *assembly,
 					guint16 ref, guint8 max, guint8 seq);
 void sms_assembly_expire(struct sms_assembly *assembly, time_t before);
 
+struct status_report_assembly *status_report_assembly_new(const char *imsi);
+void status_report_assembly_free(struct status_report_assembly *assembly);
+gboolean status_report_assembly_report(struct status_report_assembly *assembly,
+					const struct sms *status_report,
+					unsigned int *msg_id,
+					gboolean *msg_delivered);
+void status_report_assembly_add_fragment(struct status_report_assembly
+					*assembly, unsigned int msg_id,
+					const struct sms_address *to,
+					unsigned char mr, time_t expiration,
+					unsigned char total_mrs);
+void status_report_assembly_expire(struct status_report_assembly *assembly,
+					time_t before, GFunc foreach_func,
+					gpointer data);
+
 GSList *sms_text_prepare(const char *utf8, guint16 ref,
 				gboolean use_16bit, int *ref_offset,
 				gboolean use_delivery_reports);
-- 
1.6.0.4



^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2010-06-21 23:35 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-06-17 13:14 SMS status report Pasi Miettinen
2010-06-17 13:14 ` [RFC PATCH 1/5] smsutil: Status report assembly Pasi Miettinen
2010-06-17 13:14   ` [RFC PATCH 2/5] history: print SMS status Pasi Miettinen
2010-06-17 13:14     ` [RFC PATCH 3/5] history: API change for status report notify Pasi Miettinen
2010-06-17 13:14       ` [RFC PATCH 4/5] sms: Status " Pasi Miettinen
2010-06-17 13:14         ` [RFC PATCH 5/5] smsutil: save pending status reports to imsi file Pasi Miettinen
2010-06-21 21:07           ` Denis Kenzior
2010-06-21 23:35     ` [RFC PATCH 2/5] history: print SMS status Denis Kenzior
2010-06-21 21:09   ` [RFC PATCH 1/5] smsutil: Status report assembly Denis Kenzior
  -- strict thread matches above, loose matches on Subject: below --
2010-06-16 14:08 Pasi Miettinen
2010-06-16 14:08 ` [RFC PATCH 2/5] history: print SMS status Pasi Miettinen

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.