1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/quic/quic_sent_entropy_manager.h"
6
7#include "base/logging.h"
8#include "net/base/linked_hash_map.h"
9
10using std::make_pair;
11using std::max;
12using std::min;
13
14namespace net {
15
16QuicSentEntropyManager::QuicSentEntropyManager()
17    : packets_entropy_hash_(0) {}
18
19QuicSentEntropyManager::~QuicSentEntropyManager() {}
20
21void QuicSentEntropyManager::RecordPacketEntropyHash(
22    QuicPacketSequenceNumber sequence_number,
23    QuicPacketEntropyHash entropy_hash) {
24  // TODO(satyamshekhar): Check this logic again when/if we enable packet
25  // reordering.
26  packets_entropy_hash_ ^= entropy_hash;
27  packets_entropy_.insert(
28      make_pair(sequence_number,
29                make_pair(entropy_hash, packets_entropy_hash_)));
30  DVLOG(2) << "setting cumulative sent entropy hash to: "
31           << static_cast<int>(packets_entropy_hash_)
32           << " updated with sequence number " << sequence_number
33           << " entropy hash: " << static_cast<int>(entropy_hash);
34}
35
36QuicPacketEntropyHash QuicSentEntropyManager::EntropyHash(
37    QuicPacketSequenceNumber sequence_number) const {
38  SentEntropyMap::const_iterator it =
39      packets_entropy_.find(sequence_number);
40  if (it == packets_entropy_.end()) {
41    // Should only happen when we have not received ack for any packet.
42    DCHECK_EQ(0u, sequence_number);
43    return 0;
44  }
45  return it->second.second;
46}
47
48bool QuicSentEntropyManager::IsValidEntropy(
49    QuicPacketSequenceNumber sequence_number,
50    const SequenceNumberSet& missing_packets,
51    QuicPacketEntropyHash entropy_hash) const {
52  SentEntropyMap::const_iterator entropy_it =
53      packets_entropy_.find(sequence_number);
54  if (entropy_it == packets_entropy_.end()) {
55    DCHECK_EQ(0u, sequence_number);
56    // Close connection if something goes wrong.
57    return 0 == sequence_number;
58  }
59  QuicPacketEntropyHash expected_entropy_hash = entropy_it->second.second;
60  for (SequenceNumberSet::const_iterator it = missing_packets.begin();
61       it != missing_packets.end(); ++it) {
62    entropy_it = packets_entropy_.find(*it);
63    DCHECK(entropy_it != packets_entropy_.end());
64    expected_entropy_hash ^= entropy_it->second.first;
65  }
66  DLOG_IF(WARNING, entropy_hash != expected_entropy_hash)
67      << "Invalid entropy hash: " << static_cast<int>(entropy_hash)
68      << " expected entropy hash: " << static_cast<int>(expected_entropy_hash);
69  return entropy_hash == expected_entropy_hash;
70}
71
72void QuicSentEntropyManager::ClearEntropyBefore(
73    QuicPacketSequenceNumber sequence_number) {
74  if (packets_entropy_.empty()) {
75    return;
76  }
77  SentEntropyMap::iterator it = packets_entropy_.begin();
78  while (it->first < sequence_number) {
79    packets_entropy_.erase(it);
80    it = packets_entropy_.begin();
81    DCHECK(it != packets_entropy_.end());
82  }
83  DVLOG(2) << "Cleared entropy before: "
84           << packets_entropy_.begin()->first;
85}
86
87}  // namespace net
88