| // 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 <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/dbus_adaptor.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 { |
| |
| // public static |
| const char DBusAdaptor::kNullPath[] = "/"; |
| |
| DBusAdaptor::DBusAdaptor(DBus::Connection* conn, const string &object_path) |
| : DBus::ObjectAdaptor(*conn, object_path) { |
| SLOG(DBus, 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(DBus, 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>(), &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())) { |
| SLOG(DBus, 1) << " can't yet handle setting type " << value.signature(); |
| ret = false; |
| e.Populate(Error::kInternalError); |
| } else { |
| NOTREACHED() << " unknown type: " << value.signature(); |
| ret = false; |
| e.Populate(Error::kInternalError); |
| } |
| |
| if (error != NULL) { |
| 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> it = store.GetInt16PropertiesIter(); |
| for ( ; !it.AtEnd(); it.Advance()) { |
| (*out)[it.Key()] = Int16ToVariant(it.value()); |
| } |
| } |
| { |
| ReadablePropertyConstIterator<int32> 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> it = store.GetUint8PropertiesIter(); |
| for ( ; !it.AtEnd(); it.Advance()) { |
| (*out)[it.Key()] = ByteToVariant(it.value()); |
| } |
| } |
| { |
| ReadablePropertyConstIterator<uint16> 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> it = store.GetUint32PropertiesIter(); |
| for ( ; !it.AtEnd(); it.Advance()) { |
| (*out)[it.Key()] = Uint32ToVariant(it.value()); |
| } |
| } |
| { |
| ReadablePropertyConstIterator<uint64> 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 != NULL) { |
| 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> int32_type; |
| |
| if (key_value_pair.second.signature() == bool_type.sig()) { |
| SLOG(DBus, 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(DBus, 5) << "Got int32 property " << key; |
| out->SetInt(key, key_value_pair.second.reader().get_int32()); |
| } else if (key_value_pair.second.signature() == string_type.sig()) { |
| SLOG(DBus, 5) << "Got string property " << key; |
| out->SetString(key, key_value_pair.second.reader().get_string()); |
| } else if (DBusAdaptor::IsStrings(key_value_pair.second.signature())) { |
| SLOG(DBus, 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(DBus, 5) << "Got stringmap property " << key; |
| out->SetStringmap( |
| key, key_value_pair.second.operator map<string, string>()); |
| } else { |
| Error::PopulateAndLog(error, Error::kInternalError, |
| "unsupported type for property " + key); |
| return; // Skip remaining args after error. |
| } |
| } |
| } |
| |
| // 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 value) { |
| ::DBus::Variant v; |
| v.writer().append_byte(value); |
| return v; |
| } |
| |
| // static |
| ::DBus::Variant DBusAdaptor::Int16ToVariant(int16 value) { |
| ::DBus::Variant v; |
| v.writer().append_int16(value); |
| return v; |
| } |
| |
| // static |
| ::DBus::Variant DBusAdaptor::Int32ToVariant(int32 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 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 value) { |
| ::DBus::Variant v; |
| v.writer().append_uint32(value); |
| return v; |
| } |
| |
| // static |
| ::DBus::Variant DBusAdaptor::Uint64ToVariant(uint64 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>::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>::sig(); |
| } |
| |
| // static |
| bool DBusAdaptor::IsInt32(::DBus::Signature signature) { |
| return signature == ::DBus::type<int32>::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>::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>::sig(); |
| } |
| |
| // static |
| bool DBusAdaptor::IsUint64(::DBus::Signature signature) { |
| return signature == ::DBus::type<uint64>::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."; |
| 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 |