Chromium Code Reviews| Index: net/tools/gdig/gdig.cc |
| diff --git a/net/tools/gdig/gdig.cc b/net/tools/gdig/gdig.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..6c8a4070e4b4e5ee07a8dc87d11e407e0bac430f |
| --- /dev/null |
| +++ b/net/tools/gdig/gdig.cc |
| @@ -0,0 +1,214 @@ |
| +#include <stdio.h> |
| +#include <iostream> |
| + |
| +#include "base/at_exit.h" |
| +#include "base/command_line.h" |
| +#if defined(OS_MACOSX) |
| +#include "base/mac/scoped_nsautorelease_pool.h" |
| +#endif |
| +#include "base/memory/scoped_ptr.h" |
| +#include "base/message_loop.h" |
| +#include "base/string_number_conversions.h" |
| + |
| +#include "net/base/host_resolver_impl.h" |
| +#include "net/base/net_errors.h" |
| +#include "net/base/net_util.h" |
| +#include "net/base/sys_addrinfo.h" |
| + |
| +namespace net { |
| + |
| +namespace { |
| + |
| +class GDig; |
| + |
| +// This class is a wrapper around the real DnsConfigService. |
| +// It is used to intercept the OnDnsConfig and notify the main program |
|
szym
2012/05/18 18:15:05
Not clear which "OnDnsConfig." How about:
"It will
|
| +// that a DnsConfig has been loaded. |
| +class DnsConfigServiceMock : public DnsConfigService { |
|
szym
2012/05/18 18:15:05
nit: in src/net MockXxx is much more common than X
|
| + public: |
| + explicit DnsConfigServiceMock(GDig* gdig); |
| + |
| + virtual ~DnsConfigServiceMock(); |
| + |
| + virtual void Watch(const CallbackType& callback) OVERRIDE; |
| + void OnDnsConfig(const DnsConfig& dns_config_); |
|
szym
2012/05/18 18:15:05
Can be private.
|
| + private: |
| + GDig* gdig_; |
| + scoped_ptr<DnsConfigService> real_service_; |
| + DnsConfigService::CallbackType callback_; |
| +}; |
| + |
| +class GDig { |
| + public: |
| + GDig(); |
| + |
| + static void PrintUsage(const char* program_name); |
| + |
| + enum Result { |
| + RESULT_NO_RESOLVE = -3, |
| + RESULT_NO_CONFIG = -2, |
| + RESULT_WRONG_USAGE = -1, |
| + RESULT_OK = 0, |
| + }; |
| + |
| + Result Main(int argc, const char* argv[]); |
| + |
| + private: |
| + bool ParseCommandLine(int argc, const char* argv[]); |
| + |
| + void Start(); |
| + |
| + void OnDnsConfig(const DnsConfig& dns_config); |
| + friend void DnsConfigServiceMock::OnDnsConfig(const DnsConfig&); |
|
szym
2012/05/18 18:15:05
I think it's reasonable to friend the whole class.
|
| + void OnResolveComplete(int val); |
| + void OnTimeout(); |
| + |
| + Result result_; |
| + |
| + int resolve_name_ret_; |
| + AddressList addrlist_; |
| + |
| + base::CancelableClosure timeout_; |
| + DnsConfig dns_config_; |
| + |
| + int timeout_seconds_; |
|
szym
2012/06/01 17:54:49
Use base::TimeDelta.
|
| + std::string domain_name_; |
| + |
| + scoped_ptr<HostResolver> resolver_; |
| +}; |
| + |
| + |
| +DnsConfigServiceMock::DnsConfigServiceMock(GDig* gdig) : gdig_(gdig) { |
| +} |
| + |
| +DnsConfigServiceMock::~DnsConfigServiceMock() {} |
| + |
| +void DnsConfigServiceMock::Watch(const CallbackType& callback) OVERRIDE { |
| + DCHECK(CalledOnValidThread()); |
| + DCHECK(!callback.is_null()); |
| + callback_ = callback; |
| + real_service_ = DnsConfigService::CreateSystemService(); |
| + real_service_->Watch(base::Bind(&DnsConfigServiceMock::OnDnsConfig, |
| + Unretained(this))); |
| +} |
| + |
| +void DnsConfigServiceMock::OnDnsConfig(const DnsConfig& dns_config_) { |
| + callback_.Run(dns_config_); |
| + gdig_->OnDnsConfig(dns_config_); |
| + real_service_.reset(); |
| +} |
| + |
| +GDig::GDig() |
| + : result_(GDig::RESULT_OK), |
| + resolve_name_ret_(ERR_TIMED_OUT), |
| + timeout_seconds_(5) { |
| +} |
| + |
| +void GDig::PrintUsage(const char* program_name) { |
| + std::cout << "usage: " << program_name << |
|
szym
2012/05/18 18:15:05
This is so basic, could consider removing this fun
|
| + " [--read_config_timeout=<seconds>] domain_name" << |
| + std::endl; |
| +} |
| + |
| +GDig::Result GDig::Main(int argc, const char* argv[]) { |
| + if (!ParseCommandLine(argc, argv)) { |
| + PrintUsage(argv[0]); |
| + return RESULT_WRONG_USAGE; |
| + } |
| + |
| +#if defined(OS_MACOSX) |
| + // Without this there will be a mem leak on osx |
| + base::mac::ScopedNSAutoreleasePool scoped_pool; |
| +#endif |
| + |
| + base::AtExitManager exit_manager; |
| + MessageLoop loop(MessageLoop::TYPE_IO); |
| + |
| + Start(); |
| + |
| + MessageLoop::current()->Run(); |
| + return result_; |
| +} |
| + |
| +void GDig::OnResolveComplete(int val) { |
| + MessageLoop::current()->Quit(); |
| + if (val < 0) { |
|
szym
2012/05/18 18:15:05
val != OK
|
| + std::cout << "Error trying to resolve hostname " << domain_name_ << |
| + ":" << ErrorToString(resolve_name_ret_) << std::endl; |
| + result_ = RESULT_NO_RESOLVE; |
| + } else { |
| + const struct addrinfo* addrinf = addrlist_.head(); |
|
szym
2012/05/18 18:15:05
AddressList has been changed to std::vector<IPEndP
|
| + while (addrinf) { |
| + std::string ip = NetAddressToStringWithPort(addrinf); |
| + std::cout << ip << std::endl; |
| + addrinf = addrinf->ai_next; |
| + } |
| + } |
| +} |
| + |
| +void GDig::OnTimeout() { |
| + MessageLoop::current()->Quit(); |
| + std::cout << "Timed out waiting to load the dns config" << std::endl; |
| + result_ = RESULT_NO_CONFIG; |
| +} |
| + |
| +void GDig::Start() { |
| + scoped_ptr<DnsConfigService> |
| + dns_config_service(new DnsConfigServiceMock(this)); |
| + |
| + resolver_.reset( |
| + new HostResolverImpl( |
| + HostCache::CreateDefaultCache(), |
| + PrioritizedDispatcher::Limits(NUM_PRIORITIES, 1), |
| + HostResolverImpl::ProcTaskParams(NULL, 1), |
| + dns_config_service.Pass(), |
| + NULL)); |
| + |
| + timeout_.Reset(base::Bind(&GDig::OnTimeout, base::Unretained(this))); |
| + |
| + MessageLoop::current()->PostDelayedTask( |
| + FROM_HERE, |
| + timeout_.callback(), |
| + base::TimeDelta::FromSeconds(timeout_seconds_)); |
| +} |
| + |
| +void GDig::OnDnsConfig(const DnsConfig& dns_config) { |
| + timeout_.Cancel(); |
| + |
| + DCHECK(dns_config.IsValid()); |
| + dns_config_ = dns_config; |
| + |
| + HostResolver::RequestInfo info(HostPortPair(domain_name_.c_str(), 80)); |
| + |
| + CompletionCallback callback = base::Bind(&GDig::OnResolveComplete, |
| + base::Unretained(this)); |
| + int ret = resolver_->Resolve(info, &addrlist_, callback, NULL, BoundNetLog()); |
| + DCHECK(ret == ERR_IO_PENDING); |
| +} |
| + |
| +bool GDig::ParseCommandLine(int argc, const char* argv[]) { |
| + CommandLine::Init(argc, argv); |
| + const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); |
| + |
| + if (parsed_command_line.GetArgs().size() != 1) { |
| + return false; |
| + } |
| + domain_name_ = parsed_command_line.GetArgs().at(0); |
| + |
| + if (parsed_command_line.HasSwitch("read_config_timeout")) { |
|
szym
2012/05/18 18:15:05
Perhaps just config_timeout
|
| + base::StringToInt( |
| + parsed_command_line.GetSwitchValueASCII("read_config_timeout"), |
| + &timeout_seconds_); |
| + } |
| + |
| + return true; |
| +} |
| + |
| +} // empty namespace |
| + |
| +} // namespace net |
| + |
| +int main(int argc, const char* argv[]) { |
| + net::GDig dig; |
| + return dig.Main(argc, argv); |
| +} |