1//
2// Copyright (C) 2015 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include "shill/dhcp_properties.h"
18
19#include <string>
20
21#include <base/macros.h>
22#if defined(__ANDROID__)
23#include <dbus/service_constants.h>
24#else
25#include <chromeos/dbus/service_constants.h>
26#endif  // __ANDROID__
27
28#include "shill/key_value_store.h"
29#include "shill/logging.h"
30#include "shill/property_accessor.h"
31#include "shill/property_store.h"
32#include "shill/store_interface.h"
33
34using std::string;
35
36namespace shill {
37
38namespace Logging {
39static auto kModuleLogScope = ScopeLogger::kDHCP;
40static string ObjectID(const DhcpProperties* d) { return "(dhcp_properties)"; }
41}
42
43namespace {
44
45// Prefix used for DhcpProperties in the PropertyStore.
46const char kStoragePrefix[] = "DHCPProperty.";
47
48const char* kPropertyNames[] = {DhcpProperties::kHostnameProperty,
49                                DhcpProperties::kVendorClassProperty};
50
51std::string GetFullPropertyName(const std::string& property_name) {
52  return kStoragePrefix + property_name;
53}
54
55}  // namespace
56
57const char DhcpProperties::kHostnameProperty[] = "Hostname";
58const char DhcpProperties::kVendorClassProperty[] = "VendorClass";
59
60DhcpProperties::DhcpProperties() {}
61
62DhcpProperties::~DhcpProperties() {}
63
64void DhcpProperties::InitPropertyStore(PropertyStore* store) {
65  SLOG(this, 2) << __func__;
66  int i = 0;
67  for (const auto& name : kPropertyNames) {
68    store->RegisterDerivedString(
69        GetFullPropertyName(name),
70        StringAccessor(
71            new CustomMappedAccessor<DhcpProperties, string, size_t>(
72                this,
73                &DhcpProperties::ClearMappedStringProperty,
74                &DhcpProperties::GetMappedStringProperty,
75                &DhcpProperties::SetMappedStringProperty,
76                i)));
77    ++i;
78  }
79}
80
81void DhcpProperties::Load(StoreInterface* storage, const string& id) {
82  SLOG(this, 2) << __func__;
83  properties_.Clear();
84  for (const auto& name : kPropertyNames) {
85    string property_value;
86    if (storage->GetString(id, GetFullPropertyName(name), &property_value)) {
87      properties_.SetString(name, property_value);
88      SLOG(this, 3) << "found DhcpProperty: setting " << name;
89    }
90  }
91}
92
93void DhcpProperties::Save(StoreInterface* storage, const string& id) const {
94  SLOG(this, 2) << __func__;
95  for (const auto& name : kPropertyNames) {
96    string property_value;
97    if (properties_.Contains(name)) {
98      // The property is in the property store and it may have a setting or be
99      // set to an empty string.  This setting should be saved to the profile.
100      property_value = properties_.GetString(name);
101      storage->SetString(id, GetFullPropertyName(name), property_value);
102      SLOG(this, 3) << "saved " << GetFullPropertyName(name);
103    } else {
104      // The property is not found and should be deleted from the property store
105      // if it was there.
106      storage->DeleteKey(id, GetFullPropertyName(name));
107    }
108  }
109}
110
111std::unique_ptr<DhcpProperties> DhcpProperties::Combine(
112    const DhcpProperties& base, const DhcpProperties& to_merge) {
113  SLOG(nullptr, 2) << __func__;
114  std::unique_ptr<DhcpProperties> to_return(new DhcpProperties());
115  to_return->properties_ = base.properties_;
116  for (const auto& it : to_merge.properties_.properties()) {
117    const string& name = it.first;
118    const brillo::Any& value = it.second;
119    to_return->properties_.Set(name, value);
120  }
121  return to_return;
122}
123
124bool DhcpProperties::GetValueForProperty(const string& name,
125                                         string* value) const {
126  if (properties_.ContainsString(name)) {
127    *value = properties_.GetString(name);
128    return true;
129  }
130  return false;
131}
132
133void DhcpProperties::ClearMappedStringProperty(const size_t& index,
134                                               Error* error) {
135  CHECK(index < arraysize(kPropertyNames));
136  if (properties_.ContainsString(kPropertyNames[index])) {
137    properties_.RemoveString(kPropertyNames[index]);
138  } else {
139    error->Populate(Error::kNotFound, "Property is not set");
140  }
141}
142
143string DhcpProperties::GetMappedStringProperty(const size_t& index,
144                                               Error* error) {
145  CHECK(index < arraysize(kPropertyNames));
146  if (properties_.ContainsString(kPropertyNames[index])) {
147    return properties_.GetString(kPropertyNames[index]);
148  }
149  error->Populate(Error::kNotFound, "Property is not set");
150  return string();
151}
152
153bool DhcpProperties::SetMappedStringProperty(
154    const size_t& index, const string& value, Error* error) {
155  CHECK(index < arraysize(kPropertyNames));
156  if (properties_.ContainsString(kPropertyNames[index]) &&
157      properties_.GetString(kPropertyNames[index]) == value) {
158        return false;
159  }
160  properties_.SetString(kPropertyNames[index], value);
161  return true;
162}
163
164}  // namespace shill
165