1 /*
2  * Copyright (c) 2017  David Lamparter, for NetDEF, Inc.
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #ifndef _FRR_MONOTIME_H
18 #define _FRR_MONOTIME_H
19 
20 #include <stdint.h>
21 #include <time.h>
22 #include <sys/time.h>
23 
24 #ifdef __cplusplus
25 extern "C" {
26 #endif
27 
28 #ifndef TIMESPEC_TO_TIMEVAL
29 /* should be in sys/time.h on BSD & Linux libcs */
30 #define TIMESPEC_TO_TIMEVAL(tv, ts)                                            \
31 	do {                                                                   \
32 		(tv)->tv_sec = (ts)->tv_sec;                                   \
33 		(tv)->tv_usec = (ts)->tv_nsec / 1000;                          \
34 	} while (0)
35 #endif
36 #ifndef TIMEVAL_TO_TIMESPEC
37 /* should be in sys/time.h on BSD & Linux libcs */
38 #define TIMEVAL_TO_TIMESPEC(tv, ts)                                            \
39 	do {                                                                   \
40 		(ts)->tv_sec = (tv)->tv_sec;                                   \
41 		(ts)->tv_nsec = (tv)->tv_usec * 1000;                          \
42 	} while (0)
43 #endif
44 
monotime(struct timeval * tvo)45 static inline time_t monotime(struct timeval *tvo)
46 {
47 	struct timespec ts;
48 
49 	clock_gettime(CLOCK_MONOTONIC, &ts);
50 	if (tvo) {
51 		TIMESPEC_TO_TIMEVAL(tvo, &ts);
52 	}
53 	return ts.tv_sec;
54 }
55 
56 #define ONE_DAY_SECOND 60*60*24
57 #define ONE_WEEK_SECOND ONE_DAY_SECOND*7
58 #define ONE_YEAR_SECOND ONE_DAY_SECOND*365
59 
60 /* the following two return microseconds, not time_t!
61  *
62  * also, they're negative forms of each other, but having both makes the
63  * code more readable
64  */
monotime_since(const struct timeval * ref,struct timeval * out)65 static inline int64_t monotime_since(const struct timeval *ref,
66 				     struct timeval *out)
67 {
68 	struct timeval tv;
69 	monotime(&tv);
70 	timersub(&tv, ref, &tv);
71 	if (out)
72 		*out = tv;
73 	return (int64_t)tv.tv_sec * 1000000LL + tv.tv_usec;
74 }
75 
monotime_until(const struct timeval * ref,struct timeval * out)76 static inline int64_t monotime_until(const struct timeval *ref,
77 				     struct timeval *out)
78 {
79 	struct timeval tv;
80 	monotime(&tv);
81 	timersub(ref, &tv, &tv);
82 	if (out)
83 		*out = tv;
84 	return (int64_t)tv.tv_sec * 1000000LL + tv.tv_usec;
85 }
86 
monotime_to_realtime(const struct timeval * mono,struct timeval * realout)87 static inline time_t monotime_to_realtime(const struct timeval *mono,
88 					  struct timeval *realout)
89 {
90 	struct timeval delta, real;
91 
92 	monotime_since(mono, &delta);
93 	gettimeofday(&real, NULL);
94 
95 	timersub(&real, &delta, &real);
96 	if (realout)
97 		*realout = real;
98 	return real.tv_sec;
99 }
100 
101 /* Char buffer size for time-to-string api */
102 #define MONOTIME_STRLEN 32
103 
time_to_string(time_t ts,char * buf)104 static inline char *time_to_string(time_t ts, char *buf)
105 {
106 	struct timeval tv;
107 	time_t tbuf;
108 
109 	monotime(&tv);
110 	tbuf = time(NULL) - (tv.tv_sec - ts);
111 
112 	return ctime_r(&tbuf, buf);
113 }
114 
115 /* Convert interval to human-friendly string, used in cli output e.g. */
frrtime_to_interval(time_t t,char * buf,size_t buflen)116 static inline const char *frrtime_to_interval(time_t t, char *buf,
117 					      size_t buflen)
118 {
119 	struct tm tm;
120 
121 	gmtime_r(&t, &tm);
122 
123 	if (t < ONE_DAY_SECOND)
124 		snprintf(buf, buflen, "%02d:%02d:%02d", tm.tm_hour, tm.tm_min,
125 			 tm.tm_sec);
126 	else if (t < ONE_WEEK_SECOND)
127 		snprintf(buf, buflen, "%dd%02dh%02dm", tm.tm_yday, tm.tm_hour,
128 			 tm.tm_min);
129 	else
130 		snprintf(buf, buflen, "%02dw%dd%02dh", tm.tm_yday / 7,
131 			 tm.tm_yday - ((tm.tm_yday / 7) * 7), tm.tm_hour);
132 	return buf;
133 }
134 
135 #ifdef __cplusplus
136 }
137 #endif
138 
139 #endif /* _FRR_MONOTIME_H */
140