]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
time: add support for time64 libcs
authorPhilip Prindeville <philipp@redfish-solutions.com>
Sun, 13 Feb 2022 19:06:37 +0000 (12:06 -0700)
committerFriendly Automation <jenkins2@gerrit.asterisk.org>
Thu, 24 Mar 2022 16:22:59 +0000 (11:22 -0500)
Treat time_t's as entirely unique and use the POSIX API's for
converting to/from strings.

Lastly, a 64-bit integer formats as 20 digits at most in base10.
Don't need to have any 100 byte buffers to hold that.

ASTERISK-29674 #close

Signed-off-by: Philip Prindeville <philipp@redfish-solutions.com>
Change-Id: Id7b25bdca8f92e34229f6454f6c3e500f2cd6f56

13 files changed:
include/asterisk/time.h
main/Makefile
main/time.c
res/res_calendar_caldav.c
res/res_calendar_icalendar.c
res/res_http_media_cache.c
res/res_odbc.c
res/res_pjsip/location.c
res/res_pjsip/pjsip_options.c
res/res_pjsip_history.c
res/res_pjsip_pubsub.c
res/res_pjsip_registrar.c
res/res_stir_shaken.c

index e2ab513384fd2e307066c3991a835340a8dae2e8..3e0c064fc7ec5dfd281df2440dd683f95d2ee42e 100644 (file)
 
 #include "asterisk/inline_api.h"
 
+/* A time_t can be represented as an unsigned long long (or uint64_t).
+ * Formatted in base 10, UINT64_MAX is 20 digits long, plus one for NUL.
+ * This should be the size of the receiving char buffer for calls to
+ * ast_time_t_to_string().
+ */
+#define AST_TIME_T_LEN         21
+
 /* We have to let the compiler learn what types to use for the elements of a
    struct timeval since on linux, it's time_t and suseconds_t, but on *BSD,
    they are just a long.
@@ -316,4 +323,17 @@ struct timeval ast_time_create_by_unit(unsigned long val, enum TIME_UNIT unit);
  */
 struct timeval ast_time_create_by_unit_str(unsigned long val, const char *unit);
 
+/*!
+ * \brief Converts to a string representation of a time_t as decimal
+ * seconds since the epoch. Returns -1 on failure, zero otherwise.
+ *
+ * The buffer should be at least 22 bytes long.
+ */
+int ast_time_t_to_string(time_t time, char *buf, size_t length);
+
+/*!
+ * \brief Returns a time_t from a string containing seconds since the epoch.
+ */
+time_t ast_string_to_time_t(const char *str);
+
 #endif /* _ASTERISK_TIME_H */
index 1cb2c25eff5aa9ffbce1cec53b8f105a48b2526e..db3bcb51af20d6be8aa9445ffcc486a4658c8a4b 100644 (file)
@@ -167,6 +167,7 @@ options.o: _ASTCFLAGS+=$(call get_menuselect_cflags,REF_DEBUG)
 sched.o: _ASTCFLAGS+=$(call get_menuselect_cflags,DEBUG_SCHEDULER DUMP_SCHEDULER)
 tcptls.o: _ASTCFLAGS+=$(OPENSSL_INCLUDE) -Wno-deprecated-declarations
 uuid.o: _ASTCFLAGS+=$(UUID_INCLUDE)
+time.o: _ASTCFLAGS+=-D_XOPEN_SOURCE=700
 
 
 OBJS:=$(sort $(OBJS))
index 266c5cfc0f13c0ca119e94a1887746893f549af6..7babafed96a7e25074eddf3394f5726f7a2a2efc 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <inttypes.h>
 #include <string.h>
+#include <strings.h>
 #include <time.h>
 
 #include "asterisk/time.h"
@@ -143,3 +144,31 @@ struct timeval ast_time_create_by_unit_str(unsigned long val, const char *unit)
 {
        return ast_time_create_by_unit(val, ast_time_str_to_unit(unit));
 }
+
+/*!
+ * \brief Returns a string representation of a time_t as decimal seconds
+ * since the epoch.
+ */
+int ast_time_t_to_string(time_t time, char *buf, size_t length)
+{
+       struct tm tm;
+
+       localtime_r(&time, &tm);
+       return (strftime(buf, length, "%s", &tm) == 0) ? -1 : 0;
+}
+
+/*!
+ * \brief Returns a time_t from a string containing seconds since the epoch.
+ */
+time_t ast_string_to_time_t(const char *str)
+{
+       struct tm tm = { 0, };
+
+       /* handle leading spaces */
+       if (strptime(str, " %s", &tm) == NULL) {
+               return (time_t)-1;
+       }
+       tm.tm_isdst = -1;
+       return mktime(&tm);
+}
+
index 9bdde0e94bb5a357f40842be7d942558cbd1fae6..a5266f3369bf2c2b2bf6afa15df4108c89487233 100644 (file)
@@ -404,8 +404,8 @@ static void caldav_add_event(icalcomponent *comp, struct icaltime_span *span, vo
                if (!ast_strlen_zero(event->summary)) {
                        ast_string_field_set(event, uid, event->summary);
                } else {
-                       char tmp[100];
-                       snprintf(tmp, sizeof(tmp), "%ld", event->start);
+                       char tmp[AST_TIME_T_LEN];
+                       ast_time_t_to_string(event->start, tmp, sizeof(tmp));
                        ast_string_field_set(event, uid, tmp);
                }
        }
