// Copyright (c) 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/dns/mdns_cache.h"

#include <algorithm>
#include <tuple>
#include <utility>

#include "base/strings/string_number_conversions.h"
#include "net/dns/public/dns_protocol.h"
#include "net/dns/record_parsed.h"
#include "net/dns/record_rdata.h"

// TODO(noamsml): Recursive CNAME closure (backwards and forwards).

namespace net {

// The effective TTL given to records with a nominal zero TTL.
// Allows time for hosts to send updated records, as detailed in RFC 6762
// Section 10.1.
static const unsigned kZeroTTLSeconds = 1;

MDnsCache::Key::Key(unsigned type, const std::string& name,
                    const std::string& optional)
    : type_(type), name_(name), optional_(optional) {
}

MDnsCache::Key::Key(const MDnsCache::Key& other) = default;

MDnsCache::Key& MDnsCache::Key::operator=(const MDnsCache::Key& other) =
    default;

MDnsCache::Key::~Key() = default;

bool MDnsCache::Key::operator<(const MDnsCache::Key& other) const {
  return std::tie(name_, type_, optional_) <
         std::tie(other.name_, other.type_, other.optional_);
}

bool MDnsCache::Key::operator==(const MDnsCache::Key& key) const {
  return type_ == key.type_ && name_ == key.name_ && optional_ == key.optional_;
}

// static
MDnsCache::Key MDnsCache::Key::CreateFor(const RecordParsed* record) {
  return Key(record->type(),
             record->name(),
             GetOptionalFieldForRecord(record));
}

MDnsCache::MDnsCache() = default;

MDnsCache::~MDnsCache() = default;

const RecordParsed* MDnsCache::LookupKey(const Key& key) {
  auto found = mdns_cache_.find(key);
  if (found != mdns_cache_.end()) {
    return found->second.get();
  }
  return nullptr;
}

MDnsCache::UpdateType MDnsCache::UpdateDnsRecord(
    std::unique_ptr<const RecordParsed> record) {
  Key cache_key = Key::CreateFor(record.get());

  // Ignore "goodbye" packets for records not in cache.
  if (record->ttl() == 0 && mdns_cache_.find(cache_key) == mdns_cache_.end())
    return NoChange;

  base::Time new_expiration = GetEffectiveExpiration(record.get());
  if (next_expiration_ != base::Time())
    new_expiration = std::min(new_expiration, next_expiration_);

  std::pair<RecordMap::iterator, bool> insert_result =
      mdns_cache_.insert(std::make_pair(cache_key, nullptr));
  UpdateType type = NoChange;
  if (insert_result.second) {
    type = RecordAdded;
  } else {
    if (record->ttl() != 0 &&
        !record->IsEqual(insert_result.first->second.get(), true)) {
      type = RecordChanged;
    }
  }

  insert_result.first->second = std::move(record);
  next_expiration_ = new_expiration;
  return type;
}

void MDnsCache::CleanupRecords(
    base::Time now,
    const RecordRemovedCallback& record_removed_callback) {
  base::Time next_expiration;

  // We are guaranteed that |next_expiration_| will be at or before the next
  // expiration. This allows clients to eagrely call CleanupRecords with
  // impunity.
  if (now < next_expiration_) return;

  for (auto i = mdns_cache_.begin(); i != mdns_cache_.end();) {
    base::Time expiration = GetEffectiveExpiration(i->second.get());
    if (now >= expiration) {
      record_removed_callback.Run(i->second.get());
      mdns_cache_.erase(i++);
    } else {
      if (next_expiration == base::Time() ||  expiration < next_expiration) {
        next_expiration = expiration;
      }
      ++i;
    }
  }

  next_expiration_ = next_expiration;
}

void MDnsCache::FindDnsRecords(unsigned type,
                               const std::string& name,
                               std::vector<const RecordParsed*>* results,
                               base::Time now) const {
  DCHECK(results);
  results->clear();

  auto i = mdns_cache_.lower_bound(Key(type, name, ""));
  for (; i != mdns_cache_.end(); ++i) {
    if (i->first.name() != name ||
        (type != 0 && i->first.type() != type)) {
      break;
    }

    const RecordParsed* record = i->second.get();

    // Records are deleted only upon request.
    if (now >= GetEffectiveExpiration(record)) continue;

    results->push_back(record);
  }
}

std::unique_ptr<const RecordParsed> MDnsCache::RemoveRecord(
    const RecordParsed* record) {
  Key key = Key::CreateFor(record);
  auto found = mdns_cache_.find(key);

  if (found != mdns_cache_.end() && found->second.get() == record) {
    std::unique_ptr<const RecordParsed> result = std::move(found->second);
    mdns_cache_.erase(key);
    return result;
  }

  return std::unique_ptr<const RecordParsed>();
}

// static
std::string MDnsCache::GetOptionalFieldForRecord(const RecordParsed* record) {
  switch (record->type()) {
    case PtrRecordRdata::kType: {
      const PtrRecordRdata* rdata = record->rdata<PtrRecordRdata>();
      return rdata->ptrdomain();
    }
    default:  // Most records are considered unique for our purposes
      return "";
  }
}

// static
base::Time MDnsCache::GetEffectiveExpiration(const RecordParsed* record) {
  base::TimeDelta ttl;

  if (record->ttl()) {
    ttl = base::TimeDelta::FromSeconds(record->ttl());
  } else {
    ttl = base::TimeDelta::FromSeconds(kZeroTTLSeconds);
  }

  return record->time_created() + ttl;
}

}  // namespace net
