[RFC PATCH 1/2] smsutil: Status Report assembly
Denis Kenzior
denkenz at gmail.com
Thu Jun 10 09:52:46 PDT 2010
Hi Pasi,
> +void status_report_assembly_free(struct status_report_assembly *assembly)
> +{
> + g_hash_table_destroy(assembly->assembly_table);
You should also be g_freeing the assembly structure itself. In general, it is
a very good idea to run valgrind --leak-check=full on the modified binary
before submitting any patches upstream. This helps to identify such issues
early.
And did I mention unit tests? :)
> +}
> +
> +enum ofono_history_sms_status status_report_assembly_report(
> + struct status_report_assembly *assembly,
> + const struct sms *status_report,
> + unsigned int *msg_id)
> +{
> + 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 = NULL;
There's no need to initialize this to NULL.
> + gpointer key;
> + gpointer value;
> + GHashTableIter iter;
> + int i;
> +
> + 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)
> + return OFONO_HISTORY_SMS_STATUS_ERROR;
> +
> + g_hash_table_iter_init(&iter, id_table);
> + while (g_hash_table_iter_next(&iter, &key, &value)) {
> + node = value;
> +
> + if (!(node->mrs[offset] & bit))
> + continue;
> +
> + if (status_report->status_report.st ==
> + SMS_ST_COMPLETED_RECEIVED) {
> + /* mr belongs to this node */
> + node->mrs[offset] ^= bit;
> + *msg_id = node->ofono_msg_id;
> +
> + for (i = 0; i < 8; i++) {
> + /* There are still pending mr(s). */
> + if (node->mrs[i] != 0)
> + return OFONO_HISTORY_SMS_STATUS_PENDING;
> + }
> + }
> + /* No more pending mrs for this node. Remove node from id_table
> + * and free it.
> + */
> + g_hash_table_iter_remove(&iter);
> + /* id_list empty, remove key and value from assembly_table */
> + if (g_hash_table_size(id_table) == 0)
> + g_hash_table_remove(assembly->assembly_table,
> + status_report->status_report.raddr.address);
> +
> + return OFONO_HISTORY_SMS_STATUS_DELIVERED;
You're marking this message as delivered even if a failure status report was
sent. Also, in the case of a failure, you're not providing the message id.
> +void status_report_assembly_add_fragment(struct status_report_assembly
> + *assembly, unsigned int *msg_id,
Please don't put the assembly on a separate line. The var name should be on
the same line as the type.
msg_id should simply be unsigned int msg_id. This is not an in/out argument.
> + struct sms_address *to,
const struct sms_address *to please.
> + unsigned char mr, time_t expiration)
> +{
> + 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);
I'd structure the code like this:
if (id_table == NULL) {
what is in the ... else clause
return;
}
node = g_hash_table_lookup();
if (node) {
return;
}
...
This makes the code much more readable. In general, avoid nested if
statements if possible.
> +
> + if (id_table) {
> + node = g_hash_table_lookup(id_table, msg_id);
> +
> + if (node) {
> + node->mrs[offset] |= bit;
> + node->expiration = expiration;
> + } else {
> + id_table_key = g_new0(unsigned int, 1);
> + node = g_new0(struct id_table_node, 1);
> + node->to = *to;
> + node->ofono_msg_id = *msg_id;
> + node->mrs[offset] |= bit;
> + node->expiration = expiration;
> +
> + *id_table_key = *msg_id;
> + g_hash_table_insert(id_table, id_table_key, node);
> + }
> + } else {
> + 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->ofono_msg_id = *msg_id;
> + node->mrs[offset] |= bit;
> + node->expiration = expiration;
> +
> + *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)
> + return;
> +
> + g_strlcpy(assembly_table_key, to->address, sizeof(to->address));
> +
> + g_hash_table_insert(assembly->assembly_table,
> + assembly_table_key, id_table);
> + }
I see one problem with this function, namely that under some bizarre
circumstances, the status report might come back before additional fragments
have been added. So this function should also take a num_fragments argument
and keep track of how many fragment status reports were actually received.
This gets a bit tricky when a failure is reported before the entire set of
fragments has been submitted...
> +struct id_table_node {
> + struct sms_address to;
> + unsigned int ofono_msg_id;
Why are you storing the message id when it is also the key for the hash table?
> + unsigned int mrs[8];
> + time_t expiration;
> +};
> +
Regards,
-Denis
More information about the ofono
mailing list