summaryrefslogtreecommitdiffstats
path: root/src/util-time.h
blob: b0f7207b3c86b4fab60aa14d2f4e6f8341b102c1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/* Copyright (C) 2007-2013 Open Information Security Foundation
 *
 * You can copy, redistribute or modify this Program under the terms of
 * the GNU General Public License version 2 as published by the Free
 * Software Foundation.
 *
 * 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
 * version 2 along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 */

/**
 * \file
 *
 * \author Victor Julien <victor@inliniac.net>
 */

#ifndef __UTIL_TIME_H__
#define __UTIL_TIME_H__

/*
 * The SCTime_t member is broken up as
 *  seconds: 44
 *  useconds: 20
 *
 * Over 500000 years can be represented in 44 bits of seconds:
 *  2^44/(365*24*60*60)
 *  557855.560
 * 1048576 microseconds can be represented in 20 bits:
 *  2^20
 *  1048576
 */

typedef struct {
    uint64_t secs : 44;
    uint64_t usecs : 20;
} SCTime_t;

#define SCTIME_INIT(t)                                                                             \
    {                                                                                              \
        (t).secs = 0;                                                                              \
        (t).usecs = 0;                                                                             \
    }

#define SCTIME_INITIALIZER                                                                         \
    (SCTime_t)                                                                                     \
    {                                                                                              \
        .secs = 0, .usecs = 0                                                                      \
    }
#define SCTIME_USECS(t)          ((uint64_t)(t).usecs)
#define SCTIME_SECS(t)           ((uint64_t)(t).secs)
#define SCTIME_MSECS(t)          (SCTIME_SECS(t) * 1000 + SCTIME_USECS(t) / 1000)
#define SCTIME_ADD_USECS(ts, us)                                                                   \
    (SCTime_t)                                                                                     \
    {                                                                                              \
        .secs = (ts).secs + ((ts).usecs + (us)) / 1000000, .usecs = ((ts).usecs + (us)) % 1000000  \
    }
#define SCTIME_ADD_SECS(ts, s)                                                                     \
    (SCTime_t)                                                                                     \
    {                                                                                              \
        .secs = (ts).secs + (s), .usecs = (ts).usecs                                               \
    }
#define SCTIME_FROM_SECS(s)                                                                        \
    (SCTime_t)                                                                                     \
    {                                                                                              \
        .secs = (s), .usecs = 0                                                                    \
    }
#define SCTIME_FROM_USECS(us)                                                                      \
    (SCTime_t)                                                                                     \
    {                                                                                              \
        .secs = 0, .usecs = (us)                                                                   \
    }
#define SCTIME_FROM_TIMEVAL(tv)                                                                    \
    (SCTime_t)                                                                                     \
    {                                                                                              \
        .secs = (tv)->tv_sec, .usecs = (tv)->tv_usec                                               \
    }
/** \brief variant to deal with potentially bad timestamps, like from pcap files */
#define SCTIME_FROM_TIMEVAL_UNTRUSTED(tv)                                                          \
    (SCTime_t)                                                                                     \
    {                                                                                              \
        .secs = ((tv)->tv_sec > 0) ? (tv)->tv_sec : 0,                                             \
        .usecs = ((tv)->tv_usec > 0) ? (tv)->tv_usec : 0                                           \
    }
#define SCTIME_FROM_TIMESPEC(ts)                                                                   \
    (SCTime_t)                                                                                     \
    {                                                                                              \
        .secs = (ts)->tv_sec, .usecs = (ts)->tv_nsec / 1000                                        \
    }

#define SCTIME_TO_TIMEVAL(tv, t)                                                                   \
    (tv)->tv_sec = SCTIME_SECS((t));                                                               \
    (tv)->tv_usec = SCTIME_USECS((t));
#define SCTIME_CMP(a, b, CMP)                                                                      \
    ((SCTIME_SECS(a) == SCTIME_SECS(b)) ? (SCTIME_USECS(a) CMP SCTIME_USECS(b))                    \
                                        : (SCTIME_SECS(a) CMP SCTIME_SECS(b)))
#define SCTIME_CMP_GTE(a, b) SCTIME_CMP((a), (b), >=)
#define SCTIME_CMP_GT(a, b)  SCTIME_CMP((a), (b), >)
#define SCTIME_CMP_LT(a, b)  SCTIME_CMP((a), (b), <)
#define SCTIME_CMP_LTE(a, b) SCTIME_CMP((a), (b), <=)
#define SCTIME_CMP_NEQ(a, b) SCTIME_CMP((a), (b), !=)

void TimeInit(void);
void TimeDeinit(void);

void TimeSetByThread(const int thread_id, SCTime_t tv);
SCTime_t TimeGet(void);

/** \brief initialize a 'struct timespec' from a 'struct timeval'. */
#define FROM_TIMEVAL(timev) { .tv_sec = (timev).tv_sec, .tv_nsec = (timev).tv_usec * 1000 }

/** \brief compare two 'struct timeval' and return if the first is earlier than the second */
static inline bool TimevalEarlier(struct timeval *first, struct timeval *second)
{
    /* from man timercmp on Linux: "Some systems (but not Linux/glibc), have a broken timercmp()
     * implementation, in which CMP of >=, <=, and == do not work; portable applications can instead
     * use ... !timercmp(..., >) */
    return !timercmp(first, second, >);
}

#ifndef timeradd
#define timeradd(a, b, r)                                                                          \
    do {                                                                                           \
        (r)->tv_sec = (a)->tv_sec + (b)->tv_sec;                                                   \
        (r)->tv_usec = (a)->tv_usec + (b)->tv_usec;                                                \
        if ((r)->tv_usec >= 1000000) {                                                             \
            (r)->tv_sec++;                                                                         \
            (r)->tv_usec -= 1000000;                                                               \
        }                                                                                          \
    } while (0)
#endif

#ifdef UNITTESTS
void TimeSet(SCTime_t);
void TimeSetToCurrentTime(void);
void TimeSetIncrementTime(uint32_t);
#endif

bool TimeModeIsReady(void);
void TimeModeSetLive(void);
void TimeModeSetOffline (void);
bool TimeModeIsLive(void);

struct tm *SCLocalTime(time_t timep, struct tm *result);
void CreateTimeString(const SCTime_t ts, char *str, size_t size);
void CreateIsoTimeString(const SCTime_t ts, char *str, size_t size);
void CreateUtcIsoTimeString(const SCTime_t ts, char *str, size_t size);
void CreateFormattedTimeString(const struct tm *t, const char * fmt, char *str, size_t size);
time_t SCMkTimeUtc(struct tm *tp);
int SCStringPatternToTime(char *string, const char **patterns,
                           int num_patterns, struct tm *time);
int SCTimeToStringPattern (time_t epoch, const char *pattern, char *str,
                           size_t size);
uint64_t SCParseTimeSizeString (const char *str);
uint64_t SCGetSecondsUntil (const char *str, time_t epoch);
uint64_t SCTimespecAsEpochMillis(const struct timespec *ts);
uint64_t TimeDifferenceMicros(struct timeval t0, struct timeval t1);

#endif /* __UTIL_TIME_H__ */