aboutsummaryrefslogtreecommitdiffstats
path: root/libtransport/src/protocols/rtc/rtc_verifier.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libtransport/src/protocols/rtc/rtc_verifier.cc')
-rw-r--r--libtransport/src/protocols/rtc/rtc_verifier.cc249
1 files changed, 163 insertions, 86 deletions
diff --git a/libtransport/src/protocols/rtc/rtc_verifier.cc b/libtransport/src/protocols/rtc/rtc_verifier.cc
index 29968dd02..7b6330a1f 100644
--- a/libtransport/src/protocols/rtc/rtc_verifier.cc
+++ b/libtransport/src/protocols/rtc/rtc_verifier.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2021 Cisco and/or its affiliates.
+ * Copyright (c) 2017-2022 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
@@ -22,8 +22,11 @@ namespace protocol {
namespace rtc {
RTCVerifier::RTCVerifier(std::shared_ptr<auth::Verifier> verifier,
- uint32_t max_unverified_delay)
- : verifier_(verifier), max_unverified_delay_(max_unverified_delay) {}
+ uint32_t max_unverified_interval,
+ double max_unverified_ratio)
+ : verifier_(verifier),
+ max_unverified_interval_(max_unverified_interval),
+ max_unverified_ratio_(max_unverified_ratio) {}
void RTCVerifier::setState(std::shared_ptr<RTCState> rtc_state) {
rtc_state_ = rtc_state;
@@ -33,15 +36,20 @@ void RTCVerifier::setVerifier(std::shared_ptr<auth::Verifier> verifier) {
verifier_ = verifier;
}
-void RTCVerifier::setMaxUnverifiedDelay(uint32_t max_unverified_delay) {
- max_unverified_delay_ = max_unverified_delay;
+void RTCVerifier::setMaxUnverifiedInterval(uint32_t max_unverified_interval) {
+ max_unverified_interval_ = max_unverified_interval;
+}
+
+void RTCVerifier::setMaxUnverifiedRatio(double max_unverified_ratio) {
+ max_unverified_ratio_ = max_unverified_ratio;
}
auth::VerificationPolicy RTCVerifier::verify(
core::ContentObject &content_object, bool is_fec) {
- uint32_t suffix = content_object.getName().getSuffix();
- core::PayloadType payload_type = content_object.getPayloadType();
+ auth::Suffix suffix = content_object.getName().getSuffix();
+ auth::VerificationPolicy default_policy = auth::VerificationPolicy::ABORT;
+ core::PayloadType payload_type = content_object.getPayloadType();
bool is_probe = ProbeHandler::getProbeType(suffix) != ProbeType::NOT_PROBE;
bool is_nack = !is_probe && content_object.payloadSize() == NACK_HEADER_SIZE;
bool is_manifest = !is_probe && !is_nack && !is_fec &&
@@ -55,29 +63,31 @@ auth::VerificationPolicy RTCVerifier::verify(
if (is_data) return verifyData(content_object);
if (is_manifest) return verifyManifest(content_object);
- auth::VerificationPolicy policy = auth::VerificationPolicy::ABORT;
- verifier_->callVerificationFailedCallback(suffix, policy);
- return policy;
+ verifier_->callVerificationFailedCallback(suffix, default_policy);
+ return default_policy;
}
auth::VerificationPolicy RTCVerifier::verifyProbe(
core::ContentObject &content_object) {
- switch (ProbeHandler::getProbeType(content_object.getName().getSuffix())) {
- case ProbeType::INIT: {
- auth::VerificationPolicy policy = verifyManifest(content_object);
- if (policy != auth::VerificationPolicy::ACCEPT) {
- return policy;
+ auth::Suffix suffix = content_object.getName().getSuffix();
+ auth::VerificationPolicy policy = auth::VerificationPolicy::ABORT;
+
+ switch (ProbeHandler::getProbeType(suffix)) {
+ case ProbeType::INIT:
+ policy = verifyManifest(content_object);
+ if (policy == auth::VerificationPolicy::ACCEPT) {
+ policy = processManifest(content_object);
}
- return processManifest(content_object);
- }
+ break;
case ProbeType::RTT:
- return verifyNack(content_object);
+ policy = verifyNack(content_object);
+ break;
default:
- auth::VerificationPolicy policy = auth::VerificationPolicy::ABORT;
- verifier_->callVerificationFailedCallback(
- content_object.getName().getSuffix(), policy);
- return policy;
+ verifier_->callVerificationFailedCallback(suffix, policy);
+ break;
}
+
+ return policy;
}
auth::VerificationPolicy RTCVerifier::verifyNack(
@@ -92,28 +102,30 @@ auth::VerificationPolicy RTCVerifier::verifyFec(
auth::VerificationPolicy RTCVerifier::verifyData(
core::ContentObject &content_object) {
- uint32_t suffix = content_object.getName().getSuffix();
-
if (_is_ah(content_object.getFormat())) {
return verifier_->verifyPackets(&content_object);
}
- unverified_bytes_[suffix] =
- content_object.headerSize() + content_object.payloadSize();
- unverified_packets_[suffix] =
- content_object.computeDigest(manifest_hash_algo_);
+ auth::Suffix suffix = content_object.getName().getSuffix();
+ auth::VerificationPolicy policy = auth::VerificationPolicy::ABORT;
+ Timestamp now = utils::SteadyTime::nowMs().count();
+
+ // Flush old packets
+ Timestamp oldest = flush_packets(now);
- // An alert is raised when too much packets remain unverified
- if (getTotalUnverified() > max_unverified_bytes_) {
- unverified_bytes_.clear();
- unverified_packets_.clear();
+ // Add packet to map of unverified packets
+ packets_unverif_.add(
+ {.suffix = suffix, .timestamp = now, .size = content_object.length()},
+ content_object.computeDigest(manifest_hash_algo_));
- auth::VerificationPolicy policy = auth::VerificationPolicy::ABORT;
- verifier_->callVerificationFailedCallback(suffix, policy);
- return policy;
+ // Check that the ratio of unverified packets stays below the limit
+ if (now - oldest < max_unverified_interval_ ||
+ getBufferRatio() < max_unverified_ratio_) {
+ policy = auth::VerificationPolicy::ACCEPT;
}
- return auth::VerificationPolicy::ACCEPT;
+ verifier_->callVerificationFailedCallback(suffix, policy);
+ return policy;
}
auth::VerificationPolicy RTCVerifier::verifyManifest(
@@ -123,8 +135,10 @@ auth::VerificationPolicy RTCVerifier::verifyManifest(
auth::VerificationPolicy RTCVerifier::processManifest(
core::ContentObject &content_object) {
- uint32_t suffix = content_object.getName().getSuffix();
+ auth::Suffix suffix = content_object.getName().getSuffix();
+ auth::VerificationPolicy accept_policy = auth::VerificationPolicy::ACCEPT;
+ // Decode manifest
core::ContentObjectManifest manifest(content_object);
manifest.decode();
@@ -133,65 +147,62 @@ auth::VerificationPolicy RTCVerifier::processManifest(
last_manifest_ = suffix;
}
- // Extract parameters
+ // Extract hash algorithm and hashes
manifest_hash_algo_ = manifest.getHashAlgorithm();
- core::ParamsRTC params = manifest.getParamsRTC();
-
- if (params.prod_rate > 0) {
- max_unverified_bytes_ = static_cast<uint64_t>(
- (max_unverified_delay_ / 1000.0) * params.prod_rate);
- }
-
- if (max_unverified_bytes_ == 0 || !rtc_state_) {
- auth::VerificationPolicy policy = auth::VerificationPolicy::ABORT;
- verifier_->callVerificationFailedCallback(suffix, policy);
- return policy;
- }
-
- // Extract hashes
auth::Verifier::SuffixMap suffix_map =
core::ContentObjectManifest::getSuffixMap(&manifest);
// Return early if the manifest is empty
if (suffix_map.empty()) {
- return auth::VerificationPolicy::ACCEPT;
+ verifier_->callVerificationFailedCallback(suffix, accept_policy);
+ return accept_policy;
}
- // Remove lost packets from digest map
+ // Add hashes to map of all manifest hashes
manifest_digests_.insert(suffix_map.begin(), suffix_map.end());
+
+ // Remove discarded and definitely lost packets from digest map
for (auto it = manifest_digests_.begin(); it != manifest_digests_.end();) {
+ auto it_erased = packets_unverif_erased_.find(it->first);
+
+ if (it_erased != packets_unverif_erased_.end()) {
+ packets_unverif_erased_.erase(it_erased);
+ it = manifest_digests_.erase(it);
+ continue;
+ }
+
if (rtc_state_->getPacketState(it->first) == PacketState::DEFINITELY_LOST) {
- unverified_packets_.erase(it->first);
- unverified_bytes_.erase(it->first);
it = manifest_digests_.erase(it);
- } else {
- ++it;
+ continue;
}
+
+ ++it;
}
// Verify packets
auth::Verifier::PolicyMap policies =
- verifier_->verifyHashes(unverified_packets_, manifest_digests_);
+ verifier_->verifyHashes(packets_unverif_.suffixMap(), manifest_digests_);
- for (const auto &policy : policies) {
- switch (policy.second) {
+ for (const auto &p : policies) {
+ switch (p.second) {
case auth::VerificationPolicy::ACCEPT: {
- manifest_digests_.erase(policy.first);
- unverified_packets_.erase(policy.first);
- unverified_bytes_.erase(policy.first);
+ auto packet_unverif_it = packets_unverif_.packetIt(p.first);
+ Packet packet_verif = *packet_unverif_it;
+ packets_unverif_.remove(packet_unverif_it);
+ packets_verif_.add(packet_verif);
+ manifest_digests_.erase(p.first);
break;
}
case auth::VerificationPolicy::UNKNOWN:
break;
case auth::VerificationPolicy::DROP:
case auth::VerificationPolicy::ABORT:
- auth::VerificationPolicy p = policy.second;
- verifier_->callVerificationFailedCallback(policy.first, p);
- return p;
+ return p.second;
}
}
- return auth::VerificationPolicy::ACCEPT;
+ verifier_->callVerificationFailedCallback(suffix, accept_policy);
+ return accept_policy;
}
void RTCVerifier::onDataRecoveredFec(uint32_t suffix) {
@@ -203,35 +214,101 @@ void RTCVerifier::onJumpForward(uint32_t next_suffix) {
return;
}
- // When we jump forward in the suffix sequence, we remove packets that
- // probably won't be verified. Those packets have a suffix in the range
- // [last_manifest_ + 1, next_suffix[.
- for (auto it = unverified_packets_.begin();
- it != unverified_packets_.end();) {
- if (it->first > last_manifest_) {
- unverified_bytes_.erase(it->first);
- it = unverified_packets_.erase(it);
- } else {
- ++it;
+ // When we jump forward in the suffix sequence, we remove packets that won't
+ // be verified. Those packets have a suffix in the range [last_manifest_ + 1,
+ // next_suffix[.
+ for (auth::Suffix suffix = last_manifest_ + 1; suffix < next_suffix;
+ ++suffix) {
+ auto packet_it = packets_unverif_.packetIt(suffix);
+ if (packet_it != packets_unverif_.set().end()) {
+ packets_unverif_.remove(packet_it);
}
}
}
-uint32_t RTCVerifier::getTotalUnverified() const {
- uint32_t total = 0;
+double RTCVerifier::getBufferRatio() const {
+ size_t total = packets_verif_.size() + packets_unverif_.size();
+ double total_unverified = static_cast<double>(packets_unverif_.size());
+ return total ? total_unverified / total : 0.0;
+}
+
+RTCVerifier::Timestamp RTCVerifier::flush_packets(Timestamp now) {
+ Timestamp oldest_verified = packets_verif_.set().empty()
+ ? now
+ : packets_verif_.set().begin()->timestamp;
+ Timestamp oldest_unverified = packets_unverif_.set().empty()
+ ? now
+ : packets_unverif_.set().begin()->timestamp;
+
+ // Prune verified packets older than the unverified interval
+ for (auto it = packets_verif_.set().begin();
+ it != packets_verif_.set().end();) {
+ if (now - it->timestamp < max_unverified_interval_) {
+ break;
+ }
+ it = packets_verif_.remove(it);
+ }
- for (auto bytes : unverified_bytes_) {
- if (bytes.second > UINT32_MAX - total) {
- total = UINT32_MAX;
+ // Prune unverified packets older than the unverified interval
+ for (auto it = packets_unverif_.set().begin();
+ it != packets_unverif_.set().end();) {
+ if (now - it->timestamp < max_unverified_interval_) {
break;
}
- total += bytes.second;
+ packets_unverif_erased_.insert(it->suffix);
+ it = packets_unverif_.remove(it);
+ }
+
+ return std::min(oldest_verified, oldest_unverified);
+}
+
+std::pair<RTCVerifier::PacketSet::iterator, bool> RTCVerifier::Packets::add(
+ const Packet &packet) {
+ auto inserted = packets_.insert(packet);
+ size_ += inserted.second ? packet.size : 0;
+ return inserted;
+}
+
+RTCVerifier::PacketSet::iterator RTCVerifier::Packets::remove(
+ PacketSet::iterator packet_it) {
+ size_ -= packet_it->size;
+ return packets_.erase(packet_it);
+}
+
+const std::set<RTCVerifier::Packet> &RTCVerifier::Packets::set() const {
+ return packets_;
+};
+
+size_t RTCVerifier::Packets::size() const { return size_; };
+
+std::pair<RTCVerifier::PacketSet::iterator, bool>
+RTCVerifier::PacketsUnverif::add(const Packet &packet,
+ const auth::CryptoHash &digest) {
+ auto inserted = add(packet);
+ if (inserted.second) {
+ packets_map_[packet.suffix] = inserted.first;
+ digests_map_[packet.suffix] = digest;
}
+ return inserted;
+}
- return total;
+RTCVerifier::PacketSet::iterator RTCVerifier::PacketsUnverif::remove(
+ PacketSet::iterator packet_it) {
+ size_ -= packet_it->size;
+ packets_map_.erase(packet_it->suffix);
+ digests_map_.erase(packet_it->suffix);
+ return packets_.erase(packet_it);
}
-uint32_t RTCVerifier::getMaxUnverified() const { return max_unverified_bytes_; }
+RTCVerifier::PacketSet::iterator RTCVerifier::PacketsUnverif::packetIt(
+ auth::Suffix suffix) {
+ return packets_map_.at(suffix);
+};
+
+const auth::Verifier::SuffixMap &RTCVerifier::PacketsUnverif::suffixMap()
+ const {
+ return digests_map_;
+}
} // end namespace rtc
} // end namespace protocol