X-Git-Url: http://www.project-moonshot.org/gitweb/?p=trust_router.git;a=blobdiff_plain;f=common%2Ftr_util.c;fp=common%2Ftr_util.c;h=c3d03fba110be30b81aebfcb757fd1d792d80a0f;hp=2ce3c82d421c6241feaf689df50e886769f229fd;hb=6f65c9cce86719147d0b4dcc9823b25443c2d185;hpb=eaa1a8ceed54fbfadc2638cf383aaa12ab446a57 diff --git a/common/tr_util.c b/common/tr_util.c index 2ce3c82..c3d03fb 100644 --- a/common/tr_util.c +++ b/common/tr_util.c @@ -36,8 +36,8 @@ #include #include #include -#include #include +#include void tr_bin_to_hex(const unsigned char * bin, size_t bin_len, char * hex_out, size_t hex_len) @@ -51,9 +51,16 @@ void tr_bin_to_hex(const unsigned char * bin, size_t bin_len, } } -/* Returns 0 if ts1==ts2, <0 if ts1= if ts1>ts2. - * Assumes that tv_nsec <= 1e9. */ -int tr_cmp_timespec(struct timespec *ts1, struct timespec *ts2) +/** + * Compare two timespecs + * + * Assumes tv_nsec <= 1e9 + * + * @param ts1 + * @param ts2 + * @return 0 if ts1==ts2, -1 if ts1ts2. + */ +int tr_cmp_timespec(const struct timespec *ts1, const struct timespec *ts2) { if (ts1->tv_sec > ts2->tv_sec) return 1; @@ -71,3 +78,135 @@ int tr_cmp_timespec(struct timespec *ts1, struct timespec *ts2) return 0; } + +/** + * Compute ts1 + ts2 + * + * @param ts1 + * @param ts2 + * @param sum ts1 + ts2 + * @return 0 on success, nonzero on error + */ +int tr_add_timespec(const struct timespec *ts1, const struct timespec *ts2, struct timespec *sum) +{ + const time_t ONE_BILLION = 1000000000; + + if (!ts1 || !ts2 || !sum) + return -1; + + /* would be nice to do range checking, but I don't know a portable way to get the + * max value of a time_t. Figure that nsec <= 1e9 and seconds are unlikely to go off + * too close to infinity, so overflow is unlikely */ + sum->tv_nsec = ts1->tv_nsec + ts2->tv_nsec; + sum->tv_sec = ts1->tv_sec + ts2->tv_sec; + + /* make sure that we have no more than a second worth of nsec */ + while (sum->tv_nsec >= ONE_BILLION) { + sum->tv_nsec -= ONE_BILLION; + sum->tv_sec += 1; + } + + return 0; +} + +/** + * Compute ts1 - ts2 + * + * Allows negative results, which will be represented as a negative tv_sec. + * The returned tv_nsec is always positive and less than 1e9. + * + * (The value represented is tv_sec + tv_nsec/1e9 seconds - this is a little + * counterintuitive when tv_sec is negative. E.g., -1.5 seconds is represented + * as {-2, 500000000). Negative time_t values are not guaranteed to be supported + * anyway, so it's probably best to stay away from them.) + * + * @param ts1 + * @param ts2 + * @param diff ts1 - ts2 + * @return 0 on success, nonzero on error + */ +int tr_sub_timespec(const struct timespec *ts1, const struct timespec *ts2, struct timespec *diff) +{ + const time_t ONE_BILLION = 1000000000; + struct timespec ts1_copy = {0}; + struct timespec ts2_copy = {0}; + + if (!ts1 || !ts2 || !diff) + return -1; + + ts1_copy = *ts1; + ts2_copy = *ts2; + + while (ts2_copy.tv_nsec > ts1_copy.tv_nsec) { + /* Reduce ts2 by one second worth of nsec, balanced by removing a second + * from ts1. Repeat until ts2->tv_nsec <= ts1->tv_nsec. */ + ts2_copy.tv_nsec -= ONE_BILLION; + ts1_copy.tv_sec -= 1; + } + + diff->tv_nsec = ts1_copy.tv_nsec - ts2_copy.tv_nsec; /* >= 0 */ + diff->tv_sec = ts1_copy.tv_sec - ts2_copy.tv_sec; /* sign indeterminate */ + + /* make sure we have no more than 1 sec worth of nsec */ + while (diff->tv_nsec > ONE_BILLION) { + diff->tv_nsec -= ONE_BILLION; + diff->tv_sec += 1; + } + + return 0; +} + +/** + * Convert a struct timespec to a string representation + * @param ts + * @return + */ +char *timespec_to_str(const struct timespec *ts) +{ + struct tm tm; + char *s=NULL; + + if (gmtime_r(&(ts->tv_sec), &tm)==NULL) + return NULL; + + s=malloc(40); /* long enough to contain strftime result */ + if (s==NULL) + return NULL; + + if (strftime(s, 40, "%F %T UTC", &tm)==0) { + free(s); + return NULL; + } + return s; +} + +/** + * Convert a time from one clock to another + * + * Because this involves reading each clock, it is not exact. + * + * @param from clock to convert from + * @param when time to convert, measured on the 'from' clock + * @param to clock to convert to + * @param dst destination, measured on the 'to' clock + * @return dst or null on error + */ +struct timespec *tr_clock_convert(clockid_t from, const struct timespec *when, + clockid_t to, struct timespec *dst) +{ + struct timespec now_from = {0}; + struct timespec diff = {0}; /* difference between when and now_from */ + struct timespec now_to = {0}; + + if ((clock_gettime(from, &now_from) != 0) + || (clock_gettime(to, &now_to) != 0)) { + return NULL; + } + if (tr_sub_timespec(when, &now_from, &diff) != 0) { + return NULL; + } + if (tr_add_timespec(&now_to, &diff, dst) != 0) { + return NULL; + } + return dst; +}