X-Git-Url: http://git.localhorst.tv/?a=blobdiff_plain;f=src%2Fnet%2Fnet.cpp;h=1f4e0a951edd655d08547ad1b4dfad7f696a7503;hb=b4e5dad2ed5c7e77573de413f3bf5be88577856d;hp=59176aac8251edcf5f18876d65060ccb80093657;hpb=c256dca7c6ca2c7f8eeffae53c02fe62bd892198;p=blank.git diff --git a/src/net/net.cpp b/src/net/net.cpp index 59176aa..1f4e0a9 100644 --- a/src/net/net.cpp +++ b/src/net/net.cpp @@ -1,3 +1,4 @@ +#include "CongestionControl.hpp" #include "Connection.hpp" #include "ConnectionHandler.hpp" #include "io.hpp" @@ -30,6 +31,168 @@ constexpr size_t Packet::BlockUpdate::MAX_LEN; constexpr size_t Packet::Message::MAX_LEN; constexpr size_t Packet::Message::MAX_MESSAGE_LEN; + +CongestionControl::CongestionControl() +// I know, I know, it's an estimate (about 20 for IPv4, 48 for IPv6) +: packet_overhead(20) +// only sample every eighth packet for measuring RTT +, sample_skip(8) +, packets_lost(0) +, packets_received(0) +, packet_loss(0.0f) +, stamp_cursor(15) +, stamp_last(0) +, rtt(64.0f) +, next_sample(1000) +, tx_bytes(0) +, rx_bytes(0) +, tx_kbps(0.0f) +, rx_kbps(0.0f) +, mode(GOOD) +// rtt > 100ms or packet loss > 5% is BAD +, bad_rtt(100.0f) +, bad_loss(0.05f) +// rtt > 250ms or packet loss > 15% is UGLY +, ugly_rtt(250.0f) +, ugly_loss(0.15f) +, mode_keep_time(1000) { + Uint32 now = SDL_GetTicks(); + for (Uint32 &s : stamps) { + s = now; + } + next_sample += now; + mode_entered = now; + mode_reset = now; + mode_step = now; +} + +void CongestionControl::PacketSent(uint16_t seq) noexcept { + if (!SamplePacket(seq)) { + return; + } + stamp_cursor = (stamp_cursor + 1) % 16; + stamps[stamp_cursor] = SDL_GetTicks(); + stamp_last = seq; +} + +void CongestionControl::PacketLost(uint16_t seq) noexcept { + ++packets_lost; + UpdatePacketLoss(); + UpdateRTT(seq); +} + +void CongestionControl::PacketReceived(uint16_t seq) noexcept { + ++packets_received; + UpdatePacketLoss(); + UpdateRTT(seq); +} + +void CongestionControl::UpdatePacketLoss() noexcept { + unsigned int packets_total = packets_lost + packets_received; + if (packets_total >= 256) { + packet_loss = float(packets_lost) / float(packets_total); + packets_lost = 0; + packets_received = 0; + } +} + +void CongestionControl::UpdateRTT(std::uint16_t seq) noexcept { + if (!SamplePacket(seq)) return; + int16_t diff = int16_t(seq) - int16_t(stamp_last); + diff /= sample_skip; + if (diff > 0 || diff < -15) { + // packet outside observed time frame + return; + } + int cur_rtt = SDL_GetTicks() - stamps[(stamp_cursor + diff + 16) % 16]; + rtt += (cur_rtt - rtt) * 0.1f; +} + +bool CongestionControl::SamplePacket(std::uint16_t seq) const noexcept { + return seq % sample_skip == 0; +} + +void CongestionControl::PacketIn(const UDPpacket &pack) noexcept { + rx_bytes += pack.len + packet_overhead; + UpdateStats(); +} + +void CongestionControl::PacketOut(const UDPpacket &pack) noexcept { + tx_bytes += pack.len + packet_overhead; + UpdateStats(); +} + +void CongestionControl::UpdateStats() noexcept { + Uint32 now = SDL_GetTicks(); + if (now < next_sample) { + // not yet + return; + } + tx_kbps = float(tx_bytes) * (1.0f / 1024.0f); + rx_kbps = float(rx_bytes) * (1.0f / 1024.0f); + tx_bytes = 0; + rx_bytes = 0; + next_sample += 1000; + UpdateMode(); +} + +void CongestionControl::UpdateMode() noexcept { + Mode now_mode = Conditions(); + if (now_mode > mode) { + ChangeMode(now_mode); + } else if (now_mode < mode) { + CheckUpgrade(now_mode); + } else { + KeepMode(); + } +} + +void CongestionControl::CheckUpgrade(Mode m) noexcept { + Uint32 now = SDL_GetTicks(); + Uint32 time_in_mode = now - mode_entered; + if (time_in_mode < mode_keep_time) { + return; + } + ChangeMode(m); +} + +void CongestionControl::ChangeMode(Mode m) noexcept { + Uint32 now = SDL_GetTicks(); + if (m > mode) { + // changed to worse mode + // if we spent less than 10 seconds in better mode + // double keep time till up to 64 seconds + if (now - mode_entered < 10000) { + if (mode_keep_time < 64000) { + mode_keep_time *= 2; + } + } + } + mode = m; + mode_entered = now; + mode_reset = mode_entered; +} + +void CongestionControl::KeepMode() noexcept { + mode_reset = SDL_GetTicks(); + // if in good mode for 10 seconds, halve keep time till down to one second + if (mode == GOOD && mode_keep_time > 1000 && mode_step - mode_reset > 10000) { + mode_keep_time /= 2; + mode_step = mode_reset; + } +} + +CongestionControl::Mode CongestionControl::Conditions() const noexcept { + if (rtt > ugly_rtt || packet_loss > ugly_loss) { + return UGLY; + } else if (rtt > bad_rtt || packet_loss > bad_loss) { + return BAD; + } else { + return GOOD; + } +} + + Connection::Connection(const IPaddress &addr) : handler(nullptr) , addr(addr) @@ -85,6 +248,7 @@ uint16_t Connection::Send(UDPpacket &udp_pack, UDPsocket sock) { } if (HasHandler()) { + Handler().PacketOut(udp_pack); Handler().PacketSent(seq); } @@ -115,6 +279,7 @@ void Connection::Received(const UDPpacket &udp_pack) { } Packet::TControl ctrl_new = pack.header.ctrl; + Handler().PacketIn(udp_pack); Handler().Handle(udp_pack); if (diff > 0) { @@ -153,69 +318,30 @@ uint16_t Connection::SendPing(UDPpacket &udp_pack, UDPsocket sock) { ConnectionHandler::ConnectionHandler() -: packets_lost(0) -, packets_received(0) -, packet_loss(0.0f) -, stamp_cursor(15) -, stamp_last(0) -, rtt(64.0f) { - Uint32 now = SDL_GetTicks(); - for (Uint32 &s : stamps) { - s = now; - } +: cc() { + } -void ConnectionHandler::PacketSent(uint16_t seq) { - if (!SamplePacket(seq)) { - return; - } - stamp_cursor = (stamp_cursor + 1) % 16; - stamps[stamp_cursor] = SDL_GetTicks(); - stamp_last = seq; +void ConnectionHandler::PacketSent(uint16_t seq) noexcept { + cc.PacketSent(seq); } void ConnectionHandler::PacketLost(uint16_t seq) { OnPacketLost(seq); - ++packets_lost; - UpdatePacketLoss(); - UpdateRTT(seq); + cc.PacketLost(seq); } void ConnectionHandler::PacketReceived(uint16_t seq) { OnPacketReceived(seq); - ++packets_received; - UpdatePacketLoss(); - UpdateRTT(seq); + cc.PacketReceived(seq); } -void ConnectionHandler::UpdatePacketLoss() noexcept { - unsigned int packets_total = packets_lost + packets_received; - if (packets_total >= 256) { - packet_loss = float(packets_lost) / float(packets_total); - packets_lost = 0; - packets_received = 0; - } -} - -void ConnectionHandler::UpdateRTT(std::uint16_t seq) noexcept { - if (!SamplePacket(seq)) return; - int diff = HeadDiff(seq); - if (diff > 0 || diff < -15) { - // packet outside observed time frame - return; - } - int cur_rtt = SDL_GetTicks() - stamps[(stamp_cursor + diff + 16) % 16]; - rtt += (cur_rtt - rtt) * 0.1f; +void ConnectionHandler::PacketIn(const UDPpacket &pack) noexcept { + cc.PacketIn(pack); } -bool ConnectionHandler::SamplePacket(std::uint16_t seq) const noexcept { - // only sample every eighth packet - return seq % 8 == 0; -} - -int ConnectionHandler::HeadDiff(std::uint16_t seq) const noexcept { - int16_t diff = int16_t(seq) - int16_t(stamp_last); - return diff / 8; +void ConnectionHandler::PacketOut(const UDPpacket &pack) noexcept { + cc.PacketOut(pack); }