1558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// Copyright 2013 The Chromium Authors. All rights reserved.
2558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// found in the LICENSE file.
4558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
5558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "net/quic/quic_sent_entropy_manager.h"
6558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
7558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "base/logging.h"
8558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "net/base/linked_hash_map.h"
9558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
10558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochusing std::make_pair;
11558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochusing std::max;
12558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochusing std::min;
13558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
14558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochnamespace net {
15558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
1603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)QuicSentEntropyManager::QuicSentEntropyManager() : map_offset_(1) {}
17558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
18558790d6acca3451cf3a6b497803a5f07d0bec58Ben MurdochQuicSentEntropyManager::~QuicSentEntropyManager() {}
19558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
2003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)QuicPacketEntropyHash QuicSentEntropyManager::GetPacketEntropy(
2103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    QuicPacketSequenceNumber sequence_number) const {
2203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return packets_entropy_[sequence_number - map_offset_];
2303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
2403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
2503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)QuicPacketSequenceNumber
2603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)QuicSentEntropyManager::GetLargestPacketWithEntropy() const {
2703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return map_offset_ + packets_entropy_.size() - 1;
2803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
2903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
3003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)QuicPacketSequenceNumber
3103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)QuicSentEntropyManager::GetSmallestPacketWithEntropy() const {
3203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return map_offset_;
3303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
3403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
3503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void QuicSentEntropyManager::UpdateCumulativeEntropy(
3603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    QuicPacketSequenceNumber sequence_number,
3703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    CumulativeEntropy* cumulative) const {
3803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  while (cumulative->sequence_number < sequence_number) {
3903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    ++cumulative->sequence_number;
4003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    cumulative->entropy ^= GetPacketEntropy(cumulative->sequence_number);
4103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
4203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
4303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
44558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochvoid QuicSentEntropyManager::RecordPacketEntropyHash(
45558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    QuicPacketSequenceNumber sequence_number,
46558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    QuicPacketEntropyHash entropy_hash) {
4703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!packets_entropy_.empty()) {
4803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // Ensure packets always are recorded in order.
4903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // Every packet's entropy is recorded, even if it's not sent, so there
5003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // are not sequence number gaps.
511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DCHECK_EQ(GetLargestPacketWithEntropy() + 1, sequence_number);
5203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
5303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  packets_entropy_.push_back(entropy_hash);
5403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DVLOG(2) << "Recorded sequence number " << sequence_number
5503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)           << " with entropy hash: " << static_cast<int>(entropy_hash);
56558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
57558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
5803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)QuicPacketEntropyHash QuicSentEntropyManager::GetCumulativeEntropy(
5903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    QuicPacketSequenceNumber sequence_number) {
6003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DCHECK_LE(last_cumulative_entropy_.sequence_number, sequence_number);
6103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DCHECK_GE(GetLargestPacketWithEntropy(), sequence_number);
6203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // First the entropy for largest_observed sequence number should be updated.
6303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  UpdateCumulativeEntropy(sequence_number, &last_cumulative_entropy_);
6403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return last_cumulative_entropy_.entropy;
65558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
66558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
67558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochbool QuicSentEntropyManager::IsValidEntropy(
6803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    QuicPacketSequenceNumber largest_observed,
69558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    const SequenceNumberSet& missing_packets,
7003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    QuicPacketEntropyHash entropy_hash) {
7103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DCHECK_GE(largest_observed, last_valid_entropy_.sequence_number);
7203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Ensure the largest and smallest sequence numbers are in range.
7303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (largest_observed > GetLargestPacketWithEntropy()) {
7403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return false;
7503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
7603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (!missing_packets.empty() &&
7703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      *missing_packets.begin() < GetSmallestPacketWithEntropy()) {
7803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return false;
79558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
8003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // First the entropy for largest_observed sequence number should be updated.
8103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  UpdateCumulativeEntropy(largest_observed, &last_valid_entropy_);
8203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
8303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Now XOR out all the missing entropies.
8403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  QuicPacketEntropyHash expected_entropy_hash = last_valid_entropy_.entropy;
85558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  for (SequenceNumberSet::const_iterator it = missing_packets.begin();
86558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch       it != missing_packets.end(); ++it) {
8703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    expected_entropy_hash ^= GetPacketEntropy(*it);
88558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
89558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  DLOG_IF(WARNING, entropy_hash != expected_entropy_hash)
90558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      << "Invalid entropy hash: " << static_cast<int>(entropy_hash)
91558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      << " expected entropy hash: " << static_cast<int>(expected_entropy_hash);
92558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  return entropy_hash == expected_entropy_hash;
93558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
94558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
95558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochvoid QuicSentEntropyManager::ClearEntropyBefore(
96558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    QuicPacketSequenceNumber sequence_number) {
9703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Don't discard entropy before updating the cumulative entropy used to
9803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // calculate EntropyHash and IsValidEntropy.
9903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (last_cumulative_entropy_.sequence_number < sequence_number) {
10003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    UpdateCumulativeEntropy(sequence_number, &last_cumulative_entropy_);
10103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
10203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (last_valid_entropy_.sequence_number < sequence_number) {
10303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    UpdateCumulativeEntropy(sequence_number, &last_valid_entropy_);
104558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
10503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  while (map_offset_ < sequence_number) {
10603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    packets_entropy_.pop_front();
10703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    ++map_offset_;
108558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  }
10903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DVLOG(2) << "Cleared entropy before: " << sequence_number;
110558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
111558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
112558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}  // namespace net
113