blob: 780b1c07bbb39fbd0694e3bc66a8bf53c47e6631 [file] [log] [blame]
Darin Petkovb451d6e2012-04-23 11:56:41 +02001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "shill/vpn_driver.h"
6
Paul Stewartdf4e3c92013-06-13 17:50:30 -07007#include <string>
8#include <vector>
9
Darin Petkovb451d6e2012-04-23 11:56:41 +020010#include <base/string_util.h>
11#include <chromeos/dbus/service_constants.h>
12
Darin Petkov0e9735d2012-04-24 12:33:45 +020013#include "shill/connection.h"
Darin Petkov602303f2012-06-06 12:15:59 +020014#include "shill/event_dispatcher.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070015#include "shill/logging.h"
Darin Petkov0e9735d2012-04-24 12:33:45 +020016#include "shill/manager.h"
Darin Petkovb451d6e2012-04-23 11:56:41 +020017#include "shill/property_accessor.h"
18#include "shill/property_store.h"
Darin Petkovb451d6e2012-04-23 11:56:41 +020019#include "shill/store_interface.h"
20
21using std::string;
Paul Stewartdf4e3c92013-06-13 17:50:30 -070022using std::vector;
Darin Petkovb451d6e2012-04-23 11:56:41 +020023
24namespace shill {
25
Darin Petkov602303f2012-06-06 12:15:59 +020026// static
27const int VPNDriver::kDefaultConnectTimeoutSeconds = 60;
28
29VPNDriver::VPNDriver(EventDispatcher *dispatcher,
30 Manager *manager,
Darin Petkov0e9735d2012-04-24 12:33:45 +020031 const Property *properties,
32 size_t property_count)
Darin Petkov602303f2012-06-06 12:15:59 +020033 : weak_ptr_factory_(this),
34 dispatcher_(dispatcher),
35 manager_(manager),
Darin Petkov0e9735d2012-04-24 12:33:45 +020036 properties_(properties),
Darin Petkov602303f2012-06-06 12:15:59 +020037 property_count_(property_count),
Darin Petkov0cd0d1e2013-02-11 12:49:10 +010038 connect_timeout_seconds_(0) {}
Darin Petkovb451d6e2012-04-23 11:56:41 +020039
40VPNDriver::~VPNDriver() {}
41
42bool VPNDriver::Load(StoreInterface *storage, const string &storage_id) {
43 SLOG(VPN, 2) << __func__;
44 for (size_t i = 0; i < property_count_; i++) {
45 if ((properties_[i].flags & Property::kEphemeral)) {
46 continue;
47 }
48 const string property = properties_[i].property;
Paul Stewartdf4e3c92013-06-13 17:50:30 -070049 if (properties_[i].flags & Property::kArray) {
50 CHECK(!(properties_[i].flags & Property::kCredential))
51 << "Property cannot be both an array and a credential";
52 vector<string> value;
53 if (storage->GetStringList(storage_id, property, &value)) {
54 args_.SetStrings(property, value);
55 } else {
56 args_.RemoveStrings(property);
57 }
Darin Petkovb451d6e2012-04-23 11:56:41 +020058 } else {
Paul Stewartdf4e3c92013-06-13 17:50:30 -070059 string value;
60 bool loaded = (properties_[i].flags & Property::kCredential) ?
61 storage->GetCryptedString(storage_id, property, &value) :
62 storage->GetString(storage_id, property, &value);
63 if (loaded) {
64 args_.SetString(property, value);
65 } else {
66 args_.RemoveString(property);
67 }
Darin Petkovb451d6e2012-04-23 11:56:41 +020068 }
69 }
70 return true;
71}
72
Darin Petkovcb715292012-04-25 13:04:37 +020073bool VPNDriver::Save(StoreInterface *storage,
74 const string &storage_id,
75 bool save_credentials) {
Darin Petkovb451d6e2012-04-23 11:56:41 +020076 SLOG(VPN, 2) << __func__;
77 for (size_t i = 0; i < property_count_; i++) {
78 if ((properties_[i].flags & Property::kEphemeral)) {
79 continue;
80 }
Darin Petkovcb715292012-04-25 13:04:37 +020081 bool credential = (properties_[i].flags & Property::kCredential);
Darin Petkovb451d6e2012-04-23 11:56:41 +020082 const string property = properties_[i].property;
Paul Stewartdf4e3c92013-06-13 17:50:30 -070083 if (properties_[i].flags & Property::kArray) {
84 CHECK(!credential)
85 << "Property cannot be both an array and a credential";
86 if (!args_.ContainsStrings(property)) {
87 storage->DeleteKey(storage_id, property);
88 continue;
89 }
90 Strings value = args_.GetStrings(property);
91 storage->SetStringList(storage_id, property, value);
Darin Petkovb451d6e2012-04-23 11:56:41 +020092 } else {
Paul Stewartdf4e3c92013-06-13 17:50:30 -070093 if (!args_.ContainsString(property) ||
94 (credential && !save_credentials)) {
95 storage->DeleteKey(storage_id, property);
96 continue;
97 }
98 string value = args_.GetString(property);
99 if (credential) {
100 storage->SetCryptedString(storage_id, property, value);
101 } else {
102 storage->SetString(storage_id, property, value);
103 }
Darin Petkovb451d6e2012-04-23 11:56:41 +0200104 }
105 }
106 return true;
107}
108
Darin Petkovcb715292012-04-25 13:04:37 +0200109void VPNDriver::UnloadCredentials() {
110 SLOG(VPN, 2) << __func__;
111 for (size_t i = 0; i < property_count_; i++) {
112 if ((properties_[i].flags &
113 (Property::kEphemeral | Property::kCredential))) {
114 args_.RemoveString(properties_[i].property);
115 }
116 }
117}
118
Darin Petkovb451d6e2012-04-23 11:56:41 +0200119void VPNDriver::InitPropertyStore(PropertyStore *store) {
120 SLOG(VPN, 2) << __func__;
121 for (size_t i = 0; i < property_count_; i++) {
Paul Stewartdf4e3c92013-06-13 17:50:30 -0700122 if (properties_[i].flags & Property::kArray) {
123 store->RegisterDerivedStrings(
124 properties_[i].property,
125 StringsAccessor(
126 new CustomMappedAccessor<VPNDriver, Strings, size_t>(
127 this,
128 &VPNDriver::ClearMappedStringsProperty,
129 &VPNDriver::GetMappedStringsProperty,
130 &VPNDriver::SetMappedStringsProperty,
131 i)));
132 } else {
133 store->RegisterDerivedString(
134 properties_[i].property,
135 StringAccessor(
136 new CustomMappedAccessor<VPNDriver, string, size_t>(
137 this,
138 &VPNDriver::ClearMappedStringProperty,
139 &VPNDriver::GetMappedStringProperty,
140 &VPNDriver::SetMappedStringProperty,
141 i)));
142 }
Darin Petkovb451d6e2012-04-23 11:56:41 +0200143 }
144
Darin Petkovb536a742012-04-26 11:31:28 +0200145 store->RegisterDerivedKeyValueStore(
Darin Petkovb451d6e2012-04-23 11:56:41 +0200146 flimflam::kProviderProperty,
Darin Petkovb536a742012-04-26 11:31:28 +0200147 KeyValueStoreAccessor(
148 new CustomAccessor<VPNDriver, KeyValueStore>(
Darin Petkovb451d6e2012-04-23 11:56:41 +0200149 this, &VPNDriver::GetProvider, NULL)));
150}
151
Paul Stewartdf4e3c92013-06-13 17:50:30 -0700152void VPNDriver::ClearMappedStringProperty(const size_t &index, Error *error) {
Darin Petkovb451d6e2012-04-23 11:56:41 +0200153 CHECK(index < property_count_);
154 if (args_.ContainsString(properties_[index].property)) {
155 args_.RemoveString(properties_[index].property);
156 } else {
157 error->Populate(Error::kNotFound, "Property is not set");
158 }
159}
160
Paul Stewartdf4e3c92013-06-13 17:50:30 -0700161void VPNDriver::ClearMappedStringsProperty(const size_t &index, Error *error) {
162 CHECK(index < property_count_);
163 if (args_.ContainsStrings(properties_[index].property)) {
164 args_.RemoveStrings(properties_[index].property);
165 } else {
166 error->Populate(Error::kNotFound, "Property is not set");
167 }
168}
169
170string VPNDriver::GetMappedStringProperty(const size_t &index, Error *error) {
Darin Petkovb451d6e2012-04-23 11:56:41 +0200171 // Provider properties are set via SetProperty calls to "Provider.XXX",
172 // however, they are retrieved via a GetProperty call, which returns all
173 // properties in a single "Provider" dict. Therefore, none of the individual
174 // properties in the kProperties are available for enumeration in
175 // GetProperties. Instead, they are retrieved via GetProvider below.
176 error->Populate(Error::kInvalidArguments,
177 "Provider properties are not read back in this manner");
178 return string();
179}
180
Paul Stewartdf4e3c92013-06-13 17:50:30 -0700181Strings VPNDriver::GetMappedStringsProperty(const size_t &index, Error *error) {
182 // Provider properties are set via SetProperty calls to "Provider.XXX",
183 // however, they are retrieved via a GetProperty call, which returns all
184 // properties in a single "Provider" dict. Therefore, none of the individual
185 // properties in the kProperties are available for enumeration in
186 // GetProperties. Instead, they are retrieved via GetProvider below.
187 error->Populate(Error::kInvalidArguments,
188 "Provider properties are not read back in this manner");
189 return Strings();
190}
191
192bool VPNDriver::SetMappedStringProperty(
Darin Petkovb451d6e2012-04-23 11:56:41 +0200193 const size_t &index, const string &value, Error *error) {
194 CHECK(index < property_count_);
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700195 if (args_.ContainsString(properties_[index].property) &&
196 args_.GetString(properties_[index].property) == value) {
197 return false;
198 }
Darin Petkovb451d6e2012-04-23 11:56:41 +0200199 args_.SetString(properties_[index].property, value);
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700200 return true;
Darin Petkovb451d6e2012-04-23 11:56:41 +0200201}
202
Paul Stewartdf4e3c92013-06-13 17:50:30 -0700203bool VPNDriver::SetMappedStringsProperty(
204 const size_t &index, const Strings &value, Error *error) {
205 CHECK(index < property_count_);
206 if (args_.ContainsStrings(properties_[index].property) &&
207 args_.GetStrings(properties_[index].property) == value) {
208 return false;
209 }
210 args_.SetStrings(properties_[index].property, value);
211 return true;
212}
213
Darin Petkovb536a742012-04-26 11:31:28 +0200214KeyValueStore VPNDriver::GetProvider(Error *error) {
Darin Petkovb451d6e2012-04-23 11:56:41 +0200215 SLOG(VPN, 2) << __func__;
216 string provider_prefix = string(flimflam::kProviderProperty) + ".";
Darin Petkovb536a742012-04-26 11:31:28 +0200217 KeyValueStore provider_properties;
Darin Petkovb451d6e2012-04-23 11:56:41 +0200218
219 for (size_t i = 0; i < property_count_; i++) {
Darin Petkovcb715292012-04-25 13:04:37 +0200220 if ((properties_[i].flags & Property::kWriteOnly)) {
Darin Petkovb451d6e2012-04-23 11:56:41 +0200221 continue;
222 }
Darin Petkov4e9066f2012-06-11 13:17:06 +0200223 string prop = properties_[i].property;
Paul Stewartdf4e3c92013-06-13 17:50:30 -0700224
Darin Petkov4e9066f2012-06-11 13:17:06 +0200225 // Chomp off leading "Provider." from properties that have this prefix.
Paul Stewartdf4e3c92013-06-13 17:50:30 -0700226 string chopped_prop;
Darin Petkov4e9066f2012-06-11 13:17:06 +0200227 if (StartsWithASCII(prop, provider_prefix, false)) {
Paul Stewartdf4e3c92013-06-13 17:50:30 -0700228 chopped_prop = prop.substr(provider_prefix.length());
229 } else {
230 chopped_prop = prop;
Darin Petkov4e9066f2012-06-11 13:17:06 +0200231 }
Paul Stewartdf4e3c92013-06-13 17:50:30 -0700232
233 if (properties_[i].flags & Property::kArray) {
234 if (!args_.ContainsStrings(prop)) {
235 continue;
236 }
237 Strings value = args_.GetStrings(prop);
238 provider_properties.SetStrings(chopped_prop, value);
239 } else {
240 if (!args_.ContainsString(prop)) {
241 continue;
242 }
243 string value = args_.GetString(prop);
244 provider_properties.SetString(chopped_prop, value);
245 }
Darin Petkovb451d6e2012-04-23 11:56:41 +0200246 }
247
248 return provider_properties;
249}
250
Darin Petkov0cd0d1e2013-02-11 12:49:10 +0100251void VPNDriver::StartConnectTimeout(int timeout_seconds) {
Darin Petkov602303f2012-06-06 12:15:59 +0200252 if (IsConnectTimeoutStarted()) {
253 return;
254 }
Darin Petkov0cd0d1e2013-02-11 12:49:10 +0100255 LOG(INFO) << "Schedule VPN connect timeout: "
256 << timeout_seconds << " seconds.";
257 connect_timeout_seconds_ = timeout_seconds;
Darin Petkov602303f2012-06-06 12:15:59 +0200258 connect_timeout_callback_.Reset(
259 Bind(&VPNDriver::OnConnectTimeout, weak_ptr_factory_.GetWeakPtr()));
260 dispatcher_->PostDelayedTask(
Darin Petkov0cd0d1e2013-02-11 12:49:10 +0100261 connect_timeout_callback_.callback(), timeout_seconds * 1000);
Darin Petkov602303f2012-06-06 12:15:59 +0200262}
263
264void VPNDriver::StopConnectTimeout() {
265 SLOG(VPN, 2) << __func__;
266 connect_timeout_callback_.Cancel();
Darin Petkov0cd0d1e2013-02-11 12:49:10 +0100267 connect_timeout_seconds_ = 0;
Darin Petkov602303f2012-06-06 12:15:59 +0200268}
269
270bool VPNDriver::IsConnectTimeoutStarted() const {
271 return !connect_timeout_callback_.IsCancelled();
272}
273
274void VPNDriver::OnConnectTimeout() {
Darin Petkova42afe32013-02-05 16:53:52 +0100275 LOG(INFO) << "VPN connect timeout.";
Darin Petkov602303f2012-06-06 12:15:59 +0200276 StopConnectTimeout();
Darin Petkov602303f2012-06-06 12:15:59 +0200277}
278
Darin Petkov9c6e9812013-03-26 13:49:07 +0100279string VPNDriver::GetHost() const {
280 return args_.LookupString(flimflam::kProviderHostProperty, "");
281}
282
Darin Petkovb451d6e2012-04-23 11:56:41 +0200283} // namespace shill