Index: net/dns/dns_config_service_posix.cc |
diff --git a/net/dns/dns_config_service_posix.cc b/net/dns/dns_config_service_posix.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..29973d73cd141c37f7b31f3121ccb1d78174998e |
--- /dev/null |
+++ b/net/dns/dns_config_service_posix.cc |
@@ -0,0 +1,141 @@ |
+// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include <resolv.h> |
+ |
+#include "base/compiler_specific.h" |
+#include "base/file_path.h" |
+#include "base/files/file_path_watcher.h" |
+#include "base/memory/ref_counted.h" |
+#include "base/message_loop.h" |
+#include "base/message_loop_proxy.h" |
+#include "base/scoped_ptr.h" |
+#include "base/task.h" |
+#include "base/threading/worker_pool.h" |
+#include "net/base/ip_endpoint.h" |
+#include "net/base/net_util.h" |
+#include "net/dns/dns_config_service.h" |
+ |
+namespace net { |
+ |
+using base::files::FilePathWatcher; |
+ |
+class DnsConfigReaderPosix : public DnsConfigReader { |
+ public: |
+ bool Read(DnsConfig* dns_config) OVERRIDE { |
+ // res_ninit is available on Linux (glibc 2+), Mac OS X, and Android. |
+ // TODO(szym): res_ninit is not thread-safe on BSD? |
+ struct __res_state res; |
+ 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
|
+ return false; |
+ |
+ dns_config->nameservers.clear(); |
+ for (int i = 0; i < res.nscount; ++i) { |
+ IPEndPoint ipe; |
+ if (ipe.FromSockAddr( |
+ reinterpret_cast<struct sockaddr*>(&res.nsaddr_list[i]), |
+ sizeof res.nsaddr_list[i])) |
+ dns_config->nameservers.push_back(ipe); |
+ } |
+ |
+ dns_config->search.clear(); |
+ for (int i = 0; (i < MAXDNSRCH) && *res.dnsrch[i]; ++i) { |
+ dns_config->search.push_back(std::string(res.dnsrch[i])); |
+ } |
+ |
+ dns_config->domain = res.defdname; // use only if |search| is empty |
+ dns_config->ndots = res.ndots; |
+ dns_config->timeout = res.retrans; |
+ dns_config->attempts = res.retry; |
+ dns_config->rotate = res.options & RES_ROTATE; |
+ dns_config->edns0 = res.options & RES_USE_EDNS0; |
+ return true; |
+ } |
+}; |
+ |
+// NOTE: this makes it ref counted thread-safe |
+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
|
+ public FilePathWatcher::Delegate { |
+ public: |
+ DnsConfigServicePosix() {} |
+ virtual ~DnsConfigServicePosix() {} |
+ virtual bool Watch(DnsConfigService::Delegate* delegate) OVERRIDE; |
+ |
+ private: |
+ // TODO(szym): convert Task -> Closure? |
+ |
+ // called on the worker thread |
+ // reads DnsConfig and posts OnResultAvailable to |message_loop| |
+ void ReadConfig(scoped_refptr<base::MessageLoopProxy> message_loop); |
+ |
+ // called on the delegate's thread |
+ // communicates result from DnsConfigReader to the delegate |
+ void OnResultAvailable(const DnsConfig &config, bool error); |
+ |
+ // FilePathWatcher::Delegate interface |
+ virtual void OnFilePathChanged(const FilePath& path) OVERRIDE; |
+ |
+ virtual void OnFilePathError(const FilePath& path) OVERRIDE { |
+ delegate_->OnConfigError(); |
+ } |
+ |
+ // message loop for the thread on which Watch is called |
+ // this should be an IO loop |
+ scoped_refptr<base::MessageLoopProxy> message_loop_; |
+ scoped_ptr<FilePathWatcher> resolv_file_watcher_; |
+ DnsConfigService::Delegate* delegate_; |
+ DnsConfig last_config_; |
+}; |
+ |
+bool DnsConfigServicePosix::Watch(DnsConfigService::Delegate* delegate) { |
+ DCHECK(!resolv_file_watcher_.get()); |
+ DCHECK(MessageLoopForIO::current()); |
+ |
cbentzel
2011/08/01 19:52:26
Should probably DCHECK that delegate_ is NULL.
szym
2011/08/01 20:22:01
Done.
|
+ message_loop_ = base::MessageLoopProxy::CreateForCurrentThread(); |
+ delegate_ = delegate; |
+ |
+ // start FilePathWatcher |
+ resolv_file_watcher_.reset(new FilePathWatcher()); |
+ return resolv_file_watcher_->Watch( |
+ FilePath(FILE_PATH_LITERAL("/etc/resolv.conf")), |
+ this |
+ ); |
+} |
+ |
+void DnsConfigServicePosix::ReadConfig( |
+ scoped_refptr<base::MessageLoopProxy> message_loop) { |
+ // on the WorkerPool |
+ DnsConfigReaderPosix reader; |
+ DnsConfig config; |
+ bool error = reader.Read(&config); |
+ message_loop->PostTask(FROM_HERE, NewRunnableMethod( |
+ this, &DnsConfigServicePosix::OnResultAvailable, config, error)); |
+} |
+ |
+void DnsConfigServicePosix::OnResultAvailable(const DnsConfig &config, |
+ bool error) { |
+ if (error) { |
+ delegate_->OnConfigError(); |
+ } else if (config != last_config_) { |
+ delegate_->OnConfigChanged(config); |
+ last_config_ = config; |
+ } |
+} |
+ |
+// FilePathWatcher::Delegate interface |
+void DnsConfigServicePosix::OnFilePathChanged(const FilePath& path) { |
+ DCHECK(MessageLoopForIO::current()); |
+ // we should be on the same thread that called Watch so delegate should |
+ // still exist? |
+ if (!base::WorkerPool::PostTask(FROM_HERE, NewRunnableMethod( |
+ this, &DnsConfigServicePosix::ReadConfig, message_loop_), false)) { |
+ delegate_->OnConfigError(); |
+ } |
+} |
+ |
+DnsConfigService* DnsConfigService::CreateSystemService() { |
+ return new DnsConfigServicePosix(); |
+} |
+} |
+ |