Measure RTT
This commit is contained in:
parent
c5541d1e79
commit
a08808344e
8 changed files with 253 additions and 17 deletions
38
UdpVpn.cpp
38
UdpVpn.cpp
|
@ -1,5 +1,6 @@
|
||||||
#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>
|
||||||
|
@ -18,6 +19,8 @@ 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_control_sent =
|
||||||
|
std::chrono::steady_clock::now() - std::chrono::seconds(1);
|
||||||
_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)
|
||||||
|
@ -49,7 +52,7 @@ void UdpVpn::run() {
|
||||||
_dump_requested = false;
|
_dump_requested = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = poll(poll_fds, nfds, -1);
|
rc = poll(poll_fds, nfds, 100); // timeout every 100ms
|
||||||
|
|
||||||
if(rc < 0) {
|
if(rc < 0) {
|
||||||
if(errno == EINTR) // Interrupt.
|
if(errno == EINTR) // Interrupt.
|
||||||
|
@ -57,7 +60,18 @@ void UdpVpn::run() {
|
||||||
throw UdpVpn::NetError(
|
throw UdpVpn::NetError(
|
||||||
"Error polling from interface", errno, true);
|
"Error polling from interface", errno, true);
|
||||||
}
|
}
|
||||||
else if(rc == 0) // Nothing to read
|
|
||||||
|
// ## Check periodic actions
|
||||||
|
if(_peer) {
|
||||||
|
if(std::chrono::steady_clock::now() - _last_control_sent
|
||||||
|
> std::chrono::milliseconds(100))
|
||||||
|
{
|
||||||
|
if(_peer->send_control_packet())
|
||||||
|
_last_control_sent = std::chrono::steady_clock::now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rc == 0) // Nothing to read -- timeout
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
cur_fd = start_at_fd;
|
cur_fd = start_at_fd;
|
||||||
|
@ -181,6 +195,14 @@ void UdpVpn::receive_from_udp() {
|
||||||
tlv.seek_next_tlv())
|
tlv.seek_next_tlv())
|
||||||
{
|
{
|
||||||
switch(tlv.get_type()) {
|
switch(tlv.get_type()) {
|
||||||
|
case VpnPacketTLV::PAYLOAD_TYPE_RTTQ:
|
||||||
|
if(_peer)
|
||||||
|
_peer->make_rtta_for(VpnTlvRTTQ(tlv));
|
||||||
|
break;
|
||||||
|
case VpnPacketTLV::PAYLOAD_TYPE_RTTA:
|
||||||
|
if(_peer)
|
||||||
|
_peer->log_rtta(VpnTlvRTTA(tlv));
|
||||||
|
break;
|
||||||
case VpnPacketTLV::PAYLOAD_TYPE_UNDEF:
|
case VpnPacketTLV::PAYLOAD_TYPE_UNDEF:
|
||||||
default:
|
default:
|
||||||
debugf("#%d+%lu: ignoring TLV with bad type %d.\n",
|
debugf("#%d+%lu: ignoring TLV with bad type %d.\n",
|
||||||
|
@ -197,6 +219,11 @@ void UdpVpn::receive_from_udp() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void UdpVpn::receive_tunnelled_tlv(VpnDataPacket& packet) {
|
void UdpVpn::receive_tunnelled_tlv(VpnDataPacket& packet) {
|
||||||
|
if(!packet.parse_as_ipv6()) {
|
||||||
|
debugf("Reinjection: dropping packet with bad IPv6 header.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Reinject into tun
|
// Reinject into tun
|
||||||
kdebugf("Reinjecting tunnelled packet of size %d [#%ld, TS=%ld μs]\n",
|
kdebugf("Reinjecting tunnelled packet of size %d [#%ld, TS=%ld μs]\n",
|
||||||
packet.get_payload_size(),
|
packet.get_payload_size(),
|
||||||
|
@ -209,5 +236,12 @@ void UdpVpn::dump_state() const {
|
||||||
printf("====== State dump ======\n");
|
printf("====== State dump ======\n");
|
||||||
printf("Packet loss rate: %.0lf%%\n",
|
printf("Packet loss rate: %.0lf%%\n",
|
||||||
round(_peer->get_loss_logger().get_loss_rate() * 100));
|
round(_peer->get_loss_logger().get_loss_rate() * 100));
|
||||||
|
printf("RTT: %.02lf ms avg, %.02lf ms last [last updated: %lu ms ago]\n",
|
||||||
|
(double)_peer->get_rtt().avg_rtt() / 1e3,
|
||||||
|
(double)_peer->get_rtt().cur_rtt() / 1e3,
|
||||||
|
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||||
|
std::chrono::steady_clock::now()
|
||||||
|
- _peer->get_rtt().get_last_update()).count()
|
||||||
|
);
|
||||||
printf("==== End state dump ====\n");
|
printf("==== End state dump ====\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,10 @@ class UdpVpn {
|
||||||
// A state dump has been requested
|
// A state dump has been requested
|
||||||
void dump_requested() { _dump_requested = true; }
|
void dump_requested() { _dump_requested = true; }
|
||||||
|
|
||||||
|
size_t get_mtu() const { return _vpn_mtu; }
|
||||||
|
|
||||||
|
size_t transmit_to_peer(VpnPacket& packet);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void acquire_peer(
|
virtual void acquire_peer(
|
||||||
VpnDataPacket& packet,
|
VpnDataPacket& packet,
|
||||||
|
@ -54,8 +58,6 @@ class UdpVpn {
|
||||||
size_t read_from_udp(char* buffer, size_t len, sockaddr_in6& peer_addr);
|
size_t read_from_udp(char* buffer, size_t len, sockaddr_in6& peer_addr);
|
||||||
size_t read_from_udp(VpnPacket& packet, sockaddr_in6& peer_addr);
|
size_t read_from_udp(VpnPacket& packet, sockaddr_in6& peer_addr);
|
||||||
|
|
||||||
size_t transmit_to_peer(VpnPacket& packet);
|
|
||||||
|
|
||||||
void receive_from_tun();
|
void receive_from_tun();
|
||||||
void receive_from_udp();
|
void receive_from_udp();
|
||||||
|
|
||||||
|
@ -70,4 +72,6 @@ class UdpVpn {
|
||||||
|
|
||||||
TunDevice _tun_dev;
|
TunDevice _tun_dev;
|
||||||
std::unique_ptr<VpnPeer> _peer;
|
std::unique_ptr<VpnPeer> _peer;
|
||||||
|
|
||||||
|
std::chrono::steady_clock::time_point _last_control_sent;
|
||||||
};
|
};
|
||||||
|
|
|
@ -68,18 +68,21 @@ void VpnPacket::set_control(bool is_control) {
|
||||||
|
|
||||||
void VpnPacket::prepare_for_sending() {
|
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 &= 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((std::chrono::time_point_cast<std::chrono::microseconds>(
|
htonl(to_us_timestamp(
|
||||||
std::chrono::steady_clock::now()).time_since_epoch().count())
|
std::chrono::time_point_cast<std::chrono::microseconds>(
|
||||||
& 0x7fffffffUL);
|
std::chrono::steady_clock::now()
|
||||||
|
).time_since_epoch().count())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VpnPacket::upon_reception() {
|
void VpnPacket::upon_reception() {
|
||||||
_reception_timestamp =
|
_reception_timestamp = to_us_timestamp(
|
||||||
std::chrono::time_point_cast<std::chrono::microseconds>(
|
std::chrono::time_point_cast<std::chrono::microseconds>(
|
||||||
std::chrono::steady_clock::now()).time_since_epoch().count();
|
std::chrono::steady_clock::now()
|
||||||
|
).time_since_epoch().count());
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t VpnPacket::next_seqno() {
|
uint32_t VpnPacket::next_seqno() {
|
||||||
|
@ -112,8 +115,13 @@ VpnDataPacket::VpnDataPacket(VpnPacket&& move_from)
|
||||||
: VpnPacket(std::move(move_from)), _ipv6_parsed(false)
|
: VpnPacket(std::move(move_from)), _ipv6_parsed(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool VpnDataPacket::parse_as_ipv6() {
|
bool VpnDataPacket::parse_as_ipv6(bool reparse) {
|
||||||
return parse_ipv6_header(get_payload(), get_payload_size(), _ipv6_header);
|
if(_ipv6_parsed && !reparse)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
_ipv6_parsed =
|
||||||
|
parse_ipv6_header(get_payload(), get_payload_size(), _ipv6_header);
|
||||||
|
return _ipv6_parsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
VpnPacketTLV::VpnPacketTLV(VpnControlPacket& packet, size_t payload_offset)
|
VpnPacketTLV::VpnPacketTLV(VpnControlPacket& packet, size_t payload_offset)
|
||||||
|
@ -169,3 +177,45 @@ VpnPacketTLV::PayloadType VpnPacketTLV::get_type() const {
|
||||||
void VpnPacketTLV::set_type(VpnPacketTLV::PayloadType type) {
|
void VpnPacketTLV::set_type(VpnPacketTLV::PayloadType type) {
|
||||||
*(uint8_t*)(get_data()) = (uint8_t) type;
|
*(uint8_t*)(get_data()) = (uint8_t) type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ========== VpnTlvRTTQ ========== */
|
||||||
|
VpnTlvRTTQ::VpnTlvRTTQ(VpnControlPacket& packet, size_t payload_offset)
|
||||||
|
: VpnPacketTLV(packet, payload_offset) {}
|
||||||
|
VpnTlvRTTQ::VpnTlvRTTQ(const VpnPacketTLV& other)
|
||||||
|
: VpnPacketTLV(other) {}
|
||||||
|
|
||||||
|
VpnTlvRTTQ VpnTlvRTTQ::create(VpnControlPacket& packet) {
|
||||||
|
return VpnPacketTLV::create(packet, VpnPacketTLV::PAYLOAD_TYPE_RTTQ);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========== VpnTlvRTTA ========== */
|
||||||
|
const uint32_t VpnTlvRTTA::EXP_TS_POS = 0, VpnTlvRTTA::RECV_TS_POS = 4;
|
||||||
|
|
||||||
|
VpnTlvRTTA::VpnTlvRTTA(VpnControlPacket& packet, size_t payload_offset)
|
||||||
|
: VpnPacketTLV(packet, payload_offset) {}
|
||||||
|
VpnTlvRTTA::VpnTlvRTTA(const VpnPacketTLV& other)
|
||||||
|
: VpnPacketTLV(other) {}
|
||||||
|
|
||||||
|
VpnTlvRTTA VpnTlvRTTA::create(VpnControlPacket& packet) {
|
||||||
|
VpnTlvRTTA tlv =
|
||||||
|
VpnPacketTLV::create(packet, VpnPacketTLV::PAYLOAD_TYPE_RTTA);
|
||||||
|
tlv.set_payload_size(8);
|
||||||
|
memset(tlv.get_payload(), 0, 8);
|
||||||
|
return tlv;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t VpnTlvRTTA::get_exp_ts() const {
|
||||||
|
return ntohl(*(uint32_t*)(get_payload() + EXP_TS_POS));
|
||||||
|
}
|
||||||
|
void VpnTlvRTTA::set_exp_ts(uint32_t ts) {
|
||||||
|
*(uint32_t*)(get_payload() + EXP_TS_POS) = htonl(ts);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t VpnTlvRTTA::get_recv_ts() const {
|
||||||
|
return ntohl(*(uint32_t*)(get_payload() + RECV_TS_POS));
|
||||||
|
}
|
||||||
|
void VpnTlvRTTA::set_recv_ts(uint32_t ts) {
|
||||||
|
*(uint32_t*)(get_payload() + RECV_TS_POS) = htonl(ts);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,9 @@ class VpnPacket {
|
||||||
/// Set packet peer -- used for sequence numbers and loss rate
|
/// Set packet peer -- used for sequence numbers and loss rate
|
||||||
void set_peer(VpnPeer* peer);
|
void set_peer(VpnPeer* peer);
|
||||||
|
|
||||||
|
/// Checks whether the packet currently bears a payload
|
||||||
|
bool is_empty() const { return get_payload_size() == 0; }
|
||||||
|
|
||||||
/// Get a pointer to the packet payload (const version)
|
/// Get a pointer to the packet payload (const version)
|
||||||
const char* get_payload() const {
|
const char* get_payload() const {
|
||||||
return _data.get() + VPN_HEADER_BYTES; }
|
return _data.get() + VPN_HEADER_BYTES; }
|
||||||
|
@ -155,8 +158,10 @@ class VpnDataPacket: public VpnPacket {
|
||||||
|
|
||||||
static VpnDataPacket create(VpnPacket& packet);
|
static VpnDataPacket create(VpnPacket& packet);
|
||||||
|
|
||||||
/// Try to parse the packet as IPv6, return `false` upon failure.
|
/** Try to parse the packet as IPv6, return `false` upon failure.
|
||||||
bool parse_as_ipv6();
|
* Does not reparse if _ipv6_parsed, unless reparse is true
|
||||||
|
*/
|
||||||
|
bool parse_as_ipv6(bool reparse=false);
|
||||||
bool ipv6_parsed() const { return _ipv6_parsed; }
|
bool ipv6_parsed() const { return _ipv6_parsed; }
|
||||||
const IPv6Header& get_ipv6_header() const { return _ipv6_header; }
|
const IPv6Header& get_ipv6_header() const { return _ipv6_header; }
|
||||||
|
|
||||||
|
@ -175,6 +180,8 @@ class VpnPacketTLV {
|
||||||
PAYLOAD_TYPE_UNDEF, ///< Undefined packet type
|
PAYLOAD_TYPE_UNDEF, ///< Undefined packet type
|
||||||
PAYLOAD_TYPE_RR, ///< Receiver report
|
PAYLOAD_TYPE_RR, ///< Receiver report
|
||||||
PAYLOAD_TYPE_REMB, ///< Receiver Estimated Maximum Bitrate
|
PAYLOAD_TYPE_REMB, ///< Receiver Estimated Maximum Bitrate
|
||||||
|
PAYLOAD_TYPE_RTTQ, ///< RTT update query
|
||||||
|
PAYLOAD_TYPE_RTTA, ///< RTT update answer
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -238,3 +245,28 @@ class VpnPacketTLV {
|
||||||
VpnControlPacket& _packet;
|
VpnControlPacket& _packet;
|
||||||
size_t _tlv_pos;
|
size_t _tlv_pos;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class VpnTlvRTTQ: public VpnPacketTLV {
|
||||||
|
public:
|
||||||
|
VpnTlvRTTQ(VpnControlPacket& packet, size_t payload_offset);
|
||||||
|
VpnTlvRTTQ(const VpnPacketTLV& other);
|
||||||
|
|
||||||
|
static VpnTlvRTTQ create(VpnControlPacket& packet);
|
||||||
|
};
|
||||||
|
|
||||||
|
class VpnTlvRTTA: public VpnPacketTLV {
|
||||||
|
public:
|
||||||
|
VpnTlvRTTA(VpnControlPacket& packet, size_t payload_offset);
|
||||||
|
VpnTlvRTTA(const VpnPacketTLV& other);
|
||||||
|
|
||||||
|
static VpnTlvRTTA create(VpnControlPacket& packet);
|
||||||
|
|
||||||
|
uint32_t get_exp_ts() const;
|
||||||
|
void set_exp_ts(uint32_t ts);
|
||||||
|
|
||||||
|
uint32_t get_recv_ts() const;
|
||||||
|
void set_recv_ts(uint32_t ts);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const uint32_t EXP_TS_POS, RECV_TS_POS;
|
||||||
|
};
|
||||||
|
|
67
VpnPeer.cpp
67
VpnPeer.cpp
|
@ -5,10 +5,21 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
|
const double RTTLogger::EXP_AVG_FACTOR = 0.75;
|
||||||
|
const unsigned int RTTLogger::BASE_UPDATE_DELAY = 1000; // ms
|
||||||
|
|
||||||
VpnPeer::VpnPeer(UdpVpn* vpn, const sockaddr_in6& ext_addr,
|
VpnPeer::VpnPeer(UdpVpn* vpn, const sockaddr_in6& ext_addr,
|
||||||
const in6_addr& int_addr)
|
const in6_addr& int_addr)
|
||||||
: _vpn(vpn), _ext_addr(ext_addr), _int_addr(int_addr), _next_send_seqno(0)
|
: _vpn(vpn), _ext_addr(ext_addr), _int_addr(int_addr), _next_send_seqno(0)
|
||||||
{}
|
{
|
||||||
|
cycle_next_control();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VpnPeer::cycle_next_control() {
|
||||||
|
_next_control_packet =
|
||||||
|
std::make_unique<VpnControlPacket>(_vpn->get_mtu(), false);
|
||||||
|
_next_control_packet->set_peer(this);
|
||||||
|
}
|
||||||
|
|
||||||
void VpnPeer::set_int_addr(const in6_addr& int_addr) {
|
void VpnPeer::set_int_addr(const in6_addr& int_addr) {
|
||||||
memcpy(&_int_addr, &int_addr, sizeof(_int_addr));
|
memcpy(&_int_addr, &int_addr, sizeof(_int_addr));
|
||||||
|
@ -33,10 +44,28 @@ void VpnPeer::got_inbound_packet(const VpnPacket& packet) {
|
||||||
_packet_loss.log_packet(packet.get_seqno());
|
_packet_loss.log_packet(packet.get_seqno());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VpnPeer::send_control_packet() {
|
||||||
|
if(_rtt.update_due(!_next_control_packet->is_empty()))
|
||||||
|
VpnTlvRTTQ::create(*_next_control_packet);
|
||||||
|
|
||||||
|
if(!_next_control_packet->is_empty()) {
|
||||||
|
_next_control_packet->prepare_for_sending();
|
||||||
|
_vpn->transmit_to_peer(*_next_control_packet);
|
||||||
|
cycle_next_control();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VpnPeer::make_rtta_for(const VpnTlvRTTQ& rttq) {
|
||||||
|
VpnTlvRTTA rtta = VpnTlvRTTA::create(*_next_control_packet);
|
||||||
|
rtta.set_exp_ts(rttq.get_packet().get_sending_timestamp());
|
||||||
|
rtta.set_recv_ts(rttq.get_packet().get_reception_timestamp());
|
||||||
|
}
|
||||||
|
|
||||||
PacketLossLogger::PacketLossLogger() : _cur_seqno(0) {}
|
PacketLossLogger::PacketLossLogger() : _cur_seqno(0) {}
|
||||||
|
|
||||||
void PacketLossLogger::log_packet(uint32_t seqno) {
|
void PacketLossLogger::log_packet(uint32_t seqno) {
|
||||||
kdebugf(">> Logging %lu (loss %lf)\n", seqno, get_loss_rate());
|
|
||||||
uint32_t m_seqno = seqno % PACKET_LOSS_HISTSIZE;
|
uint32_t m_seqno = seqno % PACKET_LOSS_HISTSIZE;
|
||||||
int64_t diff = (int64_t)seqno - _cur_seqno;
|
int64_t diff = (int64_t)seqno - _cur_seqno;
|
||||||
|
|
||||||
|
@ -73,3 +102,37 @@ void PacketLossLogger::reboot() {
|
||||||
_packet_loss_hist.reset();
|
_packet_loss_hist.reset();
|
||||||
_received_ahead.reset();
|
_received_ahead.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
// This avoids situations where both peers try to renew their RTT at the
|
||||||
|
// same time.
|
||||||
|
_update_delay = BASE_UPDATE_DELAY + rand() % 100 - 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RTTLogger::log(const VpnTlvRTTA& rtt_answer) {
|
||||||
|
uint32_t local_t0 = rtt_answer.get_exp_ts(),
|
||||||
|
remote_t0 = rtt_answer.get_recv_ts(),
|
||||||
|
remote_t1 = rtt_answer.get_packet().get_sending_timestamp(),
|
||||||
|
local_t1 = rtt_answer.get_packet().get_reception_timestamp();
|
||||||
|
|
||||||
|
_cur_rtt = (local_t1 - local_t0) - (remote_t1 - remote_t0);
|
||||||
|
if(UNLIKELY(_avg_rtt == 0))
|
||||||
|
_avg_rtt = _cur_rtt;
|
||||||
|
else
|
||||||
|
_avg_rtt = (1 - EXP_AVG_FACTOR) * _avg_rtt
|
||||||
|
+ EXP_AVG_FACTOR * _cur_rtt;
|
||||||
|
|
||||||
|
_last_update = std::chrono::steady_clock::now();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RTTLogger::update_due(bool soon) const {
|
||||||
|
unsigned int ms_since_last_update =
|
||||||
|
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||||
|
std::chrono::steady_clock::now() - _last_update).count();
|
||||||
|
return ms_since_last_update >= (soon ? _update_delay/2 : _update_delay);
|
||||||
|
}
|
||||||
|
|
43
VpnPeer.hpp
43
VpnPeer.hpp
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <bitset>
|
#include <bitset>
|
||||||
|
#include <chrono>
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
#include "VpnPacket.hpp"
|
#include "VpnPacket.hpp"
|
||||||
|
|
||||||
|
@ -37,6 +38,32 @@ class PacketLossLogger {
|
||||||
uint32_t _cur_seqno;
|
uint32_t _cur_seqno;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Round-trip time logger. All timestamps/delays are in microseconds. */
|
||||||
|
class RTTLogger {
|
||||||
|
public:
|
||||||
|
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 {
|
||||||
|
return _last_update;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Checks whether an update is due.
|
||||||
|
* If soon is true, divides the inter-update delay by 2.
|
||||||
|
*/
|
||||||
|
bool update_due(bool soon=false) const;
|
||||||
|
|
||||||
|
void log(const VpnTlvRTTA& rtt_answer);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t _avg_rtt, _cur_rtt;
|
||||||
|
static const double EXP_AVG_FACTOR;
|
||||||
|
|
||||||
|
unsigned int _update_delay; // in ms
|
||||||
|
static const unsigned int BASE_UPDATE_DELAY; // in ms
|
||||||
|
std::chrono::steady_clock::time_point _last_update;
|
||||||
|
};
|
||||||
|
|
||||||
class VpnPeer {
|
class VpnPeer {
|
||||||
public:
|
public:
|
||||||
class NetError : public MsgException {
|
class NetError : public MsgException {
|
||||||
|
@ -57,6 +84,9 @@ class VpnPeer {
|
||||||
void set_int_addr(const in6_addr& int_addr);
|
void set_int_addr(const in6_addr& int_addr);
|
||||||
|
|
||||||
const PacketLossLogger& get_loss_logger() { return _packet_loss; }
|
const PacketLossLogger& get_loss_logger() { return _packet_loss; }
|
||||||
|
const RTTLogger& get_rtt() { return _rtt; }
|
||||||
|
|
||||||
|
void log_rtta(const VpnTlvRTTA& rtta) { _rtt.log(rtta); }
|
||||||
|
|
||||||
size_t write(const char* data, size_t len);
|
size_t write(const char* data, size_t len);
|
||||||
size_t write(const VpnPacket& packet);
|
size_t write(const VpnPacket& packet);
|
||||||
|
@ -66,6 +96,16 @@ class VpnPeer {
|
||||||
|
|
||||||
void got_inbound_packet(const VpnPacket& packet);
|
void got_inbound_packet(const VpnPacket& packet);
|
||||||
|
|
||||||
|
/* === Control protocol === */
|
||||||
|
/// Send a control packet if there is data to be sent
|
||||||
|
bool send_control_packet();
|
||||||
|
|
||||||
|
/// Append a RTTA for the given RTTQ to the next control packet
|
||||||
|
void make_rtta_for(const VpnTlvRTTQ& rttq);
|
||||||
|
|
||||||
|
private: // meth
|
||||||
|
void cycle_next_control(); /// Generate a fresh next control packet
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UdpVpn* _vpn;
|
UdpVpn* _vpn;
|
||||||
sockaddr_in6 _ext_addr;
|
sockaddr_in6 _ext_addr;
|
||||||
|
@ -73,4 +113,7 @@ class VpnPeer {
|
||||||
uint32_t _next_send_seqno;
|
uint32_t _next_send_seqno;
|
||||||
|
|
||||||
PacketLossLogger _packet_loss;
|
PacketLossLogger _packet_loss;
|
||||||
|
RTTLogger _rtt;
|
||||||
|
|
||||||
|
std::unique_ptr<VpnControlPacket> _next_control_packet;
|
||||||
};
|
};
|
||||||
|
|
3
main.cpp
3
main.cpp
|
@ -1,4 +1,5 @@
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
@ -94,6 +95,8 @@ int main(int argc, char** argv) {
|
||||||
}
|
}
|
||||||
printf("=== END OPTIONS ==\n\n");
|
printf("=== END OPTIONS ==\n\n");
|
||||||
|
|
||||||
|
srand(time(NULL)); // FIXME something more secure if we ever need crypto
|
||||||
|
|
||||||
signal(SIGINT, stop_sig_handler);
|
signal(SIGINT, stop_sig_handler);
|
||||||
signal(SIGUSR1, dump_sig_handler);
|
signal(SIGUSR1, dump_sig_handler);
|
||||||
|
|
||||||
|
|
7
util.hpp
7
util.hpp
|
@ -48,6 +48,13 @@ void do_debugf(int level, const char *format, ...);
|
||||||
const char* format_address(const unsigned char* address);
|
const char* format_address(const unsigned char* address);
|
||||||
|
|
||||||
|
|
||||||
|
/** remove the upper bit from a microsecond timestamp, to conform with the
|
||||||
|
* packet header timestamp format. */
|
||||||
|
inline uint32_t to_us_timestamp(uint32_t clock_output) {
|
||||||
|
return clock_output & 0x7fffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** in6_addr hash & equality */
|
/** in6_addr hash & equality */
|
||||||
namespace std {
|
namespace std {
|
||||||
template<>
|
template<>
|
||||||
|
|
Loading…
Reference in a new issue