From 99f14b84c128aea6284536a17f2709eb8679cb14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophile=20Bastian?= Date: Wed, 22 Jul 2020 15:45:16 +0200 Subject: [PATCH] C rewrite: phase out std::chrono --- UdpVpn.cpp | 25 ++++++++++--------------- UdpVpn.hpp | 3 ++- VpnPacket.cpp | 13 ++----------- VpnPeer.cpp | 22 +++++++++------------- VpnPeer.hpp | 8 ++++---- congestion_control.cpp | 13 ++++++++----- congestion_control.hpp | 6 +++--- util.cpp | 36 ++++++++++++++++++++++++++++++++++++ util.hpp | 24 ++++++++++++++++++++++++ 9 files changed, 98 insertions(+), 52 deletions(-) diff --git a/UdpVpn.cpp b/UdpVpn.cpp index 95d9cf4..6c2c64c 100644 --- a/UdpVpn.cpp +++ b/UdpVpn.cpp @@ -1,6 +1,5 @@ #include "UdpVpn.hpp" -#include #include #include #include @@ -19,8 +18,10 @@ UdpVpn::UdpVpn() : _stopped(false), _dump_requested(false), _vpn_mtu(VPN_MTU), _tun_dev("cvpn%d"), _peer(nullptr) { - _last_tick = _last_control_sent = - std::chrono::steady_clock::now() - std::chrono::seconds(1); + clock_gettime(CLOCK_MONOTONIC, &_last_tick); + _last_tick.tv_sec--; + memcpy(&_last_control_sent, &_last_tick, sizeof(struct timespec)); + _tun_dev.set_mtu(VpnPacket::get_tunnelled_mtu(_vpn_mtu)); _socket = socket(AF_INET6, SOCK_DGRAM, 0); if(_socket < 0) @@ -63,17 +64,13 @@ void UdpVpn::run() { // ## Check periodic actions if(_peer) { - if(std::chrono::steady_clock::now() - _last_control_sent - > std::chrono::milliseconds(100)) - { + if(timespec_us_ellapsed(_last_control_sent) > 1000*1000) { 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 - > std::chrono::milliseconds(50)) - { - _last_tick = std::chrono::steady_clock::now(); + if(timespec_us_ellapsed(_last_tick) > 50*1000) { + clock_gettime(CLOCK_MONOTONIC, &_last_tick); if(_peer) _peer->tick(); } @@ -257,12 +254,10 @@ void UdpVpn::dump_state() const { round(_peer->get_loss_logger().get_loss_rate() * 100)); printf("Packet loss rate (outbound): %.0lf%%\n", 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().cur_rtt() / 1e3, - std::chrono::duration_cast( - std::chrono::steady_clock::now() - - _peer->get_rtt().get_last_update()).count() + timespec_us_ellapsed(_peer->get_rtt().get_last_update()) / 1000 ); printf("Total bytes transmitted: %s\n", human_readable_unit(_peer->get_tot_bytes_sent(), "B")); diff --git a/UdpVpn.hpp b/UdpVpn.hpp index a43bb77..cc549a5 100644 --- a/UdpVpn.hpp +++ b/UdpVpn.hpp @@ -2,6 +2,7 @@ #include #include +#include #include "util.hpp" #include "TunDevice.hpp" @@ -73,7 +74,7 @@ class UdpVpn { TunDevice _tun_dev; std::unique_ptr _peer; - std::chrono::steady_clock::time_point + struct timespec _last_control_sent, /**< A control is offered to be sent approx. every 100ms */ _last_tick /**< A tick occurs approx. each 50ms */; diff --git a/VpnPacket.cpp b/VpnPacket.cpp index 2bd4552..1c3a0e1 100644 --- a/VpnPacket.cpp +++ b/VpnPacket.cpp @@ -1,7 +1,6 @@ #include "VpnPacket.hpp" #include "VpnPeer.hpp" -#include #include 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); *ts_field &= htonl(0x80000000UL); *(uint32_t*)(_data.get() + DATA_SEQNO_POS) = htonl(next_seqno()); - *ts_field |= - htonl(to_us_timestamp( - std::chrono::time_point_cast( - std::chrono::steady_clock::now() - ).time_since_epoch().count()) - ); + *ts_field |= htonl(to_us_timestamp(current_us_timestamp())); } void VpnPacket::upon_reception() { - _reception_timestamp = to_us_timestamp( - std::chrono::time_point_cast( - std::chrono::steady_clock::now() - ).time_since_epoch().count()); + _reception_timestamp = to_us_timestamp(current_us_timestamp()); } uint32_t VpnPacket::next_seqno() { diff --git a/VpnPeer.cpp b/VpnPeer.cpp index 6e65ae6..df632e2 100644 --- a/VpnPeer.cpp +++ b/VpnPeer.cpp @@ -14,7 +14,7 @@ VpnPeer::VpnPeer(UdpVpn* vpn, const sockaddr_in6& ext_addr, _tot_bytes_sent(0), _prev_tot_bytes_sent(0), _congestion_controller(*this) { - _prev_tick_time = std::chrono::steady_clock::now(); + clock_gettime(CLOCK_MONOTONIC, &_prev_tick_time); cycle_next_control(); } @@ -35,13 +35,13 @@ void VpnPeer::set_int_addr(const in6_addr& int_addr) { } void VpnPeer::tick() { - auto cur_time = std::chrono::steady_clock::now(); + struct timespec cur_time; + clock_gettime(CLOCK_MONOTONIC, &cur_time); // Compute byte rate _outbound_byte_rate = /* byte per second */ (double)(_tot_bytes_sent - _prev_tot_bytes_sent) - / (double)(std::chrono::duration_cast( - cur_time - _prev_tick_time).count()) + / timespec_us_diff(cur_time, _prev_tick_time) * 1e6; _prev_tot_bytes_sent = _tot_bytes_sent; @@ -153,12 +153,9 @@ void PacketLossLogger::maybe_start_window(int offs) { } } -RTTLogger::RTTLogger() : - _avg_rtt(0), _cur_rtt(0), - _last_update(std::chrono::steady_clock::time_point::min()) -{ - _last_update = - std::chrono::steady_clock::now() - std::chrono::seconds(1); +RTTLogger::RTTLogger() : _avg_rtt(0), _cur_rtt(0) { + clock_gettime(CLOCK_MONOTONIC, &_last_update); + _last_update.tv_sec--; // This avoids situations where both peers try to renew their RTT at the // same time. _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 + 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 { unsigned int ms_since_last_update = - std::chrono::duration_cast( - std::chrono::steady_clock::now() - _last_update).count(); + timespec_us_ellapsed(_last_update) / 1000; return ms_since_last_update >= (soon ? _update_delay/2 : _update_delay); } diff --git a/VpnPeer.hpp b/VpnPeer.hpp index bd440d3..c89e8d2 100644 --- a/VpnPeer.hpp +++ b/VpnPeer.hpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include "util.hpp" #include "VpnPacket.hpp" #include "congestion_control.hpp" @@ -47,7 +47,7 @@ class RTTLogger { RTTLogger(); uint32_t avg_rtt() const { return _avg_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; } @@ -64,7 +64,7 @@ class RTTLogger { unsigned int _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 { @@ -139,7 +139,7 @@ class VpnPeer { uint64_t _tot_bytes_sent, _prev_tot_bytes_sent; double _outbound_byte_rate; - std::chrono::steady_clock::time_point _prev_tick_time; + struct timespec _prev_tick_time; PacketLossLogger _packet_loss; LossReports _loss_reports; diff --git a/congestion_control.cpp b/congestion_control.cpp index e3f9225..2e2341b 100644 --- a/congestion_control.cpp +++ b/congestion_control.cpp @@ -1,5 +1,6 @@ #include "congestion_control.hpp" #include "VpnPeer.hpp" +#include "util.hpp" CongestionController::CongestionController(const VpnPeer& peer): _peer(peer) @@ -7,8 +8,8 @@ CongestionController::CongestionController(const VpnPeer& peer): _last_seqno = _peer.get_loss_logger().get_cur_seqno(); _loss_based.bandwidth = 3e5; // 300kBps seems a good value to start with _loss_based.prev_tot_sent = _peer.get_tot_bytes_sent(); - _last_bucket_update = _loss_based.prev_time = - std::chrono::steady_clock::now(); + clock_gettime(CLOCK_MONOTONIC, &_last_bucket_update); + clock_gettime(CLOCK_MONOTONIC, &_loss_based.prev_time); update_params(); } @@ -20,12 +21,14 @@ void CongestionController::update_lossbased() { 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(); + double instant_bandwidth = /* byte per second */ (double)(cur_sent - _loss_based.prev_tot_sent) - / (double)(std::chrono::duration_cast( - cur_time - _loss_based.prev_time).count()) + / (double)(timespec_us_diff(cur_time, _loss_based.prev_time)) * 1e6; _loss_based.prev_time = cur_time; diff --git a/congestion_control.hpp b/congestion_control.hpp index 63de53e..5e22753 100644 --- a/congestion_control.hpp +++ b/congestion_control.hpp @@ -1,6 +1,6 @@ #pragma once #include -#include +#include class VpnPeer; @@ -9,7 +9,7 @@ class CongestionController { struct LossBased { uint64_t bandwidth; // bytes per second 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); @@ -34,6 +34,6 @@ class CongestionController { uint64_t _bucket_level, ///< implements a leaky bucket _bucket_max_level; // bandwidth * RTT - std::chrono::steady_clock::time_point _last_bucket_update; + struct timespec _last_bucket_update; }; diff --git a/util.cpp b/util.cpp index b3f9005..36fd440 100644 --- a/util.cpp +++ b/util.cpp @@ -53,6 +53,42 @@ human_readable_unit(double value, const char* unit) { 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 { size_t hash::operator() (const in6_addr& addr) const { diff --git a/util.hpp b/util.hpp index 1b324c3..17e926d 100644 --- a/util.hpp +++ b/util.hpp @@ -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 */ namespace std { template<>