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