diff --git a/configure.ac b/configure.ac index 10c3a21ff..6e32ae620 100644 --- a/configure.ac +++ b/configure.ac @@ -36,7 +36,6 @@ if test "x$PKG_CONFIG_INSTALLED" = "xno"; then fi PKG_PROG_PKG_CONFIG([0.20]) -PKG_CHECK_MODULES(LIBSQLITE3, sqlite3) PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.6.0) PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.6.0) PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.6.0) diff --git a/contrib/osmo-msc.spec.in b/contrib/osmo-msc.spec.in index 9c342f863..146d57e81 100644 --- a/contrib/osmo-msc.spec.in +++ b/contrib/osmo-msc.spec.in @@ -32,7 +32,6 @@ BuildRequires: libtool BuildRequires: systemd-rpm-macros %endif BuildRequires: pkgconfig >= 0.20 -BuildRequires: pkgconfig(sqlite3) BuildRequires: pkgconfig(libcrypto) >= 0.9.5 BuildRequires: pkgconfig(libosmo-gsup-client) >= 1.4.0 BuildRequires: pkgconfig(libosmo-mgcp-client) >= 1.9.0 diff --git a/debian/control b/debian/control index 0b26c8e50..88bd09d69 100644 --- a/debian/control +++ b/debian/control @@ -9,7 +9,6 @@ Build-Depends: debhelper (>=9), automake, libtool, pkg-config, - libsqlite3-dev, libsctp-dev, libtalloc-dev, libsmpp34-dev (>= 1.14.0), diff --git a/include/osmocom/msc/Makefile.am b/include/osmocom/msc/Makefile.am index faf1048dc..b3892ed9b 100644 --- a/include/osmocom/msc/Makefile.am +++ b/include/osmocom/msc/Makefile.am @@ -1,7 +1,6 @@ noinst_HEADERS = \ call_leg.h \ cell_id_list.h \ - db.h \ debug.h \ e_link.h \ gsm_04_08.h \ @@ -47,6 +46,7 @@ noinst_HEADERS = \ silent_call.h \ smpp.h \ sms_queue.h \ + sms_storage.h \ transaction.h \ vlr.h \ vlr_sgs.h \ diff --git a/include/osmocom/msc/db.h b/include/osmocom/msc/db.h deleted file mode 100644 index fc1781bd6..000000000 --- a/include/osmocom/msc/db.h +++ /dev/null @@ -1,56 +0,0 @@ -/* (C) 2008 by Jan Luebbe - * (C) 2009 by Holger Hans Peter Freyther - * (C) 2022 by Harald Welte - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -#ifndef _DB_H -#define _DB_H - -#include - -#include "gsm_subscriber.h" - -#define VSUB_USE_SMS_RECEIVER "SMS-receiver" - -struct gsm_network; -struct gsm_sms; - -/* one time initialisation */ -int db_init(void *ctx, const char *fname, bool enable_sqlite_logging); -int db_prepare(void); -int db_fini(void); - -/* SMS store-and-forward */ -int db_sms_store(struct gsm_sms *sms); -struct gsm_sms *db_sms_get(struct gsm_network *net, unsigned long long id); -struct gsm_sms *db_sms_get_next_unsent(struct gsm_network *net, - unsigned long long min_sms_id, - int max_failed); -struct gsm_sms *db_sms_get_next_unsent_rr_msisdn(struct gsm_network *net, - const char *last_msisdn, - int max_failed); -struct gsm_sms *db_sms_get_unsent_for_subscr(struct vlr_subscr *vsub, - int max_failed); -int db_sms_mark_delivered(struct gsm_sms *sms); -int db_sms_inc_deliver_attempts(struct gsm_sms *sms); -int db_sms_delete_by_msisdn(const char *msisdn); -int db_sms_delete_sent_message_by_id(unsigned long long sms_id); -int db_sms_delete_expired_message_by_id(unsigned long long sms_id); -void db_sms_delete_oldest_expired_message(void); - -#endif /* _DB_H */ diff --git a/include/osmocom/msc/gsm_data.h b/include/osmocom/msc/gsm_data.h index 55ee73185..465d2f41e 100644 --- a/include/osmocom/msc/gsm_data.h +++ b/include/osmocom/msc/gsm_data.h @@ -182,6 +182,7 @@ struct gsm_network { } rrlp; struct gsm_sms_queue *sms_queue; + struct sms_storage_inst *sms_storage; /* The "SMS over GSUP" kill-switch that basically breaks internal * SMS routing (i.e. SQLite DB and SMPP), and enables forwarding @@ -318,6 +319,8 @@ struct gsm_sms { uint8_t user_data_len; uint8_t user_data[SMS_TEXT_SIZE]; + int failed_attempts; + char text[SMS_TEXT_SIZE]; }; diff --git a/include/osmocom/msc/sms_queue.h b/include/osmocom/msc/sms_queue.h index a6e6aebd3..c51519cd4 100644 --- a/include/osmocom/msc/sms_queue.h +++ b/include/osmocom/msc/sms_queue.h @@ -21,6 +21,7 @@ struct sms_queue_config *sms_queue_cfg_alloc(void *ctx); #define VSUB_USE_SMS_PENDING "SMS-pending" #define MSC_A_USE_SMS_PENDING "SMS-pending" +#define VSUB_USE_SMS_RECEIVER "SMS-receiver" int sms_queue_start(struct gsm_network *net); int sms_queue_trigger(struct gsm_sms_queue *); diff --git a/include/osmocom/msc/vlr.h b/include/osmocom/msc/vlr.h index d23661db0..8c859333e 100644 --- a/include/osmocom/msc/vlr.h +++ b/include/osmocom/msc/vlr.h @@ -199,6 +199,10 @@ struct vlr_subscr { struct osmo_plmn_id last_eutran_plmn; } sgs; + struct { + struct llist_head pending; + } sms; + struct osmo_gsm48_classmark classmark; }; diff --git a/src/libmsc/Makefile.am b/src/libmsc/Makefile.am index e673a4bd5..4c6f4584d 100644 --- a/src/libmsc/Makefile.am +++ b/src/libmsc/Makefile.am @@ -32,7 +32,6 @@ libmsc_a_SOURCES = \ cell_id_list.c \ sccp_ran.c \ msc_vty.c \ - db.c \ e_link.c \ gsm_04_08.c \ gsm_04_08_cc.c \ diff --git a/src/libmsc/ctrl_commands.c b/src/libmsc/ctrl_commands.c index 87e9afdd7..d0ea92302 100644 --- a/src/libmsc/ctrl_commands.c +++ b/src/libmsc/ctrl_commands.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include diff --git a/src/libmsc/db.c b/src/libmsc/db.c deleted file mode 100644 index 07081d54f..000000000 --- a/src/libmsc/db.c +++ /dev/null @@ -1,1036 +0,0 @@ -/* Simple HLR/VLR database backend using sqlite3 */ -/* (C) 2008 by Jan Luebbe - * (C) 2009 by Holger Hans Peter Freyther - * (C) 2009,2022 by Harald Welte - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -enum stmt_idx { - DB_STMT_SMS_STORE, - DB_STMT_SMS_GET, - DB_STMT_SMS_GET_NEXT_UNSENT, - DB_STMT_SMS_GET_UNSENT_FOR_SUBSCR, - DB_STMT_SMS_GET_NEXT_UNSENT_RR_MSISDN, - DB_STMT_SMS_MARK_DELIVERED, - DB_STMT_SMS_INC_DELIVER_ATTEMPTS, - DB_STMT_SMS_DEL_BY_MSISDN, - DB_STMT_SMS_DEL_BY_ID, - DB_STMT_SMS_DEL_EXPIRED, - DB_STMT_SMS_GET_VALID_UNTIL_BY_ID, - DB_STMT_SMS_GET_OLDEST_EXPIRED, - _NUM_DB_STMT -}; - -struct db_context { - char *fname; - sqlite3 *db; - sqlite3_stmt *stmt[_NUM_DB_STMT]; -}; - -static struct db_context *g_dbc; - - -/*********************************************************************** - * DATABASE SCHEMA AND MIGRATION - ***********************************************************************/ - -#define SCHEMA_REVISION "5" - -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 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_META] = "INSERT OR IGNORE INTO Meta " - "(key, value) " - "VALUES " - "('revision', " SCHEMA_REVISION ")", - [SCHEMA_SUBSCRIBER] = "CREATE TABLE IF NOT EXISTS Subscriber (" - "id INTEGER PRIMARY KEY AUTOINCREMENT, " - "created TIMESTAMP NOT NULL, " - "updated TIMESTAMP NOT NULL, " - "imsi NUMERIC UNIQUE NOT NULL, " - "name TEXT, " - "extension TEXT UNIQUE, " - "authorized INTEGER NOT NULL DEFAULT 0, " - "tmsi TEXT UNIQUE, " - "lac INTEGER NOT NULL DEFAULT 0, " - "expire_lu TIMESTAMP DEFAULT NULL" - ")", - [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" - ")", - [SCHEMA_EQUIPMENT] = "CREATE TABLE IF NOT EXISTS Equipment (" - "id INTEGER PRIMARY KEY AUTOINCREMENT, " - "created TIMESTAMP NOT NULL, " - "updated TIMESTAMP NOT NULL, " - "name TEXT, " - "classmark1 NUMERIC, " - "classmark2 BLOB, " - "classmark3 BLOB, " - "imei NUMERIC UNIQUE NOT NULL" - ")", - [SCHEMA_EQUIPMENT_WATCH] = "CREATE TABLE IF NOT EXISTS EquipmentWatch (" - "id INTEGER PRIMARY KEY AUTOINCREMENT, " - "created TIMESTAMP NOT NULL, " - "updated TIMESTAMP NOT NULL, " - "subscriber_id NUMERIC NOT NULL, " - "equipment_id NUMERIC NOT NULL, " - "UNIQUE (subscriber_id, equipment_id) " - ")", - [SCHEMA_SMS] = "CREATE TABLE IF NOT EXISTS SMS (" - /* metadata, not part of sms */ - "id INTEGER PRIMARY KEY AUTOINCREMENT, " - "created TIMESTAMP NOT NULL, " - "sent TIMESTAMP, " - "deliver_attempts INTEGER NOT NULL DEFAULT 0, " - /* data directly copied/derived from SMS */ - "valid_until TIMESTAMP, " - "reply_path_req INTEGER NOT NULL, " - "status_rep_req INTEGER NOT NULL, " - "is_report INTEGER NOT NULL, " - "msg_ref INTEGER NOT NULL, " - "protocol_id INTEGER NOT NULL, " - "data_coding_scheme INTEGER NOT NULL, " - "ud_hdr_ind INTEGER NOT NULL, " - "src_addr TEXT NOT NULL, " - "src_ton INTEGER NOT NULL, " - "src_npi INTEGER NOT NULL, " - "dest_addr TEXT NOT NULL, " - "dest_ton INTEGER NOT NULL, " - "dest_npi INTEGER NOT NULL, " - "user_data BLOB, " /* TP-UD */ - /* additional data, interpreted from SMS */ - "header BLOB, " /* UD Header */ - "text TEXT " /* decoded UD after UDH */ - ")", - [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 " - ")", - [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 " - ")", - [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 " - ")", - [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 " - ")", - [SCHEMA_AUTHKEY] = "CREATE TABLE IF NOT EXISTS AuthKeys (" - "subscriber_id INTEGER PRIMARY KEY, " - "algorithm_id INTEGER NOT NULL, " - "a3a8_ki BLOB " - ")", - [SCHEMA_AUTHLAST] = "CREATE TABLE IF NOT EXISTS AuthLastTuples (" - "subscriber_id INTEGER PRIMARY KEY, " - "issued TIMESTAMP NOT NULL, " - "use_count INTEGER NOT NULL DEFAULT 0, " - "key_seq INTEGER NOT NULL, " - "rand BLOB NOT NULL, " - "sres BLOB NOT NULL, " - "kc BLOB NOT NULL " - ")", -}; - -/*********************************************************************** - * PREPARED STATEMENTS - ***********************************************************************/ - -/* don't change this order as the code assumes this ordering when dereferencing - * database query results! */ -#define SEL_COLUMNS \ - "id," \ - "strftime('%s',created)," \ - "sent," \ - "deliver_attempts," \ - "strftime('%s', valid_until)," \ - "reply_path_req," \ - "status_rep_req," \ - "is_report," \ - "msg_ref," \ - "protocol_id," \ - "data_coding_scheme," \ - "ud_hdr_ind," \ - "src_addr," \ - "src_ton," \ - "src_npi," \ - "dest_addr," \ - "dest_ton," \ - "dest_npi," \ - "user_data," \ - "header," \ - "text" - -enum db_sms_column_idx { - COL_ID, - COL_CREATED, - COL_SENT, - COL_DELIVER_ATTEMPTS, - COL_VALID_UNTIL, - COL_REPLY_PATH_REQ, - COL_STATUS_REP_REQ, - COL_IS_REPORT, - COL_MSG_REF, - COL_PROTOCOL_ID, - COL_DATA_CODING_SCHEME, - COL_UD_HDR_IND, - COL_SRC_ADDR, - COL_SRC_TON, - COL_SRC_NPI, - COL_DEST_ADDR, - COL_DEST_TON, - COL_DEST_NPI, - COL_USER_DATA, - COL_HEADER, - COL_TEXT, -}; - -static const char *stmt_sql[] = { - [DB_STMT_SMS_STORE] = - "INSERT INTO SMS " - "(created, valid_until, reply_path_req, status_rep_req, is_report, " - " msg_ref, protocol_id, data_coding_scheme, ud_hdr_ind, user_data, text, " - " dest_addr, dest_ton, dest_npi, src_addr, src_ton, src_npi) " - "VALUES " - "(datetime($created, 'unixepoch'), datetime($valid_until, 'unixepoch'), " - "$reply_path_req, $status_rep_req, $is_report, " - "$msg_ref, $protocol_id, $data_coding_scheme, $ud_hdr_ind, $user_data, $text, " - "$dest_addr, $dest_ton, $dest_npi, $src_addr, $src_ton, $src_npi)", - [DB_STMT_SMS_GET] = "SELECT " SEL_COLUMNS " FROM SMS WHERE SMS.id = $id", - [DB_STMT_SMS_GET_NEXT_UNSENT] = - "SELECT " SEL_COLUMNS " FROM SMS" - " WHERE sent IS NULL" - " AND id >= $id" - " AND deliver_attempts <= $attempts" - " ORDER BY id LIMIT 1", - [DB_STMT_SMS_GET_UNSENT_FOR_SUBSCR] = - "SELECT " SEL_COLUMNS " FROM SMS" - " WHERE sent IS NULL" - " AND dest_addr = $dest_addr" - " AND deliver_attempts <= $attempts" - " ORDER BY id LIMIT 1", - [DB_STMT_SMS_GET_NEXT_UNSENT_RR_MSISDN] = - "SELECT " SEL_COLUMNS " FROM SMS" - " WHERE sent IS NULL" - " AND dest_addr > $dest_addr" - " AND deliver_attempts <= $attempts" - " ORDER BY dest_addr, id LIMIT 1", - [DB_STMT_SMS_MARK_DELIVERED] = - "UPDATE SMS " - " SET sent = datetime('now') " - " WHERE id = $id", - [DB_STMT_SMS_INC_DELIVER_ATTEMPTS] = - "UPDATE SMS " - " SET deliver_attempts = deliver_attempts + 1 " - " WHERE id = $id", - [DB_STMT_SMS_DEL_BY_MSISDN] = - "DELETE FROM SMS WHERE src_addr=$src_addr OR dest_addr=$dest_addr", - [DB_STMT_SMS_DEL_BY_ID] = - "DELETE FROM SMS WHERE id = $id AND sent is NOT NULL", - [DB_STMT_SMS_DEL_EXPIRED] = - "DELETE FROM SMS WHERE id = $id", - [DB_STMT_SMS_GET_VALID_UNTIL_BY_ID] = - "SELECT strftime('%s', valid_until) FROM SMS WHERE id = $id", - [DB_STMT_SMS_GET_OLDEST_EXPIRED] = - "SELECT id, strftime('%s', valid_until) FROM SMS ORDER BY valid_until LIMIT 1", -}; - -/*********************************************************************** - * libsqlite3 helpers - ***********************************************************************/ - -/* libsqlite3 call-back for error logging */ -static void sql3_error_log_cb(void *arg, int err_code, const char *msg) -{ - LOGP(DDB, LOGL_ERROR, "SQLITE3: (%d) %s\n", err_code, msg); - osmo_log_backtrace(DDB, LOGL_ERROR); -} - -/* libsqlite3 call-back for normal logging */ -static void sql3_sql_log_cb(void *arg, sqlite3 *s3, const char *stmt, int type) -{ - switch (type) { - case 0: - LOGP(DDB, LOGL_DEBUG, "Opened database\n"); - break; - case 1: - LOGP(DDB, LOGL_DEBUG, "%s\n", stmt); - break; - case 2: - LOGP(DDB, LOGL_DEBUG, "Closed database\n"); - break; - default: - LOGP(DDB, LOGL_DEBUG, "Unknown %d\n", type); - break; - } -} - -/* remove statement bindings and reset statement to be re-executed */ -static void db_remove_reset(sqlite3_stmt *stmt) -{ - sqlite3_clear_bindings(stmt); - /* sqlite3_reset() just repeats an error code already evaluated during sqlite3_step(). */ - /* coverity[CHECKED_RETURN] */ - sqlite3_reset(stmt); -} - -/** bind blob arg and do proper cleanup in case of failure. If param_name is - * NULL, bind to the first parameter (useful for SQL statements that have only - * one parameter). */ -static bool db_bind_blob(sqlite3_stmt *stmt, const char *param_name, - const uint8_t *blob, size_t blob_len) -{ - int rc; - int idx = param_name ? sqlite3_bind_parameter_index(stmt, param_name) : 1; - if (idx < 1) { - LOGP(DDB, LOGL_ERROR, "Error composing SQL, cannot bind parameter '%s'\n", - param_name); - return false; - } - rc = sqlite3_bind_blob(stmt, idx, blob, blob_len, SQLITE_STATIC); - if (rc != SQLITE_OK) { - LOGP(DDB, LOGL_ERROR, "Error binding blob to SQL parameter %s: %d\n", - param_name ? param_name : "#1", rc); - db_remove_reset(stmt); - return false; - } - return true; -} - -/** bind text arg and do proper cleanup in case of failure. If param_name is - * NULL, bind to the first parameter (useful for SQL statements that have only - * one parameter). */ -static bool db_bind_text(sqlite3_stmt *stmt, const char *param_name, const char *text) -{ - int rc; - int idx = param_name ? sqlite3_bind_parameter_index(stmt, param_name) : 1; - if (idx < 1) { - LOGP(DDB, LOGL_ERROR, "Error composing SQL, cannot bind parameter '%s'\n", - param_name); - return false; - } - rc = sqlite3_bind_text(stmt, idx, text, -1, SQLITE_STATIC); - if (rc != SQLITE_OK) { - LOGP(DDB, LOGL_ERROR, "Error binding text to SQL parameter %s: %d\n", - param_name ? param_name : "#1", rc); - db_remove_reset(stmt); - return false; - } - return true; -} - -/** bind int arg and do proper cleanup in case of failure. If param_name is - * NULL, bind to the first parameter (useful for SQL statements that have only - * one parameter). */ -static bool db_bind_int(sqlite3_stmt *stmt, const char *param_name, int nr) -{ - int rc; - int idx = param_name ? sqlite3_bind_parameter_index(stmt, param_name) : 1; - if (idx < 1) { - LOGP(DDB, LOGL_ERROR, "Error composing SQL, cannot bind parameter '%s'\n", - param_name); - return false; - } - rc = sqlite3_bind_int(stmt, idx, nr); - if (rc != SQLITE_OK) { - LOGP(DDB, LOGL_ERROR, "Error binding int64 to SQL parameter %s: %d\n", - param_name ? param_name : "#1", rc); - db_remove_reset(stmt); - return false; - } - return true; -} - -/** bind int64 arg and do proper cleanup in case of failure. If param_name is - * NULL, bind to the first parameter (useful for SQL statements that have only - * one parameter). */ -static bool db_bind_int64(sqlite3_stmt *stmt, const char *param_name, int64_t nr) -{ - int rc; - int idx = param_name ? sqlite3_bind_parameter_index(stmt, param_name) : 1; - if (idx < 1) { - LOGP(DDB, LOGL_ERROR, "Error composing SQL, cannot bind parameter '%s'\n", - param_name); - return false; - } - rc = sqlite3_bind_int64(stmt, idx, nr); - if (rc != SQLITE_OK) { - LOGP(DDB, LOGL_ERROR, "Error binding int64 to SQL parameter %s: %d\n", - param_name ? param_name : "#1", rc); - db_remove_reset(stmt); - return false; - } - return true; -} - -/* callback for sqlite3_exec() below */ -static int db_rev_exec_cb(void *priv, int num_cols, char **vals, char **names) -{ - char **rev_s = priv; - OSMO_ASSERT(!strcmp(names[0], "value")); - *rev_s = talloc_strdup(NULL, vals[0]); - return 0; -} - -static int check_db_revision(struct db_context *dbc) -{ - char *errstr = NULL; - char *rev_s; - int db_rev = 0; - int rc; - - /* Make a query */ - rc = sqlite3_exec(dbc->db, "SELECT value FROM Meta WHERE key = 'revision'", - db_rev_exec_cb, &rev_s, &errstr); - if (rc != SQLITE_OK) { - LOGP(DDB, LOGL_ERROR, "Cannot execute SELECT value from META: %s\n", errstr); - sqlite3_free(errstr); - return -EINVAL; - } - - if (!strcmp(rev_s, SCHEMA_REVISION)) { - /* Everything is fine */ - talloc_free(rev_s); - return 0; - } - - LOGP(DDB, LOGL_NOTICE, "Detected DB Revision %s, expected %s\n", rev_s, SCHEMA_REVISION); - - db_rev = atoi(rev_s); - talloc_free(rev_s); - - /* Incremental migration waterfall */ - switch (db_rev) { - case 2: - case 3: - case 4: - LOGP(DDB, LOGL_FATAL, "You must use osmo-msc 1.1.0 to 1.8.0 to upgrade database " - "schema from '%u' to '5', sorry\n", db_rev); - break; -#if 0 - case 5: - if (update_db_revision_5()) - goto error; - - /* The end of waterfall */ - break; -#endif - default: - LOGP(DDB, LOGL_FATAL, "Invalid database schema revision '%d'.\n", db_rev); - return -EINVAL; - } - - return 0; - -//error: - LOGP(DDB, LOGL_FATAL, "Failed to update database from schema revision '%d'.\n", db_rev); - talloc_free(rev_s); - - return -EINVAL; -} - -/*********************************************************************** - * USER API - ***********************************************************************/ - -int db_init(void *ctx, const char *fname, bool enable_sqlite_logging) -{ - unsigned int i; - int rc; - bool has_sqlite_config_sqllog = false; - - g_dbc = talloc_zero(ctx, struct db_context); - OSMO_ASSERT(g_dbc); - - /* we are a single-threaded program; we want to avoid all the mutex/etc. overhead */ - sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); - - LOGP(DDB, LOGL_NOTICE, "Init database connection to '%s' using SQLite3 lib version %s\n", - fname, sqlite3_libversion()); - - g_dbc->fname = talloc_strdup(g_dbc, fname); - - for (i = 0; i < 0xfffff; i++) { - const char *o = sqlite3_compileoption_get(i); - if (!o) - break; - LOGP(DDB, LOGL_DEBUG, "SQLite3 compiled with '%s'\n", o); - if (!strcmp(o, "ENABLE_SQLLOG")) - has_sqlite_config_sqllog = true; - } - - if (enable_sqlite_logging) { - rc = sqlite3_config(SQLITE_CONFIG_LOG, sql3_error_log_cb, NULL); - if (rc != SQLITE_OK) - LOGP(DDB, LOGL_NOTICE, "Unable to set SQLite3 error log callback\n"); - } - - if (has_sqlite_config_sqllog) { - rc = sqlite3_config(SQLITE_CONFIG_SQLLOG, sql3_sql_log_cb, NULL); - if (rc != SQLITE_OK) - LOGP(DDB, LOGL_NOTICE, "Unable to set SQLite3 SQL log callback\n"); - } else { - LOGP(DDB, LOGL_DEBUG, "Not setting SQL log callback:" - " SQLite3 compiled without support for it\n"); - } - - rc = sqlite3_open(g_dbc->fname, &g_dbc->db); - if (rc != SQLITE_OK) { - LOGP(DDB, LOGL_ERROR, "Unable to open DB; rc =%d\n", rc); - talloc_free(g_dbc); - return -1; - } - - /* enable extended result codes */ - rc = sqlite3_extended_result_codes(g_dbc->db, 1); - if (rc != SQLITE_OK) { - LOGP(DDB, LOGL_ERROR, "Unable to enable SQLite3 extended result codes\n"); - /* non-fatal */ - } - - char *err_msg; - rc = sqlite3_exec(g_dbc->db, "PRAGMA journal_mode=WAL; PRAGMA synchronous = NORMAL;", 0, 0, &err_msg); - if (rc != SQLITE_OK) { - LOGP(DDB, LOGL_ERROR, "Unable to set Write-Ahead Logging: %s\n", err_msg); - sqlite3_free(err_msg); - /* non-fatal */ - } - - return 0; -} - -int db_fini(void) -{ - unsigned int i; - int rc; - - if (!g_dbc) - return 0; - - for (i = 0; i < ARRAY_SIZE(g_dbc->stmt); i++) { - /* it is ok to call finalize on NULL */ - sqlite3_finalize(g_dbc->stmt[i]); - } - - /* Ask sqlite3 to close DB */ - rc = sqlite3_close(g_dbc->db); - if (rc != SQLITE_OK) { /* Make sure it's actually closed! */ - LOGP(DDB, LOGL_ERROR, "Couldn't close database: (rc=%d) %s\n", - rc, sqlite3_errmsg(g_dbc->db)); - } - - talloc_free(g_dbc); - g_dbc = NULL; - - return 0; -} - -/* run (execute) a series of SQL statements */ -static int db_run_statements(struct db_context *dbc, const char **statements, size_t statements_count) -{ - int i; - for (i = 0; i < statements_count; i++) { - const char *stmt_str = statements[i]; - char *errmsg = NULL; - int rc; - - rc = sqlite3_exec(dbc->db, stmt_str, NULL, NULL, &errmsg); - if (rc != SQLITE_OK) { - LOGP(DDB, LOGL_ERROR, "SQL error during SQL statement '%s': %s\n", stmt_str, errmsg); - sqlite3_free(errmsg); - return -1; - } - } - return 0; -} - -int db_prepare(void) -{ - unsigned int i; - int rc; - - OSMO_ASSERT(g_dbc); - rc = db_run_statements(g_dbc, create_stmts, ARRAY_SIZE(create_stmts)); - if (rc < 0) { - LOGP(DDB, LOGL_ERROR, "Failed to create some table.\n"); - return 1; - } - - if (check_db_revision(g_dbc) < 0) { - LOGP(DDB, LOGL_FATAL, "Database schema revision invalid, " - "please update your database schema\n"); - return -1; - } - - /* prepare all SQL statements */ - for (i = 0; i < ARRAY_SIZE(g_dbc->stmt); i++) { - rc = sqlite3_prepare_v2(g_dbc->db, stmt_sql[i], -1, - &g_dbc->stmt[i], NULL); - if (rc != SQLITE_OK) { - LOGP(DDB, LOGL_ERROR, "Unable to prepare SQL statement '%s'\n", stmt_sql[i]); - return -1; - } - } - - return 0; -} - -/* store an [unsent] SMS to the database */ -int db_sms_store(struct gsm_sms *sms) -{ - OSMO_ASSERT(g_dbc); - sqlite3_stmt *stmt = g_dbc->stmt[DB_STMT_SMS_STORE]; - time_t now, validity_timestamp; - int rc; - - now = time(NULL); - validity_timestamp = now + sms->validity_minutes * 60; - - db_bind_int64(stmt, "$created", (int64_t) now); - db_bind_int64(stmt, "$valid_until", (int64_t) validity_timestamp); - db_bind_int(stmt, "$reply_path_req", sms->reply_path_req); - db_bind_int(stmt, "$status_rep_req", sms->status_rep_req); - db_bind_int(stmt, "$is_report", sms->is_report); - db_bind_int(stmt, "$msg_ref", sms->msg_ref); - db_bind_int(stmt, "$protocol_id", sms->protocol_id); - db_bind_int(stmt, "$data_coding_scheme", sms->data_coding_scheme); - db_bind_int(stmt, "$ud_hdr_ind", sms->ud_hdr_ind); - /* FIXME: do we need to use legacy DBI compatible quoting of sms->user_data? */ - db_bind_blob(stmt, "$user_data", sms->user_data, sms->user_data_len); - db_bind_text(stmt, "$text", (char *)sms->text); - db_bind_text(stmt, "$dest_addr", (char *)sms->dst.addr); - db_bind_int(stmt, "$dest_ton", sms->dst.ton); - db_bind_int(stmt, "$dest_npi", sms->dst.npi); - db_bind_text(stmt, "$src_addr", (char *)sms->src.addr); - db_bind_int(stmt, "$src_ton", sms->src.ton); - db_bind_int(stmt, "$src_npi", sms->src.npi); - - /* execute statement */ - rc = sqlite3_step(stmt); - db_remove_reset(stmt); - if (rc != SQLITE_DONE) { - LOGP(DDB, LOGL_ERROR, "Cannot create SMS: SQL error: (%d) %s\n", rc, sqlite3_errmsg(g_dbc->db)); - return -EIO; - } - - sms->id = sqlite3_last_insert_rowid(g_dbc->db); - - LOGP(DLSMS, LOGL_INFO, "Stored SMS id=%llu in DB\n", sms->id); - - return 0; -} - -static void parse_tp_ud_from_result(struct gsm_sms *sms, sqlite3_stmt *stmt) -{ - const unsigned char *user_data; - unsigned int user_data_len; - unsigned int text_len; - const char *text; - - /* Retrieve TP-UDL (User-Data-Length) in octets (regardless of DCS) */ - user_data_len = sqlite3_column_bytes(stmt, COL_USER_DATA); - if (user_data_len > sizeof(sms->user_data)) { - LOGP(DDB, LOGL_ERROR, - "SMS TP-UD length %u is too big, truncating to %zu\n", - user_data_len, sizeof(sms->user_data)); - user_data_len = (uint8_t) sizeof(sms->user_data); - } - sms->user_data_len = user_data_len; - - /* Retrieve the TP-UD (User-Data) itself */ - if (user_data_len > 0) { - user_data = sqlite3_column_blob(stmt, COL_USER_DATA); - memcpy(sms->user_data, user_data, user_data_len); - } - - /* Retrieve the text length (excluding '\0') */ - text_len = sqlite3_column_bytes(stmt, COL_TEXT); - if (text_len >= sizeof(sms->text)) { - LOGP(DDB, LOGL_ERROR, - "SMS text length %u is too big, truncating to %zu\n", - text_len, sizeof(sms->text) - 1); - /* OSMO_STRLCPY_ARRAY() does truncation for us */ - } - - /* Retrieve the text parsed from TP-UD (User-Data) */ - text = (const char *)sqlite3_column_text(stmt, COL_TEXT); - if (text) - OSMO_STRLCPY_ARRAY(sms->text, text); -} - -static struct gsm_sms *sms_from_result(struct gsm_network *net, sqlite3_stmt *stmt) -{ - struct gsm_sms *sms = sms_alloc(); - const char *daddr, *saddr; - time_t validity_timestamp; - - if (!sms) - return NULL; - - sms->id = sqlite3_column_int64(stmt, COL_ID); - - sms->created = sqlite3_column_int64(stmt, COL_CREATED); - validity_timestamp = sqlite3_column_int64(stmt, COL_VALID_UNTIL); - - sms->validity_minutes = (validity_timestamp - sms->created) / 60; - sms->reply_path_req = sqlite3_column_int(stmt, COL_REPLY_PATH_REQ); - sms->status_rep_req = sqlite3_column_int(stmt, COL_STATUS_REP_REQ); - sms->is_report = sqlite3_column_int(stmt, COL_IS_REPORT); - sms->msg_ref = sqlite3_column_int(stmt, COL_MSG_REF); - sms->ud_hdr_ind = sqlite3_column_int(stmt, COL_UD_HDR_IND); - sms->protocol_id = sqlite3_column_int(stmt, COL_PROTOCOL_ID); - sms->data_coding_scheme = sqlite3_column_int(stmt, COL_DATA_CODING_SCHEME); - - sms->dst.npi = sqlite3_column_int(stmt, COL_DEST_NPI); - sms->dst.ton = sqlite3_column_int(stmt, COL_DEST_TON); - daddr = (const char *)sqlite3_column_text(stmt, COL_DEST_ADDR); - if (daddr) - OSMO_STRLCPY_ARRAY(sms->dst.addr, daddr); - - if (net != NULL) /* db_sms_test passes NULL, so we need to be tolerant */ - sms->receiver = vlr_subscr_find_by_msisdn(net->vlr, sms->dst.addr, - VSUB_USE_SMS_RECEIVER); - - sms->src.npi = sqlite3_column_int(stmt, COL_SRC_NPI); - sms->src.ton = sqlite3_column_int(stmt, COL_SRC_TON); - saddr = (const char *)sqlite3_column_text(stmt, COL_SRC_ADDR); - if (saddr) - OSMO_STRLCPY_ARRAY(sms->src.addr, saddr); - - /* Parse TP-UD, TP-UDL and decoded text */ - parse_tp_ud_from_result(sms, stmt); - - return sms; -} - -struct gsm_sms *db_sms_get(struct gsm_network *net, unsigned long long id) -{ - OSMO_ASSERT(g_dbc); - sqlite3_stmt *stmt = g_dbc->stmt[DB_STMT_SMS_GET]; - struct gsm_sms *sms; - int rc; - - db_bind_int64(stmt, "$id", id); - - rc = sqlite3_step(stmt); - if (rc != SQLITE_ROW) { - db_remove_reset(stmt); - return NULL; - } - - sms = sms_from_result(net, stmt); - - db_remove_reset(stmt); - return sms; -} - -struct gsm_sms *db_sms_get_next_unsent(struct gsm_network *net, - unsigned long long min_sms_id, - int max_failed) -{ - OSMO_ASSERT(g_dbc); - sqlite3_stmt *stmt = g_dbc->stmt[DB_STMT_SMS_GET_NEXT_UNSENT]; - struct gsm_sms *sms; - int rc; - - db_bind_int64(stmt, "$id", min_sms_id); - db_bind_int(stmt, "$attempts", max_failed); - - rc = sqlite3_step(stmt); - if (rc != SQLITE_ROW) { - db_remove_reset(stmt); - return NULL; - } - - sms = sms_from_result(net, stmt); - - db_remove_reset(stmt); - return sms; -} - -/* retrieve the next unsent SMS for a given subscriber */ -struct gsm_sms *db_sms_get_unsent_for_subscr(struct vlr_subscr *vsub, - int max_failed) -{ - OSMO_ASSERT(g_dbc); - sqlite3_stmt *stmt = g_dbc->stmt[DB_STMT_SMS_GET_UNSENT_FOR_SUBSCR]; - struct gsm_network *net = vsub->vlr->user_ctx; - struct gsm_sms *sms; - int rc; - - if (!vsub->lu_complete) - return NULL; - - /* A subscriber having no phone number cannot possibly receive SMS. */ - if (*vsub->msisdn == '\0') - return NULL; - - db_bind_text(stmt, "$dest_addr", vsub->msisdn); - db_bind_int(stmt, "$attempts", max_failed); - - rc = sqlite3_step(stmt); - if (rc != SQLITE_ROW) { - db_remove_reset(stmt); - return NULL; - } - - sms = sms_from_result(net, stmt); - - db_remove_reset(stmt); - return sms; -} - -struct gsm_sms *db_sms_get_next_unsent_rr_msisdn(struct gsm_network *net, - const char *last_msisdn, - int max_failed) -{ - OSMO_ASSERT(g_dbc); - sqlite3_stmt *stmt = g_dbc->stmt[DB_STMT_SMS_GET_NEXT_UNSENT_RR_MSISDN]; - struct gsm_sms *sms; - int rc; - - db_bind_text(stmt, "$dest_addr", last_msisdn); - db_bind_int(stmt, "$attempts", max_failed); - - rc = sqlite3_step(stmt); - if (rc != SQLITE_ROW) { - db_remove_reset(stmt); - return NULL; - } - - sms = sms_from_result(net, stmt); - - db_remove_reset(stmt); - - return sms; -} - -/* mark a given SMS as delivered */ -int db_sms_mark_delivered(struct gsm_sms *sms) -{ - sqlite3_stmt *stmt; - int rc; - - /* this only happens in unit tests that don't db_init() */ - if (!g_dbc) - return 0; - - stmt = g_dbc->stmt[DB_STMT_SMS_MARK_DELIVERED]; - db_bind_int64(stmt, "$id", sms->id); - - rc = sqlite3_step(stmt); - if (rc != SQLITE_DONE) { - db_remove_reset(stmt); - LOGP(DDB, LOGL_ERROR, "Failed to mark SMS %llu as sent.\n", sms->id); - return 1; - } - - db_remove_reset(stmt); - return 0; -} - -/* increase the number of attempted deliveries */ -int db_sms_inc_deliver_attempts(struct gsm_sms *sms) -{ - sqlite3_stmt *stmt; - int rc; - - /* this only happens in unit tests that don't db_init() */ - if (!g_dbc) - return 0; - - stmt = g_dbc->stmt[DB_STMT_SMS_INC_DELIVER_ATTEMPTS]; - db_bind_int64(stmt, "$id", sms->id); - - rc = sqlite3_step(stmt); - if (rc != SQLITE_DONE) { - db_remove_reset(stmt); - LOGP(DDB, LOGL_ERROR, "Failed to inc deliver attempts for SMS %llu.\n", sms->id); - return 1; - } - - db_remove_reset(stmt); - return 0; -} - -/* Drop all pending SMS to or from the given extension */ -int db_sms_delete_by_msisdn(const char *msisdn) -{ - OSMO_ASSERT(g_dbc); - sqlite3_stmt *stmt = g_dbc->stmt[DB_STMT_SMS_DEL_BY_MSISDN]; - int rc; - - if (!msisdn || !*msisdn) - return 0; - - db_bind_text(stmt, "$src_addr", msisdn); - db_bind_text(stmt, "$dest_addr", msisdn); - - rc = sqlite3_step(stmt); - if (rc != SQLITE_DONE) { - db_remove_reset(stmt); - LOGP(DDB, LOGL_ERROR, "Failed to delete SMS for %s\n", msisdn); - return -1; - } - - db_remove_reset(stmt); - return 0; -} - -int db_sms_delete_sent_message_by_id(unsigned long long sms_id) -{ - OSMO_ASSERT(g_dbc); - sqlite3_stmt *stmt = g_dbc->stmt[DB_STMT_SMS_DEL_BY_ID]; - int rc; - - db_bind_int64(stmt, "$id", sms_id); - - rc = sqlite3_step(stmt); - if (rc != SQLITE_DONE) { - db_remove_reset(stmt); - LOGP(DDB, LOGL_ERROR, "Failed to delete SMS %llu.\n", sms_id); - return 1; - } - - db_remove_reset(stmt); - return 0; -} - -static int delete_expired_sms(unsigned long long sms_id, time_t validity_timestamp) -{ - OSMO_ASSERT(g_dbc); - sqlite3_stmt *stmt = g_dbc->stmt[DB_STMT_SMS_DEL_EXPIRED]; - time_t now; - int rc; - - now = time(NULL); - - /* Net yet expired */ - if (validity_timestamp > now) - return -1; - - db_bind_int64(stmt, "$id", sms_id); - - rc = sqlite3_step(stmt); - if (rc != SQLITE_DONE) { - db_remove_reset(stmt); - LOGP(DDB, LOGL_ERROR, "Failed to delete SMS %llu.\n", sms_id); - return -1; - } - - db_remove_reset(stmt); - return 0; -} - -int db_sms_delete_expired_message_by_id(unsigned long long sms_id) -{ - OSMO_ASSERT(g_dbc); - sqlite3_stmt *stmt = g_dbc->stmt[DB_STMT_SMS_GET_VALID_UNTIL_BY_ID]; - time_t validity_timestamp; - int rc; - - db_bind_int64(stmt, "$id", sms_id); - - rc = sqlite3_step(stmt); - if (rc != SQLITE_ROW) { - db_remove_reset(stmt); - return -1; - } - - validity_timestamp = sqlite3_column_int64(stmt, 0); - - db_remove_reset(stmt); - return delete_expired_sms(sms_id, validity_timestamp); -} - -void db_sms_delete_oldest_expired_message(void) -{ - OSMO_ASSERT(g_dbc); - sqlite3_stmt *stmt = g_dbc->stmt[DB_STMT_SMS_GET_OLDEST_EXPIRED]; - int rc; - - rc = sqlite3_step(stmt); - if (rc == SQLITE_ROW) { - unsigned long long sms_id; - time_t validity_timestamp; - - sms_id = sqlite3_column_int64(stmt, 0); - validity_timestamp = sqlite3_column_int64(stmt, 1); - delete_expired_sms(sms_id, validity_timestamp); - } - - db_remove_reset(stmt); -} diff --git a/src/libmsc/gsm_04_08_cc.c b/src/libmsc/gsm_04_08_cc.c index 6562daadd..eab4e7eaf 100644 --- a/src/libmsc/gsm_04_08_cc.c +++ b/src/libmsc/gsm_04_08_cc.c @@ -32,7 +32,6 @@ #include -#include #include #include #include diff --git a/src/libmsc/gsm_04_11.c b/src/libmsc/gsm_04_11.c index 67f86fe3f..81d58ad71 100644 --- a/src/libmsc/gsm_04_11.c +++ b/src/libmsc/gsm_04_11.c @@ -47,11 +47,10 @@ #include #include -#include +#include #include #include #include -#include #include #include #include @@ -286,7 +285,7 @@ int gsm411_mn_send(struct gsm411_smr_inst *inst, int msg_type, static int gsm340_rx_sms_submit(struct gsm_trans *trans, struct gsm_sms *gsms) { - if (db_sms_store(gsms) != 0) { + if (sms_storage_to_disk_req(trans->net->sms_storage, gsms) != 0) { LOG_TRANS(trans, LOGL_ERROR, "Failed to store SMS in Database\n"); return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER; } @@ -892,7 +891,7 @@ static int gsm411_rx_rp_ack(struct gsm_trans *trans, } /* mark this SMS as sent in database */ - db_sms_mark_delivered(sms); + sms_storage_delete_from_disk_req(trans->net->sms_storage, sms->id, SMSS_DELETE_CAUSE_DELIVERED); send_signal(S_SMS_DELIVERED, trans, sms, 0); @@ -1249,7 +1248,6 @@ int gsm411_send_sms(struct gsm_network *net, trans->sms.sms = sms; rate_ctr_inc(rate_ctr_group_get_ctr(net->msc_ctrs, MSC_CTR_SMS_DELIVERED)); - db_sms_inc_deliver_attempts(trans->sms.sms); return gsm411_rp_sendmsg(&trans->sms.smr_inst, msg, GSM411_MT_RP_DATA_MT, trans->sms.sm_rp_mr, diff --git a/src/libmsc/msc_vty.c b/src/libmsc/msc_vty.c index 879402f0f..85bba56d6 100644 --- a/src/libmsc/msc_vty.c +++ b/src/libmsc/msc_vty.c @@ -54,8 +54,8 @@ #include #include #include -#include #include +#include #include #include #include diff --git a/src/libmsc/smpp_openbsc.c b/src/libmsc/smpp_openbsc.c index 91666a9ca..c41e2d543 100644 --- a/src/libmsc/smpp_openbsc.c +++ b/src/libmsc/smpp_openbsc.c @@ -40,7 +40,7 @@ #include #include -#include +#include #include #include #include @@ -300,8 +300,7 @@ int handle_smpp_submit(struct osmo_esme *esme, struct submit_sm_t *submit, case 0: /* default */ case 1: /* datagram */ case 3: /* store-and-forward */ - rc = db_sms_store(sms); - sms_free(sms); + rc = sms_storage_to_disk_req(net->sms_storage, sms); sms = NULL; if (rc < 0) { LOGP(DLSMS, LOGL_ERROR, "SMPP SUBMIT-SM: Unable to " diff --git a/src/libmsc/sms_queue.c b/src/libmsc/sms_queue.c index 9f18f4feb..2f5186438 100644 --- a/src/libmsc/sms_queue.c +++ b/src/libmsc/sms_queue.c @@ -1,6 +1,7 @@ /* SMS queue to continuously attempt to deliver SMS */ /* * (C) 2010 by Holger Hans Peter Freyther + * (C) 2022 by Harald Welte * All Rights Reserved * * This program is free software; you can redistribute it and/or modify @@ -31,7 +32,7 @@ #include #include -#include +#include #include #include #include @@ -109,6 +110,7 @@ static const struct rate_ctr_group_desc smsq_ctrg_desc = { * a pointer to the database record. It holds a reference on the vlr_subscriber * and some counters. While this object exists in RAM, we are regularly attempting * to deliver the related SMS. */ +#if 0 struct gsm_sms_pending { struct llist_head entry; /* gsm_sms_queue.pending_sms */ @@ -118,6 +120,7 @@ struct gsm_sms_pending { int failed_attempts; /* count of failed deliver attempts so far */ int resend; /* should we try re-sending it (now) ? */ }; +#endif /* (global) state of the SMS queue. */ struct gsm_sms_queue { @@ -616,15 +619,12 @@ static int sms_sms_cb(unsigned int subsys, unsigned int signal, switch (signal) { case S_SMS_DELIVERED: smsq_rate_ctr_inc(smq, SMSQ_CTR_SMS_DELIVERY_ACK); - /* Remember the subscriber and clear the pending entry */ - vsub = pending->vsub; - vlr_subscr_get(vsub, __func__); - if (smq->cfg->delete_delivered) - db_sms_delete_sent_message_by_id(pending->sms_id); - sms_pending_free(smq, pending); + /* ask SMS thread to delete message from storage */ + ms_storage_delete_from_disk_req(network->sms_storage, sms->id, + SMSS_DELETE_CAUSE_DELIVERED); + sms_free(network->sms_storage, sms); /* Attempt to send another SMS to this subscriber */ sms_send_next(vsub); - vlr_subscr_put(vsub, __func__); break; case S_SMS_MEM_EXCEEDED: smsq_rate_ctr_inc(smq, SMSQ_CTR_SMS_DELIVERY_NOMEM); @@ -657,10 +657,6 @@ static int sms_sms_cb(unsigned int subsys, unsigned int signal, sig_sms->paging_result); } - /* While here, attempt to remove an expired SMS from the DB. */ - if (smq->cfg->delete_expired) - db_sms_delete_oldest_expired_message(); - return 0; } diff --git a/src/libmsc/sms_storage.c b/src/libmsc/sms_storage.c index 1f2b9b4d4..7c9578da8 100644 --- a/src/libmsc/sms_storage.c +++ b/src/libmsc/sms_storage.c @@ -82,15 +82,7 @@ #include #include #include - -/* configuration of SMS storage */ -struct sms_storage_cfg { - char storage_dir[PATH_MAX+1]; - /* unlink messages after delivery, or just move them? */ - bool unlink_delivered; - /* unlink messages after expiration, or just move them? */ - bool unlink_expired; -}; +#include /* all the state of a SMS storage instance */ struct sms_storage_inst { @@ -167,12 +159,6 @@ enum smss_m2s_op { SMSS_M2S_OP_SMS_DELETE_FROM_DISK_REQ, }; -enum smss_delete_cause { - SMSS_DELETE_CAUSE_UNKNOWN, - SMSS_DELETE_CAUSE_DELIVERED, - SMSS_DELETE_CAUSE_EXPIRED, -}; - struct smss_m2s_evt { struct llist_head list; @@ -770,6 +756,7 @@ static void storage2main_read_cb(struct osmo_it_q *q, struct llist_head *item) switch (evt->op) { case SMSS_S2M_OP_NULL: + break; case SMSS_S2M_OP_SMS_FROM_DISK_IND: /* SMS storage has read a SMS from disk, asks main thread to add it to queue */ break; diff --git a/src/libvlr/vlr.c b/src/libvlr/vlr.c index 37d7ffdaf..18a7e8521 100644 --- a/src/libvlr/vlr.c +++ b/src/libvlr/vlr.c @@ -402,6 +402,7 @@ static struct vlr_subscr *_vlr_subscr_alloc(struct vlr_instance *vlr) INIT_LLIST_HEAD(&vsub->cs.requests); INIT_LLIST_HEAD(&vsub->ps.pdp_list); + INIT_LLIST_HEAD(&vsub->sms.pending); /* Create an SGs FSM, which is needed to control CSFB, * in cases where CSFB/SGs is not in use, this FSM will diff --git a/src/osmo-msc/msc_main.c b/src/osmo-msc/msc_main.c index dc0497a59..244a34cf8 100644 --- a/src/osmo-msc/msc_main.c +++ b/src/osmo-msc/msc_main.c @@ -39,7 +39,7 @@ /* build switches from the configure script */ #include "config.h" -#include +#include #include #include #include @@ -790,7 +790,6 @@ TODO: we probably want some of the _net_ ctrl commands from bsc_base_ctrl_cmds_i } } while (!osmo_select_shutdown_done()); - db_fini(); log_fini(); /**