strongswan/src/libstrongswan/utils/utils/time.c

200 lines
4.2 KiB
C

/*
* Copyright (C) 2008-2017 Tobias Brunner
* Copyright (C) 2005-2008 Martin Willi
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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.
*/
#ifdef WIN32
/* for GetTickCount64, Windows 7 */
# define _WIN32_WINNT 0x0601
#endif
#define _GNU_SOURCE
#include <utils/utils.h>
#include <inttypes.h>
#include <ctype.h>
#include <time.h>
#include <errno.h>
/**
* Return monotonic time
*/
time_t time_monotonic(timeval_t *tv)
{
#ifdef WIN32
ULONGLONG ms;
time_t s;
ms = GetTickCount64();
s = ms / 1000;
if (tv)
{
tv->tv_sec = s;
tv->tv_usec = (ms - (s * 1000)) * 1000;
}
return s;
#else /* !WIN32 */
#if defined(HAVE_CLOCK_GETTIME) && \
(defined(HAVE_CONDATTR_CLOCK_MONOTONIC) || \
defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC))
/* as we use time_monotonic() for condvar operations, we use the
* monotonic time source only if it is also supported by pthread. */
timespec_t ts;
if (clock_gettime(TIME_CLOCK_ID, &ts) == 0)
{
if (tv)
{
tv->tv_sec = ts.tv_sec;
tv->tv_usec = ts.tv_nsec / 1000;
}
return ts.tv_sec;
}
#endif /* HAVE_CLOCK_GETTIME && (...) */
/* Fallback to non-monotonic timestamps:
* On MAC OS X, creating monotonic timestamps is rather difficult. We
* could use mach_absolute_time() and catch sleep/wakeup notifications.
* We stick to the simpler (non-monotonic) gettimeofday() for now.
* But keep in mind: we need the same time source here as in condvar! */
if (!tv)
{
return time(NULL);
}
if (gettimeofday(tv, NULL) != 0)
{ /* should actually never fail if passed pointers are valid */
return -1;
}
return tv->tv_sec;
#endif /* !WIN32 */
}
/*
* Described in header
*/
bool timespan_from_string(char *str, char *defunit, time_t *val)
{
char *endptr, unit;
time_t timeval;
if (str)
{
errno = 0;
timeval = strtoull(str, &endptr, 10);
if (endptr == str)
{
return FALSE;
}
if (errno == 0)
{
while (isspace(*endptr))
{
endptr++;
}
unit = *endptr;
if (!unit && defunit)
{
unit = *defunit;
}
switch (unit)
{
case 'd': /* time in days */
timeval *= 24 * 3600;
break;
case 'h': /* time in hours */
timeval *= 3600;
break;
case 'm': /* time in minutes */
timeval *= 60;
break;
case 's': /* time in seconds */
case '\0':
break;
default:
return FALSE;
}
if (val)
{
*val = timeval;
}
return TRUE;
}
}
return FALSE;
}
/*
* Described in header
*/
int time_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
const void *const *args)
{
static const char* months[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
time_t *time = *((time_t**)(args[0]));
bool utc = *((int*)(args[1]));
struct tm t, *ret = NULL;
if (*time != UNDEFINED_TIME)
{
if (utc)
{
ret = gmtime_r(time, &t);
}
else
{
ret = localtime_r(time, &t);
}
}
if (ret == NULL)
{
return print_in_hook(data, "--- -- --:--:--%s----",
utc ? " UTC " : " ");
}
return print_in_hook(data, "%s %02d %02d:%02d:%02d%s%04d",
months[t.tm_mon], t.tm_mday, t.tm_hour, t.tm_min,
t.tm_sec, utc ? " UTC " : " ", t.tm_year + 1900);
}
/*
* Described in header
*/
int time_delta_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
const void *const *args)
{
char* unit = "second";
time_t *arg1 = *((time_t**)(args[0]));
time_t *arg2 = *((time_t**)(args[1]));
uint64_t delta = llabs(*arg1 - *arg2);
if (delta > 2 * 60 * 60 * 24)
{
delta /= 60 * 60 * 24;
unit = "day";
}
else if (delta > 2 * 60 * 60)
{
delta /= 60 * 60;
unit = "hour";
}
else if (delta > 2 * 60)
{
delta /= 60;
unit = "minute";
}
return print_in_hook(data, "%" PRIu64 " %s%s", delta, unit,
(delta == 1) ? "" : "s");
}