laforge has submitted this change. ( 
https://gerrit.osmocom.org/c/osmo-msc/+/28136 )

Change subject: smpp: Parse and use SMPP-provided validity period
......................................................................

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
---
M configure.ac
M src/libmsc/smpp_openbsc.c
M src/libmsc/smpp_smsc.h
M src/libmsc/smpp_utils.c
M tests/smpp/smpp_test.c
M tests/smpp/smpp_test.ok
6 files changed, 165 insertions(+), 2 deletions(-)

Approvals:
  laforge: Looks good to me, approved; Verified
  pespin: Looks good to me, but someone else must approve



diff --git a/configure.ac b/configure.ac
index 45f6806..4b67ea6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -48,6 +48,8 @@
 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 54cd75b..4ce6c27 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 <[email protected]>
+/* (C) 2012-2022 by Harald Welte <[email protected]>
  *
  * 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 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 @@
                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 4c0d701..257589e 100644
--- a/src/libmsc/smpp_smsc.h
+++ b/src/libmsc/smpp_smsc.h
@@ -158,6 +158,7 @@

 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 7fffdd2..3c7757b 100644
--- a/src/libmsc/smpp_utils.c
+++ b/src/libmsc/smpp_utils.c
@@ -1,5 +1,5 @@

-/* (C) 2012-2013 by Harald Welte <[email protected]>
+/* (C) 2012-2022 by Harald Welte <[email protected]>
  *
  * 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 @@
        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 d86da54..4640a5f 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 <[email protected]>
  * All Rights Reserved
  *
  * This program is free software; you can redistribute it and/or modify
@@ -62,6 +63,41 @@
        }
 }

+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 @@
        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 fd44804..feb75a6 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

--
To view, visit https://gerrit.osmocom.org/c/osmo-msc/+/28136
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-msc
Gerrit-Branch: master
Gerrit-Change-Id: Iad9f2697f045ed3bc0eb74c3a9730861f82e6c48
Gerrit-Change-Number: 28136
Gerrit-PatchSet: 7
Gerrit-Owner: laforge <[email protected]>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: keith <[email protected]>
Gerrit-Reviewer: laforge <[email protected]>
Gerrit-Reviewer: pespin <[email protected]>
Gerrit-MessageType: merged

Reply via email to