| // |
| // Copyright (C) 2012 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| |
| #include "shill/vpn/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 { |
| |
| namespace Logging { |
| static auto kModuleLogScope = ScopeLogger::kVPN; |
| static string ObjectID(VPNDriver* v) { return "(vpn_driver)"; } |
| } |
| |
| // 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(this, 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_.Remove(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_.Remove(property); |
| } |
| } |
| } |
| return true; |
| } |
| |
| bool VPNDriver::Save(StoreInterface* storage, |
| const string& storage_id, |
| bool save_credentials) { |
| SLOG(this, 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(this, 2) << __func__; |
| for (size_t i = 0; i < property_count_; i++) { |
| if ((properties_[i].flags & |
| (Property::kEphemeral | Property::kCredential))) { |
| args_.Remove(properties_[i].property); |
| } |
| } |
| } |
| |
| void VPNDriver::InitPropertyStore(PropertyStore* store) { |
| SLOG(this, 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, nullptr))); |
| } |
| |
| void VPNDriver::ClearMappedStringProperty(const size_t& index, Error* error) { |
| CHECK(index < property_count_); |
| if (args_.ContainsString(properties_[index].property)) { |
| args_.Remove(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_.Remove(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(this, 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 (base::StartsWith(prop, provider_prefix, |
| base::CompareCase::INSENSITIVE_ASCII)) { |
| 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(FROM_HERE, |
| connect_timeout_callback_.callback(), timeout_seconds * 1000); |
| } |
| |
| void VPNDriver::StopConnectTimeout() { |
| SLOG(this, 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(); |
| } |
| |
| void VPNDriver::OnBeforeSuspend(const ResultCallback& callback) { |
| // Nothing to be done in the general case, so immediately report success. |
| callback.Run(Error(Error::kSuccess)); |
| } |
| |
| void VPNDriver::OnAfterResume() { |
| } |
| |
| void VPNDriver::OnDefaultServiceStateChanged(const ServiceRefPtr& service) { |
| } |
| |
| string VPNDriver::GetHost() const { |
| return args_.LookupString(kProviderHostProperty, ""); |
| } |
| |
| } // namespace shill |