Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(162)

Side by Side Diff: net/tools/hresolv/hresolv.cc

Issue 6320014: Remove hresolv (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/net.gyp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2010 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.
4
5 // hrseolv is a command line utility which runs the HostResolver in the
6 // Chromium network stack.
7 //
8 // The user specifies the hosts to lookup and when to look them up.
9 // The hosts must be specified in order.
10 // The hosts can be contained in a file or on the command line. If no
11 // time is specified, the resolv is assumed to be the same time as the
12 // previous host - which is an offset of 0 for the very first host.
13 //
14 // The user can also control whether the lookups happen asynchronously
15 // or synchronously by specifying --async on the command line.
16 //
17 // Future ideas:
18 // Specify whether the lookup is speculative.
19 // Interleave synchronous and asynchronous lookups.
20 // Specify the address family.
21
22 #include <stdio.h>
23 #include <string>
24
25 #include "base/at_exit.h"
26 #include "base/command_line.h"
27 #include "base/file_path.h"
28 #include "base/file_util.h"
29 #include "base/message_loop.h"
30 #include "base/string_number_conversions.h"
31 #include "base/string_split.h"
32 #include "base/string_util.h"
33 #include "base/threading/thread.h"
34 #include "base/time.h"
35 #include "net/base/address_list.h"
36 #include "net/base/completion_callback.h"
37 #include "net/base/host_resolver_impl.h"
38 #include "net/base/net_errors.h"
39 #include "net/base/net_util.h"
40 #include "net/base/sys_addrinfo.h"
41
42 struct FlagName {
43 int flag;
44 const char* name;
45 };
46
47 static const FlagName kAddrinfoFlagNames[] = {
48 {AI_PASSIVE, "AI_PASSIVE"},
49 {AI_CANONNAME, "AI_CANONNAME"},
50 {AI_NUMERICHOST, "AI_NUMERICHOST"},
51 {AI_V4MAPPED, "AI_V4MAPPED"},
52 {AI_ALL, "AI_ALL"},
53 {AI_ADDRCONFIG, "AI_ADDRCONFIG"},
54 #if !defined(OS_MACOSX)
55 {AI_NUMERICSERV, "AI_NUMERICSERV"},
56 #endif
57 };
58
59 std::string FormatAddrinfoFlags(int ai_flags) {
60 std::string flag_names;
61 for (unsigned int i = 0; i < arraysize(kAddrinfoFlagNames); ++i) {
62 const FlagName& flag_name = kAddrinfoFlagNames[i];
63 if (ai_flags & flag_name.flag) {
64 ai_flags &= ~flag_name.flag;
65 if (!flag_names.empty()) {
66 flag_names += "|";
67 }
68 flag_names += flag_name.name;
69 }
70 }
71 if (ai_flags) {
72 if (!flag_names.empty()) {
73 flag_names += "|";
74 }
75 base::StringAppendF(&flag_names, "0x%x", ai_flags);
76 }
77 return flag_names;
78 }
79
80 const char* GetNameOfFlag(const FlagName* flag_names,
81 unsigned int num_flag_names,
82 int flag) {
83 for (unsigned int i = 0; i < num_flag_names; ++i) {
84 const FlagName& flag_name = flag_names[i];
85 if (flag_name.flag == flag) {
86 return flag_name.name;
87 }
88 }
89 return "UNKNOWN";
90 }
91
92 static const FlagName kFamilyFlagNames[] = {
93 {AF_UNSPEC, "AF_UNSPEC"},
94 {AF_INET, "AF_INET"},
95 {AF_INET6, "AF_INET6"},
96 };
97
98 const char* FormatAddrinfoFamily(int ai_family) {
99 return GetNameOfFlag(kFamilyFlagNames,
100 arraysize(kFamilyFlagNames),
101 ai_family);
102 }
103
104 static const FlagName kSocktypeFlagNames[] = {
105 {SOCK_STREAM, "SOCK_STREAM"},
106 {SOCK_DGRAM, "SOCK_DGRAM"},
107 {SOCK_RAW, "SOCK_RAW"},
108 };
109
110 const char* FormatAddrinfoSocktype(int ai_socktype) {
111 return GetNameOfFlag(kSocktypeFlagNames,
112 arraysize(kSocktypeFlagNames),
113 ai_socktype);
114 }
115
116 static const FlagName kProtocolFlagNames[] = {
117 {IPPROTO_TCP, "IPPROTO_TCP"},
118 {IPPROTO_UDP, "IPPROTO_UDP"},
119 };
120
121 const char* FormatAddrinfoProtocol(int ai_protocol) {
122 return GetNameOfFlag(kProtocolFlagNames,
123 arraysize(kProtocolFlagNames),
124 ai_protocol);
125 }
126
127 std::string FormatAddrinfoDetails(const struct addrinfo& ai,
128 const char* indent) {
129 std::string ai_flags = FormatAddrinfoFlags(ai.ai_flags);
130 const char* ai_family = FormatAddrinfoFamily(ai.ai_family);
131 const char* ai_socktype = FormatAddrinfoSocktype(ai.ai_socktype);
132 const char* ai_protocol = FormatAddrinfoProtocol(ai.ai_protocol);
133 std::string ai_addr = net::NetAddressToString(&ai);
134 std::string ai_canonname;
135 if (ai.ai_canonname) {
136 ai_canonname = base::StringPrintf("%s ai_canonname: %s\n",
137 indent,
138 ai.ai_canonname);
139 }
140 return base::StringPrintf("%saddrinfo {\n"
141 "%s ai_flags: %s\n"
142 "%s ai_family: %s\n"
143 "%s ai_socktype: %s\n"
144 "%s ai_protocol: %s\n"
145 "%s ai_addrlen: %d\n"
146 "%s ai_addr: %s\n"
147 "%s"
148 "%s}\n",
149 indent,
150 indent, ai_flags.c_str(),
151 indent, ai_family,
152 indent, ai_socktype,
153 indent, ai_protocol,
154 indent, ai.ai_addrlen,
155 indent, ai_addr.c_str(),
156 ai_canonname.c_str(),
157 indent);
158 }
159
160 std::string FormatAddressList(const net::AddressList& address_list,
161 const std::string& host) {
162 std::string ret_string;
163 base::StringAppendF(&ret_string, "AddressList {\n");
164 base::StringAppendF(&ret_string, " Host: %s\n", host.c_str());
165 for (const struct addrinfo* it = address_list.head();
166 it != NULL;
167 it = it->ai_next) {
168 base::StringAppendF(&ret_string, "%s",
169 FormatAddrinfoDetails(*it, " ").c_str());
170 }
171 base::StringAppendF(&ret_string, "}\n");
172 return ret_string;
173 }
174
175 class ResolverInvoker;
176
177 // DelayedResolve contains state for a DNS resolution to be performed later.
178 class DelayedResolve : public base::RefCounted<DelayedResolve> {
179 public:
180 DelayedResolve(const std::string& host, bool is_async,
181 net::HostResolver* resolver,
182 ResolverInvoker* invoker)
183 : host_(host),
184 address_list_(),
185 is_async_(is_async),
186 resolver_(resolver),
187 invoker_(invoker),
188 ALLOW_THIS_IN_INITIALIZER_LIST(
189 io_callback_(this, &DelayedResolve::OnResolveComplete)) {
190 }
191
192 void Start() {
193 net::CompletionCallback* callback = (is_async_) ? &io_callback_ : NULL;
194 net::HostResolver::RequestInfo request_info(net::HostPortPair(host_, 80));
195 int rv = resolver_->Resolve(request_info,
196 &address_list_,
197 callback,
198 NULL,
199 net::BoundNetLog());
200 if (rv != net::ERR_IO_PENDING) {
201 OnResolveComplete(rv);
202 }
203 }
204
205 private:
206
207 // Without this, VC++ complains about the private destructor below.
208 friend class base::RefCounted<DelayedResolve>;
209
210 // The destructor is called by Release.
211 ~DelayedResolve() {}
212
213 void OnResolveComplete(int result);
214
215 std::string host_;
216 net::AddressList address_list_;
217 bool is_async_;
218 net::HostResolver* const resolver_;
219 ResolverInvoker* invoker_;
220 net::CompletionCallbackImpl<DelayedResolve> io_callback_;
221 };
222
223
224 struct HostAndTime {
225 // The host to resolve, i.e. www.google.com
226 std::string host;
227 // Time since the start of this program to actually kick off the resolution.
228 int delta_in_milliseconds;
229 };
230
231 // Invokes a sequence of host resolutions at specified times.
232 class ResolverInvoker {
233 public:
234 explicit ResolverInvoker(net::HostResolver* resolver)
235 : message_loop_(MessageLoop::TYPE_DEFAULT),
236 resolver_(resolver),
237 remaining_requests_(0) {
238 }
239
240 ~ResolverInvoker() {
241 }
242
243 // Resolves all specified hosts in the order provided. hosts_and_times is
244 // assumed to be ordered by the delta_in_milliseconds field. There is no
245 // guarantee that the resolutions will complete in the order specified when
246 // async is true. There is no guarantee that the DNS queries will be issued
247 // at exactly the time specified by delta_in_milliseconds, but they are
248 // guaranteed to be issued at a time >= delta_in_milliseconds.
249 //
250 // When async is true, HostResolver::Resolve will issue the DNS lookups
251 // asynchronously - this can be used to have multiple requests in flight at
252 // the same time.
253 //
254 // ResolveAll will block until all resolutions are complete.
255 void ResolveAll(const std::vector<HostAndTime>& hosts_and_times,
256 bool async) {
257 // Schedule all tasks on our message loop, and then run.
258 int num_requests = hosts_and_times.size();
259 remaining_requests_ = num_requests;
260 for (int i = 0; i < num_requests; ++i) {
261 const HostAndTime& host_and_time = hosts_and_times[i];
262 const std::string& host = host_and_time.host;
263 DelayedResolve* resolve_request = new DelayedResolve(host,
264 async, resolver_, this);
265 resolve_request->AddRef();
266 message_loop_.PostDelayedTask(
267 FROM_HERE,
268 NewRunnableMethod(resolve_request, &DelayedResolve::Start),
269 host_and_time.delta_in_milliseconds);
270 }
271 message_loop_.Run();
272 }
273
274 private:
275 friend class DelayedResolve;
276
277 void OnResolved(int err, net::AddressList* address_list,
278 const std::string& host) {
279 if (err == net::OK) {
280 printf("%s", FormatAddressList(*address_list, host).c_str());
281 } else {
282 printf("Error resolving %s\n", host.c_str());
283 }
284 DCHECK(remaining_requests_ > 0);
285 --remaining_requests_;
286 if (remaining_requests_ == 0) {
287 message_loop_.Quit();
288 }
289 }
290
291 MessageLoop message_loop_;
292 net::HostResolver* const resolver_;
293 int remaining_requests_;
294 };
295
296 void DelayedResolve::OnResolveComplete(int result) {
297 invoker_->OnResolved(result, &address_list_, host_);
298 this->Release();
299 }
300
301 struct CommandLineOptions {
302 CommandLineOptions()
303 : verbose(false),
304 async(false),
305 cache_size(100),
306 cache_ttl(50),
307 input_path() {
308 }
309
310 bool verbose;
311 bool async;
312 int cache_size;
313 int cache_ttl;
314 FilePath input_path;
315 };
316
317 const char* kAsync = "async";
318 const char* kCacheSize = "cache-size";
319 const char* kCacheTtl = "cache-ttl";
320 const char* kInputPath = "input-path";
321
322 // Parses the command line values. Returns false if there is a problem,
323 // options otherwise.
324 bool ParseCommandLine(CommandLine* command_line, CommandLineOptions* options) {
325 options->async = command_line->HasSwitch(kAsync);
326 if (command_line->HasSwitch(kCacheSize)) {
327 std::string cache_size = command_line->GetSwitchValueASCII(kCacheSize);
328 bool valid_size = base::StringToInt(cache_size, &options->cache_size);
329 if (valid_size) {
330 valid_size = options->cache_size >= 0;
331 }
332 if (!valid_size) {
333 printf("Invalid --cachesize value: %s\n", cache_size.c_str());
334 return false;
335 }
336 }
337
338 if (command_line->HasSwitch(kCacheTtl)) {
339 std::string cache_ttl = command_line->GetSwitchValueASCII(kCacheTtl);
340 bool valid_ttl = base::StringToInt(cache_ttl, &options->cache_ttl);
341 if (valid_ttl) {
342 valid_ttl = options->cache_ttl >= 0;
343 }
344 if (!valid_ttl) {
345 printf("Invalid --cachettl value: %s\n", cache_ttl.c_str());
346 return false;
347 }
348 }
349
350 if (command_line->HasSwitch(kInputPath)) {
351 options->input_path = command_line->GetSwitchValuePath(kInputPath);
352 }
353
354 return true;
355 }
356
357 bool ReadHostsAndTimesFromLooseValues(
358 const std::vector<CommandLine::StringType>& args,
359 std::vector<HostAndTime>* hosts_and_times) {
360 for (std::vector<CommandLine::StringType>::const_iterator it =
361 args.begin();
362 it != args.end();
363 ++it) {
364 // TODO(cbentzel): Read time offset.
365 #if defined(OS_WIN)
366 HostAndTime host_and_time = {WideToASCII(*it), 0};
367 #else
368 HostAndTime host_and_time = {*it, 0};
369 #endif
370 hosts_and_times->push_back(host_and_time);
371 }
372 return true;
373 }
374
375 bool ReadHostsAndTimesFromFile(const FilePath& path,
376 std::vector<HostAndTime>* hosts_and_times) {
377 // TODO(cbentzel): There are smarter and safer ways to do this.
378 std::string file_contents;
379 if (!file_util::ReadFileToString(path, &file_contents)) {
380 return false;
381 }
382 std::vector<std::string> lines;
383 // TODO(cbentzel): This should probably handle CRLF-style separators as well.
384 // Maybe it's worth adding functionality like this to base tools.
385 base::SplitString(file_contents, '\n', &lines);
386 std::vector<std::string>::const_iterator line_end = lines.end();
387 int previous_timestamp = 0;
388 for (std::vector<std::string>::const_iterator it = lines.begin();
389 it != line_end;
390 ++it) {
391 std::vector<std::string> tokens;
392 base::SplitStringAlongWhitespace(*it, &tokens);
393 switch (tokens.size()) {
394 case 0:
395 // Unexpected, but keep going.
396 break;
397 case 1: {
398 HostAndTime host_and_time = {tokens[0], previous_timestamp};
399 hosts_and_times->push_back(host_and_time);
400 break;
401 }
402 case 2: {
403 int timestamp;
404 if (!base::StringToInt(tokens[1], &timestamp)) {
405 // Unexpected value - keep going.
406 }
407 if (timestamp < previous_timestamp) {
408 // Unexpected value - ignore.
409 }
410 previous_timestamp = timestamp;
411 HostAndTime host_and_time = {tokens[0], timestamp};
412 hosts_and_times->push_back(host_and_time);
413 break;
414 }
415 default:
416 DCHECK(false);
417 break;
418 }
419 }
420 return true;
421 }
422
423 int main(int argc, char** argv) {
424 base::AtExitManager at_exit_manager;
425 CommandLine::Init(argc, argv);
426 CommandLine* command_line = CommandLine::ForCurrentProcess();
427 CommandLineOptions options;
428 if (!ParseCommandLine(command_line, &options)) {
429 exit(1);
430 }
431
432 // Get the hosts and times - either from a file or command line options.
433 // TODO(cbentzel): Add stdin support to POSIX versions - not sure if
434 // there's an equivalent in Windows.
435 // TODO(cbentzel): If really large, may not want to spool the whole
436 // file into memory.
437 std::vector<HostAndTime> hosts_and_times;
438 if (options.input_path.empty()) {
439 if (!ReadHostsAndTimesFromLooseValues(command_line->args(),
440 &hosts_and_times)) {
441 exit(1);
442 }
443 } else {
444 if (!ReadHostsAndTimesFromFile(options.input_path, &hosts_and_times)) {
445 exit(1);
446 }
447 }
448
449 net::HostCache* cache = new net::HostCache(
450 options.cache_size,
451 base::TimeDelta::FromMilliseconds(options.cache_ttl),
452 base::TimeDelta::FromSeconds(0));
453
454 net::HostResolverImpl host_resolver(NULL, cache, 100u, NULL);
455 ResolverInvoker invoker(&host_resolver);
456 invoker.ResolveAll(hosts_and_times, options.async);
457
458 CommandLine::Reset();
459 return 0;
460 }
OLDNEW
« no previous file with comments | « net/net.gyp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698