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/port_suggester.h"
6
7#include "base/logging.h"
8#include "net/base/host_port_pair.h"
9
10namespace net {
11
12PortSuggester::PortSuggester(const HostPortPair& server, uint64 seed)
13    : call_count_(0),
14      previous_suggestion_(-1) {
15  unsigned char hash_bytes[base::kSHA1Length];
16  base::SHA1HashBytes(
17      reinterpret_cast<const unsigned char*>(server.host().data()),
18      server.host().length(), hash_bytes);
19  COMPILE_ASSERT(sizeof(seed_) < sizeof(hash_bytes), seed_larger_than_hash);
20  memcpy(&seed_, hash_bytes, sizeof(seed_));
21  seed_ ^= seed ^ server.port();
22}
23
24int PortSuggester::SuggestPort(int min, int max) {
25  // Sometimes our suggestion can't be used, so we ensure that if additional
26  // calls are made, then each call (probably) provides a new suggestion.
27  if (++call_count_ > 1) {
28    // Evolve the seed.
29    unsigned char hash_bytes[base::kSHA1Length];
30    base::SHA1HashBytes(reinterpret_cast<const unsigned char *>(&seed_),
31                        sizeof(seed_), hash_bytes);
32    memcpy(&seed_, hash_bytes, sizeof(seed_));
33  }
34  DCHECK_LE(min, max);
35  DCHECK_GT(min, 0);
36  int range = max - min + 1;
37  // Ports (and hence the extent of the |range|) are generally under 2^16, so
38  // the tiny non-uniformity in the pseudo-random distribution is not
39  // significant.
40  previous_suggestion_ = static_cast<int>(seed_ % range) + min;
41  return previous_suggestion_;
42}
43
44int PortSuggester::previous_suggestion() const {
45  DCHECK_LT(0u, call_count_);
46  return previous_suggestion_;
47}
48
49}  // namespace net
50