smsutil: storing/loading sms status report over reboot

This commit is contained in:
Petteri Tikander 2010-09-01 18:59:30 +03:00 committed by Denis Kenzior
parent 2a96c7cf29
commit 95fc8bee72
2 changed files with 157 additions and 4 deletions

View File

@ -45,6 +45,9 @@
#define SMS_BACKUP_PATH_DIR SMS_BACKUP_PATH "/%s-%i-%i"
#define SMS_BACKUP_PATH_FILE SMS_BACKUP_PATH_DIR "/%03i"
#define SMS_SR_BACKUP_PATH STORAGEDIR "/%s/sms_sr"
#define SMS_SR_BACKUP_PATH_FILE SMS_SR_BACKUP_PATH "/%s-%i"
#define SMS_ADDR_FMT "%24[0-9A-F]"
static GSList *sms_assembly_add_fragment_backup(struct sms_assembly *assembly,
@ -2643,20 +2646,152 @@ void sms_assembly_expire(struct sms_assembly *assembly, time_t before)
}
}
static void sr_assembly_load_backup(GHashTable *assembly_table,
const char *imsi,
const struct dirent *addr_dir)
{
struct sms_address addr;
DECLARE_SMS_ADDR_STR(straddr);
struct id_table_node *node;
GHashTable *id_table;
int r;
char *assembly_table_key;
unsigned int *id_table_key;
unsigned int msg_id;
if (addr_dir->d_type != DT_REG)
return;
/*
* All SMS-messages under the same IMSI-code are
* included in the same directory.
* So, SMS-address and message ID are included in the same file name
* Max of SMS address size is 12 bytes, hex encoded
*/
if (sscanf(addr_dir->d_name, SMS_ADDR_FMT "-%u",
straddr, &msg_id) < 2)
return;
if (sms_assembly_extract_address(straddr, &addr) == FALSE)
return;
node = g_new0(struct id_table_node, 1);
r = read_file((unsigned char *) node,
sizeof(struct id_table_node),
SMS_SR_BACKUP_PATH "/%s",
imsi, addr_dir->d_name);
if (r < 0) {
g_free(node);
return;
}
id_table = g_hash_table_lookup(assembly_table,
sms_address_to_string(&addr));
/* Create hashtable keyed by the to address if required */
if (id_table == NULL) {
id_table = g_hash_table_new_full(g_int_hash, g_int_equal,
g_free, g_free);
assembly_table_key = g_strdup(sms_address_to_string(&addr));
g_hash_table_insert(assembly_table, assembly_table_key,
id_table);
}
/* Node ready, create key and add them to the table */
id_table_key = g_new0(unsigned int, 1);
*id_table_key = msg_id;
g_hash_table_insert(id_table, id_table_key, node);
}
struct status_report_assembly *status_report_assembly_new(const char *imsi)
{
char *path;
int len;
struct dirent **addresses;
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)
if (imsi) {
ret->imsi = imsi;
/* Restore state from backup */
path = g_strdup_printf(SMS_SR_BACKUP_PATH, imsi);
len = scandir(path, &addresses, NULL, alphasort);
g_free(path);
if (len < 0)
return ret;
/*
* Go through different addresses. Each address can relate to
* 1-n msg_ids.
*/
while (len--) {
sr_assembly_load_backup(ret->assembly_table, imsi,
addresses[len]);
g_free(addresses[len]);
}
g_free(addresses);
}
return ret;
}
static gboolean sr_assembly_add_fragment_backup(const char *imsi,
const struct id_table_node *node,
const struct sms_address *addr,
unsigned int msg_id)
{
int len = sizeof(struct id_table_node);
DECLARE_SMS_ADDR_STR(straddr);
if (!imsi)
return FALSE;
if (sms_address_to_hex_string(addr, straddr) == FALSE)
return FALSE;
/* storagedir/%s/sms_sr/%s-%i */
if (write_file((unsigned char *) node, len, SMS_BACKUP_MODE,
SMS_SR_BACKUP_PATH_FILE, imsi,
straddr, msg_id) != len)
return FALSE;
return TRUE;
}
static gboolean sr_assembly_remove_fragment_backup(const char *imsi,
const struct id_table_node *node,
const struct sms_address *addr,
unsigned int msg_id)
{
char *path;
DECLARE_SMS_ADDR_STR(straddr);
if (!imsi)
return FALSE;
if (sms_address_to_hex_string(addr, straddr) == FALSE)
return FALSE;
path = g_strdup_printf(SMS_SR_BACKUP_PATH_FILE, imsi, straddr, msg_id);
unlink(path);
g_free(path);
return TRUE;
}
void status_report_assembly_free(struct status_report_assembly *assembly)
{
g_hash_table_destroy(assembly->assembly_table);
@ -2699,6 +2834,7 @@ gboolean status_report_assembly_report(struct status_report_assembly *assembly,
GHashTableIter iter;
gboolean pending;
int i;
unsigned int msg_id;
/* We ignore temporary or tempfinal status reports */
if (sr_st_to_delivered(status_report->status_report.st,
@ -2744,14 +2880,30 @@ gboolean status_report_assembly_report(struct status_report_assembly *assembly,
}
}
if (pending == TRUE && node->deliverable == TRUE)
msg_id = *(unsigned int *) key;
if (pending == TRUE && node->deliverable == TRUE) {
/*
* More status reports expected, and already received
* reports completed. Update backup file.
*/
sr_assembly_add_fragment_backup(
assembly->imsi, node,
&status_report->status_report.raddr,
msg_id);
return FALSE;
}
if (out_delivered)
*out_delivered = node->deliverable;
if (out_id)
*out_id = *((unsigned int *) key);
*out_id = msg_id;
sr_assembly_remove_fragment_backup(assembly->imsi, node,
&status_report->status_report.raddr,
msg_id);
g_hash_table_iter_remove(&iter);
@ -2805,6 +2957,7 @@ void status_report_assembly_add_fragment(
node->mrs[offset] |= bit;
node->expiration = expiration;
node->sent_mrs++;
sr_assembly_add_fragment_backup(assembly->imsi, node, to, msg_id);
}
void status_report_assembly_expire(struct status_report_assembly *assembly,

View File

@ -370,7 +370,7 @@ struct id_table_node {
unsigned char total_mrs;
unsigned char sent_mrs;
gboolean deliverable;
};
} __attribute__((packed));
struct status_report_assembly {
const char *imsi;