Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2011 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 #include <resolv.h> | |
| 6 | |
| 7 #include "base/compiler_specific.h" | |
| 8 #include "base/file_path.h" | |
| 9 #include "base/files/file_path_watcher.h" | |
| 10 #include "base/memory/ref_counted.h" | |
| 11 #include "base/message_loop.h" | |
| 12 #include "base/message_loop_proxy.h" | |
| 13 #include "base/scoped_ptr.h" | |
| 14 #include "base/task.h" | |
| 15 #include "base/threading/worker_pool.h" | |
| 16 #include "net/base/ip_endpoint.h" | |
| 17 #include "net/base/net_util.h" | |
| 18 #include "net/dns/dns_config_service.h" | |
| 19 | |
| 20 namespace net { | |
| 21 | |
| 22 using base::files::FilePathWatcher; | |
| 23 | |
| 24 class DnsConfigReaderPosix : public DnsConfigReader { | |
| 25 public: | |
| 26 bool Read(DnsConfig* dns_config) OVERRIDE { | |
| 27 // res_ninit is available on Linux (glibc 2+), Mac OS X, and Android. | |
| 28 // TODO(szym): res_ninit is not thread-safe on BSD? | |
| 29 struct __res_state res; | |
| 30 if (res_ninit(&res) != 0) | |
|
cbentzel
2011/08/01 19:52:26
Assuming that it's a newly constructed DnsConfig o
szym
2011/08/01 20:22:01
I'm not sure this is a safe general assumption. It
| |
| 31 return false; | |
| 32 | |
| 33 dns_config->nameservers.clear(); | |
| 34 for (int i = 0; i < res.nscount; ++i) { | |
| 35 IPEndPoint ipe; | |
| 36 if (ipe.FromSockAddr( | |
| 37 reinterpret_cast<struct sockaddr*>(&res.nsaddr_list[i]), | |
| 38 sizeof res.nsaddr_list[i])) | |
| 39 dns_config->nameservers.push_back(ipe); | |
| 40 } | |
| 41 | |
| 42 dns_config->search.clear(); | |
| 43 for (int i = 0; (i < MAXDNSRCH) && *res.dnsrch[i]; ++i) { | |
| 44 dns_config->search.push_back(std::string(res.dnsrch[i])); | |
| 45 } | |
| 46 | |
| 47 dns_config->domain = res.defdname; // use only if |search| is empty | |
| 48 dns_config->ndots = res.ndots; | |
| 49 dns_config->timeout = res.retrans; | |
| 50 dns_config->attempts = res.retry; | |
| 51 dns_config->rotate = res.options & RES_ROTATE; | |
| 52 dns_config->edns0 = res.options & RES_USE_EDNS0; | |
| 53 return true; | |
| 54 } | |
| 55 }; | |
| 56 | |
| 57 // NOTE: this makes it ref counted thread-safe | |
| 58 class DnsConfigServicePosix : public DnsConfigService, | |
|
cbentzel
2011/08/01 19:52:26
Is this compiling? Doesn't it need to be derived f
szym
2011/08/01 20:22:01
It is compiling. Is that an error? Is it safe to a
| |
| 59 public FilePathWatcher::Delegate { | |
| 60 public: | |
| 61 DnsConfigServicePosix() {} | |
| 62 virtual ~DnsConfigServicePosix() {} | |
| 63 virtual bool Watch(DnsConfigService::Delegate* delegate) OVERRIDE; | |
| 64 | |
| 65 private: | |
| 66 // TODO(szym): convert Task -> Closure? | |
| 67 | |
| 68 // called on the worker thread | |
| 69 // reads DnsConfig and posts OnResultAvailable to |message_loop| | |
| 70 void ReadConfig(scoped_refptr<base::MessageLoopProxy> message_loop); | |
| 71 | |
| 72 // called on the delegate's thread | |
| 73 // communicates result from DnsConfigReader to the delegate | |
| 74 void OnResultAvailable(const DnsConfig &config, bool error); | |
| 75 | |
| 76 // FilePathWatcher::Delegate interface | |
| 77 virtual void OnFilePathChanged(const FilePath& path) OVERRIDE; | |
| 78 | |
| 79 virtual void OnFilePathError(const FilePath& path) OVERRIDE { | |
| 80 delegate_->OnConfigError(); | |
| 81 } | |
| 82 | |
| 83 // message loop for the thread on which Watch is called | |
| 84 // this should be an IO loop | |
| 85 scoped_refptr<base::MessageLoopProxy> message_loop_; | |
| 86 scoped_ptr<FilePathWatcher> resolv_file_watcher_; | |
| 87 DnsConfigService::Delegate* delegate_; | |
| 88 DnsConfig last_config_; | |
| 89 }; | |
| 90 | |
| 91 bool DnsConfigServicePosix::Watch(DnsConfigService::Delegate* delegate) { | |
| 92 DCHECK(!resolv_file_watcher_.get()); | |
| 93 DCHECK(MessageLoopForIO::current()); | |
| 94 | |
|
cbentzel
2011/08/01 19:52:26
Should probably DCHECK that delegate_ is NULL.
szym
2011/08/01 20:22:01
Done.
| |
| 95 message_loop_ = base::MessageLoopProxy::CreateForCurrentThread(); | |
| 96 delegate_ = delegate; | |
| 97 | |
| 98 // start FilePathWatcher | |
| 99 resolv_file_watcher_.reset(new FilePathWatcher()); | |
| 100 return resolv_file_watcher_->Watch( | |
| 101 FilePath(FILE_PATH_LITERAL("/etc/resolv.conf")), | |
| 102 this | |
| 103 ); | |
| 104 } | |
| 105 | |
| 106 void DnsConfigServicePosix::ReadConfig( | |
| 107 scoped_refptr<base::MessageLoopProxy> message_loop) { | |
| 108 // on the WorkerPool | |
| 109 DnsConfigReaderPosix reader; | |
| 110 DnsConfig config; | |
| 111 bool error = reader.Read(&config); | |
| 112 message_loop->PostTask(FROM_HERE, NewRunnableMethod( | |
| 113 this, &DnsConfigServicePosix::OnResultAvailable, config, error)); | |
| 114 } | |
| 115 | |
| 116 void DnsConfigServicePosix::OnResultAvailable(const DnsConfig &config, | |
| 117 bool error) { | |
| 118 if (error) { | |
| 119 delegate_->OnConfigError(); | |
| 120 } else if (config != last_config_) { | |
| 121 delegate_->OnConfigChanged(config); | |
| 122 last_config_ = config; | |
| 123 } | |
| 124 } | |
| 125 | |
| 126 // FilePathWatcher::Delegate interface | |
| 127 void DnsConfigServicePosix::OnFilePathChanged(const FilePath& path) { | |
| 128 DCHECK(MessageLoopForIO::current()); | |
| 129 // we should be on the same thread that called Watch so delegate should | |
| 130 // still exist? | |
| 131 if (!base::WorkerPool::PostTask(FROM_HERE, NewRunnableMethod( | |
| 132 this, &DnsConfigServicePosix::ReadConfig, message_loop_), false)) { | |
| 133 delegate_->OnConfigError(); | |
| 134 } | |
| 135 } | |
| 136 | |
| 137 DnsConfigService* DnsConfigService::CreateSystemService() { | |
| 138 return new DnsConfigServicePosix(); | |
| 139 } | |
| 140 } | |
| 141 | |
| OLD | NEW |