[shill] Add getting/setting for ipconfig properties

BUG=chromium-os:17261
TEST=unit tests

Change-Id: I96aed7c979c7913c568d00ce408a662898969d76
Reviewed-on: http://gerrit.chromium.org/gerrit/3583
Tested-by: Chris Masone <cmasone@chromium.org>
Reviewed-by: Darin Petkov <petkov@chromium.org>
diff --git a/dbus_adaptor.cc b/dbus_adaptor.cc
index b6dcd28..74c7545 100644
--- a/dbus_adaptor.cc
+++ b/dbus_adaptor.cc
@@ -67,7 +67,7 @@
   else
     NOTREACHED();
 
-  if (!set)
+  if (!set && error)
     e.ToDBusError(error);
   return set;
 }
diff --git a/dhcp_config.cc b/dhcp_config.cc
index 8e3bf52..4098be6 100644
--- a/dhcp_config.cc
+++ b/dhcp_config.cc
@@ -9,6 +9,7 @@
 #include <base/file_util.h>
 #include <base/logging.h>
 #include <base/stringprintf.h>
+#include <chromeos/dbus/service_constants.h>
 
 #include "shill/dhcpcd_proxy.h"
 #include "shill/dhcp_provider.h"
@@ -46,6 +47,7 @@
       child_watch_tag_(0),
       root_("/"),
       glib_(glib) {
+  RegisterConstString(flimflam::kAddressProperty, &(properties().address));
   VLOG(2) << __func__ << ": " << device_name;
 }
 
