#include "lib/time/tvdiff.h"
#include "lib/cc/compat_compiler.h"
#include "lib/defs/time.h"
#include "lib/log/log.h"
#ifdef _WIN32
#include <winsock2.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
static int64_t
tv_secdiff_impl(const struct timeval *start, const struct timeval *end)
{
const int64_t s = (int64_t)start->tv_sec;
const int64_t e = (int64_t)end->tv_sec;
if (s > 0 && e < INT64_MIN + s) {
return INT64_MAX;
} else if (s < 0 && e > INT64_MAX + s) {
return INT64_MAX;
}
return e - s;
}
long
tv_udiff(const struct timeval *start, const struct timeval *end)
{
if (start->tv_usec > TOR_USEC_PER_SEC || start->tv_usec < 0) {
log_warn(LD_GENERAL, "comparing times on microsecond detail with bad "
"start tv_usec: %"PRId64 " microseconds",
(int64_t)start->tv_usec);
return LONG_MAX;
}
if (end->tv_usec > TOR_USEC_PER_SEC || end->tv_usec < 0) {
log_warn(LD_GENERAL, "comparing times on microsecond detail with bad "
"end tv_usec: %"PRId64 " microseconds",
(int64_t)end->tv_usec);
return LONG_MAX;
}
int64_t udiff;
const int64_t secdiff = tv_secdiff_impl(start, end);
if (secdiff > (int64_t)(LONG_MAX/1000000 - 1) ||
secdiff < (int64_t)(LONG_MIN/1000000 + 1)) {
log_warn(LD_GENERAL, "comparing times on microsecond detail too far "
"apart: %"PRId64 " seconds", (secdiff));
return LONG_MAX;
}
udiff = secdiff*1000000 + ((int64_t)end->tv_usec - (int64_t)start->tv_usec);
#if SIZEOF_LONG < 8
if (udiff > (int64_t)LONG_MAX || udiff < (int64_t)LONG_MIN) {
return LONG_MAX;
}
#endif
return (long)udiff;
}
long
tv_mdiff(const struct timeval *start, const struct timeval *end)
{
if (start->tv_usec > TOR_USEC_PER_SEC || start->tv_usec < 0) {
log_warn(LD_GENERAL, "comparing times on millisecond detail with bad "
"start tv_usec: %"PRId64 " microseconds",
(int64_t)start->tv_usec);
return LONG_MAX;
}
if (end->tv_usec > TOR_USEC_PER_SEC || end->tv_usec < 0) {
log_warn(LD_GENERAL, "comparing times on millisecond detail with bad "
"end tv_usec: %"PRId64 " microseconds",
(int64_t)end->tv_usec);
return LONG_MAX;
}
int64_t mdiff;
const int64_t secdiff = tv_secdiff_impl(start, end);
if (secdiff > (int64_t)(LONG_MAX/1000 - 2) ||
secdiff < (int64_t)(LONG_MIN/1000 + 1)) {
log_warn(LD_GENERAL, "comparing times on millisecond detail too far "
"apart: %"PRId64 " seconds", (int64_t)secdiff);
return LONG_MAX;
}
mdiff = secdiff*1000 +
((int64_t)end->tv_usec - (int64_t)start->tv_usec + 500 + 1000000) / 1000
- 1000;
#if SIZEOF_LONG < 8
if (mdiff > (int64_t)LONG_MAX || mdiff < (int64_t)LONG_MIN) {
return LONG_MAX;
}
#endif
return (long)mdiff;
}
int64_t
tv_to_msec(const struct timeval *tv)
{
int64_t conv = ((int64_t)tv->tv_sec)*1000L;
conv += ((int64_t)tv->tv_usec+500)/1000L;
return conv;
}
time_t
time_diff(const time_t t1, const time_t t2)
{
if (t1 <= t2)
return t2 - t1;
return TIME_MAX;
}