yaftime.h
1/*
2 * Copyright 2024 Carnegie Mellon University
3 * See license information in LICENSE.txt.
4 */
5/*
6 * yaftime.h
7 *
8 * Types, functions, and macros for holding and manipluating timestamps and
9 * time-differences.
10 *
11 * ------------------------------------------------------------------------
12 * @DISTRIBUTION_STATEMENT_BEGIN@
13 * YAF 2.16
14 *
15 * Copyright 2024 Carnegie Mellon University.
16 *
17 * NO WARRANTY. THIS CARNEGIE MELLON UNIVERSITY AND SOFTWARE ENGINEERING
18 * INSTITUTE MATERIAL IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON
19 * UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
20 * AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR
21 * PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF
22 * THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF
23 * ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT
24 * INFRINGEMENT.
25 *
26 * Licensed under a GNU GPL 2.0-style license, please see LICENSE.txt or
27 * contact permission@sei.cmu.edu for full terms.
28 *
29 * [DISTRIBUTION STATEMENT A] This material has been approved for public
30 * release and unlimited distribution. Please see Copyright notice for
31 * non-US Government use and distribution.
32 *
33 * This Software includes and/or makes use of Third-Party Software each
34 * subject to its own license.
35 *
36 * DM24-1063
37 * @DISTRIBUTION_STATEMENT_END@
38 * ------------------------------------------------------------------------
39 */
40#ifndef _YAF_TIME_H_
41#define _YAF_TIME_H_
42
43
47typedef struct yfTime_st {
48 /* Epoch nanoseconds. Valid until 2554-07-21 */
49 uint64_t t;
50} yfTime_t;
51
55typedef struct yfDiffTime_st {
56 /* Nanosecond difference */
57 int64_t d;
59
66typedef struct yf_timespec32_st {
67 uint32_t tv_sec;
68 uint32_t tv_frac;
70
75typedef struct yf_time_milli_st {
76 long long tv_sec;
77 long tv_msec;
79
90#define YF_TIME_NTP_USEC_MASK UINT64_C(0xfffffffffffff800)
91
95#define YF_TIME_INIT { 0 }
96
100#define YF_DIFFTIME_INIT { 0 }
101
106#define YF_DIFFTIME_INIT_MILLI(ms_) { INT64_C(1000000) * (ms_) }
107
111static const yfTime_t yfTimeZeroConstant = YF_TIME_INIT;
112
116static const yfDiffTime_t yfDiffTimeZeroConstant = YF_DIFFTIME_INIT;
117
118
119
120/*
121 * Note: If we are going to continue to use functions below (instead of
122 * changing them to macros), it would make sense for the return type to be
123 * the yfTime_t* that was passed in. Doing this would allow these function
124 * calls to appear in other function calls.
125 */
126
127
128
129/*
130 * *********************************************************************
131 *
132 * Functions and Macros for yfTime_t
133 *
134 * *********************************************************************
135 */
136
140static inline void
141yfTimeClear(
142 yfTime_t *yftime)
143{
144 yftime->t = 0;
145}
146
151static inline gboolean
152yfTimeIsSet(
153 const yfTime_t yftime)
154{
155 return (0 != yftime.t);
156}
157
164static inline void
165yfTimeAdd(
166 yfTime_t *yftime_new,
167 const yfTime_t yftime_old,
168 const yfDiffTime_t yfdifftime)
169{
170 yftime_new->t = yftime_old.t + yfdifftime.d;
171}
172
179static inline void
180yfTimeSub(
181 yfTime_t *yftime_new,
182 const yfTime_t yftime_old,
183 const yfDiffTime_t yfdifftime)
184{
185 yftime_new->t = yftime_old.t - yfdifftime.d;
186}
187
197#define yfTimeCmpOp(yftime_a, yftime_b, oper_) \
198 ((yftime_a).t oper_ (yftime_b).t)
199
208static inline int
209yfTimeCompare(
210 const yfTime_t yftime_a,
211 const yfTime_t yftime_b)
212{
213 return ((yftime_a.t < yftime_b.t) ? -1 : (yftime_a.t > yftime_b.t));
214}
215
222static inline void
223yfTimeDifference(
224 yfDiffTime_t *yfdiff,
225 const yfTime_t yftime_end,
226 const yfTime_t yftime_start)
227{
228 yfdiff->d = yftime_end.t - yftime_start.t;
229}
230
235static inline void
236yfTimeFromMicro(
237 yfTime_t *yftime,
238 const uint64_t epoch_usec)
239{
240 yftime->t = UINT64_C(1000) * epoch_usec;
241}
242
247static inline void
248yfTimeFromMilli(
249 yfTime_t *yftime,
250 const uint64_t epoch_msec)
251{
252 yftime->t = UINT64_C(1000000) * epoch_msec;
253}
254
259static inline void
260yfTimeFromNano(
261 yfTime_t *yftime,
262 const uint64_t epoch_nsec)
263{
264 yftime->t = epoch_nsec;
265}
266
272static inline void
273yfTimeFromNTP(
274 yfTime_t *yftime,
275 const uint64_t ntp,
276 gboolean is_micro)
277{
278 /* The number of seconds between the NTP epoch (Jan 1, 1900) and the UNIX
279 * epoch (Jan 1, 1970). Seventy 365-day years plus 17 leap days, at 86400
280 * sec/day: ((70 * 365 + 17) * 86400) */
281 const uint64_t NTP_EPOCH_TO_UNIX_EPOCH = UINT64_C(0x83AA7E80);
282
283 /* use all lower 32 bits for the Nanosecond mask */
284 const uint64_t NANO_MASK = UINT64_C(0xffffffff);
285 /* nanoseconds per whole second, 1e9 */
286 const uint64_t NANO_PER_SEC = UINT64_C(1000000000);
287
288 /* IETF says the Microsecond mask must ignore the lowest 11 bits */
289 const uint64_t MICRO_MASK = UINT64_C(0xfffff800);
290 /* microseconds per whole second, 1e6 */
291 const uint64_t MICRO_PER_SEC = UINT64_C(1000000);
292
293 /* When the NTP value rolls over in 2036, must add 2^32 seconds to the
294 * UNIX time */
295 const uint64_t NTP_ROLLOVER = UINT64_C(0x100000000);
296
297 /* To get a proper value when converting to fractional seconds, add 1<<31
298 * before the >>32 to round up values. Not doing so introduces errors
299 * that can accumulate with repeated conversions. */
300 const uint64_t ROUNDING_DIFF = UINT64_C(0x80000000);
301
302 /* Handle fractional seconds */
303 if (!is_micro) {
304 /* Mask the lower 32 bits of `ntp` to get the fractional second part.
305 * Divide by 2^32 to get a floating point number that is a fraction of
306 * a second, and multiply by NANO_PER_SEC to get nanoeconds, but do
307 * those in reverse order, use shift for the division, and handle
308 * rounding before the division */
309 yftime->t = ((ntp & NANO_MASK) * NANO_PER_SEC + ROUNDING_DIFF) >> 32;
310 } else {
311 /* Do something similar as for nanoseconds but using microseconds,
312 * then multiply by 1000 at the end to get nanoseconds as a whole
313 * number of microseconds */
314 yftime->t = ((((ntp & MICRO_MASK) * MICRO_PER_SEC + ROUNDING_DIFF)
315 >> 32) * 1000);
316 }
317
318 /* Seconds: Right shift `ntp` by 32 to get the whole seconds since 1900.
319 * Subtract the difference between the epochs to get a UNIX time, then
320 * multiply by NANO_PER_SEC to get nanoseconds.
321 *
322 * Use the highest bit of ntp to determine (assume) the NTP Era and add
323 * NTP_ROLLOVER if Era 1; this is valid from 1968 to 2104. */
324 if (ntp >> 63) {
325 /* Assume NTP Era 0 */
326 /* valid for 1968-01-20 03:14:08Z to 2036-02-07 06:28:15Z */
327 yftime->t += ((ntp >> 32) - NTP_EPOCH_TO_UNIX_EPOCH) * NANO_PER_SEC;
328 } else {
329 /* Assume NTP Era 1 */
330 /* valid for 2036-02-07 06:28:16Z to 2104-02-26 09:42:23Z */
331 yftime->t += (((ntp >> 32) + NTP_ROLLOVER - NTP_EPOCH_TO_UNIX_EPOCH)
332 * NANO_PER_SEC);
333 }
334}
335
340static inline void
341yfTimeFromSeconds(
342 yfTime_t *yftime,
343 const uint64_t epoch_sec)
344{
345 yftime->t = UINT64_C(1000000000) * epoch_sec;
346}
347
352static inline void
353yfTimeFromTimespec(
354 yfTime_t *yftime,
355 const struct timespec *tspec)
356{
357 yftime->t = UINT64_C(1000000000) * tspec->tv_sec + tspec->tv_nsec;
358}
359
364static inline void
365yfTimeFromTimespec32(
366 yfTime_t *yftime,
367 const yf_timespec32_t *yfspec32)
368{
369 yftime->t = UINT64_C(1000000000) * yfspec32->tv_sec + yfspec32->tv_frac;
370}
371
376static inline void
377yfTimeFromTimeval(
378 yfTime_t *yftime,
379 const struct timeval *tval)
380{
381 yftime->t = (UINT64_C(1000000000) * tval->tv_sec
382 + UINT64_C(1000) * tval->tv_usec);
383}
384
389static inline void
390yfTimeFromTimeval32(
391 yfTime_t *yftime,
392 const yf_timespec32_t *yfval32)
393{
394 yftime->t = (UINT64_C(1000000000) * yfval32->tv_sec
395 + UINT64_C(1000) * yfval32->tv_frac);
396}
397
402static inline gboolean
403yfTimeCheckElapsed(
404 const yfTime_t later_time,
405 const yfTime_t earlier_time,
406 const yfDiffTime_t elapsed)
407{
408 return (later_time.t > earlier_time.t + elapsed.d);
409}
410
414static inline void
415yfTimeNow(
416 yfTime_t *yftime)
417{
418 struct timeval ct;
419
420 gettimeofday(&ct, NULL);
421 yfTimeFromTimeval(yftime, &ct);
422}
423
424
429static inline uint64_t
430yfTimeToMicro(
431 const yfTime_t yftime)
432{
433 const uint64_t divisor = UINT64_C(1000);
434
435 return yftime.t / divisor;
436}
437
442static inline uint64_t
443yfTimeToMilli(
444 const yfTime_t yftime)
445{
446 const uint64_t divisor = UINT64_C(1000000);
447
448 return yftime.t / divisor;
449}
450
455static inline uint64_t
456yfTimeToNano(
457 const yfTime_t yftime)
458{
459 return yftime.t;
460}
461
469static inline void
470yfTimeToNTP(
471 uint64_t *ntp,
472 const yfTime_t yftime)
473{
474 /* The number of seconds between the NTP epoch (Jan 1, 1900) and the UNIX
475 * epoch (Jan 1, 1970). Seventy 365-day years plus 17 leap days, at 86400
476 * sec/day: ((70 * 365 + 17) * 86400) */
477 const uint64_t NTP_EPOCH_TO_UNIX_EPOCH = UINT64_C(0x83AA7E80);
478 /* Seconds and fractional-seconds divisor */
479 const long long divisor = 1000000000LL;
480 /* seconds */
481 lldiv_t split = lldiv(yftime.t, divisor);
482 uint64_t sec;
483 uint64_t frac;
484
485 /* Adjust seconds for the difference in epochs. When NTP rolls over in
486 * 2036, sec will be > UINT32_MAX, but those are chopped off when the <<32
487 * is applied. */
488 sec = (uint64_t)split.quot + NTP_EPOCH_TO_UNIX_EPOCH;
489
490 /* Divide number of nanoseconds by 1e9 to get a fractional second, then
491 * multiply by 2^32. Do those in the reverse order and use shift for the
492 * multiplication. */
493 frac = (((uint64_t)split.rem) << UINT64_C(32)) / divisor;
494
495 *ntp = ((sec << UINT64_C(32)) | frac);
496}
497
502static inline uint64_t
503yfTimeToSeconds(
504 const yfTime_t yftime)
505{
506 const uint64_t divisor = UINT64_C(1000000000);
507
508 return yftime.t / divisor;
509}
510
515static inline void
516yfTimeToTimemilli(
517 yf_time_milli_t *tmilli,
518 const yfTime_t yftime)
519{
520 /* convert epoch nanosec to epoch millisec, then split into seconds and
521 * fractional seconds */
522 const long long nsec_per_msec = 1000000LL;
523 const long long msec_per_sec = 1000LL;
524 lldiv_t sec = lldiv((yftime.t / nsec_per_msec), msec_per_sec);
525
526 tmilli->tv_sec = sec.quot;
527 tmilli->tv_msec = sec.rem;
528}
529
534static inline void
535yfTimeToTimespec(
536 struct timespec *tspec,
537 const yfTime_t yftime)
538{
539 const long long divisor = 1000000000LL;
540 lldiv_t sec = lldiv(yftime.t, divisor);
541
542 tspec->tv_sec = sec.quot;
543 tspec->tv_nsec = sec.rem;
544}
545
551static inline void
552yfTimeToTimespec32(
553 yf_timespec32_t *yfspec32,
554 const yfTime_t yftime)
555{
556 const long long divisor = 1000000000LL;
557 lldiv_t sec = lldiv(yftime.t, divisor);
558
559 yfspec32->tv_sec = sec.quot;
560 yfspec32->tv_frac = sec.rem;
561}
562
567static inline void
568yfTimeToTimeval(
569 struct timeval *tval,
570 const yfTime_t yftime)
571{
572 /* convert epoch nanosec to epoch microsec, then split into seconds and
573 * fractional seconds */
574 const long long nsec_per_usec = 1000LL;
575 const long long usec_per_sec = 1000000LL;
576 lldiv_t sec = lldiv((yftime.t / nsec_per_usec), usec_per_sec);
577
578 tval->tv_sec = sec.quot;
579 tval->tv_usec = sec.rem;
580}
581
587static inline void
588yfTimeToTimeval32(
589 yf_timespec32_t *yfval32,
590 const yfTime_t yftime)
591{
592 /* convert epoch nanosec to epoch microsec, then split into seconds and
593 * fractional seconds */
594 const long long nsec_per_usec = 1000LL;
595 const long long usec_per_sec = 1000000LL;
596 lldiv_t sec = lldiv((yftime.t / nsec_per_usec), usec_per_sec);
597
598 yfval32->tv_sec = sec.quot;
599 yfval32->tv_frac = sec.rem;
600}
601
602
603
604/*
605 * *********************************************************************
606 *
607 * Functions / Macros for yfDiffTime_t
608 *
609 * *********************************************************************
610 */
611
615static inline void
616yfDiffTimeClear(
617 yfDiffTime_t *yfdifftime)
618{
619 yfdifftime->d = 0;
620}
621
625static inline gboolean
626yfDiffTimeIsSet(
627 const yfDiffTime_t yfdifftime)
628{
629 return (0 != yfdifftime.d);
630}
631
640static inline void
641yfDiffTimeAdd(
642 yfDiffTime_t *yfdiff_new,
643 const yfDiffTime_t yfdiff_old,
644 const yfDiffTime_t yfdiff_addend)
645{
646 yfdiff_new->d = yfdiff_old.d + yfdiff_addend.d;
647}
648
659static inline void
660yfDiffTimeSub(
661 yfDiffTime_t *yfdiff_new,
662 const yfDiffTime_t yfdiff_old,
663 const yfDiffTime_t yfdiff_subtrahend)
664{
665 yfdiff_new->d = yfdiff_old.d - yfdiff_subtrahend.d;
666}
667
675#define yfDiffTimeCmpOp(yfdiff_a, yfdiff_b, oper_) \
676 ((yfdiff_a).d oper_ (yfdiff_b).d)
677
682static inline void
683yfDiffTimeFromMicro(
684 yfDiffTime_t *yfdifftime,
685 const int64_t diff_usec)
686{
687 yfdifftime->d = INT64_C(1000) * diff_usec;
688}
689
694static inline void
695yfDiffTimeFromMilli(
696 yfDiffTime_t *yfdifftime,
697 const int64_t diff_msec)
698{
699 yfdifftime->d = INT64_C(1000000) * diff_msec;
700}
701
706static inline void
707yfDiffTimeFromSeconds(
708 yfDiffTime_t *yfdifftime,
709 const int64_t diff_sec)
710{
711 yfdifftime->d = INT64_C(1000000000) * diff_sec;
712}
713
717static inline double
718yfDiffTimeToDouble(
719 const yfDiffTime_t yfdifftime)
720{
721 const double divisor = 1e9;
722
723 return (double)yfdifftime.d / divisor;
724}
725
730static inline int64_t
731yfDiffTimeToMilli(
732 const yfDiffTime_t yfdifftime)
733{
734 const int64_t divisor = INT64_C(1000000);
735
736 return yfdifftime.d / divisor;
737}
738
743static inline int64_t
744yfDiffTimeToMicro(
745 const yfDiffTime_t yfdifftime)
746{
747 const int64_t divisor = INT64_C(1000);
748
749 return yfdifftime.d / divisor;
750}
751
756static inline int64_t
757yfDiffTimeToNano(
758 const yfDiffTime_t yfdifftime)
759{
760 return yfdifftime.d;
761}
762
767static inline void
768yfDiffTimeToTimemilli(
769 yf_time_milli_t *tmilli,
770 const yfDiffTime_t yfdifftime)
771{
772 /* convert the nanosec difference to a millisec difference, then split
773 * into seconds and fractional seconds */
774 const long long nsec_per_msec = 1000000LL;
775 const long long msec_per_sec = 1000LL;
776 lldiv_t sec;
777
778 sec = lldiv((yfdifftime.d / nsec_per_msec), msec_per_sec);
779
780 tmilli->tv_sec = sec.quot;
781 tmilli->tv_msec = sec.rem;
782
783}
784
789static inline void
790yfDiffTimeToTimespec(
791 struct timespec *tspec,
792 const yfDiffTime_t yfdifftime)
793{
794 const long long divisor = 1000000000LL;
795 lldiv_t sec = lldiv(yfdifftime.d, divisor);
796
797 tspec->tv_sec = sec.quot;
798 tspec->tv_nsec = sec.rem;
799}
800
805static inline void
806yfDiffTimeToTimeval(
807 struct timeval *tval,
808 const yfDiffTime_t yfdifftime)
809{
810 /* convert the nanosec difference to a microsec difference, then split
811 * into seconds and fractional seconds */
812 const long long nsec_per_usec = 1000LL;
813 const long long usec_per_sec = 1000000LL;
814 lldiv_t sec;
815
816 sec = lldiv((yfdifftime.d / nsec_per_usec), usec_per_sec);
817
818 tval->tv_sec = sec.quot;
819 tval->tv_usec = sec.rem;
820}
821
822#endif /* #ifndef _YAF_TIME_H_ */
A structure similar to timeval and timespec but which stores seconds and milliseconds.
Definition yaftime.h:75
Some high-performance network cards use a custom 64-bit structure similar to the standard timeval or ...
Definition yaftime.h:66
YAF time difference: represents the difference of two yfTime_t.
Definition yaftime.h:55
YAF timestamp: represents a moment in time.
Definition yaftime.h:47