diff options
author | Harald Welte <laforge@osmocom.org> | 2022-05-17 18:25:14 +0200 |
---|---|---|
committer | laforge <laforge@osmocom.org> | 2022-05-19 19:34:41 +0000 |
commit | e6f1160046c85fae4959dae880f0b45a6c88bad1 (patch) | |
tree | cbf8333fe28e0ec04aebe253c08114619651df04 | |
parent | 53e2e5fe708293f9ac8f3b1cb69e62261d90accb (diff) |
smpp: Parse and use SMPP-provided validity period
Before this patch, we always ignored any SMPP-provided validity period
and used '0' which is now, and means it expires immediately.
As SMPP allows for validity_period of NULL, use 7 days as SMSC default
in such situations.
Change-Id: Iad9f2697f045ed3bc0eb74c3a9730861f82e6c48
Closes: OS#5567
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | src/libmsc/smpp_openbsc.c | 11 | ||||
-rw-r--r-- | src/libmsc/smpp_smsc.h | 1 | ||||
-rw-r--r-- | src/libmsc/smpp_utils.c | 107 | ||||
-rw-r--r-- | tests/smpp/smpp_test.c | 38 | ||||
-rw-r--r-- | tests/smpp/smpp_test.ok | 8 |
6 files changed, 165 insertions, 2 deletions
diff --git a/configure.ac b/configure.ac index 45f6806b0..4b67ea62d 100644 --- a/configure.ac +++ b/configure.ac @@ -48,6 +48,8 @@ PKG_CHECK_MODULES(LIBOSMOSCCP, libosmo-sccp >= 1.5.0) PKG_CHECK_MODULES(LIBOSMOMGCPCLIENT, libosmo-mgcp-client >= 1.9.0) PKG_CHECK_MODULES(LIBOSMOGSUPCLIENT, libosmo-gsup-client >= 1.4.0) +AC_CHECK_FUNC([timegm], [AC_DEFINE(HAVE_TIMEGM, 1, Define if libc implements timegm)]) + old_LIBS=$LIBS AC_SEARCH_LIBS([sctp_send], [sctp], [ AC_DEFINE(HAVE_LIBSCTP, 1, [Define 1 to enable SCTP support]) diff --git a/src/libmsc/smpp_openbsc.c b/src/libmsc/smpp_openbsc.c index 54cd75b9a..4ce6c27d9 100644 --- a/src/libmsc/smpp_openbsc.c +++ b/src/libmsc/smpp_openbsc.c @@ -1,6 +1,6 @@ /* OpenBSC SMPP 3.4 interface, SMSC-side implementation */ -/* (C) 2012-2013 by Harald Welte <laforge@gnumonks.org> +/* (C) 2012-2022 by Harald Welte <laforge@gnumonks.org> * * All Rights Reserved * @@ -24,6 +24,7 @@ #include <string.h> #include <stdint.h> #include <errno.h> +#include <time.h> #include <smpp34.h> #include <smpp34_structs.h> @@ -122,6 +123,8 @@ static int smpp34_submit_tlv_msg_payload(const struct tlv_t *t, static int submit_to_sms(struct gsm_sms **psms, struct gsm_network *net, const struct submit_sm_t *submit) { + time_t t_now = time(NULL); + time_t t_validity_absolute; const uint8_t *sms_msg = NULL; unsigned int sms_msg_len = 0; struct vlr_subscr *dest; @@ -258,6 +261,12 @@ static int submit_to_sms(struct gsm_sms **psms, struct gsm_network *net, sms->user_data_len = sms_msg_len; } + t_validity_absolute = smpp_parse_time_format((const char *) submit->validity_period, &t_now); + if (!t_validity_absolute) + sms->validity_minutes = 7 * 24 * 60; /* default: 7 days */ + else + sms->validity_minutes = (t_validity_absolute - t_now) / 60; + *psms = sms; return ESME_ROK; } diff --git a/src/libmsc/smpp_smsc.h b/src/libmsc/smpp_smsc.h index 4c0d70154..257589e2d 100644 --- a/src/libmsc/smpp_smsc.h +++ b/src/libmsc/smpp_smsc.h @@ -158,6 +158,7 @@ int smpp_vty_init(void); int smpp_determine_scheme(uint8_t dcs, uint8_t *data_coding, int *mode); +time_t smpp_parse_time_format(const char *vp, time_t *t_now); struct gsm_sms; diff --git a/src/libmsc/smpp_utils.c b/src/libmsc/smpp_utils.c index 7fffdd27a..3c7757b9a 100644 --- a/src/libmsc/smpp_utils.c +++ b/src/libmsc/smpp_utils.c @@ -1,5 +1,5 @@ -/* (C) 2012-2013 by Harald Welte <laforge@gnumonks.org> +/* (C) 2012-2022 by Harald Welte <laforge@gnumonks.org> * * All Rights Reserved * @@ -17,6 +17,9 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "config.h" + +#include <time.h> #include "smpp_smsc.h" #include <osmocom/core/logging.h> @@ -59,3 +62,105 @@ unknown_mo: return 0; } + +/* convert a 'struct tm' holding relative time to an absolute one by adding it to t_now */ +static void relative2absolute(struct tm *tm, time_t t_now) +{ + struct tm tm_now; + + localtime_r(&t_now, &tm_now); + + tm->tm_year += tm_now.tm_year; + tm->tm_mon += tm_now.tm_mon; + tm->tm_mday += tm_now.tm_mday; + tm->tm_hour += tm_now.tm_hour; + tm->tm_min += tm_now.tm_min; + tm->tm_sec += tm_now.tm_sec; +} + +#ifndef HAVE_TIMEGM +/* for systems without a timegm() function, provide a reimplementation */ +static time_t timegm(struct tm *tm) +{ + const char *orig_tz = getenv("TZ"); + time_t ret; + + setenv("TZ", "UTC", 1); + + ret = mktime(tm); + + if (orig_tz) + setenv("TZ", orig_tz, 1); + else + unsetenv("TZ"); + + return ret; +} +#endif + + +/*! Parse a SMPP time format as defined in SMPP v3.4 7.1.1. + * \param[in] vp string containing the time as encoded in SMPP v3.4 + * \param[in] t_now pointer to a time value for 'now'. Can be NULL, then we call time() ourselves. + * \returns time_t value in seconds since the epoch of the absolute decoded time */ +time_t smpp_parse_time_format(const char *vp, time_t *t_now) +{ + unsigned int year, month, day, hour, minute, second, tenth, gmt_off_quarter; + char plus_minus_relative; + int gmt_off_minutes; + struct tm tm; + time_t ret; + int rc; + + memset(&tm, 0, sizeof(tm)); + + if (vp[0] == '\0') + return 0; + + /* YYMMDDhhmmsstnnp (where p can be -, + or R) */ + rc = sscanf(vp, "%2u%2u%2u%2u%2u%2u%1u%2u%c", &year, &month, &day, &hour, &minute, + &second, &tenth, &gmt_off_quarter, &plus_minus_relative); + if (rc != 9) + return (time_t) -1; + + tm.tm_year = year; + /* month handling differs between absolute/relative below... */ + tm.tm_mday = day; + tm.tm_hour = hour; + tm.tm_min = minute; + tm.tm_sec = second; + tm.tm_isdst = 0; + + switch (plus_minus_relative) { + case '+': /* time is in quarter hours advanced compared to UTC */ + if (year < 70) + tm.tm_year += 100; + tm.tm_mon = month - 1; + gmt_off_minutes = 15 * gmt_off_quarter; + tm.tm_min -= gmt_off_minutes; + ret = timegm(&tm); + break; + case '-': /* time is in quarter hours retared compared to UTC */ + if (year < 70) + tm.tm_year += 100; + tm.tm_mon = month - 1; + gmt_off_minutes = 15 * gmt_off_quarter; + tm.tm_min += gmt_off_minutes; + ret = timegm(&tm); + break; + case 'R': + /* relative time */ + tm.tm_mon = month; + if (t_now) + relative2absolute(&tm, *t_now); + else + relative2absolute(&tm, time(NULL)); + /* here we do want local time, as we're passing local time in above! */ + ret = mktime(&tm); + break; + default: + return (time_t) -1; + } + + return ret; +} diff --git a/tests/smpp/smpp_test.c b/tests/smpp/smpp_test.c index d86da5486..4640a5f8d 100644 --- a/tests/smpp/smpp_test.c +++ b/tests/smpp/smpp_test.c @@ -1,5 +1,6 @@ /* * (C) 2013 by Holger Hans Peter Freyther + * (C) 2022 by Harald Welte <laforge@osmocom.org> * All Rights Reserved * * This program is free software; you can redistribute it and/or modify @@ -62,6 +63,41 @@ static void test_coding_scheme(void) } } +static const char *smpp_time_tests[] = { + "\0", + "220517175524000+", + "220517175524000-", + "220517175524004+", /* 1 hour advanced compared to GMT */ + "220517175524004-", /* 1 hour retarded compared to GMT */ + "000000010000000R", /* 1 hour */ + "000001000000000R", /* 1 day */ +}; + +static void test_smpp_parse_time_format(void) +{ + time_t t_now = 1652745600; /* 2022-05-17 00:00:00 UTC */ + char *orig_tz; + + printf("Testing SMPP time format parser\n"); + + /* relative time format conversion depends on the local time */ + orig_tz = getenv("TZ"); + setenv("TZ", "UTC", 1); + + for (unsigned int i = 0; i < ARRAY_SIZE(smpp_time_tests); i++) { + time_t t = smpp_parse_time_format(smpp_time_tests[i], &t_now); + char buf[32]; + strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", gmtime(&t)); + printf("'%s': %ld == %s\n", smpp_time_tests[i], t, buf); + } + + if (orig_tz) + setenv("TZ", orig_tz, 1); + else + unsetenv("TZ"); + +} + static const struct log_info_cat smpp_mirror_default_categories[] = { [DSMPP] = { .name = "DSMPP", @@ -85,5 +121,7 @@ int main(int argc, char **argv) log_set_print_category_hex(osmo_stderr_target, 0); test_coding_scheme(); + test_smpp_parse_time_format(); + return EXIT_SUCCESS; } diff --git a/tests/smpp/smpp_test.ok b/tests/smpp/smpp_test.ok index fd44804d1..feb75a6ed 100644 --- a/tests/smpp/smpp_test.ok +++ b/tests/smpp/smpp_test.ok @@ -1 +1,9 @@ Testing coding scheme support +Testing SMPP time format parser +'': 0 == 1970-01-01 00:00:00 +'220517175524000+': 1652810124 == 2022-05-17 17:55:24 +'220517175524000-': 1652810124 == 2022-05-17 17:55:24 +'220517175524004+': 1652806524 == 2022-05-17 16:55:24 +'220517175524004-': 1652813724 == 2022-05-17 18:55:24 +'000000010000000R': 1652749200 == 2022-05-17 01:00:00 +'000001000000000R': 1652832000 == 2022-05-18 00:00:00 |