| // Copyright (c) 2012 The Chromium OS 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 "shill/vpn_driver.h" |
| |
| #include <string> |
| #include <vector> |
| |
| #include <base/strings/string_util.h> |
| #include <chromeos/dbus/service_constants.h> |
| |
| #include "shill/connection.h" |
| #include "shill/event_dispatcher.h" |
| #include "shill/logging.h" |
| #include "shill/manager.h" |
| #include "shill/property_accessor.h" |
| #include "shill/property_store.h" |
| #include "shill/store_interface.h" |
| |
| using std::string; |
| using std::vector; |
| |
| namespace shill { |
| |
| // static |
| const int VPNDriver::kDefaultConnectTimeoutSeconds = 60; |
| |
| VPNDriver::VPNDriver(EventDispatcher *dispatcher, |
| Manager *manager, |
| const Property *properties, |
| size_t property_count) |
| : weak_ptr_factory_(this), |
| dispatcher_(dispatcher), |
| manager_(manager), |
| properties_(properties), |
| property_count_(property_count), |
| connect_timeout_seconds_(0) {} |
| |
| VPNDriver::~VPNDriver() {} |
| |
| bool VPNDriver::Load(StoreInterface *storage, const string &storage_id) { |
| SLOG(VPN, 2) << __func__; |
| for (size_t i = 0; i < property_count_; i++) { |
| if ((properties_[i].flags & Property::kEphemeral)) { |
| continue; |
| } |
| const string property = properties_[i].property; |
| if (properties_[i].flags & Property::kArray) { |
| CHECK(!(properties_[i].flags & Property::kCredential)) |
| << "Property cannot be both an array and a credential"; |
| vector<string> value; |
| if (storage->GetStringList(storage_id, property, &value)) { |
| args_.SetStrings(property, value); |
| } else { |
| args_.RemoveStrings(property); |
| } |
| } else { |
| string value; |
| bool loaded = (properties_[i].flags & Property::kCredential) ? |
| storage->GetCryptedString(storage_id, property, &value) : |
| storage->GetString(storage_id, property, &value); |
| if (loaded) { |
| args_.SetString(property, value); |
| } else { |
| args_.RemoveString(property); |
| } |
| } |
| } |
| return true; |
| } |
| |
| bool VPNDriver::Save(StoreInterface *storage, |
| const string &storage_id, |
| bool save_credentials) { |
| SLOG(VPN, 2) << __func__; |
| for (size_t i = 0; i < property_count_; i++) { |
| if ((properties_[i].flags & Property::kEphemeral)) { |
| continue; |
| } |
| bool credential = (properties_[i].flags & Property::kCredential); |
| const string property = properties_[i].property; |
| if (properties_[i].flags & Property::kArray) { |
| CHECK(!credential) |
| << "Property cannot be both an array and a credential"; |
| if (!args_.ContainsStrings(property)) { |
| storage->DeleteKey(storage_id, property); |
| continue; |
| } |
| Strings value = args_.GetStrings(property); |
| storage->SetStringList(storage_id, property, value); |
| } else { |
| if (!args_.ContainsString(property) || |
| (credential && !save_credentials)) { |
| storage->DeleteKey(storage_id, property); |
| continue; |
| } |
| string value = args_.GetString(property); |
| if (credential) { |
| storage->SetCryptedString(storage_id, property, value); |
| } else { |
| storage->SetString(storage_id, property, value); |
| } |
| } |
| } |
| return true; |
| } |
| |
| void VPNDriver::UnloadCredentials() { |
| SLOG(VPN, 2) << __func__; |
| for (size_t i = 0; i < property_count_; i++) { |
| if ((properties_[i].flags & |
| (Property::kEphemeral | Property::kCredential))) { |
| args_.RemoveString(properties_[i].property); |
| } |
| } |
| } |
| |
| void VPNDriver::InitPropertyStore(PropertyStore *store) { |
| SLOG(VPN, 2) << __func__; |
| for (size_t i = 0; i < property_count_; i++) { |
| if (properties_[i].flags & Property::kArray) { |
| store->RegisterDerivedStrings( |
| properties_[i].property, |
| StringsAccessor( |
| new CustomMappedAccessor<VPNDriver, Strings, size_t>( |
| this, |
| &VPNDriver::ClearMappedStringsProperty, |
| &VPNDriver::GetMappedStringsProperty, |
| &VPNDriver::SetMappedStringsProperty, |
| i))); |
| } else { |
| store->RegisterDerivedString( |
| properties_[i].property, |
| StringAccessor( |
| new CustomMappedAccessor<VPNDriver, string, size_t>( |
| this, |
| &VPNDriver::ClearMappedStringProperty, |
| &VPNDriver::GetMappedStringProperty, |
| &VPNDriver::SetMappedStringProperty, |
| i))); |
| } |
| } |
| |
| store->RegisterDerivedKeyValueStore( |
| kProviderProperty, |
| KeyValueStoreAccessor( |
| new CustomAccessor<VPNDriver, KeyValueStore>( |
| this, &VPNDriver::GetProvider, NULL))); |
| } |
| |
| void VPNDriver::ClearMappedStringProperty(const size_t &index, Error *error) { |
| CHECK(index < property_count_); |
| if (args_.ContainsString(properties_[index].property)) { |
| args_.RemoveString(properties_[index].property); |
| } else { |
| error->Populate(Error::kNotFound, "Property is not set"); |
| } |
| } |
| |
| void VPNDriver::ClearMappedStringsProperty(const size_t &index, Error *error) { |
| CHECK(index < property_count_); |
| if (args_.ContainsStrings(properties_[index].property)) { |
| args_.RemoveStrings(properties_[index].property); |
| } else { |
| error->Populate(Error::kNotFound, "Property is not set"); |
| } |
| } |
| |
| string VPNDriver::GetMappedStringProperty(const size_t &index, Error *error) { |
| // Provider properties are set via SetProperty calls to "Provider.XXX", |
| // however, they are retrieved via a GetProperty call, which returns all |
| // properties in a single "Provider" dict. Therefore, none of the individual |
| // properties in the kProperties are available for enumeration in |
| // GetProperties. Instead, they are retrieved via GetProvider below. |
| error->Populate(Error::kInvalidArguments, |
| "Provider properties are not read back in this manner"); |
| return string(); |
| } |
| |
| Strings VPNDriver::GetMappedStringsProperty(const size_t &index, Error *error) { |
| // Provider properties are set via SetProperty calls to "Provider.XXX", |
| // however, they are retrieved via a GetProperty call, which returns all |
| // properties in a single "Provider" dict. Therefore, none of the individual |
| // properties in the kProperties are available for enumeration in |
| // GetProperties. Instead, they are retrieved via GetProvider below. |
| error->Populate(Error::kInvalidArguments, |
| "Provider properties are not read back in this manner"); |
| return Strings(); |
| } |
| |
| bool VPNDriver::SetMappedStringProperty( |
| const size_t &index, const string &value, Error *error) { |
| CHECK(index < property_count_); |
| if (args_.ContainsString(properties_[index].property) && |
| args_.GetString(properties_[index].property) == value) { |
| return false; |
| } |
| args_.SetString(properties_[index].property, value); |
| return true; |
| } |
| |
| bool VPNDriver::SetMappedStringsProperty( |
| const size_t &index, const Strings &value, Error *error) { |
| CHECK(index < property_count_); |
| if (args_.ContainsStrings(properties_[index].property) && |
| args_.GetStrings(properties_[index].property) == value) { |
| return false; |
| } |
| args_.SetStrings(properties_[index].property, value); |
| return true; |
| } |
| |
| KeyValueStore VPNDriver::GetProvider(Error *error) { |
| SLOG(VPN, 2) << __func__; |
| string provider_prefix = string(kProviderProperty) + "."; |
| KeyValueStore provider_properties; |
| |
| for (size_t i = 0; i < property_count_; i++) { |
| if ((properties_[i].flags & Property::kWriteOnly)) { |
| continue; |
| } |
| string prop = properties_[i].property; |
| |
| // Chomp off leading "Provider." from properties that have this prefix. |
| string chopped_prop; |
| if (StartsWithASCII(prop, provider_prefix, false)) { |
| chopped_prop = prop.substr(provider_prefix.length()); |
| } else { |
| chopped_prop = prop; |
| } |
| |
| if (properties_[i].flags & Property::kArray) { |
| if (!args_.ContainsStrings(prop)) { |
| continue; |
| } |
| Strings value = args_.GetStrings(prop); |
| provider_properties.SetStrings(chopped_prop, value); |
| } else { |
| if (!args_.ContainsString(prop)) { |
| continue; |
| } |
| string value = args_.GetString(prop); |
| provider_properties.SetString(chopped_prop, value); |
| } |
| } |
| |
| return provider_properties; |
| } |
| |
| void VPNDriver::StartConnectTimeout(int timeout_seconds) { |
| if (IsConnectTimeoutStarted()) { |
| return; |
| } |
| LOG(INFO) << "Schedule VPN connect timeout: " |
| << timeout_seconds << " seconds."; |
| connect_timeout_seconds_ = timeout_seconds; |
| connect_timeout_callback_.Reset( |
| Bind(&VPNDriver::OnConnectTimeout, weak_ptr_factory_.GetWeakPtr())); |
| dispatcher_->PostDelayedTask( |
| connect_timeout_callback_.callback(), timeout_seconds * 1000); |
| } |
| |
| void VPNDriver::StopConnectTimeout() { |
| SLOG(VPN, 2) << __func__; |
| connect_timeout_callback_.Cancel(); |
| connect_timeout_seconds_ = 0; |
| } |
| |
| bool VPNDriver::IsConnectTimeoutStarted() const { |
| return !connect_timeout_callback_.IsCancelled(); |
| } |
| |
| void VPNDriver::OnConnectTimeout() { |
| LOG(INFO) << "VPN connect timeout."; |
| StopConnectTimeout(); |
| } |
| |
| string VPNDriver::GetHost() const { |
| return args_.LookupString(kProviderHostProperty, ""); |
| } |
| |
| } // namespace shill |