@@ -188,6 +190,7 @@
 bool DHCPConfig::ParseConfiguration(const Configuration& configuration,
                                     IPConfig::Properties *properties) {
   VLOG(2) << __func__;
+  properties->method = flimflam::kTypeDHCP;
   properties->address_family = IPConfig::kAddressFamilyIPv4;
   for (Configuration::const_iterator it = configuration.begin();
        it != configuration.end(); ++it) {
diff --git a/dhcp_config_unittest.cc b/dhcp_config_unittest.cc
index 44d638d..4d736f6 100644
--- a/dhcp_config_unittest.cc
+++ b/dhcp_config_unittest.cc
@@ -5,11 +5,14 @@
 #include <base/file_util.h>
 #include <base/memory/scoped_temp_dir.h>
 #include <base/stringprintf.h>
+#include <chromeos/dbus/service_constants.h>
 
+#include "shill/dbus_adaptor.h"
 #include "shill/dhcp_config.h"
 #include "shill/dhcp_provider.h"
 #include "shill/mock_dhcp_proxy.h"
 #include "shill/mock_glib.h"
+#include "shill/property_store_unittest.h"
 
 using std::string;
 using std::vector;
@@ -24,7 +27,7 @@
 const char kDeviceName[] = "testdevicename";
 }  // namespace {}
 
-class DHCPConfigTest : public Test {
+class DHCPConfigTest : public PropertyStoreTest {
  public:
   DHCPConfigTest()
       : proxy_(new MockDHCPProxy()),
@@ -282,4 +285,18 @@
   EXPECT_CALL(glib_, SpawnClosePID(kPID)).Times(1);  // Invoked by destuctor.
 }
 
+TEST_F(DHCPConfigTest, Dispatch) {
+  EXPECT_TRUE(DBusAdaptor::DispatchOnType(config_.get(),
+                                          flimflam::kMtuProperty,
+                                          PropertyStoreTest::kInt32V,
+                                          NULL));
+  ::DBus::Error error;
+  // Ensure that an attempt to write a R/O property returns InvalidArgs error.
+  EXPECT_FALSE(DBusAdaptor::DispatchOnType(config_.get(),
+                                           flimflam::kAddressProperty,
+                                           PropertyStoreTest::kStringV,
+                                           &error));
+  EXPECT_EQ(invalid_args_, error.name());
+}
+
 }  // namespace shill
diff --git a/ipconfig.cc b/ipconfig.cc
index a1d4182..b8c55d7 100644
--- a/ipconfig.cc
+++ b/ipconfig.cc
@@ -5,14 +5,31 @@
 #include "shill/ipconfig.h"
 
 #include <base/logging.h>
+#include <base/stl_util-inl.h>
+#include <chromeos/dbus/service_constants.h>
 
 #include "shill/adaptor_interfaces.h"
+#include "shill/error.h"
 
 using std::string;
 
 namespace shill {
 
 IPConfig::IPConfig(const std::string &device_name) : device_name_(device_name) {
+  // Address might be R/O or not, depending on the type of IPconfig, so
+  // we'll leave this up to the subclasses.
+  // Register(Const?)String(flimflam::kAddressProperty, &properties_.address);
+  RegisterString(flimflam::kBroadcastProperty, &properties_.broadcast_address);
+  RegisterString(flimflam::kDomainNameProperty, &properties_.domain_name);
+  RegisterString(flimflam::kGatewayProperty, &properties_.gateway);
+  RegisterConstString(flimflam::kMethodProperty, &properties_.method);
+  RegisterInt32(flimflam::kMtuProperty, &properties_.mtu);
+  RegisterStrings(flimflam::kNameServersProperty, &properties_.dns_servers);
+  RegisterString(flimflam::kPeerAddressProperty, &properties_.peer_address);
+  RegisterInt32(flimflam::kPrefixlenProperty, &properties_.subnet_cidr);
+  // TODO(cmasone): Does anyone use this?
+  // RegisterStrings(flimflam::kSearchDomainsProperty,
+  //                 &properties_.domain_search);
   VLOG(2) << __func__ << " device: " << device_name;
 }
 
@@ -36,6 +53,28 @@
   return false;
 }
 
+bool IPConfig::SetInt32Property(const std::string& name,
+                                int32 value,
+                                Error *error) {
+  VLOG(2) << "Setting " << name << " as an int32.";
+  bool set = (ContainsKey(int32_properties_, name) &&
+              int32_properties_[name]->Set(value));
+  if (!set && error)
+    error->Populate(Error::kInvalidArguments, name + " is not a R/W int32.");
+  return set;
+}
+
+bool IPConfig::SetStringProperty(const string& name,
+                                 const string& value,
+                                 Error *error) {
+  VLOG(2) << "Setting " << name << " as a string.";
+  bool set = (ContainsKey(string_properties_, name) &&
+              string_properties_[name]->Set(value));
+  if (!set && error)
+    error->Populate(Error::kInvalidArguments, name + " is not a R/W string.");
+  return set;
+}
+
 void IPConfig::UpdateProperties(const Properties &properties, bool success) {
   properties_ = properties;
   if (update_callback_.get()) {
diff --git a/ipconfig.h b/ipconfig.h
index 08915e3..f4f634d 100644
--- a/ipconfig.h
+++ b/ipconfig.h
@@ -38,13 +38,15 @@
 
     AddressFamily address_family;
     std::string address;
-    int subnet_cidr;
+    int32 subnet_cidr;
     std::string broadcast_address;
-    std::string gateway;
     std::vector<std::string> dns_servers;
     std::string domain_name;
     std::vector<std::string> domain_search;
-    int mtu;
+    std::string gateway;
+    std::string method;
+    std::string peer_address;
+    int32 mtu;
   };
 
   explicit IPConfig(const std::string &device_name);
@@ -72,6 +74,14 @@
   virtual bool RenewIP();
   virtual bool ReleaseIP();
 
+  // Implementation of PropertyStore
+  virtual bool SetInt32Property(const std::string& name,
+                                int32 value,
+                                Error *error);
+  virtual bool SetStringProperty(const std::string &name,
+                                 const std::string &value,
+                                 Error *error);
+
  protected:
   // Updates the IP configuration properties and notifies registered listeners
   // about the event. |success| is set to false if the IP configuration failed.
diff --git a/property_store.cc b/property_store.cc
index c2ceac4..dbf51ff 100644
--- a/property_store.cc
+++ b/property_store.cc
@@ -163,16 +163,20 @@
       StringAccessor(new ConstPropertyAccessor<string>(prop));
 }
 
-void PropertyStore::RegisterStringmap(const string &name,
-                                      map<string, string> *prop) {
+void PropertyStore::RegisterStringmap(const string &name, Stringmap *prop) {
   stringmap_properties_[name] =
-      StringmapAccessor(new PropertyAccessor<map<string, string> >(prop));
+      StringmapAccessor(new PropertyAccessor<Stringmap>(prop));
 }
 
 void PropertyStore::RegisterConstStringmap(const string &name,
-                                           const map<string, string> *prop) {
+                                           const Stringmap *prop) {
   stringmap_properties_[name] =
-      StringmapAccessor(new ConstPropertyAccessor<map<string, string> >(prop));
+      StringmapAccessor(new ConstPropertyAccessor<Stringmap>(prop));
+}
+
+void PropertyStore::RegisterStrings(const string &name, Strings *prop) {
+  strings_properties_[name] =
+      StringsAccessor(new PropertyAccessor<Strings>(prop));
 }
 
 void PropertyStore::RegisterConstUint8(const string &name, const uint8 *prop) {
diff --git a/property_store.h b/property_store.h
index 42f3cd4..485f429 100644
--- a/property_store.h
+++ b/property_store.h
@@ -89,10 +89,9 @@
   void RegisterConstInt32(const std::string &name, const int32 *prop);
   void RegisterString(const std::string &name, std::string *prop);
   void RegisterConstString(const std::string &name, const std::string *prop);
-  void RegisterStringmap(const std::string &name,
-                         std::map<std::string, std::string> *prop);
-  void RegisterConstStringmap(const std::string &name,
-                              const std::map<std::string, std::string> *prop);
+  void RegisterStringmap(const std::string &name, Stringmap *prop);
+  void RegisterConstStringmap(const std::string &name, const Stringmap *prop);
+  void RegisterStrings(const std::string &name, Strings *prop);
   void RegisterConstUint8(const std::string &name, const uint8 *prop);
   void RegisterUint16(const std::string &name, uint16 *prop);
   void RegisterConstUint16(const std::string &name, const uint16 *prop);
diff --git a/service.cc b/service.cc
index 4856dbf..1fe64ca 100644
--- a/service.cc
+++ b/service.cc
@@ -74,18 +74,14 @@
   RegisterDerivedString(flimflam::kProfileProperty,
                         &Service::GetProfileRpcId,
                         NULL);
+  // RegisterDerivedString(flimflam::kProfileProperty, &Getter, &Setter);
+  // TODO(cmasone): Create VPN Service with this property
+  // RegisterConstStringmap(flimflam::kProviderProperty, &provider_);
   RegisterString(flimflam::kProxyConfigProperty, &proxy_config_);
   RegisterBool(flimflam::kSaveCredentialsProperty, &save_credentials_);
   RegisterDerivedString(flimflam::kStateProperty,
                         &Service::CalculateState,
                         NULL);
-
-  // TODO(cmasone): Create VPN Service with this property
-  // RegisterConstStringmap(flimflam::kProviderProperty, &provider_);
-
-  // TODO(cmasone): Add support for R/O properties that return DBus object paths
-  // flimflam::kDeviceProperty, flimflam::kProfileProperty
-
   VLOG(2) << "Service initialized.";
 }