summaryrefslogtreecommitdiff
path: root/chromium/net/quic/port_suggester.cc
blob: 6b7940e83efae21a49750ded5b579d151196d71b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/quic/port_suggester.h"

#include "base/logging.h"
#include "net/base/host_port_pair.h"

namespace net {

PortSuggester::PortSuggester(const HostPortPair& server, uint64 seed)
    : call_count_(0),
      previous_suggestion_(-1) {
  unsigned char hash_bytes[base::kSHA1Length];
  base::SHA1HashBytes(
      reinterpret_cast<const unsigned char*>(server.host().data()),
      server.host().length(), hash_bytes);
  COMPILE_ASSERT(sizeof(seed_) < sizeof(hash_bytes), seed_larger_than_hash);
  memcpy(&seed_, hash_bytes, sizeof(seed_));
  seed_ ^= seed ^ server.port();
}

int PortSuggester::SuggestPort(int min, int max) {
  // Sometimes our suggestion can't be used, so we ensure that if additional
  // calls are made, then each call (probably) provides a new suggestion.
  if (++call_count_ > 1) {
    // Evolve the seed.
    unsigned char hash_bytes[base::kSHA1Length];
    base::SHA1HashBytes(reinterpret_cast<const unsigned char *>(&seed_),
                        sizeof(seed_), hash_bytes);
    memcpy(&seed_, hash_bytes, sizeof(seed_));
  }
  DCHECK_LE(min, max);
  DCHECK_GT(min, 0);
  int range = max - min + 1;
  // Ports (and hence the extent of the |range|) are generally under 2^16, so
  // the tiny non-uniformity in the pseudo-random distribution is not
  // significant.
  previous_suggestion_ = static_cast<int>(seed_ % range) + min;
  return previous_suggestion_;
}

int PortSuggester::previous_suggestion() const {
  DCHECK_LT(0u, call_count_);
  return previous_suggestion_;
}

}  // namespace net