congestvpn/VpnPeer.hpp

151 lines
4.8 KiB
C++

#pragma once
/** A peer of a bound (server) instance of UdpVpn */
#include <netinet/in.h>
#include <bitset>
#include <chrono>
#include "util.hpp"
#include "VpnPacket.hpp"
#include "congestion_control.hpp"
class UdpVpn;
const int PACKET_LOSS_WINDOW = 128, PACKET_LOST_AFTER = 8;
class PacketLossLogger {
public:
PacketLossLogger();
void log_packet(uint32_t seqno);
double get_loss_rate() const {
return (double)(_win_start_losses - _last_window_losses)
/ (double)PACKET_LOSS_WINDOW;
}
const std::bitset<PACKET_LOST_AFTER> get_received_ahead() const {
return _received_ahead;
}
uint32_t get_cur_seqno() const { return _cur_seqno; }
unsigned int get_tot_losses() const { return _tot_losses; }
private:
void reboot(); ///< completely reset the internal state
/// roll loss window values if `_cur_seqno + offs` is a window start.
void maybe_start_window(int offs=0);
std::bitset<PACKET_LOST_AFTER> _received_ahead;
uint32_t _cur_seqno;
unsigned int _tot_losses;
unsigned int _last_window_losses, _win_start_losses;
};
/** 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 {
public:
class NetError : public MsgException {
public:
NetError(
const std::string& msg,
int code=0,
bool is_perror=false)
: MsgException(msg, code, is_perror) {}
};
/// Logs the loss reports sent by the remote peer
struct LossReports {
uint32_t prev_seqno, last_seqno;
uint32_t prev_losses, last_losses;
double loss_rate() const {
return (double)(last_losses - prev_losses)
/ (double)(last_seqno - prev_seqno);
}
};
VpnPeer(UdpVpn* vpn, const sockaddr_in6& ext_addr,
const in6_addr& int_addr);
const sockaddr_in6& get_ext_addr() const { return _ext_addr; }
const in6_addr& get_int_addr() const { return _int_addr; }
void set_int_addr(const in6_addr& int_addr);
const PacketLossLogger& get_loss_logger() const { return _packet_loss; }
const RTTLogger& get_rtt() const { return _rtt; }
const LossReports& get_loss_reports() const { return _loss_reports; }
const CongestionController& get_congestion_controller() const {
return _congestion_controller; }
void tick(); ///< periodic actions, triggered every UdpVpn tick
void log_rtta(const VpnTlvRTTA& rtta) { _rtt.log(rtta); }
void log_loss_report(const VpnTlvLossReport& loss_rep);
size_t write(const char* data, size_t len);
size_t write(const VpnPacket& packet);
uint32_t peek_next_seqno() const { return _next_send_seqno; }
uint32_t next_seqno() { return _next_send_seqno++; }
uint64_t get_tot_bytes_sent() const { return _tot_bytes_sent; }
double get_outbound_byte_rate() const { return _outbound_byte_rate; }
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 make_loss_report(); ///< Add a loss report to the next control packet
void cycle_next_control(); ///< Generate a fresh next control packet
private:
UdpVpn* _vpn;
sockaddr_in6 _ext_addr;
in6_addr _int_addr;
uint32_t _next_send_seqno;
uint64_t _tot_bytes_sent, _prev_tot_bytes_sent;
double _outbound_byte_rate;
std::chrono::steady_clock::time_point _prev_tick_time;
PacketLossLogger _packet_loss;
LossReports _loss_reports;
RTTLogger _rtt;
CongestionController _congestion_controller;
std::unique_ptr<VpnControlPacket> _next_control_packet;
};