mobile/sms: add sqlite db support

This commit is contained in:
Vadim Yanitskiy 2017-04-20 20:58:46 +07:00
parent 9b8b6a3eec
commit a0407b1b25
9 changed files with 382 additions and 3 deletions

View File

@ -1,6 +1,8 @@
#ifndef osmocom_data_h
#define osmocom_data_h
#include <sqlite3.h>
#include <osmocom/core/select.h>
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/core/write_queue.h>
@ -77,6 +79,8 @@ struct osmocom_ms {
struct gsm48_cclayer cclayer;
struct osmomncc_entity mncc_entity;
struct llist_head trans_list;
sqlite3 *db_sms;
};
enum osmobb_sig_subsys {

View File

@ -0,0 +1,6 @@
#pragma once
#include <sqlite3.h>
int db_open(sqlite3 **db, const char *db_name);
void db_close(sqlite3 *db);

View File

@ -0,0 +1,16 @@
#pragma once
#include <sqlite3.h>
#include <stdint.h>
struct db_sms_record {
char *dst_number;
char *src_imsi;
char *text;
int row_id;
};
int db_prepare(sqlite3 *db);
int db_pop_sms(sqlite3 *db, struct db_sms_record **sms);
int db_push_sms(sqlite3 *db, char *dst_imsi, uint32_t dst_tmsi,
char *src_number, char *text);

View File

@ -118,6 +118,7 @@ char *gsm_check_imsi(const char *imsi);
int gsm_subscr_get_key_seq(struct osmocom_ms *ms, struct gsm_subscriber *subscr);
int multi_imsi_work(struct osmocom_ms *ms);
int multi_imsi_spoof(struct osmocom_ms *ms, struct gsm_subscriber_creds *src);
int multi_imsi_switch_imsi(struct osmocom_ms *ms, const char *imsi);
#endif /* _SUBSCRIBER_H */

View File

@ -1,11 +1,20 @@
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBGPS_CFLAGS)
LDADD = ../common/liblayer23.a $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOCODEC_LIBS) $(LIBGPS_LIBS)
LDADD = \
../common/liblayer23.a \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOVTY_LIBS) \
$(LIBOSMOGSM_LIBS) \
$(LIBOSMOCODEC_LIBS) \
$(LIBGPS_LIBS) \
-lsqlite3
noinst_LIBRARIES = libmobile.a
libmobile_a_SOURCES = gsm322.c gsm480_ss.c gsm411_sms.c gsm48_cc.c gsm48_mm.c \
libmobile_a_SOURCES = \
gsm322.c gsm480_ss.c gsm411_sms.c gsm48_cc.c gsm48_mm.c \
gsm48_rr.c mnccms.c settings.c subscriber.c support.c \
transaction.c vty_interface.c voice.c mncc_sock.c
transaction.c vty_interface.c voice.c mncc_sock.c \
db.c db_sms.c
bin_PROGRAMS = mobile

View File

