shill: Add connection to device

Also in the process, do a few bits like setting up a run path in
the manager so it can initialize the resolver output path.

BUG=chromium-os:19095
TEST=Ran unit tests (for regression), tested that DNS and routes applied
for Ethernet on real system.

Change-Id: If505200643efa6c3152f6e61db3b91a04e739c18
Reviewed-on: http://gerrit.chromium.org/gerrit/6087
Reviewed-by: Paul Stewart <pstew@chromium.org>
Tested-by: Paul Stewart <pstew@chromium.org>
diff --git a/connection.cc b/connection.cc
index 5ca7d86..d788020 100644
--- a/connection.cc
+++ b/connection.cc
@@ -35,6 +35,10 @@
 
 void Connection::UpdateFromIPConfig(const IPConfigRefPtr &config) {
   VLOG(2) << __func__;
+
+  // TODO(pstew): Create a centralized resource (perhaps in DeviceInfo?) to
+  // keep apply and keep track of addresses associated with an interface.
+  // Use this instead of directly setting the address over RTNL.
   rtnl_handler_->AddInterfaceAddress(interface_index_, *config);
 
   uint32 metric = is_default_ ? kDefaultMetric : kNonDefaultMetric;
diff --git a/device.cc b/device.cc
index 04d0a3c..851c922 100644
--- a/device.cc
+++ b/device.cc
@@ -15,6 +15,7 @@
 #include <base/stringprintf.h>
 #include <chromeos/dbus/service_constants.h>
 
+#include "shill/connection.h"
 #include "shill/control_interface.h"
 #include "shill/device_dbus_adaptor.h"
 #include "shill/dhcp_config.h"
@@ -167,11 +168,15 @@
 
 void Device::DestroyIPConfig() {
   if (ipconfig_.get()) {
+    // TODO(pstew): Instead we should do this in DestroyConnection(), which
+    // should have a facility at its disposal that returns all addresses
+    // assigned to the interface.
     RTNLHandler::GetInstance()->RemoveInterfaceAddress(interface_index_,
                                                        *ipconfig_);
     ipconfig_->ReleaseIP();
     ipconfig_ = NULL;
   }
+  DestroyConnection();
 }
 
 bool Device::AcquireDHCPConfig() {
@@ -192,15 +197,29 @@
 
 void Device::IPConfigUpdatedCallback(const IPConfigRefPtr &ipconfig,
                                      bool success) {
-  // TODO(petkov): Use DeviceInfo to configure IP, etc. -- maybe through
-  // ConfigIP? Also, maybe allow forwarding the callback to interested listeners
-  // (e.g., the Manager).
+  VLOG(2) << __func__ << " " << " success: " << success;
   if (success) {
-      RTNLHandler::GetInstance()->AddInterfaceAddress(interface_index_,
-                                                      *ipconfig);
+    CreateConnection();
+    connection_->UpdateFromIPConfig(ipconfig);
+  } else {
+    // TODO(pstew): This logic gets more complex when multiple IPConfig types
+    // are run in parallel (e.g. DHCP and DHCP6)
+    DestroyConnection();
   }
 }
 
+void Device::CreateConnection() {
+  VLOG(2) << __func__;
+  if (!connection_.get()) {
+    connection_ = new Connection(interface_index_, link_name_);
+  }
+}
+
+void Device::DestroyConnection() {
+  VLOG(2) << __func__;
+  connection_ = NULL;
+}
+
 string Device::SerializeIPConfigsForStorage() {
   return StringPrintf("%s:%s",
                       ipconfig_->GetStorageIdentifier().c_str(),
diff --git a/device.h b/device.h
index 6998f39..27fee74 100644
--- a/device.h
+++ b/device.h
@@ -66,6 +66,7 @@
 
   const std::string &link_name() const { return link_name_; }
   int interface_index() const { return interface_index_; }
+  const ConnectionRefPtr &connection() const { return connection_; }
 
   const std::string &FriendlyName() const;
 
@@ -97,6 +98,12 @@
   // request was successfully sent.
   bool AcquireDHCPConfig();
 
+  // Maintain connection state (Routes, IP Addresses and DNS) in the OS.
+  void CreateConnection();
+
+  // Remove connection state
+  void DestroyConnection();
+
   void HelpRegisterDerivedStrings(const std::string &name,
                                   Strings(Device::*get)(void),
                                   bool(Device::*set)(const Strings&));
@@ -117,6 +124,7 @@
   EventDispatcher *dispatcher_;
   Manager *manager_;
   IPConfigRefPtr ipconfig_;
+  ConnectionRefPtr connection_;
 
  private:
   friend class DeviceAdaptorInterface;
diff --git a/manager.cc b/manager.cc
index 9395269..43e9bf1 100644
--- a/manager.cc
+++ b/manager.cc
@@ -10,6 +10,7 @@
 #include <string>
 #include <vector>
 
+#include <base/file_util.h>
 #include <base/logging.h>
 #include <base/memory/ref_counted.h>
 #include <chromeos/dbus/service_constants.h>
@@ -24,6 +25,7 @@
 #include "shill/error.h"
 #include "shill/profile.h"
 #include "shill/property_accessor.h"
+#include "shill/resolver.h"
 #include "shill/shill_event.h"
 #include "shill/service.h"
 
@@ -31,10 +33,15 @@
 using std::vector;
 
 namespace shill {
+
+// static
+const char Manager::kDefaultRunDirectory[] = "/var/run/shill";
+
 Manager::Manager(ControlInterface *control_interface,
                  EventDispatcher *dispatcher,
                  GLib *glib)
-  : adaptor_(control_interface->CreateManagerAdaptor(this)),
+  : run_path_(FilePath(kDefaultRunDirectory)),
+    adaptor_(control_interface->CreateManagerAdaptor(this)),
     device_info_(control_interface, dispatcher, this),
     modem_info_(control_interface, dispatcher, this, glib),
     running_(false),
@@ -96,6 +103,9 @@
 
 void Manager::Start() {
   LOG(INFO) << "Manager started.";
+
+  CHECK(file_util::CreateDirectory(run_path_));
+  Resolver::GetInstance()->set_path(run_path_.Append("resolv.conf"));
   running_ = true;
   adaptor_->UpdateRunning();
   device_info_.Start();
diff --git a/manager.h b/manager.h
index 154e51c..5f6f925 100644
--- a/manager.h
+++ b/manager.h
@@ -8,6 +8,7 @@
 #include <string>
 #include <vector>
 
+#include <base/file_path.h>
 #include <base/memory/ref_counted.h>
 #include <base/memory/scoped_ptr.h>
 #include <chromeos/dbus/service_constants.h>
@@ -70,6 +71,8 @@
  private:
   friend class ManagerAdaptorInterface;
 
+  static const char kDefaultRunDirectory[];
+
   std::string CalculateState();
   std::vector<std::string> AvailableTechnologies();
   std::vector<std::string> ConnectedTechnologies();
@@ -87,6 +90,7 @@
                                   Strings(Manager::*get)(void),
                                   bool(Manager::*set)(const Strings&));
 
+  FilePath run_path_;
   scoped_ptr<ManagerAdaptorInterface> adaptor_;
   DeviceInfo device_info_;
   ModemInfo modem_info_;
diff --git a/resolver.cc b/resolver.cc
index bb7105b..d0d4d7a 100644
--- a/resolver.cc
+++ b/resolver.cc
@@ -31,6 +31,8 @@
 }
 
 bool Resolver::SetDNSFromIPConfig(const IPConfigRefPtr &ipconfig) {
+  VLOG(2) << __func__;
+
   CHECK(!path_.empty());
 
   const IPConfig::Properties &props = ipconfig->properties();
@@ -40,7 +42,10 @@
 
 bool Resolver::SetDNSFromLists(const std::vector<std::string> &dns_servers,
                                const std::vector<std::string> &domain_search) {
+  VLOG(2) << __func__;
+
   if (dns_servers.empty() && domain_search.empty()) {
+    VLOG(2) << "DNS list is empty";
     return ClearDNS();
   }
 
@@ -59,12 +64,16 @@
   lines.push_back("");
 
   string contents = JoinString(lines, '\n');
+
+  VLOG(2) << "Writing DNS out to " << path_.value();
   int count = file_util::WriteFile(path_, contents.c_str(), contents.size());
 
   return count == static_cast<int>(contents.size());
 }
 
 bool Resolver::ClearDNS() {
+  VLOG(2) << __func__;
+
   CHECK(!path_.empty());
 
   return file_util::Delete(path_, false);
diff --git a/routing_table.cc b/routing_table.cc
index dc78f4b..25b9b8f 100644
--- a/routing_table.cc
+++ b/routing_table.cc
@@ -285,7 +285,7 @@
   RTNLMessage msg(
       RTNLMessage::kMessageTypeRoute,
       mode,
-      flags,
+      NLM_F_REQUEST | flags,
       0,
       0,
       0,
diff --git a/routing_table_unittest.cc b/routing_table_unittest.cc
index 39e7d1b..066c411 100644
--- a/routing_table_unittest.cc
+++ b/routing_table_unittest.cc
@@ -95,7 +95,7 @@
   return
     msg.type() == RTNLMessage::kMessageTypeRoute &&
     msg.family() == entry.gateway.family() &&
-    msg.flags() == flags &&
+    msg.flags() == (NLM_F_REQUEST | flags) &&
     status.table == RT_TABLE_MAIN &&
     status.protocol == RTPROT_BOOT &&
     status.scope == entry.scope &&