#pragma once /** A peer of a bound (server) instance of UdpVpn */ #include #include #include #include "util.hpp" #include "VpnPacket.hpp" class UdpVpn; const int PACKET_LOSS_HISTSIZE = 128, PACKET_LOST_AFTER = 8; class PacketLossLogger { public: PacketLossLogger(); void log_packet(uint32_t seqno); double get_loss_rate() const { return (double)_packet_loss_hist.count() / PACKET_LOSS_HISTSIZE; } const std::bitset get_loss_hist() const { return _packet_loss_hist; } const std::bitset get_received_ahead() const { return _received_ahead; } uint32_t get_cur_seqno() const { return _cur_seqno; } private: void reboot(); ///< completely reset the internal state std::bitset _packet_loss_hist; std::bitset _received_ahead; 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 { public: class NetError : public MsgException { public: NetError( const std::string& msg, int code=0, bool is_perror=false) : MsgException(msg, code, is_perror) {} }; 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() { 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 VpnPacket& packet); uint32_t peek_next_seqno() const { return _next_send_seqno; } uint32_t next_seqno() { return _next_send_seqno++; } 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: UdpVpn* _vpn; sockaddr_in6 _ext_addr; in6_addr _int_addr; uint32_t _next_send_seqno; PacketLossLogger _packet_loss; RTTLogger _rtt; std::unique_ptr _next_control_packet; };