| // Copyright 2014 The Chromium 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 "chromeos/dbus/shill_third_party_vpn_driver_client.h" |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| #include <map> |
| #include <set> |
| |
| #include "base/bind.h" |
| #include "base/bind_helpers.h" |
| #include "base/stl_util.h" |
| #include "chromeos/dbus/shill_third_party_vpn_observer.h" |
| #include "dbus/bus.h" |
| #include "dbus/message.h" |
| #include "dbus/object_proxy.h" |
| #include "third_party/cros_system_api/dbus/service_constants.h" |
| |
| namespace chromeos { |
| |
| namespace { |
| |
| const char* kSetParametersKeyList[] = { |
| shill::kAddressParameterThirdPartyVpn, |
| shill::kBroadcastAddressParameterThirdPartyVpn, |
| shill::kExclusionListParameterThirdPartyVpn, |
| shill::kInclusionListParameterThirdPartyVpn, |
| shill::kSubnetPrefixParameterThirdPartyVpn, |
| shill::kMtuParameterThirdPartyVpn, |
| shill::kDomainSearchParameterThirdPartyVpn, |
| shill::kDnsServersParameterThirdPartyVpn, |
| shill::kReconnectParameterThirdPartyVpn}; |
| |
| // The ShillThirdPartyVpnDriverClient implementation. |
| class ShillThirdPartyVpnDriverClientImpl |
| : public ShillThirdPartyVpnDriverClient { |
| public: |
| ShillThirdPartyVpnDriverClientImpl(); |
| ~ShillThirdPartyVpnDriverClientImpl() override; |
| |
| // ShillThirdPartyVpnDriverClient overrides |
| void AddShillThirdPartyVpnObserver( |
| const std::string& object_path_value, |
| ShillThirdPartyVpnObserver* observer) override; |
| |
| void RemoveShillThirdPartyVpnObserver( |
| const std::string& object_path_value) override; |
| |
| void SetParameters( |
| const std::string& object_path_value, |
| const base::DictionaryValue& parameters, |
| const ShillClientHelper::StringCallback& callback, |
| const ShillClientHelper::ErrorCallback& error_callback) override; |
| |
| void UpdateConnectionState( |
| const std::string& object_path_value, |
| const uint32_t connection_state, |
| const base::Closure& callback, |
| const ShillClientHelper::ErrorCallback& error_callback) override; |
| |
| void SendPacket( |
| const std::string& object_path_value, |
| const std::vector<char>& ip_packet, |
| const base::Closure& callback, |
| const ShillClientHelper::ErrorCallback& error_callback) override; |
| |
| protected: |
| void Init(dbus::Bus* bus) override { bus_ = bus; } |
| |
| ShillThirdPartyVpnDriverClient::TestInterface* GetTestInterface() override { |
| return nullptr; |
| } |
| |
| private: |
| class HelperInfo { |
| public: |
| explicit HelperInfo(dbus::ObjectProxy* object_proxy); |
| |
| ShillClientHelper* helper() { return &helper_; } |
| ShillThirdPartyVpnObserver* observer() { return observer_; } |
| |
| void set_observer(ShillThirdPartyVpnObserver* observer) { |
| observer_ = observer; |
| } |
| |
| base::WeakPtr<HelperInfo> GetWeakPtr() { |
| return weak_ptr_factory_.GetWeakPtr(); |
| } |
| |
| private: |
| ShillClientHelper helper_; |
| ShillThirdPartyVpnObserver* observer_; |
| |
| base::WeakPtrFactory<HelperInfo> weak_ptr_factory_; |
| }; |
| using HelperMap = std::map<std::string, HelperInfo*>; |
| |
| static void OnPacketReceived(base::WeakPtr<HelperInfo> helper_info, |
| dbus::Signal* signal); |
| static void OnPlatformMessage(base::WeakPtr<HelperInfo> helper_info, |
| dbus::Signal* signal); |
| static void OnSignalConnected(const std::string& interface, |
| const std::string& signal, |
| bool success); |
| |
| // Returns or creates the corresponding ShillClientHelper for the |
| // |object_path_value|. |
| ShillClientHelper* GetHelper(const std::string& object_path_value); |
| |
| // Returns or creates the corresponding HelperInfo for the |
| // |object_path_value|. |
| HelperInfo* GetHelperInfo(const std::string& object_path_value); |
| |
| // Returns the corresponding HelperInfo for the |object_path| if exists, |
| // nullptr if not. |
| HelperInfo* FindHelperInfo(const dbus::ObjectPath& object_path); |
| |
| // Deletes the helper object corresponding to |object_path|. |
| void DeleteHelper(const dbus::ObjectPath& object_path); |
| |
| dbus::Bus* bus_; |
| HelperMap helpers_; |
| std::set<std::string> valid_keys_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ShillThirdPartyVpnDriverClientImpl); |
| }; |
| |
| ShillThirdPartyVpnDriverClientImpl::HelperInfo::HelperInfo( |
| dbus::ObjectProxy* object_proxy) |
| : helper_(object_proxy), observer_(nullptr), weak_ptr_factory_(this) { |
| } |
| |
| ShillThirdPartyVpnDriverClientImpl::ShillThirdPartyVpnDriverClientImpl() |
| : bus_(nullptr) { |
| for (uint32_t i = 0; i < base::size(kSetParametersKeyList); ++i) { |
| valid_keys_.insert(kSetParametersKeyList[i]); |
| } |
| } |
| |
| ShillThirdPartyVpnDriverClientImpl::~ShillThirdPartyVpnDriverClientImpl() { |
| for (auto& iter : helpers_) { |
| HelperInfo* helper_info = iter.second; |
| bus_->RemoveObjectProxy( |
| shill::kFlimflamServiceName, |
| helper_info->helper()->object_proxy()->object_path(), |
| base::DoNothing()); |
| delete helper_info; |
| } |
| } |
| |
| void ShillThirdPartyVpnDriverClientImpl::AddShillThirdPartyVpnObserver( |
| const std::string& object_path_value, |
| ShillThirdPartyVpnObserver* observer) { |
| HelperInfo* helper_info = GetHelperInfo(object_path_value); |
| if (helper_info->observer()) { |
| LOG(ERROR) << "Observer exists for " << object_path_value; |
| return; |
| } |
| |
| // TODO(kaliamoorthi): Remove the const_cast. |
| helper_info->set_observer(observer); |
| dbus::ObjectProxy* proxy = |
| const_cast<dbus::ObjectProxy*>(helper_info->helper()->object_proxy()); |
| |
| proxy->ConnectToSignal( |
| shill::kFlimflamThirdPartyVpnInterface, shill::kOnPlatformMessageFunction, |
| base::Bind(&ShillThirdPartyVpnDriverClientImpl::OnPlatformMessage, |
| helper_info->GetWeakPtr()), |
| base::BindOnce(&ShillThirdPartyVpnDriverClientImpl::OnSignalConnected)); |
| |
| proxy->ConnectToSignal( |
| shill::kFlimflamThirdPartyVpnInterface, shill::kOnPacketReceivedFunction, |
| base::Bind(&ShillThirdPartyVpnDriverClientImpl::OnPacketReceived, |
| helper_info->GetWeakPtr()), |
| base::BindOnce(&ShillThirdPartyVpnDriverClientImpl::OnSignalConnected)); |
| } |
| |
| void ShillThirdPartyVpnDriverClientImpl::RemoveShillThirdPartyVpnObserver( |
| const std::string& object_path_value) { |
| HelperInfo* helper_info = FindHelperInfo(dbus::ObjectPath(object_path_value)); |
| if (!helper_info) { |
| LOG(ERROR) << "Unknown object_path_value " << object_path_value; |
| return; |
| } |
| |
| CHECK(helper_info->observer()); |
| helper_info->set_observer(nullptr); |
| DeleteHelper(dbus::ObjectPath(object_path_value)); |
| } |
| |
| void ShillThirdPartyVpnDriverClientImpl::DeleteHelper( |
| const dbus::ObjectPath& object_path) { |
| HelperInfo* helper_info = FindHelperInfo(dbus::ObjectPath(object_path)); |
| if (!helper_info) { |
| LOG(ERROR) << "Unknown object_path " << object_path.value(); |
| return; |
| } |
| |
| bus_->RemoveObjectProxy(shill::kFlimflamServiceName, object_path, |
| base::DoNothing()); |
| helpers_.erase(helpers_.find(object_path.value())); |
| delete helper_info; |
| } |
| |
| void ShillThirdPartyVpnDriverClientImpl::SetParameters( |
| const std::string& object_path_value, |
| const base::DictionaryValue& parameters, |
| const ShillClientHelper::StringCallback& callback, |
| const ShillClientHelper::ErrorCallback& error_callback) { |
| dbus::MethodCall method_call(shill::kFlimflamThirdPartyVpnInterface, |
| shill::kSetParametersFunction); |
| dbus::MessageWriter writer(&method_call); |
| dbus::MessageWriter array_writer(nullptr); |
| writer.OpenArray("{ss}", &array_writer); |
| for (base::DictionaryValue::Iterator it(parameters); !it.IsAtEnd(); |
| it.Advance()) { |
| if (valid_keys_.find(it.key()) == valid_keys_.end()) { |
| LOG(WARNING) << "Unknown key " << it.key(); |
| continue; |
| } |
| std::string value; |
| if (!it.value().GetAsString(&value)) { |
| LOG(WARNING) << "Non string value " << it.value(); |
| continue; |
| } |
| dbus::MessageWriter entry_writer(nullptr); |
| array_writer.OpenDictEntry(&entry_writer); |
| entry_writer.AppendString(it.key()); |
| entry_writer.AppendString(value); |
| array_writer.CloseContainer(&entry_writer); |
| } |
| writer.CloseContainer(&array_writer); |
| GetHelper(object_path_value) |
| ->CallStringMethodWithErrorCallback(&method_call, callback, |
| error_callback); |
| } |
| |
| void ShillThirdPartyVpnDriverClientImpl::UpdateConnectionState( |
| const std::string& object_path_value, |
| const uint32_t connection_state, |
| const base::Closure& callback, |
| const ShillClientHelper::ErrorCallback& error_callback) { |
| dbus::MethodCall method_call(shill::kFlimflamThirdPartyVpnInterface, |
| shill::kUpdateConnectionStateFunction); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendUint32(connection_state); |
| GetHelper(object_path_value) |
| ->CallVoidMethodWithErrorCallback(&method_call, callback, error_callback); |
| } |
| |
| void ShillThirdPartyVpnDriverClientImpl::SendPacket( |
| const std::string& object_path_value, |
| const std::vector<char>& ip_packet, |
| const base::Closure& callback, |
| const ShillClientHelper::ErrorCallback& error_callback) { |
| dbus::MethodCall method_call(shill::kFlimflamThirdPartyVpnInterface, |
| shill::kSendPacketFunction); |
| dbus::MessageWriter writer(&method_call); |
| static_assert(sizeof(uint8_t) == sizeof(char), |
| "Can't reinterpret ip_packet if char is not 8 bit large."); |
| writer.AppendArrayOfBytes(reinterpret_cast<const uint8_t*>(ip_packet.data()), |
| ip_packet.size()); |
| GetHelper(object_path_value) |
| ->CallVoidMethodWithErrorCallback(&method_call, callback, error_callback); |
| } |
| |
| // static |
| void ShillThirdPartyVpnDriverClientImpl::OnPacketReceived( |
| base::WeakPtr<HelperInfo> helper_info, |
| dbus::Signal* signal) { |
| if (!helper_info || !helper_info->observer()) |
| return; |
| |
| dbus::MessageReader reader(signal); |
| const uint8_t* data = nullptr; |
| size_t length = 0; |
| if (reader.PopArrayOfBytes(&data, &length)) { |
| helper_info->observer()->OnPacketReceived( |
| std::vector<char>(data, data + length)); |
| } |
| } |
| |
| // static |
| void ShillThirdPartyVpnDriverClientImpl::OnPlatformMessage( |
| base::WeakPtr<HelperInfo> helper_info, |
| dbus::Signal* signal) { |
| if (!helper_info || !helper_info->observer()) |
| return; |
| |
| dbus::MessageReader reader(signal); |
| uint32_t platform_message = 0; |
| if (reader.PopUint32(&platform_message)) |
| helper_info->observer()->OnPlatformMessage(platform_message); |
| } |
| |
| // static |
| void ShillThirdPartyVpnDriverClientImpl::OnSignalConnected( |
| const std::string& interface, |
| const std::string& signal, |
| bool success) { |
| LOG_IF(ERROR, !success) << "Connect to " << interface << " " << signal |
| << " failed."; |
| } |
| |
| ShillClientHelper* ShillThirdPartyVpnDriverClientImpl::GetHelper( |
| const std::string& object_path_value) { |
| return GetHelperInfo(object_path_value)->helper(); |
| } |
| |
| ShillThirdPartyVpnDriverClientImpl::HelperInfo* |
| ShillThirdPartyVpnDriverClientImpl::FindHelperInfo( |
| const dbus::ObjectPath& object_path) { |
| HelperMap::iterator it = helpers_.find(object_path.value()); |
| return (it != helpers_.end()) ? it->second : nullptr; |
| } |
| |
| ShillThirdPartyVpnDriverClientImpl::HelperInfo* |
| ShillThirdPartyVpnDriverClientImpl::GetHelperInfo( |
| const std::string& object_path_value) { |
| dbus::ObjectPath object_path(object_path_value); |
| HelperInfo* helper_info = FindHelperInfo(object_path); |
| if (helper_info) |
| return helper_info; |
| |
| // There is no helper for the profile, create it. |
| dbus::ObjectProxy* object_proxy = |
| bus_->GetObjectProxy(shill::kFlimflamServiceName, object_path); |
| helper_info = new HelperInfo(object_proxy); |
| helpers_[object_path_value] = helper_info; |
| return helper_info; |
| } |
| |
| } // namespace |
| |
| ShillThirdPartyVpnDriverClient::ShillThirdPartyVpnDriverClient() = default; |
| |
| ShillThirdPartyVpnDriverClient::~ShillThirdPartyVpnDriverClient() = default; |
| |
| // static |
| ShillThirdPartyVpnDriverClient* ShillThirdPartyVpnDriverClient::Create() { |
| return new ShillThirdPartyVpnDriverClientImpl(); |
| } |
| |
| } // namespace chromeos |