This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/OpenBSC@lists.osmocom.org/.
Alexander Chemeris alexander.chemeris at gmail.comHi Holger,
Thank you for improving robustness of the code. I looked through it and it
looks good to me.
Please let me know when you merge to the master so I could rebase the SMS
validity decoding code on top of it and submit it for review.
On Sat, Mar 8, 2014 at 1:54 PM, Holger Hans Peter Freyther <
holger at freyther.de> wrote:
> From: Holger Hans Peter Freyther <holger at moiji-mobile.com>
>
> This is mostly based on Alexander's migration code. The code
> adds transaction handling and some sanity checks and cleanups
> to the code. We made the decision to fork the sms_from_result
> method and freeze it to that version. This way sms_from_result
> can move forward without having to deal with legacy.
> ---
> openbsc/src/libbsc/gsm_subscriber_base.c | 6 +
> openbsc/src/libmsc/db.c | 209
> ++++++++++++++++++++++++++++---
> 2 files changed, 199 insertions(+), 16 deletions(-)
>
> diff --git a/openbsc/src/libbsc/gsm_subscriber_base.c
> b/openbsc/src/libbsc/gsm_subscriber_base.c
> index 5755687..5e00443 100644
> --- a/openbsc/src/libbsc/gsm_subscriber_base.c
> +++ b/openbsc/src/libbsc/gsm_subscriber_base.c
> @@ -72,6 +72,12 @@ static void subscr_free(struct gsm_subscriber *subscr)
> talloc_free(subscr);
> }
>
> +void subscr_direct_free(struct gsm_subscriber *subscr)
> +{
> + OSMO_ASSERT(subscr->use_count == 1);
> + subscr_free(subscr);
> +}
> +
> struct gsm_subscriber *subscr_get(struct gsm_subscriber *subscr)
> {
> subscr->use_count++;
> diff --git a/openbsc/src/libmsc/db.c b/openbsc/src/libmsc/db.c
> index 2351485..3b92691 100644
> --- a/openbsc/src/libmsc/db.c
> +++ b/openbsc/src/libmsc/db.c
> @@ -38,23 +38,42 @@
> #include <osmocom/core/statistics.h>
> #include <osmocom/core/rate_ctr.h>
>
> +/* Semi-Private-Interface (SPI) for the subscriber code */
> +void subscr_direct_free(struct gsm_subscriber *subscr);
> +
> static char *db_basename = NULL;
> static char *db_dirname = NULL;
> static dbi_conn conn;
>
> -#define SCHEMA_REVISION "3"
> +#define SCHEMA_REVISION "4"
> +
> +enum {
> + SCHEMA_META,
> + INSERT_META,
> + SCHEMA_SUBSCRIBER,
> + SCHEMA_AUTH,
> + SCHEMA_EQUIPMENT,
> + SCHEMA_EQUIPMENT_WATCH,
> + SCHEMA_SMS,
> + SCHEMA_VLR,
> + SCHEMA_APDU,
> + SCHEMA_COUNTERS,
> + SCHEMA_RATE,
> + SCHEMA_AUTHKEY,
> + SCHEMA_AUTHLAST,
> +};
>
> -static char *create_stmts[] = {
> - "CREATE TABLE IF NOT EXISTS Meta ("
> +static const char *create_stmts[] = {
> + [SCHEMA_META] = "CREATE TABLE IF NOT EXISTS Meta ("
> "id INTEGER PRIMARY KEY AUTOINCREMENT, "
> "key TEXT UNIQUE NOT NULL, "
> "value TEXT NOT NULL"
> ")",
> - "INSERT OR IGNORE INTO Meta "
> + [INSERT_META] = "INSERT OR IGNORE INTO Meta "
> "(key, value) "
> "VALUES "
> "('revision', " SCHEMA_REVISION ")",
> - "CREATE TABLE IF NOT EXISTS Subscriber ("
> + [SCHEMA_SUBSCRIBER] = "CREATE TABLE IF NOT EXISTS Subscriber ("
> "id INTEGER PRIMARY KEY AUTOINCREMENT, "
> "created TIMESTAMP NOT NULL, "
> "updated TIMESTAMP NOT NULL, "
> @@ -66,13 +85,13 @@ static char *create_stmts[] = {
> "lac INTEGER NOT NULL DEFAULT 0, "
> "expire_lu TIMESTAMP DEFAULT NULL"
> ")",
> - "CREATE TABLE IF NOT EXISTS AuthToken ("
> + [SCHEMA_AUTH] = "CREATE TABLE IF NOT EXISTS AuthToken ("
> "id INTEGER PRIMARY KEY AUTOINCREMENT, "
> "subscriber_id INTEGER UNIQUE NOT NULL, "
> "created TIMESTAMP NOT NULL, "
> "token TEXT UNIQUE NOT NULL"
> ")",
> - "CREATE TABLE IF NOT EXISTS Equipment ("
> + [SCHEMA_EQUIPMENT] = "CREATE TABLE IF NOT EXISTS Equipment ("
> "id INTEGER PRIMARY KEY AUTOINCREMENT, "
> "created TIMESTAMP NOT NULL, "
> "updated TIMESTAMP NOT NULL, "
> @@ -82,7 +101,7 @@ static char *create_stmts[] = {
> "classmark3 BLOB, "
> "imei NUMERIC UNIQUE NOT NULL"
> ")",
> - "CREATE TABLE IF NOT EXISTS EquipmentWatch ("
> + [SCHEMA_EQUIPMENT_WATCH] = "CREATE TABLE IF NOT EXISTS
> EquipmentWatch ("
> "id INTEGER PRIMARY KEY AUTOINCREMENT, "
> "created TIMESTAMP NOT NULL, "
> "updated TIMESTAMP NOT NULL, "
> @@ -90,7 +109,7 @@ static char *create_stmts[] = {
> "equipment_id NUMERIC NOT NULL, "
> "UNIQUE (subscriber_id, equipment_id) "
> ")",
> - "CREATE TABLE IF NOT EXISTS SMS ("
> + [SCHEMA_SMS] = "CREATE TABLE IF NOT EXISTS SMS ("
> /* metadata, not part of sms */
> "id INTEGER PRIMARY KEY AUTOINCREMENT, "
> "created TIMESTAMP NOT NULL, "
> @@ -114,39 +133,39 @@ static char *create_stmts[] = {
> "header BLOB, " /* UD Header */
> "text TEXT " /* decoded UD after UDH */
> ")",
> - "CREATE TABLE IF NOT EXISTS VLR ("
> + [SCHEMA_VLR] = "CREATE TABLE IF NOT EXISTS VLR ("
> "id INTEGER PRIMARY KEY AUTOINCREMENT, "
> "created TIMESTAMP NOT NULL, "
> "updated TIMESTAMP NOT NULL, "
> "subscriber_id NUMERIC UNIQUE NOT NULL, "
> "last_bts NUMERIC NOT NULL "
> ")",
> - "CREATE TABLE IF NOT EXISTS ApduBlobs ("
> + [SCHEMA_APDU] = "CREATE TABLE IF NOT EXISTS ApduBlobs ("
> "id INTEGER PRIMARY KEY AUTOINCREMENT, "
> "created TIMESTAMP NOT NULL, "
> "apdu_id_flags INTEGER NOT NULL, "
> "subscriber_id INTEGER NOT NULL, "
> "apdu BLOB "
> ")",
> - "CREATE TABLE IF NOT EXISTS Counters ("
> + [SCHEMA_COUNTERS] = "CREATE TABLE IF NOT EXISTS Counters ("
> "id INTEGER PRIMARY KEY AUTOINCREMENT, "
> "timestamp TIMESTAMP NOT NULL, "
> "value INTEGER NOT NULL, "
> "name TEXT NOT NULL "
> ")",
> - "CREATE TABLE IF NOT EXISTS RateCounters ("
> + [SCHEMA_RATE] = "CREATE TABLE IF NOT EXISTS RateCounters ("
> "id INTEGER PRIMARY KEY AUTOINCREMENT, "
> "timestamp TIMESTAMP NOT NULL, "
> "value INTEGER NOT NULL, "
> "name TEXT NOT NULL, "
> "idx INTEGER NOT NULL "
> ")",
> - "CREATE TABLE IF NOT EXISTS AuthKeys ("
> + [SCHEMA_AUTHKEY] = "CREATE TABLE IF NOT EXISTS AuthKeys ("
> "subscriber_id INTEGER PRIMARY KEY, "
> "algorithm_id INTEGER NOT NULL, "
> "a3a8_ki BLOB "
> ")",
> - "CREATE TABLE IF NOT EXISTS AuthLastTuples ("
> + [SCHEMA_AUTHLAST] = "CREATE TABLE IF NOT EXISTS AuthLastTuples ("
> "subscriber_id INTEGER PRIMARY KEY, "
> "issued TIMESTAMP NOT NULL, "
> "use_count INTEGER NOT NULL DEFAULT 0, "
> @@ -185,12 +204,164 @@ static int update_db_revision_2(void)
> "WHERE key = 'revision'");
> if (!result) {
> LOGP(DDB, LOGL_ERROR,
> - "Failed set new revision (upgrade vom rev 2).\n");
> + "Failed to update DB schema revision (upgrade from
> rev 2).\n");
> + return -EINVAL;
> + }
> + dbi_result_free(result);
> +
> + return 0;
> +}
> +
> +/**
> + * Copied from the normal sms_from_result_v3 to avoid having
> + * to make sure that the real routine will remain backward
> + * compatible.
> + */
> +static struct gsm_sms *sms_from_result_v3(dbi_result result)
> +{
> + struct gsm_sms *sms = sms_alloc();
> + long long unsigned int sender_id;
> + struct gsm_subscriber *sender;
> + const char *text, *daddr;
> + const unsigned char *user_data;
> + char buf[32];
> +
> + if (!sms)
> + return NULL;
> +
> + sms->id = dbi_result_get_ulonglong(result, "id");
> +
> + sender_id = dbi_result_get_ulonglong(result, "sender_id");
> + snprintf(buf, sizeof(buf), "%llu", sender_id);
> + sender = db_get_subscriber(GSM_SUBSCRIBER_ID, buf);
> + OSMO_ASSERT(sender);
> + strncpy(sms->src.addr, sender->extension, sizeof(sms->src.addr)-1);
> + subscr_direct_free(sender);
> + sender = NULL;
> +
> + sms->reply_path_req = dbi_result_get_uint(result,
> "reply_path_req");
> + sms->status_rep_req = dbi_result_get_uint(result,
> "status_rep_req");
> + sms->ud_hdr_ind = dbi_result_get_uint(result, "ud_hdr_ind");
> + sms->protocol_id = dbi_result_get_uint(result, "protocol_id");
> + sms->data_coding_scheme = dbi_result_get_uint(result,
> + "data_coding_scheme");
> +
> + daddr = dbi_result_get_string(result, "dest_addr");
> + if (daddr) {
> + strncpy(sms->dst.addr, daddr, sizeof(sms->dst.addr));
> + sms->dst.addr[sizeof(sms->dst.addr)-1] = '\0';
> + }
> +
> + sms->user_data_len = dbi_result_get_field_length(result,
> "user_data");
> + user_data = dbi_result_get_binary(result, "user_data");
> + if (sms->user_data_len > sizeof(sms->user_data))
> + sms->user_data_len = (uint8_t) sizeof(sms->user_data);
> + memcpy(sms->user_data, user_data, sms->user_data_len);
> +
> + text = dbi_result_get_string(result, "text");
> + if (text) {
> + strncpy(sms->text, text, sizeof(sms->text));
> + sms->text[sizeof(sms->text)-1] = '\0';
> + }
> + return sms;
> +}
> +
> +static int update_db_revision_3(void)
> +{
> + dbi_result result;
> + struct gsm_sms *sms;
> +
> + result = dbi_conn_query(conn, "BEGIN EXCLUSIVE TRANSACTION");
> + if (!result) {
> + LOGP(DDB, LOGL_ERROR,
> + "Failed to begin transaction (upgrade from rev
> 3)\n");
> return -EINVAL;
> }
> dbi_result_free(result);
>
> + /* Rename old SMS table to be able create a new one */
> + result = dbi_conn_query(conn, "ALTER TABLE SMS RENAME TO SMS_3");
> + if (!result) {
> + LOGP(DDB, LOGL_ERROR,
> + "Failed to rename the old SMS table (upgrade from rev
> 3).\n");
> + goto rollback;
> + }
> + dbi_result_free(result);
> +
> + /* Create new SMS table with all the bells and whistles! */
> + result = dbi_conn_query(conn, create_stmts[SCHEMA_SMS]);
> + if (!result) {
> + LOGP(DDB, LOGL_ERROR,
> + "Failed to create a new SMS table (upgrade from rev
> 3).\n");
> + goto rollback;
> + }
> + dbi_result_free(result);
> +
> + /* Cycle through old messages and convert them to the new format */
> + result = dbi_conn_queryf(conn, "SELECT * FROM SMS_3");
> + if (!result) {
> + LOGP(DDB, LOGL_ERROR,
> + "Failed fetch messages from the old SMS table
> (upgrade from rev 3).\n");
> + goto rollback;
> + }
> + while (dbi_result_next_row(result)) {
> + sms = sms_from_result_v3(result);
> + if (db_sms_store(sms) != 0) {
> + LOGP(DDB, LOGL_ERROR, "Failed to store message to
> the new SMS table(upgrade from rev 3).\n");
> + sms_free(sms);
> + dbi_result_free(result);
> + goto rollback;
> + }
> + sms_free(sms);
> + }
> + dbi_result_free(result);
> +
> + /* Remove the temporary table */
> + result = dbi_conn_query(conn, "DROP TABLE SMS_3");
> + if (!result) {
> + LOGP(DDB, LOGL_ERROR,
> + "Failed to drop the old SMS table (upgrade from rev
> 3).\n");
> + goto rollback;
> + }
> + dbi_result_free(result);
> +
> + /* We're done. Bump DB Meta revision to 4 */
> + result = dbi_conn_query(conn,
> + "UPDATE Meta "
> + "SET value = '4' "
> + "WHERE key = 'revision'");
> + if (!result) {
> + LOGP(DDB, LOGL_ERROR,
> + "Failed to update DB schema revision (upgrade from
> rev 3).\n");
> + goto rollback;
> + }
> + dbi_result_free(result);
> +
> + result = dbi_conn_query(conn, "COMMIT TRANSACTION");
> + if (!result) {
> + LOGP(DDB, LOGL_ERROR,
> + "Failed to commit the transaction (upgrade from
> rev 3)\n");
> + return -EINVAL;
> + }
> +
> + /* Shrink DB file size by actually wiping out SMS_3 table data */
> + result = dbi_conn_query(conn, "VACUUM");
> + if (!result)
> + LOGP(DDB, LOGL_ERROR,
> + "VACUUM failed. Ignoring it (upgrade from rev
> 3).\n");
> + else
> + dbi_result_free(result);
> +
> return 0;
> +
> +rollback:
> + result = dbi_conn_query(conn, "ROLLBACK TRANSACTION");
> + if (!result)
> + LOGP(DDB, LOGL_ERROR,
> + "Rollback failed (upgrade from rev 3).\n");
> + else
> + dbi_result_free(result);
> + return -EINVAL;
> }
>
> static int check_db_revision(void)
> @@ -218,6 +389,12 @@ static int check_db_revision(void)
> dbi_result_free(result);
> return -EINVAL;
> }
> + } else if (!strcmp(rev_s, "3")) {
> + if (update_db_revision_3()) {
> + LOGP(DDB, LOGL_FATAL, "Failed to update database
> from schema revision '%s'.\n", rev_s);
> + dbi_result_free(result);
> + return -EINVAL;
> + }
> } else if (!strcmp(rev_s, SCHEMA_REVISION)) {
> /* everything is fine */
> } else {
> --
> 1.9.0
>
>
>
--
Regards,
Alexander Chemeris.
CEO, Fairwaves, Inc. / ООО УмРадио
https://fairwaves.co
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/openbsc/attachments/20140308/a9106da4/attachment.htm>