C rewrite: phase out std::chrono

This commit is contained in:
Théophile Bastian 2020-07-22 15:45:16 +02:00
parent 3f4e5ee227
commit 99f14b84c1
9 changed files with 98 additions and 52 deletions

View file

@ -1,6 +1,5 @@
#include "UdpVpn.hpp" #include "UdpVpn.hpp"
#include <chrono>
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
@ -19,8 +18,10 @@ UdpVpn::UdpVpn()
: _stopped(false), _dump_requested(false), _vpn_mtu(VPN_MTU), : _stopped(false), _dump_requested(false), _vpn_mtu(VPN_MTU),
_tun_dev("cvpn%d"), _peer(nullptr) _tun_dev("cvpn%d"), _peer(nullptr)
{ {
_last_tick = _last_control_sent = clock_gettime(CLOCK_MONOTONIC, &_last_tick);
std::chrono::steady_clock::now() - std::chrono::seconds(1); _last_tick.tv_sec--;
memcpy(&_last_control_sent, &_last_tick, sizeof(struct timespec));
_tun_dev.set_mtu(VpnPacket::get_tunnelled_mtu(_vpn_mtu)); _tun_dev.set_mtu(VpnPacket::get_tunnelled_mtu(_vpn_mtu));
_socket = socket(AF_INET6, SOCK_DGRAM, 0); _socket = socket(AF_INET6, SOCK_DGRAM, 0);
if(_socket < 0) if(_socket < 0)
@ -63,17 +64,13 @@ void UdpVpn::run() {
// ## Check periodic actions // ## Check periodic actions
if(_peer) { if(_peer) {
if(std::chrono::steady_clock::now() - _last_control_sent if(timespec_us_ellapsed(_last_control_sent) > 1000*1000) {
> std::chrono::milliseconds(100))
{
if(_peer->send_control_packet()) if(_peer->send_control_packet())
_last_control_sent = std::chrono::steady_clock::now(); clock_gettime(CLOCK_MONOTONIC, &_last_control_sent);
} }
} }
if(std::chrono::steady_clock::now() - _last_tick if(timespec_us_ellapsed(_last_tick) > 50*1000) {
> std::chrono::milliseconds(50)) clock_gettime(CLOCK_MONOTONIC, &_last_tick);
{
_last_tick = std::chrono::steady_clock::now();
if(_peer) if(_peer)
_peer->tick(); _peer->tick();
} }
@ -257,12 +254,10 @@ void UdpVpn::dump_state() const {
round(_peer->get_loss_logger().get_loss_rate() * 100)); round(_peer->get_loss_logger().get_loss_rate() * 100));
printf("Packet loss rate (outbound): %.0lf%%\n", printf("Packet loss rate (outbound): %.0lf%%\n",
round(_peer->get_loss_reports().loss_rate() * 100)); round(_peer->get_loss_reports().loss_rate() * 100));
printf("RTT: %.02lf ms avg, %.02lf ms last [last updated: %lu ms ago]\n", printf("RTT: %.02lf ms avg, %.02lf ms last [last updated: %u ms ago]\n",
(double)_peer->get_rtt().avg_rtt() / 1e3, (double)_peer->get_rtt().avg_rtt() / 1e3,
(double)_peer->get_rtt().cur_rtt() / 1e3, (double)_peer->get_rtt().cur_rtt() / 1e3,
std::chrono::duration_cast<std::chrono::milliseconds>( timespec_us_ellapsed(_peer->get_rtt().get_last_update()) / 1000
std::chrono::steady_clock::now()
- _peer->get_rtt().get_last_update()).count()
); );
printf("Total bytes transmitted: %s\n", printf("Total bytes transmitted: %s\n",
human_readable_unit(_peer->get_tot_bytes_sent(), "B")); human_readable_unit(_peer->get_tot_bytes_sent(), "B"));

View file

@ -2,6 +2,7 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <time.h>
#include "util.hpp" #include "util.hpp"
#include "TunDevice.hpp" #include "TunDevice.hpp"
@ -73,7 +74,7 @@ class UdpVpn {
TunDevice _tun_dev; TunDevice _tun_dev;
std::unique_ptr<VpnPeer> _peer; std::unique_ptr<VpnPeer> _peer;
std::chrono::steady_clock::time_point struct timespec
_last_control_sent, /**< A control is offered to be sent approx. _last_control_sent, /**< A control is offered to be sent approx.
every 100ms */ every 100ms */
_last_tick /**< A tick occurs approx. each 50ms */; _last_tick /**< A tick occurs approx. each 50ms */;

View file

@ -1,7 +1,6 @@
#include "VpnPacket.hpp" #include "VpnPacket.hpp"
#include "VpnPeer.hpp" #include "VpnPeer.hpp"
#include <chrono>
#include <cstring> #include <cstring>
const size_t VpnPacket::VPN_HEADER_BYTES = 8; const size_t VpnPacket::VPN_HEADER_BYTES = 8;
@ -70,19 +69,11 @@ void VpnPacket::prepare_for_sending() {
uint32_t* ts_field = (uint32_t*) (_data.get() + DATA_TIMESTAMP_POS); uint32_t* ts_field = (uint32_t*) (_data.get() + DATA_TIMESTAMP_POS);
*ts_field &= htonl(0x80000000UL); *ts_field &= htonl(0x80000000UL);
*(uint32_t*)(_data.get() + DATA_SEQNO_POS) = htonl(next_seqno()); *(uint32_t*)(_data.get() + DATA_SEQNO_POS) = htonl(next_seqno());
*ts_field |= *ts_field |= htonl(to_us_timestamp(current_us_timestamp()));
htonl(to_us_timestamp(
std::chrono::time_point_cast<std::chrono::microseconds>(
std::chrono::steady_clock::now()
).time_since_epoch().count())
);
} }
void VpnPacket::upon_reception() { void VpnPacket::upon_reception() {
_reception_timestamp = to_us_timestamp( _reception_timestamp = to_us_timestamp(current_us_timestamp());
std::chrono::time_point_cast<std::chrono::microseconds>(
std::chrono::steady_clock::now()
).time_since_epoch().count());
} }
uint32_t VpnPacket::next_seqno() { uint32_t VpnPacket::next_seqno() {

View file

@ -14,7 +14,7 @@ VpnPeer::VpnPeer(UdpVpn* vpn, const sockaddr_in6& ext_addr,
_tot_bytes_sent(0), _prev_tot_bytes_sent(0), _tot_bytes_sent(0), _prev_tot_bytes_sent(0),
_congestion_controller(*this) _congestion_controller(*this)
{ {
_prev_tick_time = std::chrono::steady_clock::now(); clock_gettime(CLOCK_MONOTONIC, &_prev_tick_time);
cycle_next_control(); cycle_next_control();
} }
@ -35,13 +35,13 @@ void VpnPeer::set_int_addr(const in6_addr& int_addr) {
} }
void VpnPeer::tick() { void VpnPeer::tick() {
auto cur_time = std::chrono::steady_clock::now(); struct timespec cur_time;
clock_gettime(CLOCK_MONOTONIC, &cur_time);
// Compute byte rate // Compute byte rate
_outbound_byte_rate = /* byte per second */ _outbound_byte_rate = /* byte per second */
(double)(_tot_bytes_sent - _prev_tot_bytes_sent) (double)(_tot_bytes_sent - _prev_tot_bytes_sent)
/ (double)(std::chrono::duration_cast<std::chrono::microseconds>( / timespec_us_diff(cur_time, _prev_tick_time)
cur_time - _prev_tick_time).count())
* 1e6; * 1e6;
_prev_tot_bytes_sent = _tot_bytes_sent; _prev_tot_bytes_sent = _tot_bytes_sent;
@ -153,12 +153,9 @@ void PacketLossLogger::maybe_start_window(int offs) {
} }
} }
RTTLogger::RTTLogger() : RTTLogger::RTTLogger() : _avg_rtt(0), _cur_rtt(0) {
_avg_rtt(0), _cur_rtt(0), clock_gettime(CLOCK_MONOTONIC, &_last_update);
_last_update(std::chrono::steady_clock::time_point::min()) _last_update.tv_sec--;
{
_last_update =
std::chrono::steady_clock::now() - std::chrono::seconds(1);
// This avoids situations where both peers try to renew their RTT at the // This avoids situations where both peers try to renew their RTT at the
// same time. // same time.
_update_delay = BASE_UPDATE_DELAY + rand() % 100 - 50; _update_delay = BASE_UPDATE_DELAY + rand() % 100 - 50;
@ -177,12 +174,11 @@ void RTTLogger::log(const VpnTlvRTTA& rtt_answer) {
_avg_rtt = (1 - EXP_AVG_FACTOR) * _avg_rtt _avg_rtt = (1 - EXP_AVG_FACTOR) * _avg_rtt
+ EXP_AVG_FACTOR * _cur_rtt; + EXP_AVG_FACTOR * _cur_rtt;
_last_update = std::chrono::steady_clock::now(); clock_gettime(CLOCK_MONOTONIC, &_last_update);
} }
bool RTTLogger::update_due(bool soon) const { bool RTTLogger::update_due(bool soon) const {
unsigned int ms_since_last_update = unsigned int ms_since_last_update =
std::chrono::duration_cast<std::chrono::milliseconds>( timespec_us_ellapsed(_last_update) / 1000;
std::chrono::steady_clock::now() - _last_update).count();
return ms_since_last_update >= (soon ? _update_delay/2 : _update_delay); return ms_since_last_update >= (soon ? _update_delay/2 : _update_delay);
} }

View file

@ -4,7 +4,7 @@
#include <netinet/in.h> #include <netinet/in.h>
#include <bitset> #include <bitset>
#include <chrono> #include <time.h>
#include "util.hpp" #include "util.hpp"
#include "VpnPacket.hpp" #include "VpnPacket.hpp"
#include "congestion_control.hpp" #include "congestion_control.hpp"
@ -47,7 +47,7 @@ class RTTLogger {
RTTLogger(); RTTLogger();
uint32_t avg_rtt() const { return _avg_rtt; } uint32_t avg_rtt() const { return _avg_rtt; }
uint32_t cur_rtt() const { return _cur_rtt; } uint32_t cur_rtt() const { return _cur_rtt; }
std::chrono::steady_clock::time_point get_last_update() const { struct timespec get_last_update() const {
return _last_update; return _last_update;
} }
@ -64,7 +64,7 @@ class RTTLogger {
unsigned int _update_delay; // in ms unsigned int _update_delay; // in ms
static const unsigned int BASE_UPDATE_DELAY; // in ms static const unsigned int BASE_UPDATE_DELAY; // in ms
std::chrono::steady_clock::time_point _last_update; struct timespec _last_update;
}; };
class VpnPeer { class VpnPeer {
@ -139,7 +139,7 @@ class VpnPeer {
uint64_t _tot_bytes_sent, _prev_tot_bytes_sent; uint64_t _tot_bytes_sent, _prev_tot_bytes_sent;
double _outbound_byte_rate; double _outbound_byte_rate;
std::chrono::steady_clock::time_point _prev_tick_time; struct timespec _prev_tick_time;
PacketLossLogger _packet_loss; PacketLossLogger _packet_loss;
LossReports _loss_reports; LossReports _loss_reports;

View file

@ -1,5 +1,6 @@
#include "congestion_control.hpp" #include "congestion_control.hpp"
#include "VpnPeer.hpp" #include "VpnPeer.hpp"
#include "util.hpp"
CongestionController::CongestionController(const VpnPeer& peer): CongestionController::CongestionController(const VpnPeer& peer):
_peer(peer) _peer(peer)
@ -7,8 +8,8 @@ CongestionController::CongestionController(const VpnPeer& peer):
_last_seqno = _peer.get_loss_logger().get_cur_seqno(); _last_seqno = _peer.get_loss_logger().get_cur_seqno();
_loss_based.bandwidth = 3e5; // 300kBps seems a good value to start with _loss_based.bandwidth = 3e5; // 300kBps seems a good value to start with
_loss_based.prev_tot_sent = _peer.get_tot_bytes_sent(); _loss_based.prev_tot_sent = _peer.get_tot_bytes_sent();
_last_bucket_update = _loss_based.prev_time = clock_gettime(CLOCK_MONOTONIC, &_last_bucket_update);
std::chrono::steady_clock::now(); clock_gettime(CLOCK_MONOTONIC, &_loss_based.prev_time);
update_params(); update_params();
} }
@ -20,12 +21,14 @@ void CongestionController::update_lossbased() {
double loss_rate = (double)delta_losses / (double)delta_seqno; double loss_rate = (double)delta_losses / (double)delta_seqno;
auto cur_time = std::chrono::steady_clock::now(); struct timespec cur_time;
clock_gettime(CLOCK_MONOTONIC, &cur_time);
uint64_t cur_sent = _peer.get_tot_bytes_sent(); uint64_t cur_sent = _peer.get_tot_bytes_sent();
double instant_bandwidth = /* byte per second */ double instant_bandwidth = /* byte per second */
(double)(cur_sent - _loss_based.prev_tot_sent) (double)(cur_sent - _loss_based.prev_tot_sent)
/ (double)(std::chrono::duration_cast<std::chrono::microseconds>( / (double)(timespec_us_diff(cur_time, _loss_based.prev_time))
cur_time - _loss_based.prev_time).count())
* 1e6; * 1e6;
_loss_based.prev_time = cur_time; _loss_based.prev_time = cur_time;

View file

@ -1,6 +1,6 @@
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
#include <chrono> #include <time.h>
class VpnPeer; class VpnPeer;
@ -9,7 +9,7 @@ class CongestionController {
struct LossBased { struct LossBased {
uint64_t bandwidth; // bytes per second uint64_t bandwidth; // bytes per second
uint64_t prev_tot_sent; // tot bytes sent during last update uint64_t prev_tot_sent; // tot bytes sent during last update
std::chrono::steady_clock::time_point prev_time; // last update time struct timespec prev_time; // last update time
}; };
CongestionController(const VpnPeer& peer); CongestionController(const VpnPeer& peer);
@ -34,6 +34,6 @@ class CongestionController {
uint64_t _bucket_level, ///< implements a leaky bucket uint64_t _bucket_level, ///< implements a leaky bucket
_bucket_max_level; // bandwidth * RTT _bucket_max_level; // bandwidth * RTT
std::chrono::steady_clock::time_point _last_bucket_update; struct timespec _last_bucket_update;
}; };

View file

@ -53,6 +53,42 @@ human_readable_unit(double value, const char* unit) {
return buf[cur_buf]; return buf[cur_buf];
} }
void
timespec_diff(const struct timespec t1, const struct timespec t2,
struct timespec* result)
{
result->tv_nsec = t1.tv_nsec - t2.tv_nsec;
result->tv_sec = t1.tv_sec - t2.tv_sec;
if(result->tv_nsec < 0) {
result->tv_nsec += 1000*1000*1000;
result->tv_sec--;
}
}
uint32_t timespec_us_diff(const struct timespec t1, const struct timespec t2) {
long nsec_diff = t1.tv_nsec - t2.tv_nsec;
time_t sec_diff = t1.tv_sec - t2.tv_sec;
if(nsec_diff < 0) {
nsec_diff += 1000*1000*1000;
sec_diff--;
}
if(sec_diff > MAX_USEC_DIFF)
sec_diff = MAX_USEC_DIFF;
return (nsec_diff / 1000) + (sec_diff * 1000*1000);
}
uint32_t timespec_us_ellapsed(const struct timespec ref) {
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
return timespec_us_diff(now, ref);
}
uint32_t current_us_timestamp() {
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
return (now.tv_sec * 1000*1000) + (now.tv_nsec / 1000);
}
namespace std { namespace std {
size_t hash<in6_addr>::operator() (const in6_addr& addr) const { size_t hash<in6_addr>::operator() (const in6_addr& addr) const {

View file

@ -58,6 +58,30 @@ inline uint32_t to_us_timestamp(uint32_t clock_output) {
} }
/** Max seconds that can be be represented in a microseconds timestamp, on 31
* bits. */
const uint32_t MAX_USEC_DIFF = ((1U<<31) - 1) / (1000*1000) - 1;
/** Get a `struct timespec` difference, ie `t1 - t2`, as a new `struct
* timespec`. Assumes `t1 >= t2`. */
void timespec_diff(
const struct timespec t1, const struct timespec t2,
struct timespec* result);
/** Get a `struct timespec` difference, ie `t1 - t2`, expressed in
* microseconds. Assumes `t1 >= t2`. Capped to MAX_USEC_DIFF seconds. */
uint32_t timespec_us_diff(const struct timespec t1, const struct timespec t2);
/** Get the number of microseconds ellapsed since a `struct timespec`, based on
* the monotonic clock */
uint32_t timespec_us_ellapsed(const struct timespec ref);
/** Get the current timestamp, in microseconds */
uint32_t current_us_timestamp();
/** in6_addr hash & equality */ /** in6_addr hash & equality */
namespace std { namespace std {
template<> template<>