Merge commit '86cc97e55fe346502462284d2e636a2b3708163e' as 'Sources/OpenVPN3'

This commit is contained in:
Sergey Abramchuk
2020-02-24 14:43:11 +03:00
655 changed files with 146468 additions and 0 deletions
@@ -0,0 +1,84 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2017 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
// Create an Asio time_traits class to allow Asio to natively handle
// our Time and Time::Duration classes.
#ifndef OPENVPN_TIME_ASIOTIMER_H
#define OPENVPN_TIME_ASIOTIMER_H
#include <chrono>
#include <openvpn/io/io.hpp> // was: #include <asio/basic_waitable_timer.hpp>
#include <openvpn/common/olong.hpp>
#include <openvpn/time/time.hpp>
namespace openvpn {
struct AsioClock
{
typedef olong rep;
typedef std::ratio<1, 1024> period; // time resolution of openvpn::Time
typedef std::chrono::duration<rep, period> duration;
typedef std::chrono::time_point<AsioClock> time_point;
static constexpr bool is_steady()
{
return false;
}
static time_point now()
{
return to_time_point(Time::now());
}
static time_point to_time_point(const Time& t)
{
return time_point(duration(t.raw()));
}
static duration to_duration(const Time::Duration& d)
{
return duration(d.raw());
}
};
class AsioTimer : public openvpn_io::basic_waitable_timer<AsioClock>
{
public:
AsioTimer(openvpn_io::io_context& io_context)
: openvpn_io::basic_waitable_timer<AsioClock>(io_context)
{
}
std::size_t expires_at(const Time& t)
{
return openvpn_io::basic_waitable_timer<AsioClock>::expires_at(AsioClock::to_time_point(t));
}
std::size_t expires_after(const Time::Duration& d)
{
return openvpn_io::basic_waitable_timer<AsioClock>::expires_after(AsioClock::to_duration(d));
}
};
}
#endif
@@ -0,0 +1,91 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2017 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <openvpn/common/rc.hpp>
#include <openvpn/time/asiotimer.hpp>
// AsioTimerSafe is like AsioTimer but with strict cancellation
// semantics that guarantees that a handler will never be called
// with a non-error status after the timer is cancelled.
namespace openvpn {
class AsioTimerSafe
{
public:
AsioTimerSafe(openvpn_io::io_context& io_context)
: timer_(io_context),
epoch_(new Epoch)
{
}
std::size_t expires_at(const Time& t)
{
inc_epoch();
return timer_.expires_at(t);
}
std::size_t expires_after(const Time::Duration& d)
{
inc_epoch();
return timer_.expires_after(d);
}
std::size_t cancel()
{
inc_epoch();
return timer_.cancel();
}
template <typename F>
void async_wait(F&& func)
{
inc_epoch();
timer_.async_wait([func=std::move(func), epoch=epoch(), eptr=epoch_](const openvpn_io::error_code& error)
{
func(epoch == eptr->epoch ? error : openvpn_io::error::operation_aborted);
});
}
private:
typedef std::size_t epoch_t;
struct Epoch : public RC<thread_unsafe_refcount>
{
typedef RCPtr<Epoch> Ptr;
epoch_t epoch = 0;
};
epoch_t epoch() const
{
return epoch_->epoch;
}
void inc_epoch()
{
++epoch_->epoch;
}
AsioTimer timer_;
Epoch::Ptr epoch_;
};
}
@@ -0,0 +1,70 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2017 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
#ifndef OPENVPN_TIME_COARSETIME_H
#define OPENVPN_TIME_COARSETIME_H
#include <openvpn/time/time.hpp>
namespace openvpn {
// Used to compare two time objects within the accuracy limits
// defined by pre and post.
class CoarseTime
{
public:
CoarseTime() {}
CoarseTime(const Time::Duration& pre, const Time::Duration& post)
: pre_(pre), post_(post) {}
void init(const Time::Duration& pre, const Time::Duration& post)
{
pre_ = pre;
post_ = post;
}
void reset(const Time& t) { time_ = t; }
void reset() { time_.reset(); }
bool similar(const Time& t) const
{
if (time_.defined())
{
if (t >= time_)
return (t - time_) <= post_;
else
return (time_ - t) <= pre_;
}
else
return false;
}
private:
Time time_;
Time::Duration pre_;
Time::Duration post_;
};
} // namespace openvpn
#endif // OPENVPN_TIME_COARSETIME_H
+105
View File
@@ -0,0 +1,105 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2017 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
#ifndef OPENVPN_TIME_DURHELPER_H
#define OPENVPN_TIME_DURHELPER_H
#include <openvpn/common/options.hpp>
#include <openvpn/time/time.hpp>
#include <openvpn/random/randapi.hpp>
namespace openvpn {
inline void set_duration_parm(Time::Duration& dur,
const std::string& name,
const std::string& valstr,
const unsigned int min_value,
const bool x2, // multiply result by 2
const bool ms) // values are in milliseconds rather than seconds
{
const unsigned int maxdur = ms ? 1000*60*60*24 : 60*60*24*7; // maximum duration -- milliseconds: 1 day, seconds: 7 days
unsigned int value = 0;
const bool status = parse_number<unsigned int>(valstr, value);
if (!status)
OPENVPN_THROW(option_error, name << ": error parsing number of " << (ms ? "milliseconds" : "seconds"));
if (x2)
value *= 2;
if (value == 0 || value > maxdur)
value = maxdur;
if (value < min_value)
value = min_value;
dur = ms ? Time::Duration::milliseconds(value) : Time::Duration::seconds(value);
}
inline const Option* load_duration_parm(Time::Duration& dur,
const std::string& name,
const OptionList& opt,
const unsigned int min_value,
const bool x2,
const bool allow_ms)
{
// look for milliseconds given as <name>-ms
if (allow_ms)
{
const Option *o = opt.get_ptr(name + "-ms");
if (o)
{
set_duration_parm(dur, name, o->get(1, 16), min_value, x2, true);
return o;
}
}
// look for seconds given as <name>
{
const Option *o = opt.get_ptr(name);
if (o)
set_duration_parm(dur, name, o->get(1, 16), allow_ms ? 1 : min_value, x2, false);
return o;
}
}
inline Time::Duration load_duration_default(const std::string& name,
const OptionList& opt,
const Time::Duration& default_duration,
const unsigned int min_value,
const bool x2,
const bool allow_ms)
{
Time::Duration ret(default_duration);
load_duration_parm(ret, name, opt, min_value, x2, allow_ms);
return ret;
}
inline Time::Duration skew_duration(const Time::Duration& dur,
const Time::Duration& min,
const unsigned int flux_order,
RandomAPI& rng)
{
const unsigned int range = 1 << flux_order;
const int delta = int(rng.rand_get<unsigned int>() & (range-1)) - int(range>>1);
const Time::Duration ret = dur + delta;
if (ret >= min)
return ret;
else
return min;
}
}
#endif
+52
View File
@@ -0,0 +1,52 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2017 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
#ifndef OPENVPN_TIME_EPOCH_H
#define OPENVPN_TIME_EPOCH_H
#include <time.h>
#include <cstdint> // for std::uint64_t
namespace openvpn {
typedef std::uint64_t nanotime_t;
inline std::uint64_t milliseconds_since_epoch()
{
struct timespec ts;
if (::clock_gettime(CLOCK_REALTIME, &ts))
return 0;
return std::uint64_t(ts.tv_sec) * std::uint64_t(1000)
+ std::uint64_t(ts.tv_nsec) / std::uint64_t(1000000);
}
inline nanotime_t nanoseconds_since_epoch()
{
struct timespec ts;
if (::clock_gettime(CLOCK_REALTIME, &ts))
return 0;
return std::uint64_t(ts.tv_sec) * std::uint64_t(1000000000)
+ std::uint64_t(ts.tv_nsec);
}
}
#endif
+53
View File
@@ -0,0 +1,53 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2019 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <algorithm>
#include <openvpn/time/time.hpp>
#include <openvpn/random/randapi.hpp>
namespace openvpn {
struct TimeSkew
{
// Skew factors (+/- %).
// Pass these to skew() via factor parameter.
enum {
PCT_50 = 0,
PCT_25 = 1,
PCT_12_5 = 2,
PCT_6_25 = 3,
PCT_3_125 = 4,
PCT_1_5625 = 5,
};
// Skew a duration by some random flux.
static Time::Duration skew(const Time::Duration& dur, const unsigned int factor, RandomAPI& prng)
{
const std::uint32_t bms = std::min(dur.to_binary_ms() >> factor, oulong(0x40000000)); // avoid 32-bit overflow in next step
const int flux = int(prng.randrange32(bms)) - int(bms/2);
return dur + flux;
}
};
}
+379
View File
@@ -0,0 +1,379 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2017 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
// These are our fundamental Time and Time Duration classes.
// We normally deal with time in units of 1/1024 of a second.
// This allows us to use 32-bit values to represent most time
// and time duration values, but still gives us reasonable
// accuracy. Using units of 1/1024 of a second vs. straight
// milliseconds gives us an advantage of not needing to do
// very much integer multiplication and division which can
// help us on platforms such as ARM that lack integer division
// instructions. Note that the data type used to store the time
// is an oulong, so it will automatically expand to 64 bits on
// 64-bit machines (see olong.hpp). Using a 32-bit
// data type for time durations is normally fine for clients,
// but imposes a wraparound limit of ~ 48 days. Servers
// should always use a 64-bit data type to avoid this
// limitation.
#ifndef OPENVPN_TIME_TIME_H
#define OPENVPN_TIME_TIME_H
#include <limits>
#include <cstdint> // for std::uint32_t, uint64_t
#include <openvpn/common/platform.hpp>
#include <openvpn/common/exception.hpp>
#include <openvpn/common/olong.hpp>
#include <openvpn/common/to_string.hpp>
#ifdef OPENVPN_PLATFORM_WIN
#include <time.h> // for ::time() on Windows
#include <windows.h> // for GetTickCount
#else
#include <sys/time.h> // for ::time() and ::gettimeofday()
#endif
namespace openvpn {
OPENVPN_SIMPLE_EXCEPTION(get_time_error);
template <typename T>
class TimeType
{
public:
enum { prec=1024 };
typedef ::time_t base_type;
typedef T type;
class Duration
{
friend class TimeType;
public:
static Duration seconds(const T v) { return Duration(v * prec); }
static Duration binary_ms(const T v) { return Duration(v); }
static Duration infinite() { return Duration(std::numeric_limits<T>::max()); }
static Duration milliseconds(const T v)
{
// NOTE: assumes that prec == 1024
// Also note that this might wrap if v is larger than 1/3 of max size of T
return Duration(v + (v * T(3) / T(128)));
}
Duration() noexcept : duration_(T(0)) {}
bool defined() const { return duration_ != T(0); }
bool operator!() const { return duration_ == T(0); }
bool is_infinite() const { return duration_ == std::numeric_limits<T>::max(); }
bool enabled() const { return defined() && !is_infinite(); }
void set_infinite() { duration_ = std::numeric_limits<T>::max(); }
void set_zero() { duration_ = T(0); }
Duration operator+(const Duration& d) const
{
if (is_infinite() || d.is_infinite())
return infinite();
else
return Duration(duration_ + d.duration_);
}
Duration operator+(const int delta) const
{
T duration = duration_;
if (delta >= 0)
duration += delta;
else
{
const unsigned int ndelta = -delta;
if (duration_ >= ndelta)
duration -= ndelta;
else
duration = 0;
}
return Duration(duration);
}
Duration operator*(const unsigned int mult) const
{
return Duration(duration_ * mult);
}
Duration& operator+=(const Duration& d)
{
if (is_infinite() || d.is_infinite())
set_infinite();
else
duration_ += d.duration_;
return *this;
}
void min(const Duration& d)
{
if (d.duration_ < duration_)
duration_ = d.duration_;
}
void max(const Duration& d)
{
if (d.duration_ > duration_)
duration_ = d.duration_;
}
Duration operator-(const Duration& d) const
{
if (d.duration_ >= duration_)
return Duration(0);
else if (is_infinite())
return Duration::infinite();
else
return Duration(duration_ - d.duration_);
}
Duration& operator-=(const Duration& d)
{
if (d.duration_ >= duration_)
set_zero();
else if (!is_infinite())
duration_ -= d.duration_;
return *this;
}
T to_seconds() const { return duration_ / prec; }
T to_binary_ms() const { return duration_; }
T to_milliseconds() const
{
// NOTE: assumes that prec == 1024
// Also note that this might wrap if duration_ is larger than 1/3 of max size of T
return duration_ - (duration_ * T(3) / T(128));
}
double to_double() const
{
return double(duration_) / double(prec);
}
T raw() const { return duration_; }
# define OPENVPN_DURATION_REL(OP) bool operator OP(const Duration& d) const { return duration_ OP d.duration_; }
OPENVPN_DURATION_REL(==)
OPENVPN_DURATION_REL(!=)
OPENVPN_DURATION_REL(>)
OPENVPN_DURATION_REL(<)
OPENVPN_DURATION_REL(>=)
OPENVPN_DURATION_REL(<=)
# undef OPENVPN_DURATION_REL
private:
explicit Duration(const T duration) : duration_(duration) {}
T duration_;
};
TimeType() noexcept : time_(T(0)) {}
static TimeType zero() { return TimeType(T(0)); }
static TimeType infinite() { return TimeType(std::numeric_limits<T>::max()); }
bool is_infinite() const { return time_ == std::numeric_limits<T>::max(); }
void reset() { time_ = 0; }
void set_infinite() { time_ = std::numeric_limits<T>::max(); }
bool defined() const { return time_ != 0; }
bool operator!() const { return time_ == 0; }
base_type seconds_since_epoch() const { return base_ + time_ / prec; }
T fractional_binary_ms() const { return time_ % prec; }
static TimeType now() { return TimeType(now_()); }
void update() { time_ = now_(); }
TimeType operator+(const Duration& d) const
{
if (is_infinite() || d.is_infinite())
return infinite();
else
return TimeType(time_ + d.duration_);
}
TimeType& operator+=(const Duration& d)
{
if (is_infinite() || d.is_infinite())
set_infinite();
else
time_ += d.duration_;
return *this;
}
Duration operator-(const TimeType& t) const
{
if (t.time_ >= time_)
return Duration(0);
else if (is_infinite())
return Duration::infinite();
else
return Duration(time_ - t.time_);
}
void min(const TimeType& t)
{
if (t.time_ < time_)
time_ = t.time_;
}
void max(const TimeType& t)
{
if (t.time_ > time_)
time_ = t.time_;
}
long delta_prec(const TimeType& t) const
{
return long(time_) - long(t.time_);
}
long delta(const TimeType& t) const
{
return delta_prec(t) / long(prec);
}
double delta_float(const TimeType& t) const
{
return (double(time_) - double(t.time_)) / double(prec);
}
std::string delta_str(const TimeType& t) const
{
if (!defined())
return "UNDEF-TIME";
if (is_infinite())
return "INF";
const double df = delta_float(t);
std::string ret;
if (df >= 0.0)
ret += '+';
ret += openvpn::to_string(df);
return ret;
}
# define OPENVPN_TIME_REL(OP) bool operator OP(const TimeType& t) const { return time_ OP t.time_; }
OPENVPN_TIME_REL(==)
OPENVPN_TIME_REL(!=)
OPENVPN_TIME_REL(>)
OPENVPN_TIME_REL(<)
OPENVPN_TIME_REL(>=)
OPENVPN_TIME_REL(<=)
# undef OPENVPN_TIME_REL
T raw() const { return time_; }
static void reset_base_conditional()
{
// on 32-bit systems, reset time base after 30 days
if (sizeof(T) == 4)
{
const base_type newbase = ::time(0);
if (newbase - base_ >= (60*60*24*30))
reset_base();
}
}
static void reset_base()
{
base_ = ::time(0);
#ifdef OPENVPN_PLATFORM_WIN
#if (_WIN32_WINNT >= 0x0600)
win_recalibrate((DWORD)::GetTickCount64());
#else
win_recalibrate(::GetTickCount());
#endif
#endif
}
// number of tenths of a microsecond since January 1, 1601.
static uint64_t win_time()
{
// NOTE: assumes that prec == 1024
return ((11644473600ULL * uint64_t(prec)) + (uint64_t(base_) * uint64_t(prec)) + uint64_t(now_())) * 78125ULL / 8ULL;
}
private:
explicit TimeType(const T time) : time_(time) {}
#ifdef OPENVPN_PLATFORM_WIN
static void win_recalibrate(const DWORD gtc)
{
gtc_last = gtc;
gtc_base = ::time(0) - gtc_last/1000;
}
static T now_()
{
#if (_WIN32_WINNT >= 0x0600)
const DWORD gtc = (DWORD)::GetTickCount64();
#else
const DWORD gtc = ::GetTickCount();
#endif
if (gtc < gtc_last)
win_recalibrate(gtc);
const time_t sec = gtc_base + gtc / 1000;
const unsigned int msec = gtc % 1000;
return T((sec - base_) * prec + msec * prec / 1000);
}
static DWORD gtc_last;
static time_t gtc_base;
#else
static T now_()
{
::timeval tv;
if (::gettimeofday(&tv, nullptr) != 0)
throw get_time_error();
return T((tv.tv_sec - base_) * prec + tv.tv_usec * prec / 1000000);
}
#endif
static base_type base_;
T time_;
};
#ifdef OPENVPN_PLATFORM_WIN
template <typename T> DWORD TimeType<T>::gtc_last;
template <typename T> time_t TimeType<T>::gtc_base;
#endif
template <typename T> typename TimeType<T>::base_type TimeType<T>::base_;
typedef TimeType<oulong> Time;
typedef Time* TimePtr;
} // namespace openvpn
#endif // OPENVPN_TIME_TIME_H
+204
View File
@@ -0,0 +1,204 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2017 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
// Function to return the current date/time as a string.
#ifndef OPENVPN_TIME_TIMESTR_H
#define OPENVPN_TIME_TIMESTR_H
#include <string>
#include <cstring> // for std::strlen and std::memset
#include <time.h>
#include <stdio.h>
#include <ctype.h>
#include <cstdint> // for std::uint64_t
#include <openvpn/common/platform.hpp>
#include <openvpn/common/size.hpp>
#include <openvpn/common/string.hpp>
#if defined(OPENVPN_PLATFORM_WIN)
#include <windows.h>
#else
#include <sys/time.h>
#endif
namespace openvpn {
#if defined(OPENVPN_PLATFORM_WIN)
inline std::string date_time(const time_t now)
{
struct tm *lt = localtime(&now);
char *ret = asctime(lt);
const size_t len = std::strlen(ret);
if (len > 0 && ret[len-1] == '\n')
ret[len-1] = '\0';
return ret;
}
inline std::string date_time()
{
const time_t now = time(NULL);
return date_time(now);
}
inline std::string date_time_store_time_t(time_t& save)
{
save = time(NULL);
return date_time(save);
}
#else
inline std::string date_time(const time_t t)
{
struct tm lt;
char buf[64];
std::memset(&lt, 0, sizeof(lt));
if (!localtime_r(&t, &lt))
return "LOCALTIME_ERROR";
if (!asctime_r(&lt, buf))
return "ASCTIME_ERROR";
const size_t len = std::strlen(buf);
if (len > 0 && buf[len-1] == '\n')
buf[len-1] = '\0';
return std::string(buf);
}
inline std::string date_time_utc(const time_t t)
{
struct tm lt;
char buf[64];
std::memset(&lt, 0, sizeof(lt));
if (!gmtime_r(&t, &lt))
return "GMTIME_ERROR";
if (!asctime_r(&lt, buf))
return "ASCTIME_ERROR";
const size_t len = std::strlen(buf);
if (len > 0 && buf[len-1] == '\n')
buf[len-1] = '\0';
return std::string(buf);
}
// msecs == false : Tue Feb 17 01:24:30 2015
// msecs == true : Tue Feb 17 01:24:30.123 2015
inline std::string date_time(const struct timeval *tv, const bool msecs)
{
const std::string dt = date_time(tv->tv_sec);
if (msecs)
{
// find correct position in string to insert milliseconds
const size_t pos = dt.find_last_of(':');
if (pos != std::string::npos
&& pos + 3 < dt.length()
&& string::is_digit(dt[pos+1])
&& string::is_digit(dt[pos+2])
&& string::is_space(dt[pos+3]))
{
char ms[5];
::snprintf(ms, sizeof(ms), ".%03u", static_cast<unsigned int>(tv->tv_usec / 1000));
return dt.substr(0, pos+3) + ms + dt.substr(pos+3);
}
}
return dt;
}
inline std::string nanosec_time_to_string(const std::uint64_t ns_time)
{
const std::uint64_t sec = ns_time / std::uint64_t(1000000000);
const std::uint64_t ns = ns_time % std::uint64_t(1000000000);
const std::string dt = date_time_utc(sec);
// find correct position in string to insert nanoseconds
const size_t pos = dt.find_last_of(':');
if (pos != std::string::npos
&& pos + 3 < dt.length()
&& string::is_digit(dt[pos+1])
&& string::is_digit(dt[pos+2])
&& string::is_space(dt[pos+3]))
{
char ms[11];
::snprintf(ms, sizeof(ms), ".%09u", (unsigned int)ns);
return dt.substr(0, pos+3) + ms + dt.substr(pos+3);
}
return dt;
}
inline std::string date_time()
{
struct timeval tv;
if (::gettimeofday(&tv, nullptr) < 0)
{
tv.tv_sec = 0;
tv.tv_usec = 0;
}
return date_time(&tv, true);
}
inline std::string date_time_store_time_t(time_t& save)
{
struct timeval tv;
if (::gettimeofday(&tv, nullptr) < 0)
{
tv.tv_sec = 0;
tv.tv_usec = 0;
}
save = tv.tv_sec;
return date_time(&tv, true);
}
#endif
inline std::string date_time_rfc822(const time_t t)
{
struct tm lt;
char buf[64];
#if defined(OPENVPN_PLATFORM_WIN)
if (gmtime_s(&lt, &t))
return "";
if (!strftime(buf, sizeof(buf),
"%a, %d %b %Y %T GMT",
&lt))
return "";
#else
if (!gmtime_r(&t, &lt))
return "";
if (!strftime(buf, sizeof(buf),
"%a, %d %b %Y %T %Z",
&lt))
return "";
#endif
return std::string(buf);
}
inline std::string date_time_rfc822()
{
return date_time_rfc822(::time(nullptr));
}
}
#endif