index 999cf0ecf4ae68c7df5a3e75aa9303afd74beb5b..cab8cf628ae077e360de84f7fdc7afe866b9e10b 100644 (file)
@@ -245,8 +245,8 @@ static void icalendar_add_event(icalcomponent *comp, struct icaltime_span *span,
                if (!ast_strlen_zero(event->summary)) {
                        ast_string_field_set(event, uid, event->summary);
                } else {
-                       char tmp[100];
-                       snprintf(tmp, sizeof(tmp), "%ld", event->start);
+                       char tmp[AST_TIME_T_LEN];
+                       ast_time_t_to_string(event->start, tmp, sizeof(tmp));
                        ast_string_field_set(event, uid, tmp);
                }
        }
index a4efadf6e7648b8d4aa302627b9beed58ed9c79e..0ad5ea8047cfae4f44b61e2655915f6cb8d140a1 100644 (file)
@@ -116,7 +116,7 @@ static size_t curl_body_callback(void *ptr, size_t size, size_t nitems, void *da
 static void bucket_file_set_expiration(struct ast_bucket_file *bucket_file)
 {
        struct ast_bucket_metadata *metadata;
-       char time_buf[32];
+       char time_buf[32], secs[AST_TIME_T_LEN];
        struct timeval actual_expires = ast_tvnow();
 
        metadata = ast_bucket_file_metadata_get(bucket_file, "cache-control");
@@ -150,7 +150,8 @@ static void bucket_file_set_expiration(struct ast_bucket_file *bucket_file)
        }
 
        /* Use 'now' if we didn't get an expiration time */
-       snprintf(time_buf, sizeof(time_buf), "%30lu", actual_expires.tv_sec);
+       ast_time_t_to_string(actual_expires.tv_sec, secs, sizeof(secs));
+       snprintf(time_buf, sizeof(time_buf), "%30s", secs);
 
        ast_bucket_file_metadata_set(bucket_file, "__actual_expires", time_buf);
 }
@@ -314,7 +315,7 @@ static int bucket_file_expired(struct ast_bucket_file *bucket_file)
                return 1;
        }
 
