| // 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/dbus_adaptor.h" |
| |
| #include <map> |
| #include <string> |
| #include <vector> |
| |
| #include <base/bind.h> |
| #include <base/callback.h> |
| #include <dbus-c++/dbus.h> |
| |
| #include "shill/accessor_interface.h" |
| #include "shill/error.h" |
| #include "shill/key_value_store.h" |
| #include "shill/logging.h" |
| #include "shill/property_store.h" |
| |
| using base::Bind; |
| using base::Owned; |
| using std::map; |
| using std::string; |
| using std::vector; |
| |
| namespace shill { |
| |
| namespace Logging { |
| static auto kModuleLogScope = ScopeLogger::kDBus; |
| static string ObjectID(DBusAdaptor* d) { |
| if (d == nullptr) |
| return "(dbus_adaptor)"; |
| return d->path(); |
| } |
| } |
| |
| // public static |
| const char DBusAdaptor::kNullPath[] = "/"; |
| |
| DBusAdaptor::DBusAdaptor(DBus::Connection* conn, const string& object_path) |
| : DBus::ObjectAdaptor(*conn, object_path) { |
| SLOG(this, 2) << "DBusAdaptor: " << object_path; |
| } |
| |
| DBusAdaptor::~DBusAdaptor() {} |
| |
| // static |
| bool DBusAdaptor::SetProperty(PropertyStore* store, |
| const string& name, |
| const ::DBus::Variant& value, |
| ::DBus::Error* error) { |
| Error e; |
| bool ret; |
| |
| if (DBusAdaptor::IsBool(value.signature())) { |
| ret = store->SetBoolProperty(name, value.reader().get_bool(), &e); |
| } else if (DBusAdaptor::IsByte(value.signature())) { |
| ret = store->SetUint8Property(name, value.reader().get_byte(), &e); |
| } else if (DBusAdaptor::IsInt16(value.signature())) { |
| ret = store->SetInt16Property(name, value.reader().get_int16(), &e); |
| } else if (DBusAdaptor::IsInt32(value.signature())) { |
| ret = store->SetInt32Property(name, value.reader().get_int32(), &e); |
| } else if (DBusAdaptor::IsPath(value.signature())) { |
| ret = store->SetStringProperty(name, value.reader().get_path(), &e); |
| } else if (DBusAdaptor::IsString(value.signature())) { |
| ret = store->SetStringProperty(name, value.reader().get_string(), &e); |
| } else if (DBusAdaptor::IsStringmap(value.signature())) { |
| ret = store->SetStringmapProperty(name, |
| value.operator map<string, string>(), |
| &e); |
| } else if (DBusAdaptor::IsStringmaps(value.signature())) { |
| SLOG(nullptr, 1) << " can't yet handle setting type " << value.signature(); |
| ret = false; |
| e.Populate(Error::kInternalError); |
| } else if (DBusAdaptor::IsStrings(value.signature())) { |
| ret = store->SetStringsProperty(name, value.operator vector<string>(), &e); |
| } else if (DBusAdaptor::IsUint16(value.signature())) { |
| ret = store->SetUint16Property(name, value.reader().get_uint16(), &e); |
| } else if (DBusAdaptor::IsUint16s(value.signature())) { |
| ret = |
| store->SetUint16sProperty(name, value.operator vector<uint16_t>(), &e); |
| } else if (DBusAdaptor::IsUint32(value.signature())) { |
| ret = store->SetUint32Property(name, value.reader().get_uint32(), &e); |
| } else if (DBusAdaptor::IsUint64(value.signature())) { |
| ret = store->SetUint64Property(name, value.reader().get_uint64(), &e); |
| } else if (DBusAdaptor::IsKeyValueStore(value.signature())) { |
| KeyValueStore key_value_store; |
| auto dict = value.operator map<string, DBus::Variant>(); |
| DBusAdaptor::ArgsToKeyValueStore(dict, &key_value_store, &e); |
| if (e.IsSuccess()) { |
| ret = store->SetKeyValueStoreProperty(name, key_value_store, &e); |
| } else { |
| ret = false; |
| } |
| } else { |
| NOTREACHED() << " unknown type: " << value.signature(); |
| ret = false; |
| e.Populate(Error::kInternalError); |
| } |
| |
| if (error != nullptr) { |
| e.ToDBusError(error); |
| } |
| |
| return ret; |
| } |
| |
| // static |
| bool DBusAdaptor::GetProperties(const PropertyStore& store, |
| map<string, ::DBus::Variant>* out, |
| ::DBus::Error* /*error*/) { |
| { |
| ReadablePropertyConstIterator<bool> it = store.GetBoolPropertiesIter(); |
| for ( ; !it.AtEnd(); it.Advance()) { |
| (*out)[it.Key()] = BoolToVariant(it.value()); |
| } |
| } |
| { |
| ReadablePropertyConstIterator<int16_t> it = store.GetInt16PropertiesIter(); |
| for ( ; !it.AtEnd(); it.Advance()) { |
| (*out)[it.Key()] = Int16ToVariant(it.value()); |
| } |
| } |
| { |
| ReadablePropertyConstIterator<int32_t> it = store.GetInt32PropertiesIter(); |
| for ( ; !it.AtEnd(); it.Advance()) { |
| (*out)[it.Key()] = Int32ToVariant(it.value()); |
| } |
| } |
| { |
| ReadablePropertyConstIterator<KeyValueStore> it = |
| store.GetKeyValueStorePropertiesIter(); |
| for ( ; !it.AtEnd(); it.Advance()) { |
| (*out)[it.Key()] = KeyValueStoreToVariant(it.value()); |
| } |
| } |
| { |
| ReadablePropertyConstIterator<RpcIdentifiers> it = |
| store.GetRpcIdentifiersPropertiesIter(); |
| for ( ; !it.AtEnd(); it.Advance()) { |
| vector < ::DBus::Path> rpc_identifiers_as_paths; |
| for (const auto& path : it.value()) { |
| rpc_identifiers_as_paths.push_back(path); |
| } |
| (*out)[it.Key()] = PathsToVariant(rpc_identifiers_as_paths); |
| } |
| } |
| { |
| ReadablePropertyConstIterator<string> it = store.GetStringPropertiesIter(); |
| for ( ; !it.AtEnd(); it.Advance()) { |
| (*out)[it.Key()] = StringToVariant(it.value()); |
| } |
| } |
| { |
| ReadablePropertyConstIterator<Stringmap> it = |
| store.GetStringmapPropertiesIter(); |
| for ( ; !it.AtEnd(); it.Advance()) { |
| (*out)[it.Key()]= StringmapToVariant(it.value()); |
| } |
| } |
| { |
| ReadablePropertyConstIterator<Stringmaps> it = |
| store.GetStringmapsPropertiesIter(); |
| for ( ; !it.AtEnd(); it.Advance()) { |
| (*out)[it.Key()]= StringmapsToVariant(it.value()); |
| } |
| } |
| { |
| ReadablePropertyConstIterator<Strings> it = |
| store.GetStringsPropertiesIter(); |
| for ( ; !it.AtEnd(); it.Advance()) { |
| (*out)[it.Key()] = StringsToVariant(it.value()); |
| } |
| } |
| { |
| ReadablePropertyConstIterator<uint8_t> it = store.GetUint8PropertiesIter(); |
| for ( ; !it.AtEnd(); it.Advance()) { |
| (*out)[it.Key()] = ByteToVariant(it.value()); |
| } |
| } |
| { |
| ReadablePropertyConstIterator<uint16_t> it = |
| store.GetUint16PropertiesIter(); |
| for ( ; !it.AtEnd(); it.Advance()) { |
| (*out)[it.Key()] = Uint16ToVariant(it.value()); |
| } |
| } |
| { |
| ReadablePropertyConstIterator<Uint16s> it = |
| store.GetUint16sPropertiesIter(); |
| for ( ; !it.AtEnd(); it.Advance()) { |
| (*out)[it.Key()] = Uint16sToVariant(it.value()); |
| } |
| } |
| { |
| ReadablePropertyConstIterator<uint32_t> it = |
| store.GetUint32PropertiesIter(); |
| for ( ; !it.AtEnd(); it.Advance()) { |
| (*out)[it.Key()] = Uint32ToVariant(it.value()); |
| } |
| } |
| { |
| ReadablePropertyConstIterator<uint64_t> it = |
| store.GetUint64PropertiesIter(); |
| for ( ; !it.AtEnd(); it.Advance()) { |
| (*out)[it.Key()] = Uint64ToVariant(it.value()); |
| } |
| } |
| { |
| ReadablePropertyConstIterator<RpcIdentifier> it = |
| store.GetRpcIdentifierPropertiesIter(); |
| for ( ; !it.AtEnd(); it.Advance()) { |
| (*out)[it.Key()] = PathToVariant(it.value()); |
| } |
| } |
| return true; |
| } |
| |
| // static |
| bool DBusAdaptor::ClearProperty(PropertyStore* store, |
| const string& name, |
| ::DBus::Error* error) { |
| Error e; |
| store->ClearProperty(name, &e); |
| |
| if (error != nullptr) { |
| e.ToDBusError(error); |
| } |
| |
| return e.IsSuccess(); |
| } |
| |
| // static |
| void DBusAdaptor::ArgsToKeyValueStore( |
| const map<string, ::DBus::Variant>& args, |
| KeyValueStore* out, |
| Error* error) { // TODO(quiche): Should be ::DBus::Error? |
| for (const auto& key_value_pair : args) { |
| string key = key_value_pair.first; |
| DBus::type<string> string_type; |
| DBus::type<bool> bool_type; |
| DBus::type<int32_t> int32_type; |
| |
| if (key_value_pair.second.signature() == bool_type.sig()) { |
| SLOG(nullptr, 5) << "Got bool property " << key; |
| out->SetBool(key, key_value_pair.second.reader().get_bool()); |
| } else if (key_value_pair.second.signature() == int32_type.sig()) { |
| SLOG(nullptr, 5) << "Got int32_t property " << key; |
| out->SetInt(key, key_value_pair.second.reader().get_int32()); |
| } else if (key_value_pair.second.signature() == string_type.sig()) { |
| SLOG(nullptr, 5) << "Got string property " << key; |
| out->SetString(key, key_value_pair.second.reader().get_string()); |
| } else if (DBusAdaptor::IsKeyValueStore( |
| key_value_pair.second.signature())) { |
| // Unwrap a recursive KeyValueStore object. |
| KeyValueStore store; |
| Error convert_error; |
| DBusAdaptor::ArgsToKeyValueStore( |
| key_value_pair.second.operator map<string, ::DBus::Variant>(), |
| &store, |
| &convert_error); |
| if (convert_error.IsSuccess()) { |
| out->SetKeyValueStore(key, store); |
| } else { |
| Error::PopulateAndLog(FROM_HERE, error, convert_error.type(), |
| convert_error.message() + " in sub-key " + key); |
| return; // Skip remaining args after error. |
| } |
| } else if (DBusAdaptor::IsStrings(key_value_pair.second.signature())) { |
| SLOG(nullptr, 5) << "Got strings property " << key; |
| out->SetStrings(key, key_value_pair.second.operator vector<string>()); |
| } else if (DBusAdaptor::IsStringmap(key_value_pair.second.signature())) { |
| SLOG(nullptr, 5) << "Got stringmap property " << key; |
| out->SetStringmap( |
| key, key_value_pair.second.operator map<string, string>()); |
| } else { |
| Error::PopulateAndLog(FROM_HERE, error, Error::kInternalError, |
| "unsupported type for property " + key); |
| return; // Skip remaining args after error. |
| } |
| } |
| } |
| |
| // static |
| string DBusAdaptor::SanitizePathElement(const string& object_path) { |
| string sanitized_path(object_path); |
| size_t length = sanitized_path.length(); |
| |
| for (size_t i = 0; i < length; ++i) { |
| char c = sanitized_path[i]; |
| // The D-Bus specification |
| // (http://dbus.freedesktop.org/doc/dbus-specification.html) states: |
| // Each element must only contain the ASCII characters "[A-Z][a-z][0-9]_" |
| if (!(c >= 'A' && c <= 'Z') && |
| !(c >= 'a' && c <= 'z') && |
| !(c >= '0' && c <= '9') && |
| c != '_') { |
| sanitized_path[i] = '_'; |
| } |
| } |
| |
| return sanitized_path; |
| } |
| |
| // static |
| ::DBus::Variant DBusAdaptor::BoolToVariant(bool value) { |
| ::DBus::Variant v; |
| v.writer().append_bool(value); |
| return v; |
| } |
| |
| // static |
| ::DBus::Variant DBusAdaptor::ByteArraysToVariant(const ByteArrays& value) { |
| ::DBus::MessageIter writer; |
| ::DBus::Variant v; |
| |
| |
| // We have to use a local because the operator<< needs a reference |
| // to work on (the lhs) but writer() returns by-value. C++ prohibits |
| // initializing non-const references from a temporary. |
| // So: |
| // v.writer() << value; |
| // would NOT automagically promote the returned value of v.writer() to |
| // a non-const reference (if you think about it, that's almost always not what |
| // you'd want. see: http://gcc.gnu.org/ml/gcc-help/2006-04/msg00075.html). |
| // |
| // One could consider changing writer() to return a reference, but then it |
| // changes writer() semantics as it can not be a const reference. writer() |
| // currently doesn't modify the original object on which it's called. |
| writer = v.writer(); |
| writer << value; |
| return v; |
| } |
| |
| // static |
| ::DBus::Variant DBusAdaptor::ByteToVariant(uint8_t value) { |
| ::DBus::Variant v; |
| v.writer().append_byte(value); |
| return v; |
| } |
| |
| // static |
| ::DBus::Variant DBusAdaptor::Int16ToVariant(int16_t value) { |
| ::DBus::Variant v; |
| v.writer().append_int16(value); |
| return v; |
| } |
| |
| // static |
| ::DBus::Variant DBusAdaptor::Int32ToVariant(int32_t value) { |
| ::DBus::Variant v; |
| v.writer().append_int32(value); |
| return v; |
| } |
| |
| // static |
| ::DBus::Variant DBusAdaptor::PathToVariant(const ::DBus::Path& value) { |
| ::DBus::Variant v; |
| v.writer().append_path(value.c_str()); |
| return v; |
| } |
| |
| // static |
| ::DBus::Variant DBusAdaptor::PathsToVariant(const vector<::DBus::Path>& value) { |
| ::DBus::MessageIter writer; |
| ::DBus::Variant v; |
| |
| // See note above on why we need to use a local. |
| writer = v.writer(); |
| writer << value; |
| return v; |
| } |
| |
| // static |
| ::DBus::Variant DBusAdaptor::StringToVariant(const string& value) { |
| ::DBus::Variant v; |
| v.writer().append_string(value.c_str()); |
| return v; |
| } |
| |
| // static |
| ::DBus::Variant DBusAdaptor::StringmapToVariant(const Stringmap& value) { |
| ::DBus::Variant v; |
| ::DBus::MessageIter writer = v.writer(); |
| writer << value; |
| return v; |
| } |
| |
| // static |
| ::DBus::Variant DBusAdaptor::StringmapsToVariant(const Stringmaps& value) { |
| ::DBus::Variant v; |
| ::DBus::MessageIter writer = v.writer(); |
| writer << value; |
| return v; |
| } |
| |
| // static |
| ::DBus::Variant DBusAdaptor::StringsToVariant(const Strings& value) { |
| ::DBus::Variant v; |
| ::DBus::MessageIter writer = v.writer(); |
| writer << value; |
| return v; |
| } |
| |
| // static |
| ::DBus::Variant DBusAdaptor::KeyValueStoreToVariant( |
| const KeyValueStore& value) { |
| DBusPropertiesMap props; |
| DBusProperties::ConvertKeyValueStoreToMap(value, &props); |
| ::DBus::Variant v; |
| ::DBus::MessageIter writer = v.writer(); |
| writer << props; |
| return v; |
| } |
| |
| // static |
| ::DBus::Variant DBusAdaptor::Uint16ToVariant(uint16_t value) { |
| ::DBus::Variant v; |
| v.writer().append_uint16(value); |
| return v; |
| } |
| |
| // static |
| ::DBus::Variant DBusAdaptor::Uint16sToVariant(const Uint16s& value) { |
| ::DBus::Variant v; |
| ::DBus::MessageIter writer = v.writer(); |
| writer << value; |
| return v; |
| } |
| |
| // static |
| ::DBus::Variant DBusAdaptor::Uint32ToVariant(uint32_t value) { |
| ::DBus::Variant v; |
| v.writer().append_uint32(value); |
| return v; |
| } |
| |
| // static |
| ::DBus::Variant DBusAdaptor::Uint64ToVariant(uint64_t value) { |
| ::DBus::Variant v; |
| v.writer().append_uint64(value); |
| return v; |
| } |
| |
| // static |
| bool DBusAdaptor::IsBool(::DBus::Signature signature) { |
| return signature == ::DBus::type<bool>::sig(); |
| } |
| |
| // static |
| bool DBusAdaptor::IsByte(::DBus::Signature signature) { |
| return signature == ::DBus::type<uint8_t>::sig(); |
| } |
| |
| // static |
| bool DBusAdaptor::IsByteArrays(::DBus::Signature signature) { |
| return signature == ::DBus::type<ByteArrays>::sig(); |
| } |
| |
| // static |
| bool DBusAdaptor::IsInt16(::DBus::Signature signature) { |
| return signature == ::DBus::type<int16_t>::sig(); |
| } |
| |
| // static |
| bool DBusAdaptor::IsInt32(::DBus::Signature signature) { |
| return signature == ::DBus::type<int32_t>::sig(); |
| } |
| |
| // static |
| bool DBusAdaptor::IsPath(::DBus::Signature signature) { |
| return signature == ::DBus::type<::DBus::Path>::sig(); |
| } |
| |
| // static |
| bool DBusAdaptor::IsPaths(::DBus::Signature signature) { |
| return signature == ::DBus::type<vector<::DBus::Path>>::sig(); |
| } |
| |
| // static |
| bool DBusAdaptor::IsString(::DBus::Signature signature) { |
| return signature == ::DBus::type<string>::sig(); |
| } |
| |
| // static |
| bool DBusAdaptor::IsStringmap(::DBus::Signature signature) { |
| return signature == ::DBus::type<Stringmap>::sig(); |
| } |
| |
| // static |
| bool DBusAdaptor::IsStringmaps(::DBus::Signature signature) { |
| return signature == ::DBus::type<Stringmaps>::sig(); |
| } |
| |
| // static |
| bool DBusAdaptor::IsStrings(::DBus::Signature signature) { |
| return signature == ::DBus::type<Strings>::sig(); |
| } |
| |
| // static |
| bool DBusAdaptor::IsUint16(::DBus::Signature signature) { |
| return signature == ::DBus::type<uint16_t>::sig(); |
| } |
| |
| // static |
| bool DBusAdaptor::IsUint16s(::DBus::Signature signature) { |
| return signature == ::DBus::type<Uint16s>::sig(); |
| } |
| |
| // static |
| bool DBusAdaptor::IsUint32(::DBus::Signature signature) { |
| return signature == ::DBus::type<uint32_t>::sig(); |
| } |
| |
| // static |
| bool DBusAdaptor::IsUint64(::DBus::Signature signature) { |
| return signature == ::DBus::type<uint64_t>::sig(); |
| } |
| |
| // static |
| bool DBusAdaptor::IsKeyValueStore(::DBus::Signature signature) { |
| return signature == ::DBus::type<map<string, ::DBus::Variant>>::sig(); |
| } |
| |
| void DBusAdaptor::DeferReply(const DBus::Tag* tag) { |
| return_later(tag); |
| } |
| |
| void DBusAdaptor::ReplyNow(const DBus::Tag* tag) { |
| Continuation* cont = find_continuation(tag); |
| CHECK(cont) << "Failed to find continuation."; |
| return_now(cont); |
| } |
| |
| template <typename T> |
| void DBusAdaptor::TypedReplyNow(const DBus::Tag* tag, const T& value) { |
| Continuation* cont = find_continuation(tag); |
| CHECK(cont) << "Failed to find continuation."; |
| cont->writer() << value; |
| return_now(cont); |
| } |
| |
| void DBusAdaptor::ReplyNowWithError(const DBus::Tag* tag, |
| const DBus::Error& error) { |
| Continuation* cont = find_continuation(tag); |
| CHECK(cont) << "Failed to find continuation."; |
| SLOG(this, 1) << "Returning error: (" << error.name() << ": " |
| << error.message() << ")"; |
| return_error(cont, error); |
| } |
| |
| ResultCallback DBusAdaptor::GetMethodReplyCallback( |
| const DBus::Tag* tag) { |
| return Bind(&DBusAdaptor::MethodReplyCallback, AsWeakPtr(), Owned(tag)); |
| } |
| |
| ResultStringCallback DBusAdaptor::GetStringMethodReplyCallback( |
| const DBus::Tag* tag) { |
| return Bind(&DBusAdaptor::StringMethodReplyCallback, AsWeakPtr(), Owned(tag)); |
| } |
| |
| ResultBoolCallback DBusAdaptor::GetBoolMethodReplyCallback( |
| const DBus::Tag* tag) { |
| return Bind(&DBusAdaptor::BoolMethodReplyCallback, AsWeakPtr(), Owned(tag)); |
| } |
| |
| template<typename T> |
| void DBusAdaptor::TypedMethodReplyCallback(const DBus::Tag* tag, |
| const Error& error, |
| const T& returned) { |
| if (error.IsFailure()) { |
| DBus::Error dberror; |
| error.ToDBusError(&dberror); |
| ReplyNowWithError(tag, dberror); |
| } else { |
| TypedReplyNow(tag, returned); |
| } |
| } |
| |
| void DBusAdaptor::ReturnResultOrDefer(const DBus::Tag* tag, |
| const Error& error, |
| DBus::Error* dberror) { |
| if (error.IsOngoing()) { |
| DeferReply(tag); |
| } else if (error.IsFailure()) { |
| error.ToDBusError(dberror); |
| } |
| } |
| |
| void DBusAdaptor::MethodReplyCallback(const DBus::Tag* tag, |
| const Error& error) { |
| if (error.IsFailure()) { |
| DBus::Error dberror; |
| error.ToDBusError(&dberror); |
| ReplyNowWithError(tag, dberror); |
| } else { |
| ReplyNow(tag); |
| } |
| } |
| |
| void DBusAdaptor::StringMethodReplyCallback(const DBus::Tag* tag, |
| const Error& error, |
| const string& returned) { |
| TypedMethodReplyCallback(tag, error, returned); |
| } |
| |
| void DBusAdaptor::BoolMethodReplyCallback(const DBus::Tag* tag, |
| const Error& error, |
| bool returned) { |
| TypedMethodReplyCallback(tag, error, returned); |
| } |
| |
| } // namespace shill |