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

Side by Side Diff: net/base/dns_reload_timer.cc

Issue 6033006: Use FileWatcher to watch system resolver config, on systems that require... Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: Created 10 years 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
« no previous file with comments | « net/base/dns_reload_timer.h ('k') | net/base/dnsrr_resolver.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/base/dns_reload_timer.h" 5 #include "net/base/dns_reload_timer.h"
6 6
7 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) 7 #if WATCH_RESOLV_CONF
8 #include <resolv.h>
9
10 #include "base/file_path.h"
8 #include "base/lazy_instance.h" 11 #include "base/lazy_instance.h"
12 #include "base/scoped_ptr.h"
13 #include "base/lock.h"
14 #include "base/task.h"
15 #include "base/thread.h"
9 #include "base/thread_local_storage.h" 16 #include "base/thread_local_storage.h"
10 #include "base/time.h" 17 #include "base/time.h"
18 #include "chrome/browser/file_path_watcher/file_path_watcher.h"
willchan no longer on Chromium 2011/01/04 23:50:41 net is a lower level module than chrome. chrome d
11 19
12 namespace { 20 namespace net {
13 21
14 // On Linux/BSD, changes to /etc/resolv.conf can go unnoticed thus resulting 22 // On Linux/BSD, changes to /etc/resolv.conf can go unnoticed thus resulting
15 // in DNS queries failing either because nameservers are unknown on startup 23 // in DNS queries failing either because nameservers are unknown on startup
16 // or because nameserver info has changed as a result of e.g. connecting to 24 // or because nameserver info has changed as a result of e.g. connecting to
17 // a new network. Some distributions patch glibc to stat /etc/resolv.conf 25 // a new network. Some distributions patch glibc to stat /etc/resolv.conf
18 // to try to automatically detect such changes but these patches are not 26 // to try to automatically detect such changes but these patches are not
19 // universal and even patched systems such as Jaunty appear to need calls 27 // universal and even patched systems such as Jaunty appear to need calls
20 // to res_ninit to reload the nameserver information in different threads. 28 // to res_ninit to reload the nameserver information in different threads.
21 // 29 //
22 // We adopt the Mozilla solution here which is to call res_ninit when 30 // We adopt the Mozilla solution here which is to call res_ninit when
23 // lookups fail and to rate limit the reloading to once per second per 31 // lookups fail and to rate limit the reloading to once per second per
24 // thread. 32 // thread.
25 // 33 //
26 // OpenBSD does not have thread-safe res_ninit/res_nclose so we can't do 34 // OpenBSD does not have thread-safe res_ninit/res_nclose so we can't do
27 // the same trick there. 35 // the same trick there.
28 36
29 // Keep a timer per calling thread to rate limit the calling of res_ninit. 37 // Keep a timer per calling thread to rate limit the calling of res_ninit.
30 class DnsReloadTimer { 38 class DnsReloadTimer {
31 public: 39 public:
40
41 bool ResolvConfUpdated() {
42 struct DnsReloadTimer::LocalState* local_state = GetLocalState();
43 AutoLock l(lock_);
44 if (local_state->resolv_conf_generation < resolv_conf_generation_ &&
45 Expired()) {
46 local_state->resolv_conf_generation = resolv_conf_generation_;
47 return true;
48 }
49 return false;
50 }
51
32 // Check if the timer for the calling thread has expired. When no 52 // Check if the timer for the calling thread has expired. When no
33 // timer exists for the calling thread, create one. 53 // timer exists for the calling thread, create one.
34 bool Expired() { 54 bool Expired() {
35 const base::TimeDelta kRetryTime = base::TimeDelta::FromSeconds(1); 55 const base::TimeDelta kRetryTime = base::TimeDelta::FromSeconds(1);
56 struct DnsReloadTimer::LocalState* local_state = GetLocalState();
36 base::TimeTicks now = base::TimeTicks::Now(); 57 base::TimeTicks now = base::TimeTicks::Now();
37 base::TimeTicks* timer_ptr =
38 static_cast<base::TimeTicks*>(tls_index_.Get());
39 58
40 if (!timer_ptr) { 59 if (now - local_state->timer > kRetryTime) {
41 timer_ptr = new base::TimeTicks(); 60 local_state->timer = now;
42 *timer_ptr = base::TimeTicks::Now();
43 tls_index_.Set(timer_ptr);
44 // Return true to reload dns info on the first call for each thread.
45 return true;
46 } else if (now - *timer_ptr > kRetryTime) {
47 *timer_ptr = now;
48 return true; 61 return true;
49 } else { 62 } else {
50 return false; 63 return false;
51 } 64 }
52 } 65 }
53 66
54 // Free the allocated timer. 67 // Free the allocated LocalState.
55 static void SlotReturnFunction(void* data) { 68 static void SlotReturnFunction(void* data) {
56 base::TimeTicks* tls_data = static_cast<base::TimeTicks*>(data); 69 DnsReloadTimer::LocalState* tls_data =
70 static_cast<DnsReloadTimer::LocalState*>(data);
57 delete tls_data; 71 delete tls_data;
58 } 72 }
59 73
74 // Installs FileWatcher for _PATH_RESCONF (i.e. /etc/resolv.conf).
75 // Must be run on file thread.
76 void InitResolvConfWatcher();
77
60 private: 78 private:
61 friend struct base::DefaultLazyInstanceTraits<DnsReloadTimer>; 79 friend struct base::DefaultLazyInstanceTraits<DnsReloadTimer>;
62 80
63 DnsReloadTimer() { 81 // One LocalState struct is kept in TLS.
82 struct LocalState {
83 base::TimeTicks timer; // Reload timer, used to rate-limit reloads.
84 int resolv_conf_generation; // resolv.conf generation known to this thread.
85 };
86
87 class ResolvConfWatcherDelegate : public FilePathWatcher::Delegate {
88 public:
89 explicit ResolvConfWatcherDelegate(int* conf_generation, Lock* lock)
90 : conf_generation_(conf_generation), lock_(lock) {
91 }
92
93 virtual void OnFilePathChanged(const FilePath& path) {
94 AutoLock l(*lock_);
95 (*conf_generation_)++;
96 LOG(INFO) << _PATH_RESCONF << " updated, new generation: "
97 << *conf_generation_;
98 }
99 private:
100 int* conf_generation_;
101 Lock* lock_;
102
103 DISALLOW_COPY_AND_ASSIGN(ResolvConfWatcherDelegate);
104 };
105
106 // Generation starts at 1 so that all threads reload resolv.conf
107 // on first invocation.
108 DnsReloadTimer() : resolv_conf_generation_(1) {
64 // During testing the DnsReloadTimer Singleton may be created and destroyed 109 // During testing the DnsReloadTimer Singleton may be created and destroyed
65 // multiple times. Initialize the ThreadLocalStorage slot only once. 110 // multiple times. Initialize the ThreadLocalStorage slot only once.
66 if (!tls_index_.initialized()) 111 if (!tls_index_.initialized())
67 tls_index_.Initialize(SlotReturnFunction); 112 tls_index_.Initialize(SlotReturnFunction);
68 } 113 }
69 114
70 ~DnsReloadTimer() { 115 ~DnsReloadTimer() {
71 } 116 }
72 117
118 DnsReloadTimer::LocalState* GetLocalState();
119
120 Lock lock_; // Protects resolv_conf_generation_
121 int resolv_conf_generation_;
122
123 scoped_ptr<FilePathWatcher> resolv_conf_watcher_;
124 scoped_ptr<ResolvConfWatcherDelegate> resolv_conf_watcher_delegate_;
125
73 // We use thread local storage to identify which base::TimeTicks to 126 // We use thread local storage to identify which base::TimeTicks to
74 // interact with. 127 // interact with.
75 static ThreadLocalStorage::Slot tls_index_ ; 128 static ThreadLocalStorage::Slot tls_index_;
76 129
77 DISALLOW_COPY_AND_ASSIGN(DnsReloadTimer); 130 DISALLOW_COPY_AND_ASSIGN(DnsReloadTimer);
78 }; 131 };
79 132
133 void DnsReloadTimer::InitResolvConfWatcher() {
134 resolv_conf_watcher_.reset(new FilePathWatcher());
135 resolv_conf_watcher_delegate_.reset(
136 new ResolvConfWatcherDelegate(&resolv_conf_generation_, &lock_));
137 if (!resolv_conf_watcher_->Watch(
138 FilePath(FilePath::StringType(_PATH_RESCONF)),
139 resolv_conf_watcher_delegate_.get())) {
140 LOG(WARNING) << "Failed to install watcher for " << _PATH_RESCONF;
141 // We failed to install watcher, for whatever reason. Free the watcher.
142 resolv_conf_watcher_.reset();
143 resolv_conf_watcher_delegate_.reset();
144 } else {
145 LOG(INFO) << "Installed watcher for " << _PATH_RESCONF;
146 }
147 }
148
149 DnsReloadTimer::LocalState* DnsReloadTimer::GetLocalState() {
150 DnsReloadTimer::LocalState* state =
151 static_cast<DnsReloadTimer::LocalState*>(tls_index_.Get());
152 if (!state) {
153 state = new DnsReloadTimer::LocalState();
154 state->timer = base::TimeTicks::Now();
155 state->resolv_conf_generation = 0;
156 tls_index_.Set(state);
157 }
158 return state;
159 }
160
80 // A TLS slot to the TimeTicks for the current thread. 161 // A TLS slot to the TimeTicks for the current thread.
81 // static 162 // static
82 ThreadLocalStorage::Slot DnsReloadTimer::tls_index_(base::LINKER_INITIALIZED); 163 ThreadLocalStorage::Slot DnsReloadTimer::tls_index_(base::LINKER_INITIALIZED);
83 164
84 base::LazyInstance<DnsReloadTimer, 165 typedef base::LazyInstance<DnsReloadTimer,
85 base::LeakyLazyInstanceTraits<DnsReloadTimer> > 166 base::LeakyLazyInstanceTraits<DnsReloadTimer> >
86 g_dns_reload_timer(base::LINKER_INITIALIZED); 167 DnsReloadTimerInstance;
168 DnsReloadTimerInstance g_dns_reload_timer(base::LINKER_INITIALIZED);
87 169
88 } // namespace 170 // This task is run on file thread
171 // and calls DnsReloadTimer::InitResolvConfWatcher().
172 class InitResolvConfWatcherTask : public Task {
173 public:
174 InitResolvConfWatcherTask(DnsReloadTimerInstance* dns_reload_timer_instance)
175 : dns_reload_timer_instance_(dns_reload_timer_instance) {
176 }
89 177
90 namespace net { 178 virtual void Run() {
179 dns_reload_timer_instance_->Pointer()->InitResolvConfWatcher();
180 }
181
182 private:
183 DnsReloadTimerInstance* dns_reload_timer_instance_;
184
185 DISALLOW_COPY_AND_ASSIGN(InitResolvConfWatcherTask);
186 };
91 187
92 bool DnsReloadTimerHasExpired() { 188 bool DnsReloadTimerHasExpired() {
93 DnsReloadTimer* dns_timer = g_dns_reload_timer.Pointer(); 189 DnsReloadTimer* dns_timer = g_dns_reload_timer.Pointer();
94 return dns_timer->Expired(); 190 return dns_timer->Expired();
95 } 191 }
96 192
193 bool ResolvConfUpdated() {
194 DnsReloadTimer* dns_timer = g_dns_reload_timer.Pointer();
195 return dns_timer->ResolvConfUpdated();
196 }
197
198 void InitResolvConfWatcher(base::Thread* file_thread) {
199 // FileWatcher must be used on the file thread.
200 // Additionally, we delay initialization - resolv.conf is read on first use
201 // anyway, this watcher will most likely be useful later.
202 file_thread->message_loop()->PostDelayedTask(
203 FROM_HERE, new InitResolvConfWatcherTask(&g_dns_reload_timer), 5000);
204 }
205
97 } // namespace net 206 } // namespace net
98 207
99 #endif // defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) 208 #endif // WATCH_RESOLV_CONF
OLDNEW
« no previous file with comments | « net/base/dns_reload_timer.h ('k') | net/base/dnsrr_resolver.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698