@ -37,6 +37,8 @@
#include <osmocom/bb/mobile/app_mobile.h>
#include <osmocom/bb/mobile/mncc.h>
#include <osmocom/bb/mobile/voice.h>
#include <osmocom/bb/mobile/db.h>
#include <osmocom/bb/mobile/db_sms.h>
#include <osmocom/bb/common/sap_interface.h>
#include <osmocom/vty/telnet_interface.h>
@ -56,6 +58,38 @@ int mncc_recv_dummy(struct osmocom_ms *ms, int msg_type, void *arg);
int (*mncc_recv_app)(struct osmocom_ms *ms, int, void *);
static int quit;
static int db_sms_check(struct osmocom_ms *ms)
{
struct gsm322_cellsel *cs = &ms->cellsel;
struct gsm_settings *set = &ms->settings;
struct db_sms_record *sms = NULL;
const char *sms_sca = "99999";
int rc;
// Phone should be registered and should support SMS
if (cs->state != GSM322_C3_CAMPED_NORMALLY || !set->sms_ptp)
return 0;
// Check if we have a new message to send
rc = db_pop_sms(ms->db_sms, &sms);
if (rc || !sms)
return 0;
// So, we got a new SMS to send
vty_notify(ms, "Got a new SMS to send:\n");
vty_notify(ms, "IMSI (%s) -> extension (%s)\n",
sms->src_imsi, sms->dst_number);
// Set up required IMSI
multi_imsi_switch_imsi(ms, sms->src_imsi);
// Send SMS
sms_send(ms, sms_sca, sms->dst_number, sms->text);
talloc_free(sms);
return 0;
}
/* handle ms instance */
int mobile_work(struct osmocom_ms *ms)
{
@ -73,6 +107,7 @@ int mobile_work(struct osmocom_ms *ms)
w |= gsm_sim_job_dequeue(ms);
w |= mncc_dequeue(ms);
w |= multi_imsi_work(ms);
w |= db_sms_check(ms);
if (w)
work = 1;
} while (w);
@ -166,6 +201,7 @@ int mobile_exit(struct osmocom_ms *ms, int force)
gsm411_sms_exit(ms);
gsm_sim_exit(ms);
lapdm_channel_exit(&ms->lapdm_channel);
db_close(ms->db_sms);
if (ms->started) {
ms->shutdown = 2; /* being down, wait for reset */
@ -183,6 +219,7 @@ int mobile_exit(struct osmocom_ms *ms, int force)
/* power-on ms instance */
int mobile_init(struct osmocom_ms *ms)
{
char *db_name;
int rc;
gsm_settings_arfcn(ms);
@ -196,6 +233,27 @@ int mobile_init(struct osmocom_ms *ms)
ms->lapdm_channel.lapdm_acch.datalink[DL_SAPI3].dl.t200_usec = 0;
lapdm_channel_set_l1(&ms->lapdm_channel, l1ctl_ph_prim_cb, ms);
// Compose database name
db_name = talloc_asprintf(ms, "sms_db_%s.sqlite3", ms->name);
// Init database connection
rc = db_open(&ms->db_sms, db_name);
if (rc) {
ms->l2_wq.bfd.fd = -1;
mobile_exit(ms, 1);
return rc;
}
// Prepare database if required
rc = db_prepare(ms->db_sms);
if (rc) {
ms->l2_wq.bfd.fd = -1;
mobile_exit(ms, 1);
return rc;
}
talloc_free(db_name);
/* init SAP client before SIM card starts up */
osmosap_init(ms);

View File

@ -0,0 +1,88 @@
/*
* (C) 2017 by Vadim Yanitskiy <axilirator@gmail.com>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <stdio.h>
#include <errno.h>
#include <talloc.h>
#include <string.h>
#include <sqlite3.h>
#include <osmocom/bb/common/logging.h>
#include <osmocom/bb/mobile/db.h>
extern void *l23_ctx;
static char *db_compose_path(const char *db_name)
{
const char *db_home_path = ".osmocom/bb";
const char *db_tmp_path = "/tmp";
char const *home = getenv("HOME");
char *db_full_path;
size_t len;
if (home != NULL) {
len = strlen(home) + strlen(db_home_path) + strlen(db_name) + 3;
db_full_path = talloc_size(l23_ctx, len);
if (db_full_path != NULL)
snprintf(db_full_path, len, "%s/%s/%s",
home, db_home_path, db_name);
} else {
len = strlen(db_tmp_path) + strlen(db_name) + 2;
db_full_path = talloc_size(l23_ctx, len);
if (db_full_path != NULL)
snprintf(db_full_path, len, "%s/%s",
db_tmp_path, db_name);
}
return db_full_path;
}
int db_open(sqlite3 **db, const char *db_name)
{
char *db_full_path;
int rc;
// Compose full database path
db_full_path = db_compose_path(db_name);
if (db_full_path == NULL)
return -ENOMEM;
// Connect to database
rc = sqlite3_open(db_full_path, db);
if (rc) {
fprintf(stderr, "[!] Couldn't open database: %s\n",
sqlite3_errmsg(*db));
goto final;
}
fprintf(stderr, "[i] Successfully connected to database\n");
final:
talloc_free(db_full_path);
return rc;
}
void db_close(sqlite3 *db)
{
if (!db)
sqlite3_close(db);
}

View File

@ -0,0 +1,191 @@
/*
* (C) 2017 by Vadim Yanitskiy <axilirator@gmail.com>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <stdio.h>
#include <errno.h>
#include <talloc.h>
#include <string.h>
#include <stdint.h>
#include <sqlite3.h>
#include <osmocom/bb/common/logging.h>
#include <osmocom/bb/mobile/db.h>
#include <osmocom/bb/mobile/db_sms.h>
extern void *l23_ctx;
int db_prepare(sqlite3 *db)
{
char *err = 0;
int rc = 0;
const char *inbox_sql = \
"CREATE TABLE IF NOT EXISTS inbox (" \
"dst_imsi TEXT NOT NULL, " \
"dst_tmsi TEXT NOT NULL, " \
"src_number TEXT NOT NULL, " \
"date DATETIME DEFAULT CURRENT_TIMESTAMP, " \
"handled INT DEFAULT 0, " \
"text TEXT NOT NULL" \
");";
const char *outbox_sql = \
"CREATE TABLE IF NOT EXISTS outbox (" \
"src_imsi text TEXT NOT NULL, " \
"dst_number text TEXT NOT NULL, " \
"date DATETIME DEFAULT CURRENT_TIMESTAMP, " \
"handled INT DEFAULT 0, " \
"text TEXT NOT NULL" \
");";
rc = sqlite3_exec(db, inbox_sql, NULL, 0, &err);
if (rc != SQLITE_DONE && rc != SQLITE_OK) {
fprintf(stderr, "[!] Couldn't init database: %s\n", err);
return rc;
}
rc = sqlite3_exec(db, outbox_sql, NULL, 0, &err) == SQLITE_DONE;
if (rc != SQLITE_DONE && rc != SQLITE_OK) {
fprintf(stderr, "[!] Couldn't init database: %s\n", err);
return rc;
}
fprintf(stderr, "[i] Database init complete\n");
return 0;
}
int db_push_sms(sqlite3 *db, char *dst_imsi, uint32_t dst_tmsi,
char *src_number, char *text)
{
sqlite3_stmt *stmt;
char *tmsi_str;
int rc;
const char *push_sql = \
"INSERT INTO inbox " \
"(dst_imsi, dst_tmsi, src_number, text) "
"VALUES (?, ?, ?, ?);";
rc = sqlite3_prepare(db, push_sql, strlen(push_sql), &stmt, NULL);
if (rc != SQLITE_OK) {
fprintf(stderr, "[!] SQLite error: %s\n", sqlite3_errmsg(db));
return rc;
}
// Convert TMSI to string
tmsi_str = talloc_asprintf(l23_ctx, "0x%08x", dst_tmsi);
// Bind query params
sqlite3_bind_text(stmt, 1, dst_imsi, strlen(dst_imsi), 0);
sqlite3_bind_text(stmt, 2, tmsi_str, strlen(tmsi_str), 0);
sqlite3_bind_text(stmt, 3, src_number, strlen(src_number), 0);
sqlite3_bind_text(stmt, 4, text, strlen(text), 0);
// Commit
rc = sqlite3_step(stmt);
if (rc != SQLITE_DONE && rc != SQLITE_OK) {
fprintf(stderr, "[!] SQLite error: %s\n", sqlite3_errmsg(db));
return rc;
}
printf("[i] Message saved\n");
sqlite3_finalize(stmt);
talloc_free(tmsi_str);
return 0;
}
int db_pop_sms(sqlite3 *db, struct db_sms_record **sms)
{
struct db_sms_record *sms_new = NULL;
sqlite3_stmt *stmt;
int rc;
const char *pop_select_sql = \
"SELECT rowid, src_imsi, dst_number, text " \
"FROM outbox WHERE handled = 0;";
const char *pop_update_sql = \
"UPDATE outbox SET handled = 1 " \
"WHERE rowid = ?;";
// Prepare query
rc = sqlite3_prepare(db, pop_select_sql, strlen(pop_select_sql),
&stmt, NULL);
if (rc != SQLITE_OK) {
fprintf(stderr, "[!] SQLite error: %s\n", sqlite3_errmsg(db));
return rc;
}
// Attempt to get a record
rc = sqlite3_step(stmt);
if (rc != SQLITE_ROW) {
if (rc != SQLITE_DONE && rc != SQLITE_OK)
fprintf(stderr, "[!] SQLite error: %s\n", sqlite3_errmsg(db));
goto final;
}
// Allocate a new structure for SMS
sms_new = talloc(l23_ctx, struct db_sms_record);
if (sms_new == NULL) {
rc = -ENOMEM;
goto final;
}
// Fill structure
sms_new->row_id = sqlite3_column_int(stmt, 0);
sms_new->src_imsi = talloc_strdup(sms_new,
(char *) sqlite3_column_text(stmt, 1));
sms_new->dst_number = talloc_strdup(sms_new,
(char *) sqlite3_column_text(stmt, 2));
sms_new->text = talloc_strdup(sms_new,
(char *) sqlite3_column_text(stmt, 3));
// Set external pointer
*sms = sms_new;
// Prepare another query
sqlite3_finalize(stmt);
rc = sqlite3_prepare(db, pop_update_sql, strlen(pop_update_sql),
&stmt, NULL);
if (rc != SQLITE_OK) {
fprintf(stderr, "[!] SQLite error: %s\n", sqlite3_errmsg(db));
return rc;
}
// Mark this record as 'handled'
sqlite3_bind_int(stmt, 1, sms_new->row_id);
rc = sqlite3_step(stmt);
if (rc != SQLITE_DONE && rc != SQLITE_OK) {
fprintf(stderr, "[!] SQLite error: %s\n", sqlite3_errmsg(db));
goto final;
}
printf("[i] Got a new message from DB\n");
final:
sqlite3_finalize(stmt);
return (rc != SQLITE_DONE && rc != SQLITE_OK) ? rc : 0;
}

View File

@ -37,6 +37,8 @@
#include <osmocom/bb/mobile/mncc.h>
#include <osmocom/bb/mobile/transaction.h>
#include <osmocom/bb/mobile/gsm411_sms.h>
#include <osmocom/bb/mobile/db.h>
#include <osmocom/bb/mobile/db_sms.h>
#include <osmocom/gsm/gsm0411_utils.h>
#include <osmocom/core/talloc.h>
#include <osmocom/bb/mobile/vty.h>
@ -213,6 +215,10 @@ fail:
fprintf(fp, "[SMS from %s]\n%s\n", gsms->address, gsms->text);
fclose(fp);
// Save SMS to database
db_push_sms(ms->db_sms, ms->subscr.imsi, ms->subscr.tmsi,
gsms->address, gsms->text);
talloc_free(sms_file);
return 0;