aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/db.h6
-rw-r--r--src/db_hlr.c21
-rw-r--r--src/hlr_vty_subscr.c17
3 files changed, 44 insertions, 0 deletions
diff --git a/src/db.h b/src/db.h
index 5129b8d..ae592fb 100644
--- a/src/db.h
+++ b/src/db.h
@@ -84,8 +84,14 @@ struct hlr_subscriber {
uint32_t lmsi;
bool ms_purged_cs;
bool ms_purged_ps;
+ time_t last_lu_seen;
};
+/* A format string for use with strptime(3). This format string is
+ * used to parse the last_lu_seen column stored in the HLR database.
+ * See https://sqlite.org/lang_datefunc.html, function datetime(). */
+#define DB_LAST_LU_SEEN_FMT "%Y-%m-%d %H:%M:%S"
+
/* Like struct osmo_sub_auth_data, but the keys are in hexdump representation.
* This is useful because SQLite requires them in hexdump format, and callers
* like the VTY and CTRL interface also have them available as hexdump to begin
diff --git a/src/db_hlr.c b/src/db_hlr.c
index db31009..c97cd82 100644
--- a/src/db_hlr.c
+++ b/src/db_hlr.c
@@ -17,6 +17,11 @@
*
*/
+#define _POSIX_C_SOURCE 200809L /* for strptime(3) */
+/* These are needed as well due to the above _POSIX_C_SOURCE definition: */
+#define _DEFAULT_SOURCE /* for struct timezone */
+#define _XOPEN_SOURCE /* for clockid_t */
+
#include <string.h>
#include <errno.h>
#include <inttypes.h>
@@ -387,6 +392,8 @@ static int db_sel(struct db_context *dbc, sqlite3_stmt *stmt, struct hlr_subscri
{
int rc;
int ret = 0;
+ const char *last_lu_seen_str;
+ struct tm tm;
/* execute the statement */
rc = sqlite3_step(stmt);
@@ -419,6 +426,20 @@ static int db_sel(struct db_context *dbc, sqlite3_stmt *stmt, struct hlr_subscri
subscr->lmsi = sqlite3_column_int(stmt, 10);
subscr->ms_purged_cs = sqlite3_column_int(stmt, 11);
subscr->ms_purged_ps = sqlite3_column_int(stmt, 12);
+ last_lu_seen_str = (const char *)sqlite3_column_text(stmt, 13);
+ if (last_lu_seen_str && last_lu_seen_str[0] != '\0') {
+ if (strptime(last_lu_seen_str, DB_LAST_LU_SEEN_FMT, &tm) == NULL) {
+ LOGP(DAUC, LOGL_ERROR, "Cannot parse last LU timestamp '%s' of subscriber with IMSI='%s': %s\n",
+ last_lu_seen_str, subscr->imsi, strerror(errno));
+ } else {
+ subscr->last_lu_seen = mktime(&tm);
+ if (subscr->last_lu_seen == -1) {
+ LOGP(DAUC, LOGL_ERROR, "Cannot convert LU timestamp '%s' to time_t: %s\n",
+ last_lu_seen_str, strerror(errno));
+ subscr->last_lu_seen = 0;
+ }
+ }
+ }
out:
db_remove_reset(stmt);
diff --git a/src/hlr_vty_subscr.c b/src/hlr_vty_subscr.c
index bc6f6a5..92cfa2a 100644
--- a/src/hlr_vty_subscr.c
+++ b/src/hlr_vty_subscr.c
@@ -20,6 +20,8 @@
#include <inttypes.h>
#include <string.h>
#include <errno.h>
+#include <sys/types.h>
+#include <time.h>
#include <osmocom/gsm/gsm23003.h>
#include <osmocom/vty/vty.h>
@@ -33,11 +35,24 @@ struct vty;
#define hexdump_buf(buf) osmo_hexdump_nospc((void*)buf, sizeof(buf))
+static char *
+get_datestr(const time_t *t, char *datebuf)
+{
+ char *p, *s = ctime_r(t, datebuf);
+
+ /* Strip trailing newline. */
+ p = strchr(s, '\n');
+ if (p)
+ *p = '\0';
+ return s;
+}
+
static void subscr_dump_full_vty(struct vty *vty, struct hlr_subscriber *subscr)
{
int rc;
struct osmo_sub_auth_data aud2g;
struct osmo_sub_auth_data aud3g;
+ char datebuf[26]; /* for ctime_r(3) */
vty_out(vty, " ID: %"PRIu64"%s", subscr->id, VTY_NEWLINE);
@@ -63,6 +78,8 @@ static void subscr_dump_full_vty(struct vty *vty, struct hlr_subscriber *subscr)
vty_out(vty, " PS disabled%s", VTY_NEWLINE);
if (subscr->ms_purged_ps)
vty_out(vty, " PS purged%s", VTY_NEWLINE);
+ if (subscr->last_lu_seen)
+ vty_out(vty, " last LU seen: %s UTC%s", get_datestr(&subscr->last_lu_seen, datebuf), VTY_NEWLINE);
if (!*subscr->imsi)
return;