15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// See header file for description of DnsQueue class
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/renderer/net/predictor_queue.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/stats_counters.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DnsQueue::DnsQueue(BufferSize size)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : buffer_(new char[size + 2]),
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buffer_size_(size + 1),
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buffer_sentinel_(size + 1),
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      size_(0) {
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(0 < static_cast<BufferSize>(size + 3));  // Avoid overflow worries.
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  buffer_[buffer_sentinel_] = '\0';  // Guard byte to help reading data.
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  readable_ = writeable_ = 0;  // Buffer starts empty.
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DnsQueue::~DnsQueue(void) {
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DnsQueue::Clear() {
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_ = 0;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  readable_ = writeable_;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(Validate());
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Push takes an unterminated string plus its length.
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The string must not contain a null terminator.
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Exactly length chars are written, or nothing is written.
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true for success, false there was no room to push.
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DnsQueue::PushResult DnsQueue::Push(const char* source,
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    const size_t unsigned_length) {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BufferSize length = static_cast<BufferSize>(unsigned_length);
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (0 > length+1)  // Avoid overflows in conversion to signed.
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return OVERFLOW_PUSH;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // To save on sites with a LOT of links to the SAME domain, we have a
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a compaction hack that removes duplicates when we try to push() a
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // match with the last push.
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (0 < size_ && readable_ + length < buffer_sentinel_ &&
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    0 == strncmp(source, &buffer_[readable_], unsigned_length) &&
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    '\0' == buffer_[readable_ + unsigned_length]) {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SIMPLE_STATS_COUNTER("DNS.PrefetchDnsRedundantPush");
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We already wrote this name to the queue, so we'll skip this repeat.
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return REDUNDANT_PUSH;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Calling convention precludes nulls.
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!length || '\0' != source[length - 1]);
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(Validate());
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BufferSize available_space = readable_ - writeable_;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (0 >= available_space) {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    available_space += buffer_size_;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (length + 1 >= available_space) {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SIMPLE_STATS_COUNTER("DNS.PrefetchDnsQueueFull");
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return OVERFLOW_PUSH;  // Not enough space to push.
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BufferSize dest = writeable_;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BufferSize space_till_wrap = buffer_sentinel_ - dest;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (space_till_wrap < length + 1) {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Copy until we run out of room at end of buffer.
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::memcpy(&buffer_[dest], source, space_till_wrap);
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Ensure caller didn't have embedded '\0' and also
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // ensure trailing sentinel was in place.
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Relies on sentinel.
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(static_cast<size_t>(space_till_wrap) == strlen(&buffer_[dest]));
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    length -= space_till_wrap;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    source += space_till_wrap;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dest = 0;  // Continue writing at start of buffer.
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Copy any remaining portion of source.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::memcpy(&buffer_[dest], source, length);
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(dest + length < buffer_sentinel_);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  buffer_[dest + length] = '\0';  // We need termination in our buffer.
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Preclude embedded '\0'.
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(static_cast<size_t>(length) == strlen(&buffer_[dest]));
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dest += length + 1;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (dest == buffer_sentinel_)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dest = 0;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  writeable_ = dest;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_++;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(Validate());
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SUCCESSFUL_PUSH;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Extracts the next available string from the buffer.
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The returned string is null terminated, and hence has length
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// that is exactly one greater than the written string.
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If the buffer is empty, then the Pop and returns false.
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DnsQueue::Pop(std::string* out_string) {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(Validate());
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sentinel will preclude memory reads beyond buffer's end.
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK('\0' == buffer_[buffer_sentinel_]);
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (readable_ == writeable_) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // buffer was empty
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Constructor *may* rely on sentinel for null termination.
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (*out_string) = &buffer_[readable_];
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Our sentinel_ at end of buffer precludes an overflow in cast.
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BufferSize first_fragment_size = static_cast<BufferSize> (out_string->size());
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BufferSize terminal_null;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (readable_ + first_fragment_size >= buffer_sentinel_) {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Sentinel was used, so we need the portion after the wrap.
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    out_string->append(&buffer_[0]);  // Fragment at start of buffer.
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Sentinel precludes overflow in cast to signed type.
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    terminal_null = static_cast<BufferSize>(out_string->size())
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    - first_fragment_size;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    terminal_null = readable_ + first_fragment_size;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK('\0' == buffer_[terminal_null]);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BufferSize new_readable = terminal_null + 1;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (buffer_sentinel_ == new_readable)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_readable = 0;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  readable_ = new_readable;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_--;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (readable_ == writeable_ || 0 == size_) {
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Queue is empty, so reset to start of buffer to help with peeking.
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    readable_ = writeable_ = 0;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(Validate());
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DnsQueue::Validate() {
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (readable_ >= 0) &&
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          readable_ < buffer_sentinel_ &&
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          writeable_ >= 0 &&
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          writeable_ < buffer_sentinel_ &&
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          '\0' == buffer_[buffer_sentinel_] &&
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ((0 == size_) == (readable_ == writeable_));
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
153