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

Side by Side Diff: net/dns/dns_config_service_posix.cc

Issue 7518028: DnsConfigService and a posix implementation (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: delinted Created 9 years, 4 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
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698