-       if (sscanf(metadata->value, "%lu", &expires.tv_sec) != 1) {
+       if ((expires.tv_sec = ast_string_to_time_t(metadata->value)) == -1) {
                return 1;
        }
 
index 63fdf37c087e251e58d1c90ffcbcf8d9507de45f..54037f9ff0d4c78906e00fd69cadb443513b27ce 100644 (file)
@@ -1029,7 +1029,9 @@ static odbc_status odbc_obj_connect(struct odbc_obj *obj)
        /* Dont connect while server is marked as unreachable via negative_connection_cache */
        negative_cache_expiration = obj->parent->last_negative_connect.tv_sec + obj->parent->negative_connection_cache.tv_sec;
        if (time(NULL) < negative_cache_expiration) {
-               ast_log(LOG_WARNING, "Not connecting to %s. Negative connection cache for %ld seconds\n", obj->parent->name, negative_cache_expiration - time(NULL));
+               char secs[AST_TIME_T_LEN];
+               ast_time_t_to_string(negative_cache_expiration - time(NULL), secs, sizeof(secs));
+               ast_log(LOG_WARNING, "Not connecting to %s. Negative connection cache for %s seconds\n", obj->parent->name, secs);
                return ODBC_FAIL;
        }
 
index bae8a2d7255c8362b064415678e2d43df1fea92e..a507b8903d43be7dfa35fcb05c1cf7214ccc4242 100644 (file)
@@ -489,7 +489,10 @@ static int expiration_str2struct(const struct aco_option *opt, struct ast_variab
 static int expiration_struct2str(const void *obj, const intptr_t *args, char **buf)
 {
        const struct ast_sip_contact *contact = obj;
-       return (ast_asprintf(buf, "%ld", contact->expiration_time.tv_sec) < 0) ? -1 : 0;
+       char secs[AST_TIME_T_LEN];
+
+       ast_time_t_to_string(contact->expiration_time.tv_sec, secs, sizeof(secs));
+       return (ast_asprintf(buf, "%s", secs) < 0) ? -1 : 0;
 }
 
 static int permanent_uri_sort_fn(const void *obj_left, const void *obj_right, int flags)
index e1f048e9a6a78d2839488347a1b1c11350bf61ca..14013ade5ae910d3cd220746e73a7e0082db192c 100644 (file)
@@ -2722,6 +2722,7 @@ int ast_sip_format_contact_ami(void *obj, void *arg, int flags)
        struct ast_sip_contact_status *status;
        struct ast_str *buf;
        const struct ast_sip_endpoint *endpoint = ami->arg;
+       char secs[AST_TIME_T_LEN];
 
        buf = ast_sip_create_ami_event("ContactStatusDetail", ami);
        if (!buf) {
@@ -2733,7 +2734,8 @@ int ast_sip_format_contact_ami(void *obj, void *arg, int flags)
        ast_str_append(&buf, 0, "AOR: %s\r\n", wrapper->aor_id);
        ast_str_append(&buf, 0, "URI: %s\r\n", contact->uri);
        ast_str_append(&buf, 0, "UserAgent: %s\r\n", contact->user_agent);
-       ast_str_append(&buf, 0, "RegExpire: %ld\r\n", contact->expiration_time.tv_sec);
+       ast_time_t_to_string(contact->expiration_time.tv_sec, secs, sizeof(secs));
+       ast_str_append(&buf, 0, "RegExpire: %s\r\n", secs);
        if (!ast_strlen_zero(contact->via_addr)) {
                ast_str_append(&buf, 0, "ViaAddress: %s", contact->via_addr);
                if (contact->via_port) {
index de1063b9d6179794dff7fab4470954caeaa87149..9da0af4f33181c12995fbed084039c2490965eff 100644 (file)
@@ -199,7 +199,7 @@ static int evaluate_equal(struct operator *op, enum aco_option_type type, void *
        {
                struct timeval right = { 0, };
 
-               if (sscanf(op_right->field, "%ld", &right.tv_sec) != 1) {
+               if ((right.tv_sec = ast_string_to_time_t(op_right->field)) == -1) {
                        ast_log(LOG_WARNING, "Unable to extract field '%s': not a timestamp\n", op_right->field);
                        return -1;
                }
@@ -270,7 +270,7 @@ static int evaluate_less_than(struct operator *op, enum aco_option_type type, vo
        {
                struct timeval right = { 0, };
 
-               if (sscanf(op_right->field, "%ld", &right.tv_sec) != 1) {
+               if ((right.tv_sec = ast_string_to_time_t(op_right->field)) == -1) {
                        ast_log(LOG_WARNING, "Unable to extract field '%s': not a timestamp\n", op_right->field);
                        return -1;
                }
@@ -319,7 +319,7 @@ static int evaluate_greater_than(struct operator *op, enum aco_option_type type,
        {
                struct timeval right = { 0, };
 
-               if (sscanf(op_right->field, "%ld", &right.tv_sec) != 1) {
+               if ((right.tv_sec = ast_string_to_time_t(op_right->field)) == -1) {
                        ast_log(LOG_WARNING, "Unable to extract field '%s': not a timestamp\n", op_right->field);
                        return -1;
                }
@@ -656,7 +656,7 @@ static struct pjsip_history_entry *pjsip_history_entry_alloc(pjsip_msg *msg)
 /*! \brief Format single line history entry */
 static void sprint_list_entry(struct pjsip_history_entry *entry, char *line, int len)
 {
-       char addr[64];
+       char addr[64], secs[AST_TIME_T_LEN];
 
        if (entry->transmitted) {
                pj_sockaddr_print(&entry->dst, addr, sizeof(addr), 3);
@@ -664,22 +664,24 @@ static void sprint_list_entry(struct pjsip_history_entry *entry, char *line, int
                pj_sockaddr_print(&entry->src, addr, sizeof(addr), 3);
        }
 
+       ast_time_t_to_string(entry->timestamp.tv_sec, secs, sizeof(secs));
+
        if (entry->msg->type == PJSIP_REQUEST_MSG) {
                char uri[128];
 
                pjsip_uri_print(PJSIP_URI_IN_REQ_URI, entry->msg->line.req.uri, uri, sizeof(uri));
-               snprintf(line, len, "%-5.5d %-10.10ld %-5.5s %-24.24s %.*s %s SIP/2.0",
+               snprintf(line, len, "%-5.5d %-10.10s %-5.5s %-24.24s %.*s %s SIP/2.0",
                        entry->number,
-                       entry->timestamp.tv_sec,
+                       secs,
                        entry->transmitted ? "* ==>" : "* <==",
                        addr,
                        (int)pj_strlen(&entry->msg->line.req.method.name),
                        pj_strbuf(&entry->msg->line.req.method.name),
                        uri);
        } else {
-               snprintf(line, len, "%-5.5d %-10.10ld %-5.5s %-24.24s SIP/2.0 %u %.*s",
+               snprintf(line, len, "%-5.5d %-10.10s %-5.5s %-24.24s SIP/2.0 %u %.*s",
                        entry->number,
-                       entry->timestamp.tv_sec,
+                       secs,
                        entry->transmitted ? "* ==>" : "* <==",
                        addr,
                        entry->msg->line.status.code,
@@ -1149,7 +1151,7 @@ static struct vector_history_t *filter_history(struct ast_cli_args *a)
 /*! \brief Print a detailed view of a single entry in the history to the CLI */
 static void display_single_entry(struct ast_cli_args *a, struct pjsip_history_entry *entry)
 {
-       char addr[64];
+       char addr[64], secs[AST_TIME_T_LEN];
        char *buf;
 
        buf = ast_calloc(1, PJSIP_MAX_PKT_LEN * sizeof(char));
@@ -1169,11 +1171,12 @@ static void display_single_entry(struct ast_cli_args *a, struct pjsip_history_en
                pj_sockaddr_print(&entry->src, addr, sizeof(addr), 3);
        }
 
-       ast_cli(a->fd, "<--- History Entry %d %s %s at %-10.10ld --->\n",
+       ast_time_t_to_string(entry->timestamp.tv_sec, secs, sizeof(secs));
+       ast_cli(a->fd, "<--- History Entry %d %s %s at %-10.10s --->\n",
                entry->number,
                entry->transmitted ? "Sent to" : "Received from",
                addr,
-               entry->timestamp.tv_sec);
+               secs);
        ast_cli(a->fd, "%s\n", buf);
 
        ast_free(buf);
index 1d136955bf3e90afa4f18e38bbfe53a38e9872d9..5cccdccec924ab8706b1731a3f4b432ff7bc9b49 100644 (file)
@@ -4879,7 +4879,11 @@ static int persistence_expires_str2struct(const struct aco_option *opt, struct a
 static int persistence_expires_struct2str(const void *obj, const intptr_t *args, char **buf)
 {
        const struct subscription_persistence *persistence = obj;
-       return (ast_asprintf(buf, "%ld", persistence->expires.tv_sec) < 0) ? -1 : 0;
+       char secs[AST_TIME_T_LEN];
+
+       ast_time_t_to_string(persistence->expires.tv_sec, secs, sizeof(secs));
+
+       return (ast_asprintf(buf, "%s", secs) < 0) ? -1 : 0;
 }
 
 #define RESOURCE_LIST_INIT_SIZE 4
index 9c999c15cfe62451555e08728c45d26180214426..f2b785bab99b3a9899ed7ca52f8775386f031f93 100644 (file)
@@ -1365,12 +1365,13 @@ static void *check_expiration_thread(void *data)
 {
        struct ao2_container *contacts;
        struct ast_variable *var;
-       char *time = alloca(64);
+       char time[AST_TIME_T_LEN];
 
        while (check_interval) {
                sleep(check_interval);
 
-               sprintf(time, "%ld", ast_tvnow().tv_sec);
+               ast_time_t_to_string(ast_tvnow().tv_sec, time, sizeof(time));
+
                var = ast_variable_new("expiration_time <=", time, "");
 
                ast_debug(4, "Woke up at %s  Interval: %d\n", time, check_interval);
index 373a1a1a926c3d66659509174eca8095a6bc9291..19e2654f8f948ef577d51fb29f82cc1db8098f96 100644 (file)
@@ -351,7 +351,7 @@ int ast_stir_shaken_add_verification(struct ast_channel *chan, const char *ident
  */
 static void set_public_key_expiration(const char *public_cert_url, const struct curl_cb_data *data)
 {
-       char time_buf[32];
+       char time_buf[32], secs[AST_TIME_T_LEN];
        char *value;
        struct timeval actual_expires = ast_tvnow();
        char hash[41];
@@ -389,7 +389,9 @@ static void set_public_key_expiration(const char *public_cert_url, const struct
                actual_expires.tv_sec += EXPIRATION_BUFFER;
        }
 
-       snprintf(time_buf, sizeof(time_buf), "%30lu", actual_expires.tv_sec);
+       ast_time_t_to_string(actual_expires.tv_sec, secs, sizeof(secs));
+
+       snprintf(time_buf, sizeof(time_buf), "%30s", secs);
 
        ast_db_put(hash, "expiration", time_buf);
 }