src/compat/compat-gettimeofday.c
3d163bc5
 /*
  *  OpenVPN -- An application to securely tunnel IP networks
  *             over a single UDP port, with support for SSL/TLS-based
  *             session authentication and key exchange,
  *             packet encryption, packet authentication, and
  *             packet compression.
  *
49979459
  *  Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
3d163bc5
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2
  *  as published by the Free Software Foundation.
  *
  *  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.
  *
caa54ac3
  *  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.,
  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
3d163bc5
  */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #elif defined(_MSC_VER)
 #include "config-msvc.h"
 #endif
 
 #ifndef HAVE_GETTIMEOFDAY
 
 #include "compat.h"
 
445b192a
 #ifdef _WIN32
3d163bc5
 /*
  * NOTICE: mingw has much faster gettimeofday!
  * autoconf will set HAVE_GETTIMEOFDAY
  */
 
 #include <windows.h>
 #include <time.h>
 
 static time_t gtc_base = 0;
 static DWORD gtc_last = 0;
 static time_t last_sec = 0;
 static unsigned int last_msec = 0;
 static int bt_last = 0;
 
 static void
81d882d5
 gettimeofday_calibrate(void)
3d163bc5
 {
81d882d5
     const time_t t = time(NULL);
     const DWORD gtc = GetTickCount();
     gtc_base = t - gtc/1000;
     gtc_last = gtc;
3d163bc5
 }
 
 /*
  * Rewritten by JY for OpenVPN 2.1, after I realized that
  * QueryPerformanceCounter takes nearly 2 orders of magnitude
  * more processor cycles than GetTickCount.
  */
 int
81d882d5
 gettimeofday(struct timeval *tv, void *tz)
3d163bc5
 {
81d882d5
     const DWORD gtc = GetTickCount();
     int bt = 0;
     time_t sec;
     unsigned int msec;
     const int backtrack_hold_seconds = 10;
3d163bc5
 
81d882d5
     (void)tz;
3d163bc5
 
81d882d5
     /* recalibrate at the dreaded 49.7 day mark */
     if (!gtc_base || gtc < gtc_last)
     {
         gettimeofday_calibrate();
     }
     gtc_last = gtc;
3d163bc5
 
81d882d5
     sec = gtc_base + gtc / 1000;
     msec = gtc % 1000;
3d163bc5
 
81d882d5
     if (sec == last_sec)
3d163bc5
     {
81d882d5
         if (msec < last_msec)
         {
             msec = last_msec;
             bt = 1;
         }
3d163bc5
     }
81d882d5
     else if (sec < last_sec)
3d163bc5
     {
81d882d5
         /* We try to dampen out backtracks of less than backtrack_hold_seconds.
          * Larger backtracks will be passed through and dealt with by the
          * TIME_BACKTRACK_PROTECTION code (if enabled) */
         if (sec > last_sec - backtrack_hold_seconds)
         {
             sec = last_sec;
             msec = last_msec;
         }
         bt = 1;
3d163bc5
     }
 
81d882d5
     tv->tv_sec = (long)last_sec = (long)sec;
     tv->tv_usec = (last_msec = msec) * 1000;
3d163bc5
 
81d882d5
     if (bt && !bt_last)
     {
         gettimeofday_calibrate();
     }
     bt_last = bt;
3d163bc5
 
81d882d5
     return 0;
3d163bc5
 }
 
81d882d5
 #else  /* ifdef _WIN32 */
3d163bc5
 
 #ifdef HAVE_TIME_H
 #include <time.h>
 #endif
 
 int
81d882d5
 gettimeofday(struct timeval *tv, void *tz)
3d163bc5
 {
81d882d5
     (void)tz;
     tv->tv_sec = time(NULL);
     tv->tv_usec = 0;
     return 0;
3d163bc5
 }
 
445b192a
 #endif /* _WIN32 */
3d163bc5
 
 #endif /* HAVE_GETTIMEOFDAY */