congestvpn/VpnPeer.cpp

184 lines
5.9 KiB
C++
Raw Normal View History

2020-06-05 16:14:05 +02:00
#include "UdpVpn.hpp"
#include "congestion_control.hpp"
2020-06-05 16:14:05 +02:00
#include <stdint.h>
#include <string.h>
2020-06-05 16:14:05 +02:00
2020-06-28 23:29:39 +02:00
const double RTTLogger::EXP_AVG_FACTOR = 0.75;
const unsigned int RTTLogger::BASE_UPDATE_DELAY = 1000; // ms
2020-06-05 16:14:05 +02:00
VpnPeer::VpnPeer(UdpVpn* vpn, const sockaddr_in6& ext_addr,
const in6_addr& int_addr)
: _vpn(vpn), _ext_addr(ext_addr), _int_addr(int_addr), _next_send_seqno(0),
2020-07-03 18:03:26 +02:00
_tot_bytes_sent(0), _prev_tot_bytes_sent(0),
_congestion_controller(*this)
2020-06-28 23:29:39 +02:00
{
2020-07-22 15:45:16 +02:00
clock_gettime(CLOCK_MONOTONIC, &_prev_tick_time);
2020-06-28 23:29:39 +02:00
cycle_next_control();
}
void VpnPeer::make_loss_report() {
VpnTlvLossReport report = VpnTlvLossReport::create(*_next_control_packet);
report.set_report_seqno(_packet_loss.get_cur_seqno());
report.set_losses(_packet_loss.get_tot_losses());
}
2020-06-28 23:29:39 +02:00
void VpnPeer::cycle_next_control() {
_next_control_packet =
std::make_unique<VpnControlPacket>(_vpn->get_mtu(), false);
_next_control_packet->set_peer(this);
}
2020-06-05 16:14:05 +02:00
void VpnPeer::set_int_addr(const in6_addr& int_addr) {
memcpy(&_int_addr, &int_addr, sizeof(_int_addr));
}
2020-06-05 16:14:05 +02:00
2020-07-03 18:03:26 +02:00
void VpnPeer::tick() {
2020-07-22 15:45:16 +02:00
struct timespec cur_time;
clock_gettime(CLOCK_MONOTONIC, &cur_time);
2020-07-03 18:03:26 +02:00
// Compute byte rate
_outbound_byte_rate = /* byte per second */
(double)(_tot_bytes_sent - _prev_tot_bytes_sent)
2020-07-22 15:45:16 +02:00
/ timespec_us_diff(cur_time, _prev_tick_time)
2020-07-03 18:03:26 +02:00
* 1e6;
_prev_tot_bytes_sent = _tot_bytes_sent;
_prev_tick_time = cur_time;
}
void VpnPeer::log_loss_report(const VpnTlvLossReport& loss_rep) {
_loss_reports.prev_seqno = _loss_reports.last_seqno;
_loss_reports.prev_losses = _loss_reports.last_losses;
_loss_reports.last_seqno = loss_rep.get_report_seqno();
_loss_reports.last_losses = loss_rep.get_losses();
_congestion_controller.update_lossbased();
}
2020-06-05 16:14:05 +02:00
size_t VpnPeer::write(const char* data, size_t len) {
ssize_t nsent;
nsent = sendto(_vpn->get_socket_fd(), data, len, MSG_CONFIRM,
(const struct sockaddr*) &_ext_addr, sizeof(_ext_addr));
if(nsent < 0)
throw NetError("Could not send UDP packet", errno, true);
2020-07-03 18:03:26 +02:00
_tot_bytes_sent += nsent;
2020-06-05 16:14:05 +02:00
return (size_t) nsent;
}
2020-06-05 17:31:02 +02:00
size_t VpnPeer::write(const VpnPacket& packet) {
return write(packet.get_data(), packet.get_data_size());
}
2020-06-23 15:36:49 +02:00
2020-06-26 19:41:55 +02:00
void VpnPeer::got_inbound_packet(const VpnPacket& packet) {
_packet_loss.log_packet(packet.get_seqno());
}
2020-06-28 23:29:39 +02:00
bool VpnPeer::send_control_packet() {
if(_rtt.update_due(!_next_control_packet->is_empty())) {
2020-06-28 23:29:39 +02:00
VpnTlvRTTQ::create(*_next_control_packet);
make_loss_report();
}
2020-06-28 23:29:39 +02:00
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), _tot_losses(0), _last_window_losses(0), _win_start_losses(0)
{}
2020-06-23 15:36:49 +02:00
void PacketLossLogger::log_packet(uint32_t seqno) {
int64_t diff = (int64_t)seqno - _cur_seqno;
if(diff == 1) {
_cur_seqno++;
maybe_start_window();
2020-06-23 15:36:49 +02:00
while(_received_ahead.test((_cur_seqno + 1) % PACKET_LOST_AFTER)) {
_cur_seqno++;
_received_ahead.reset(_cur_seqno % PACKET_LOST_AFTER);
maybe_start_window();
2020-06-23 15:36:49 +02:00
}
} else if(LIKELY(diff > 1)) {
if(diff < PACKET_LOST_AFTER)
_received_ahead.set(seqno % PACKET_LOST_AFTER);
else if(diff < PACKET_LOSS_WINDOW) {
2020-06-23 15:36:49 +02:00
// Packet too much forwards -- consider _cur_seqno lost
if(_cur_seqno % PACKET_LOSS_WINDOW > seqno % PACKET_LOSS_WINDOW) {
// This loss crosses a window border
for(int offs=0; offs < PACKET_LOST_AFTER; ++offs) {
maybe_start_window(offs);
if(!_received_ahead[(_cur_seqno + offs) % PACKET_LOST_AFTER])
_tot_losses++;
}
} else {
_tot_losses += PACKET_LOST_AFTER - _received_ahead.count();
2020-06-23 15:36:49 +02:00
}
_received_ahead.reset();
_cur_seqno = seqno;
} else
reboot(); // This is a huge gap -- reboot
} else {
if(diff < - 2*PACKET_LOSS_WINDOW)
2020-06-23 15:36:49 +02:00
reboot(); // this is too much backwards -- something's wrong, reboot
// else: ignore, we've moved forward and counted the packet as lost
}
}
void PacketLossLogger::reboot() {
_received_ahead.reset();
// _tot_losses unchanged
}
void PacketLossLogger::maybe_start_window(int offs) {
if(_cur_seqno + offs % PACKET_LOSS_WINDOW == 0) {
_last_window_losses = _win_start_losses;
_win_start_losses = _tot_losses;
}
2020-06-23 15:36:49 +02:00
}
2020-06-28 23:29:39 +02:00
2020-07-22 15:45:16 +02:00
RTTLogger::RTTLogger() : _avg_rtt(0), _cur_rtt(0) {
clock_gettime(CLOCK_MONOTONIC, &_last_update);
_last_update.tv_sec--;
2020-06-28 23:29:39 +02:00
// 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;
2020-07-22 15:45:16 +02:00
clock_gettime(CLOCK_MONOTONIC, &_last_update);
2020-06-28 23:29:39 +02:00
}
bool RTTLogger::update_due(bool soon) const {
unsigned int ms_since_last_update =
2020-07-22 15:45:16 +02:00
timespec_us_ellapsed(_last_update) / 1000;
2020-06-28 23:29:39 +02:00
return ms_since_last_update >= (soon ? _update_delay/2 : _update_delay);
}