/* doscan - Denial Of Service Capable Auditing of Networks
 * Copyright (C) 2003 Florian Weimer
 *
 * 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.
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "config.h"
#include "opt.h"
#include "ticks.h"

#include <cerrno>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <sys/time.h>

struct timeval epoch;
ticks_t cache;

static void safe_gettimeofday (struct timeval *);
/* Bails out on error. */

static void ticks_to_string (ticks_t, ticks_string_t, int);

void
ticks_init (void)
{
  safe_gettimeofday (&epoch);

  /* Initialize cache. */
  ticks_get ();
}

ticks_t
ticks_get (void)
{
  struct timeval tv;
  unsigned seconds;
  int usecs;

  safe_gettimeofday (&tv);

  seconds = tv.tv_sec - epoch.tv_sec;
  usecs = tv.tv_usec - epoch.tv_usec;

  cache =  (seconds * 1000) + (usecs / 1000);
  return cache;
}

ticks_t
ticks_get_cached (void)
{
  return cache;
}

void
ticks_to_string_local (ticks_t source, ticks_string_t result)
{
  ticks_to_string (source, result, 1);
}

void
ticks_to_string_utc (ticks_t source, ticks_string_t result)
{
  ticks_to_string (source, result, 0);
}

static void
ticks_to_string (ticks_t source, ticks_string_t result, int local)
{
  unsigned unix_sec, unix_msec;
  time_t tim;
  struct tm tm;

  /* This calculates the some of epoch and source and stores it in
     unix_sec and unix_msec. */

  unix_sec = epoch.tv_sec + (source / 1000);
  unix_msec = (epoch.tv_usec / 1000 ) + (source % 1000);

  unix_sec += unix_msec / 1000;
  unix_msec %= 1000;

  tim = unix_sec;
  if (local) {
    localtime_r (&tim, &tm);
  } else {
    gmtime_r (&tim, &tm);
  }

  sprintf (result, "%04d-%02d-%02d %02d:%02d:%02d.%03u",
           tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
           tm.tm_hour, tm.tm_min, tm.tm_sec, unix_msec);
}

static void
safe_gettimeofday (struct timeval *tv)
{
  if (gettimeofday (tv, 0) == -1) {
    int err = errno;
    fprintf (stderr, "%s: gettimeofday failed: %s\n",
             opt_program, strerror (err));
    exit (EXIT_FAILURE);
  }
}
