mirror of git://git.sysmocom.de/ofono
smsutil: storing/loading sms status report over reboot
This commit is contained in:
parent
2a96c7cf29
commit
95fc8bee72
159
src/smsutil.c
159
src/smsutil.c
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue