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 |