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/bind.h" | |
| 8 #include "base/compiler_specific.h" | |
| 9 #include "base/file_path.h" | |
| 10 #include "base/files/file_path_watcher.h" | |
| 11 #include "base/memory/ref_counted.h" | |
| 12 #include "base/message_loop.h" | |
| 13 #include "base/message_loop_proxy.h" | |
| 14 #include "base/scoped_ptr.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 namespace { | |
| 23 | |
| 24 using base::files::FilePathWatcher; | |
| 25 | |
| 26 // fills in |dns_config| from |res| | |
| 27 void ConfigFromResolver(const struct __res_state& res, DnsConfig* dns_config) { | |
| 28 CHECK(dns_config != NULL); | |
| 29 DCHECK(res.options & RES_INIT); | |
| 30 dns_config->nameservers.clear(); | |
| 31 for (int i = 0; i < res.nscount; ++i) { | |
| 32 IPEndPoint ipe; | |
| 33 if (ipe.FromSockAddr( | |
|
cbentzel
2011/08/04 18:09:27
You may want to handle IPv6 DNS servers here - or
szym
2011/08/04 18:55:10
I'll look into this.
| |
| 34 reinterpret_cast<const struct sockaddr*>(&res.nsaddr_list[i]), | |
| 35 sizeof res.nsaddr_list[i])) { | |
| 36 dns_config->nameservers.push_back(ipe); | |
| 37 } else { | |
| 38 NOTREACHED() << "could not convert nsaddr"; | |
|
cbentzel
2011/08/04 18:09:27
I think this function should return a boolean, and
szym
2011/08/04 18:55:10
Right. I was swayed by IPEndPoint::FromSockAddr wh
| |
| 39 } | |
| 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 | |
|
cbentzel
2011/08/04 18:09:27
This should be conditional on dns_config->search.e
szym
2011/08/04 18:55:10
Even though defdname stores all the strings in dns
cbentzel
2011/08/04 20:01:21
That seems good.
| |
| 48 dns_config->ndots = res.ndots; | |
| 49 dns_config->timeout = res.retrans; | |
|
cbentzel
2011/08/04 18:09:27
I wish there was a way to distinguish whether thes
szym
2011/08/04 18:55:10
I can't think of a way to do that without parsing
cbentzel
2011/08/04 20:01:21
Yeah, agree.
| |
| 50 dns_config->attempts = res.retry; | |
| 51 dns_config->rotate = res.options & RES_ROTATE; | |
| 52 dns_config->edns0 = res.options & RES_USE_EDNS0; | |
|
cbentzel
2011/08/04 18:09:27
It's probably good to pull in all of these things.
szym
2011/08/04 18:55:10
I'm not sure I understand. Should I remove those o
cbentzel
2011/08/04 20:01:21
No, keep them. I was musing about what we need to
| |
| 53 } | |
| 54 | |
| 55 // fills in |dns_config| using res_ninit, returns true on success | |
| 56 bool ReadConfig(DnsConfig* dns_config) { | |
| 57 // res_ninit is available on Linux (glibc 2+), Mac OS X, and Android. | |
| 58 // However, it might not be thread-safe on OpenBSD. | |
|
cbentzel
2011/08/04 18:09:27
I think it would be good to limit to only one res_
szym
2011/08/04 18:55:10
Done.
| |
| 59 struct __res_state res; | |
| 60 if (res_ninit(&res) != 0) | |
| 61 return false; | |
| 62 | |
| 63 ConfigFromResolver(res, dns_config); | |
| 64 return true; | |
| 65 } | |
| 66 | |
| 67 class DnsConfigServicePosix : public DnsConfigService { | |
| 68 public: | |
| 69 DnsConfigServicePosix() {} | |
| 70 virtual ~DnsConfigServicePosix() { | |
| 71 // we must be destroyed on the same thread that called Watch | |
| 72 if (watcher_delegate_.get()) | |
| 73 watcher_delegate_->Cancel(); | |
| 74 } | |
| 75 virtual bool Watch(DnsConfigService::Delegate* delegate) OVERRIDE; | |
| 76 | |
| 77 private: | |
| 78 // FilePathWatcher::Delegate is refcounted, so we separate it from the Service | |
| 79 // We'll also use it on the WorkerPool | |
| 80 class WatcherDelegate : public FilePathWatcher::Delegate { | |
| 81 public: | |
| 82 explicit WatcherDelegate(DnsConfigService::Delegate* delegate) | |
| 83 : message_loop_(base::MessageLoopProxy::CreateForCurrentThread()), | |
| 84 delegate_(delegate) {} | |
| 85 | |
| 86 // FilePathWatcher::Delegate interface | |
| 87 virtual void OnFilePathChanged(const FilePath& path) OVERRIDE { | |
| 88 DCHECK(message_loop_->BelongsToCurrentThread()); | |
| 89 if (!delegate_) | |
| 90 return; | |
| 91 if (!base::WorkerPool::PostTask(FROM_HERE, base::Bind( | |
| 92 &WatcherDelegate::DoRead, this), false)) { | |
| 93 delegate_->OnConfigError(); | |
|
cbentzel
2011/08/04 18:09:27
Yeah, I don't think you need to escalate this to t
szym
2011/08/04 18:55:10
Done.
| |
| 94 } | |
| 95 } | |
| 96 | |
| 97 virtual void OnFilePathError(const FilePath& path) OVERRIDE { | |
| 98 DCHECK(message_loop_->BelongsToCurrentThread()); | |
| 99 if (!delegate_) | |
| 100 return; | |
| 101 delegate_->OnConfigError(); | |
| 102 } | |
| 103 | |
| 104 // called on the worker thread | |
| 105 // reads DnsConfig and posts OnResultAvailable to |message_loop_| | |
| 106 void DoRead() { | |
| 107 // on the WorkerPool | |
| 108 DnsConfig config; | |
| 109 bool success = ReadConfig(&config); | |
| 110 message_loop_->PostTask(FROM_HERE, base::Bind( | |
|
cbentzel
2011/08/04 18:09:27
If it wasn't successful, I think we should just sk
szym
2011/08/04 18:55:10
Can I have a stupid while(!the_thing_to_do); or sh
cbentzel
2011/08/04 20:01:21
Well, if someone made a typo in resolv.conf and th
| |
| 111 &WatcherDelegate::OnResultAvailable, this, config, success)); | |
| 112 } | |
| 113 | |
| 114 // called on the delegate's thread | |
| 115 // communicates result from DnsConfigReader to the delegate | |
| 116 void OnResultAvailable(const DnsConfig &config, bool success) { | |
| 117 DCHECK(message_loop_->BelongsToCurrentThread()); | |
| 118 if (!delegate_) | |
| 119 return; | |
| 120 if (!success) { | |
| 121 delegate_->OnConfigError(); | |
| 122 } else if (config != last_config_) { | |
| 123 delegate_->OnConfigChanged(config); | |
| 124 last_config_ = config; | |
| 125 } | |
| 126 } | |
| 127 | |
| 128 void Cancel() { | |
| 129 DCHECK(message_loop_->BelongsToCurrentThread()); | |
| 130 delegate_ = NULL; | |
| 131 } | |
| 132 | |
| 133 private: | |
| 134 virtual ~WatcherDelegate() {} | |
| 135 | |
| 136 // message loop for the thread on which Watch is called | |
| 137 // this should be an IO loop | |
| 138 scoped_refptr<base::MessageLoopProxy> message_loop_; | |
| 139 DnsConfigService::Delegate* delegate_; | |
| 140 DnsConfig last_config_; | |
| 141 }; | |
| 142 | |
| 143 scoped_ptr<FilePathWatcher> resolv_file_watcher_; | |
| 144 scoped_refptr<WatcherDelegate> watcher_delegate_; | |
| 145 }; | |
|
cbentzel
2011/08/04 18:09:27
DISALLOW_COPY_AND_ASSIGN
szym
2011/08/04 18:55:10
Done.
| |
| 146 | |
| 147 bool DnsConfigServicePosix::Watch(DnsConfigService::Delegate* delegate) { | |
| 148 DCHECK(!resolv_file_watcher_.get()); | |
| 149 DCHECK(!watcher_delegate_.get()); | |
| 150 DCHECK(MessageLoopForIO::current()); | |
| 151 | |
| 152 // start FilePathWatcher | |
| 153 FilePath path(FILE_PATH_LITERAL("/etc/resolv.conf")); | |
|
cbentzel
2011/08/04 18:24:56
Is _PATH_RESCONF defined correctly in the differen
szym
2011/08/04 18:55:10
I'll add a #ifndef _PATH_RESCONF #define _PATH_RES
| |
| 154 watcher_delegate_ = new WatcherDelegate(delegate); | |
| 155 resolv_file_watcher_.reset(new FilePathWatcher()); | |
| 156 bool result = resolv_file_watcher_->Watch(path, watcher_delegate_); | |
| 157 // make the initial read | |
| 158 watcher_delegate_->OnFilePathChanged(path); | |
| 159 return result; | |
| 160 } | |
| 161 | |
| 162 } // namespace | |
| 163 | |
| 164 DnsConfigService* DnsConfigService::CreateSystemService() { | |
| 165 return new DnsConfigServicePosix(); | |
| 166 } | |
|
cbentzel
2011/08/04 18:09:27
Nit: newline between here and // namespace net.
szym
2011/08/04 18:55:10
Done.
| |
| 167 } // namespace net | |
| 168 | |
| OLD | NEW |