15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 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)#include <stdio.h>
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/at_exit.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/cancelable_callback.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/file_util.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
149ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/strings/string_split.h"
17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
19eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/address_list.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/ip_endpoint.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_log.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_util.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/dns/dns_client.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/dns/dns_config_service.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/dns/dns_protocol.h"
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/dns/host_cache.h"
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/dns/host_resolver_impl.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/tools/gdig/file_net_log.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_MACOSX)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/mac/scoped_nsautorelease_pool.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool StringToIPEndPoint(const std::string& ip_address_and_port,
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        IPEndPoint* ip_end_point) {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ip_end_point);
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string ip;
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int port;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ParseHostAndPort(ip_address_and_port, &ip, &port))
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (port == -1)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    port = dns_protocol::kDefaultPort;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net::IPAddressNumber ip_number;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!net::ParseIPLiteralToNumber(ip, &ip_number))
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *ip_end_point = net::IPEndPoint(ip_number, port);
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Convert DnsConfig to human readable text omitting the hosts member.
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string DnsConfigToString(const DnsConfig& dns_config) {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string output;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output.append("search ");
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < dns_config.search.size(); ++i) {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    output.append(dns_config.search[i] + " ");
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output.append("\n");
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < dns_config.nameservers.size(); ++i) {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    output.append("nameserver ");
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    output.append(dns_config.nameservers[i].ToString()).append("\n");
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::StringAppendF(&output, "options ndots:%d\n", dns_config.ndots);
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::StringAppendF(&output, "options timeout:%d\n",
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      static_cast<int>(dns_config.timeout.InMilliseconds()));
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::StringAppendF(&output, "options attempts:%d\n", dns_config.attempts);
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (dns_config.rotate)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    output.append("options rotate\n");
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (dns_config.edns0)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    output.append("options edns0\n");
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return output;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Convert DnsConfig hosts member to a human readable text.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string DnsHostsToString(const DnsHosts& dns_hosts) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string output;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (DnsHosts::const_iterator i = dns_hosts.begin();
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != dns_hosts.end();
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++i) {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const DnsHostsKey& key = i->first;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string host_name = key.first;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    output.append(IPEndPoint(i->second, -1).ToStringWithoutPort());
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    output.append(" ").append(host_name).append("\n");
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return output;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)struct ReplayLogEntry {
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeDelta start_time;
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string domain_name;
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)typedef std::vector<ReplayLogEntry> ReplayLog;
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Loads and parses a replay log file and fills |replay_log| with a structured
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// representation. Returns whether the operation was successful. If not, the
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// contents of |replay_log| are undefined.
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The replay log is a text file where each line contains
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//   timestamp_in_milliseconds domain_name
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The timestamp_in_milliseconds needs to be an integral delta from start of
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// resolution and is in milliseconds. domain_name is the name to be resolved.
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The file should be sorted by timestamp in ascending time.
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool LoadReplayLog(const base::FilePath& file_path, ReplayLog* replay_log) {
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string original_replay_log_contents;
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!file_util::ReadFileToString(file_path, &original_replay_log_contents)) {
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    fprintf(stderr, "Unable to open replay file %s\n",
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            file_path.MaybeAsASCII().c_str());
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Strip out \r characters for Windows files. This isn't as efficient as a
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // smarter line splitter, but this particular use does not need to target
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // efficiency.
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string replay_log_contents;
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RemoveChars(original_replay_log_contents, "\r", &replay_log_contents);
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<std::string> lines;
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::SplitString(replay_log_contents, '\n', &lines);
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeDelta previous_delta;
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool bad_parse = false;
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (unsigned i = 0; i < lines.size(); ++i) {
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (lines[i].empty())
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<std::string> time_and_name;
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::SplitString(lines[i], ' ', &time_and_name);
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (time_and_name.size() != 2) {
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      fprintf(
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          stderr,
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          "[%s %u] replay log should have format 'timestamp domain_name\\n'\n",
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          file_path.MaybeAsASCII().c_str(),
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          i + 1);
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      bad_parse = true;
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int64 delta_in_milliseconds;
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!base::StringToInt64(time_and_name[0], &delta_in_milliseconds)) {
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      fprintf(
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          stderr,
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          "[%s %u] replay log should have format 'timestamp domain_name\\n'\n",
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          file_path.MaybeAsASCII().c_str(),
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          i + 1);
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      bad_parse = true;
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::TimeDelta delta =
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::TimeDelta::FromMilliseconds(delta_in_milliseconds);
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (delta < previous_delta) {
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      fprintf(
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          stderr,
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          "[%s %u] replay log should be sorted by time\n",
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          file_path.MaybeAsASCII().c_str(),
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          i + 1);
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      bad_parse = true;
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    previous_delta = delta;
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ReplayLogEntry entry;
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    entry.start_time = delta;
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    entry.domain_name = time_and_name[1];
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    replay_log->push_back(entry);
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return !bad_parse;
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class GDig {
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GDig();
185868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  ~GDig();
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enum Result {
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RESULT_NO_RESOLVE = -3,
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RESULT_NO_CONFIG = -2,
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RESULT_WRONG_USAGE = -1,
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RESULT_OK = 0,
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RESULT_PENDING = 1,
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Result Main(int argc, const char* argv[]);
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool ParseCommandLine(int argc, const char* argv[]);
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Start();
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Finish(Result);
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void OnDnsConfig(const DnsConfig& dns_config_const);
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void OnResolveComplete(unsigned index, AddressList* address_list,
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         base::TimeDelta time_since_start, int val);
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void OnTimeout();
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void ReplayNextEntry();
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeDelta config_timeout_;
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool print_config_;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool print_hosts_;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net::IPEndPoint nameserver_;
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeDelta timeout_;
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int parallellism_;
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ReplayLog replay_log_;
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  unsigned replay_log_index_;
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::Time start_time_;
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int active_resolves_;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Result result_;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::CancelableClosure timeout_closure_;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<DnsConfigService> dns_config_service_;
223868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_ptr<FileNetLogObserver> log_observer_;
224868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_ptr<NetLog> log_;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<HostResolver> resolver_;
226ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
227ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#if defined(OS_MACOSX)
228ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Without this there will be a mem leak on osx.
229ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  base::mac::ScopedNSAutoreleasePool scoped_pool_;
230ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#endif
231ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
232ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Need AtExitManager to support AsWeakPtr (in NetLog).
233ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  base::AtExitManager exit_manager_;
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GDig::GDig()
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : config_timeout_(base::TimeDelta::FromSeconds(5)),
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print_config_(false),
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      print_hosts_(false),
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      parallellism_(6),
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      replay_log_index_(0u),
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      active_resolves_(0) {
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)GDig::~GDig() {
246868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (log_)
247868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    log_->RemoveThreadSafeObserver(log_observer_.get());
248868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
249868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GDig::Result GDig::Main(int argc, const char* argv[]) {
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ParseCommandLine(argc, argv)) {
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      fprintf(stderr,
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              "usage: %s [--net_log[=<basic|no_bytes|all>]]"
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              " [--print_config] [--print_hosts]"
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              " [--nameserver=<ip_address[:port]>]"
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              " [--timeout=<milliseconds>]"
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              " [--config_timeout=<seconds>]"
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              " [--j=<parallel resolves>]"
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              " [--replay_file=<path>]"
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              " [domain_name]\n",
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              argv[0]);
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return RESULT_WRONG_USAGE;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoopForIO loop;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result_ = RESULT_PENDING;
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Start();
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result_ == RESULT_PENDING)
27090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->Run();
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Destroy it while MessageLoopForIO is alive.
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dns_config_service_.reset();
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result_;
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GDig::ParseCommandLine(int argc, const char* argv[]) {
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandLine::Init(argc, argv);
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (parsed_command_line.HasSwitch("config_timeout")) {
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int timeout_seconds = 0;
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool parsed = base::StringToInt(
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        parsed_command_line.GetSwitchValueASCII("config_timeout"),
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        &timeout_seconds);
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (parsed && timeout_seconds > 0) {
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      config_timeout_ = base::TimeDelta::FromSeconds(timeout_seconds);
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      fprintf(stderr, "Invalid config_timeout parameter\n");
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (parsed_command_line.HasSwitch("net_log")) {
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string log_param = parsed_command_line.GetSwitchValueASCII("net_log");
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NetLog::LogLevel level = NetLog::LOG_ALL_BUT_BYTES;
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (log_param.length() > 0) {
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::map<std::string, NetLog::LogLevel> log_levels;
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      log_levels["all"] = NetLog::LOG_ALL;
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      log_levels["no_bytes"] = NetLog::LOG_ALL_BUT_BYTES;
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      log_levels["basic"] = NetLog::LOG_BASIC;
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (log_levels.find(log_param) != log_levels.end()) {
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        level = log_levels[log_param];
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        fprintf(stderr, "Invalid net_log parameter\n");
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
311868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    log_.reset(new NetLog);
312868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    log_observer_.reset(new FileNetLogObserver(stderr));
313868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    log_->AddThreadSafeObserver(log_observer_.get(), level);
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_config_ = parsed_command_line.HasSwitch("print_config");
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  print_hosts_ = parsed_command_line.HasSwitch("print_hosts");
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (parsed_command_line.HasSwitch("nameserver")) {
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string nameserver =
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parsed_command_line.GetSwitchValueASCII("nameserver");
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!StringToIPEndPoint(nameserver, &nameserver_)) {
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      fprintf(stderr,
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              "Cannot parse the namerserver string into an IPEndPoint\n");
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (parsed_command_line.HasSwitch("timeout")) {
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int timeout_millis = 0;
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool parsed = base::StringToInt(
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        parsed_command_line.GetSwitchValueASCII("timeout"),
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        &timeout_millis);
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (parsed && timeout_millis > 0) {
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      timeout_ = base::TimeDelta::FromMilliseconds(timeout_millis);
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      fprintf(stderr, "Invalid timeout parameter\n");
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (parsed_command_line.HasSwitch("replay_file")) {
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath replay_path =
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        parsed_command_line.GetSwitchValuePath("replay_file");
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!LoadReplayLog(replay_path, &replay_log_))
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (parsed_command_line.HasSwitch("j")) {
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int parallellism = 0;
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool parsed = base::StringToInt(
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        parsed_command_line.GetSwitchValueASCII("j"),
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        &parallellism);
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (parsed && parallellism > 0) {
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      parallellism_ = parallellism;
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      fprintf(stderr, "Invalid parallellism parameter\n");
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (parsed_command_line.GetArgs().size() == 1) {
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ReplayLogEntry entry;
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    entry.start_time = base::TimeDelta();
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    entry.domain_name = WideToASCII(parsed_command_line.GetArgs()[0]);
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    entry.domain_name = parsed_command_line.GetArgs()[0];
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    replay_log_.push_back(entry);
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (parsed_command_line.GetArgs().size() != 0) {
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return print_config_ || print_hosts_ || !replay_log_.empty();
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GDig::Start() {
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (nameserver_.address().size() > 0) {
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DnsConfig dns_config;
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dns_config.attempts = 1;
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dns_config.nameservers.push_back(nameserver_);
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnDnsConfig(dns_config);
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dns_config_service_ = DnsConfigService::CreateSystemService();
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dns_config_service_->ReadConfig(base::Bind(&GDig::OnDnsConfig,
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               base::Unretained(this)));
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    timeout_closure_.Reset(base::Bind(&GDig::OnTimeout,
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      base::Unretained(this)));
38890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostDelayedTask(
38990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        FROM_HERE, timeout_closure_.callback(), config_timeout_);
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GDig::Finish(Result result) {
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(RESULT_PENDING, result);
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result_ = result;
39690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (base::MessageLoop::current())
39790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->Quit();
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GDig::OnDnsConfig(const DnsConfig& dns_config_const) {
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  timeout_closure_.Cancel();
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(dns_config_const.IsValid());
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DnsConfig dns_config = dns_config_const;
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (timeout_.InMilliseconds() > 0)
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dns_config.timeout = timeout_;
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (print_config_) {
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    printf("# Dns Configuration\n"
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           "%s", DnsConfigToString(dns_config).c_str());
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (print_hosts_) {
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    printf("# Host Database\n"
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           "%s", DnsHostsToString(dns_config.hosts).c_str());
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (replay_log_.empty()) {
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Finish(RESULT_OK);
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<DnsClient> dns_client(DnsClient::CreateClient(NULL));
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dns_client->SetConfig(dns_config);
4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<HostResolverImpl> resolver(
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new HostResolverImpl(
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          HostCache::CreateDefaultCache(),
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          PrioritizedDispatcher::Limits(NUM_PRIORITIES, parallellism_),
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          HostResolverImpl::ProcTaskParams(NULL, 1),
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          log_.get()));
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  resolver->SetDnsClient(dns_client.Pass());
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  resolver_ = resolver.Pass();
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  start_time_ = base::Time::Now();
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ReplayNextEntry();
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void GDig::ReplayNextEntry() {
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_LT(replay_log_index_, replay_log_.size());
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeDelta time_since_start = base::Time::Now() - start_time_;
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  while (replay_log_index_ < replay_log_.size()) {
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const ReplayLogEntry& entry = replay_log_[replay_log_index_];
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (time_since_start < entry.start_time) {
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Delay call to next time and return.
44590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      base::MessageLoop::current()->PostDelayedTask(
44690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          FROM_HERE,
44790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          base::Bind(&GDig::ReplayNextEntry, base::Unretained(this)),
44890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          entry.start_time - time_since_start);
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    HostResolver::RequestInfo info(HostPortPair(entry.domain_name.c_str(), 80));
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AddressList* addrlist = new AddressList();
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    unsigned current_index = replay_log_index_;
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CompletionCallback callback = base::Bind(&GDig::OnResolveComplete,
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                             base::Unretained(this),
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                             current_index,
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                             base::Owned(addrlist),
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                             time_since_start);
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ++active_resolves_;
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ++replay_log_index_;
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int ret = resolver_->Resolve(
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        info, addrlist, callback, NULL,
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        BoundNetLog::Make(log_.get(), net::NetLog::SOURCE_NONE));
4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (ret != ERR_IO_PENDING)
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      callback.Run(ret);
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void GDig::OnResolveComplete(unsigned entry_index,
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             AddressList* address_list,
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             base::TimeDelta resolve_start_time,
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             int val) {
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_GT(active_resolves_, 0);
4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(address_list);
4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_LT(entry_index, replay_log_.size());
4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  --active_resolves_;
4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeDelta resolve_end_time = base::Time::Now() - start_time_;
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeDelta resolve_time = resolve_end_time - resolve_start_time;
4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  printf("%u %d %d %s %d ",
4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         entry_index,
4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         static_cast<int>(resolve_end_time.InMilliseconds()),
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         static_cast<int>(resolve_time.InMilliseconds()),
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         replay_log_[entry_index].domain_name.c_str(), val);
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (val != OK) {
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    printf("%s", ErrorToString(val));
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < address_list->size(); ++i) {
4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (i != 0)
4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        printf(" ");
4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      printf("%s", (*address_list)[i].ToStringWithoutPort().c_str());
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  printf("\n");
4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (active_resolves_ == 0 && replay_log_index_ >= replay_log_.size())
4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Finish(RESULT_OK);
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GDig::OnTimeout() {
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fprintf(stderr, "Timed out waiting to load the dns config\n");
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Finish(RESULT_NO_CONFIG);
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // empty namespace
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int main(int argc, const char* argv[]) {
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net::GDig dig;
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dig.Main(argc, argv);
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
512