[content shell] implement testRunner.overridePreference
[chromium-blink-merge.git] / net / tools / gdig / gdig.cc
blob1728fc8cc87ba8fad0ea5b8c5242f99f05ca0e77
1 // Copyright (c) 2012 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.
5 #include <stdio.h>
6 #include <string>
8 #include "base/at_exit.h"
9 #include "base/bind.h"
10 #include "base/cancelable_callback.h"
11 #include "base/command_line.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop.h"
14 #include "base/string_number_conversions.h"
15 #include "base/string_util.h"
16 #include "base/stringprintf.h"
17 #include "base/time.h"
18 #include "net/base/address_list.h"
19 #include "net/base/host_cache.h"
20 #include "net/base/host_resolver_impl.h"
21 #include "net/base/ip_endpoint.h"
22 #include "net/base/net_errors.h"
23 #include "net/base/net_log.h"
24 #include "net/base/net_util.h"
25 #include "net/dns/dns_client.h"
26 #include "net/dns/dns_config_service.h"
27 #include "net/dns/dns_protocol.h"
28 #include "net/tools/gdig/file_net_log.h"
30 #if defined(OS_MACOSX)
31 #include "base/mac/scoped_nsautorelease_pool.h"
32 #endif
34 namespace net {
36 namespace {
38 bool StringToIPEndPoint(const std::string& ip_address_and_port,
39 IPEndPoint* ip_end_point) {
40 DCHECK(ip_end_point);
42 std::string ip;
43 int port;
44 if (!ParseHostAndPort(ip_address_and_port, &ip, &port))
45 return false;
46 if (port == -1)
47 port = dns_protocol::kDefaultPort;
49 net::IPAddressNumber ip_number;
50 if (!net::ParseIPLiteralToNumber(ip, &ip_number))
51 return false;
53 *ip_end_point = net::IPEndPoint(ip_number, port);
54 return true;
57 // Convert DnsConfig to human readable text omitting the hosts member.
58 std::string DnsConfigToString(const DnsConfig& dns_config) {
59 std::string output;
60 output.append("search ");
61 for (size_t i = 0; i < dns_config.search.size(); ++i) {
62 output.append(dns_config.search[i] + " ");
64 output.append("\n");
66 for (size_t i = 0; i < dns_config.nameservers.size(); ++i) {
67 output.append("nameserver ");
68 output.append(dns_config.nameservers[i].ToString()).append("\n");
71 base::StringAppendF(&output, "options ndots:%d\n", dns_config.ndots);
72 base::StringAppendF(&output, "options timeout:%d\n",
73 static_cast<int>(dns_config.timeout.InMilliseconds()));
74 base::StringAppendF(&output, "options attempts:%d\n", dns_config.attempts);
75 if (dns_config.rotate)
76 output.append("options rotate\n");
77 if (dns_config.edns0)
78 output.append("options edns0\n");
79 return output;
82 // Convert DnsConfig hosts member to a human readable text.
83 std::string DnsHostsToString(const DnsHosts& dns_hosts) {
84 std::string output;
85 for (DnsHosts::const_iterator i = dns_hosts.begin();
86 i != dns_hosts.end();
87 ++i) {
88 const DnsHostsKey& key = i->first;
89 std::string host_name = key.first;
90 output.append(IPEndPoint(i->second, -1).ToStringWithoutPort());
91 output.append(" ").append(host_name).append("\n");
93 return output;
96 class GDig {
97 public:
98 GDig();
100 enum Result {
101 RESULT_NO_RESOLVE = -3,
102 RESULT_NO_CONFIG = -2,
103 RESULT_WRONG_USAGE = -1,
104 RESULT_OK = 0,
105 RESULT_PENDING = 1,
108 Result Main(int argc, const char* argv[]);
110 private:
111 bool ParseCommandLine(int argc, const char* argv[]);
113 void Start();
114 void Finish(Result);
116 void OnDnsConfig(const DnsConfig& dns_config_const);
117 void OnResolveComplete(int val);
118 void OnTimeout();
120 base::TimeDelta config_timeout_;
121 std::string domain_name_;
122 bool print_config_;
123 bool print_hosts_;
124 net::IPEndPoint nameserver_;
125 base::TimeDelta timeout_;
127 Result result_;
128 AddressList addrlist_;
130 base::CancelableClosure timeout_closure_;
131 scoped_ptr<DnsConfigService> dns_config_service_;
132 scoped_ptr<FileNetLog> log_;
133 scoped_ptr<HostResolver> resolver_;
136 GDig::GDig()
137 : config_timeout_(base::TimeDelta::FromSeconds(5)),
138 print_config_(false),
139 print_hosts_(false) {
142 GDig::Result GDig::Main(int argc, const char* argv[]) {
143 if (!ParseCommandLine(argc, argv)) {
144 fprintf(stderr,
145 "usage: %s [--net_log[=<basic|no_bytes|all>]]"
146 " [--print_config] [--print_hosts]"
147 " [--nameserver=<ip_address[:port]>]"
148 " [--timeout=<milliseconds>] [--config_timeout=<seconds>]"
149 " domain_name\n",
150 argv[0]);
151 return RESULT_WRONG_USAGE;
154 #if defined(OS_MACOSX)
155 // Without this there will be a mem leak on osx.
156 base::mac::ScopedNSAutoreleasePool scoped_pool;
157 #endif
159 base::AtExitManager exit_manager;
160 MessageLoopForIO loop;
162 result_ = RESULT_PENDING;
163 Start();
164 if (result_ == RESULT_PENDING)
165 MessageLoop::current()->Run();
167 // Destroy it while MessageLoopForIO is alive.
168 dns_config_service_.reset();
169 return result_;
172 bool GDig::ParseCommandLine(int argc, const char* argv[]) {
173 CommandLine::Init(argc, argv);
174 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
176 if (parsed_command_line.HasSwitch("config_timeout")) {
177 int timeout_seconds = 0;
178 bool parsed = base::StringToInt(
179 parsed_command_line.GetSwitchValueASCII("config_timeout"),
180 &timeout_seconds);
181 if (parsed && timeout_seconds > 0) {
182 config_timeout_ = base::TimeDelta::FromSeconds(timeout_seconds);
183 } else {
184 fprintf(stderr, "Invalid config_timeout parameter\n");
185 return false;
189 if (parsed_command_line.HasSwitch("net_log")) {
190 std::string log_param = parsed_command_line.GetSwitchValueASCII("net_log");
191 NetLog::LogLevel level = NetLog::LOG_ALL_BUT_BYTES;
193 if (log_param.length() > 0) {
194 std::map<std::string, NetLog::LogLevel> log_levels;
195 log_levels["all"] = NetLog::LOG_ALL;
196 log_levels["no_bytes"] = NetLog::LOG_ALL_BUT_BYTES;
197 log_levels["basic"] = NetLog::LOG_BASIC;
199 if (log_levels.find(log_param) != log_levels.end()) {
200 level = log_levels[log_param];
201 } else {
202 fprintf(stderr, "Invalid net_log parameter\n");
203 return false;
206 log_.reset(new FileNetLog(stderr, level));
209 print_config_ = parsed_command_line.HasSwitch("print_config");
210 print_hosts_ = parsed_command_line.HasSwitch("print_hosts");
212 if (parsed_command_line.HasSwitch("nameserver")) {
213 std::string nameserver =
214 parsed_command_line.GetSwitchValueASCII("nameserver");
215 if (!StringToIPEndPoint(nameserver, &nameserver_)) {
216 fprintf(stderr,
217 "Cannot parse the namerserver string into an IPEndPoint\n");
218 return false;
222 if (parsed_command_line.HasSwitch("timeout")) {
223 int timeout_millis = 0;
224 bool parsed = base::StringToInt(
225 parsed_command_line.GetSwitchValueASCII("timeout"),
226 &timeout_millis);
227 if (parsed && timeout_millis > 0) {
228 timeout_ = base::TimeDelta::FromMilliseconds(timeout_millis);
229 } else {
230 fprintf(stderr, "Invalid timeout parameter\n");
231 return false;
235 if (parsed_command_line.GetArgs().size() == 1) {
236 #if defined(OS_WIN)
237 domain_name_ = WideToASCII(parsed_command_line.GetArgs()[0]);
238 #else
239 domain_name_ = parsed_command_line.GetArgs()[0];
240 #endif
241 } else if (parsed_command_line.GetArgs().size() != 0) {
242 return false;
244 return print_config_ || print_hosts_ || domain_name_.length() > 0;
247 void GDig::Start() {
248 if (nameserver_.address().size() > 0) {
249 DnsConfig dns_config;
250 dns_config.attempts = 1;
251 dns_config.nameservers.push_back(nameserver_);
252 OnDnsConfig(dns_config);
253 } else {
254 dns_config_service_ = DnsConfigService::CreateSystemService();
255 dns_config_service_->ReadConfig(base::Bind(&GDig::OnDnsConfig,
256 base::Unretained(this)));
257 timeout_closure_.Reset(base::Bind(&GDig::OnTimeout,
258 base::Unretained(this)));
259 MessageLoop::current()->PostDelayedTask(
260 FROM_HERE,
261 timeout_closure_.callback(),
262 config_timeout_);
266 void GDig::Finish(Result result) {
267 DCHECK_NE(RESULT_PENDING, result);
268 result_ = result;
269 if (MessageLoop::current())
270 MessageLoop::current()->Quit();
273 void GDig::OnDnsConfig(const DnsConfig& dns_config_const) {
274 timeout_closure_.Cancel();
275 DCHECK(dns_config_const.IsValid());
276 DnsConfig dns_config = dns_config_const;
278 if (timeout_.InMilliseconds() > 0)
279 dns_config.timeout = timeout_;
280 if (print_config_) {
281 printf("# Dns Configuration\n"
282 "%s", DnsConfigToString(dns_config).c_str());
284 if (print_hosts_) {
285 printf("# Host Database\n"
286 "%s", DnsHostsToString(dns_config.hosts).c_str());
289 // If the user didn't specify a name to resolve we can stop here.
290 if (domain_name_.length() == 0) {
291 Finish(RESULT_OK);
292 return;
295 scoped_ptr<DnsClient> dns_client(DnsClient::CreateClient(NULL));
296 dns_client->SetConfig(dns_config);
297 scoped_ptr<HostResolverImpl> resolver(
298 new HostResolverImpl(
299 HostCache::CreateDefaultCache(),
300 PrioritizedDispatcher::Limits(NUM_PRIORITIES, 1),
301 HostResolverImpl::ProcTaskParams(NULL, 1),
302 log_.get()));
303 resolver->SetDnsClient(dns_client.Pass());
304 resolver_ = resolver.Pass();
306 HostResolver::RequestInfo info(HostPortPair(domain_name_.c_str(), 80));
308 CompletionCallback callback = base::Bind(&GDig::OnResolveComplete,
309 base::Unretained(this));
310 int ret = resolver_->Resolve(
311 info, &addrlist_, callback, NULL,
312 BoundNetLog::Make(log_.get(), net::NetLog::SOURCE_NONE));
313 switch (ret) {
314 case OK:
315 OnResolveComplete(ret);
316 break;
317 case ERR_IO_PENDING: break;
318 default:
319 Finish(RESULT_NO_RESOLVE);
320 fprintf(stderr, "Error calling resolve %s\n", ErrorToString(ret));
324 void GDig::OnResolveComplete(int val) {
325 if (val != OK) {
326 fprintf(stderr, "Error trying to resolve hostname %s: %s\n",
327 domain_name_.c_str(), ErrorToString(val));
328 Finish(RESULT_NO_RESOLVE);
329 } else {
330 for (size_t i = 0; i < addrlist_.size(); ++i)
331 printf("%s\n", addrlist_[i].ToStringWithoutPort().c_str());
332 Finish(RESULT_OK);
336 void GDig::OnTimeout() {
337 fprintf(stderr, "Timed out waiting to load the dns config\n");
338 Finish(RESULT_NO_CONFIG);
341 } // empty namespace
343 } // namespace net
345 int main(int argc, const char* argv[]) {
346 net::GDig dig;
347 return dig.Main(argc, argv);