| Index: net/dbus/dbus.cc
|
| diff --git a/net/dbus/dbus.cc b/net/dbus/dbus.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..ee7ee699993dc4e010843df6c899645255f4c415
|
| --- /dev/null
|
| +++ b/net/dbus/dbus.cc
|
| @@ -0,0 +1,886 @@
|
| +// Copyright (c) 2011 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 "net/dbus/dbus.h"
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/logging.h"
|
| +#include "base/message_loop.h"
|
| +#include "base/stringprintf.h"
|
| +#include "base/threading/thread.h"
|
| +#include "base/threading/thread_restrictions.h"
|
| +#include "base/threading/platform_thread.h"
|
| +
|
| +namespace net {
|
| +namespace dbus {
|
| +
|
| +//
|
| +// Bus implementation.
|
| +//
|
| +
|
| +Bus::Bus(const Options& options)
|
| + : bus_type_(options.bus_type),
|
| + connection_type_(options.connection_type),
|
| + connection_(NULL) {
|
| +}
|
| +
|
| +Bus::~Bus() {
|
| + // Private connection should be closed.
|
| + if (connection_ && connection_type_ == PRIVATE) {
|
| + dbus_connection_close(connection_);
|
| + }
|
| +}
|
| +
|
| +bool Bus::Init() {
|
| + // Check if it's already initialized.
|
| + if (connection_)
|
| + return true;
|
| +
|
| + DBusError error = {};
|
| + dbus_error_init(&error);
|
| + const DBusBusType dbus_bus_type = static_cast<DBusBusType>(bus_type_);
|
| + if (connection_type_ == PRIVATE) {
|
| + connection_ = dbus_bus_get_private(dbus_bus_type, &error);
|
| + } else {
|
| + connection_ = dbus_bus_get(dbus_bus_type, &error);
|
| + }
|
| + if (!connection_) {
|
| + if (dbus_error_is_set(&error)) {
|
| + LOG(ERROR) << error.message;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +void OnDispatchStatus(DBusConnection* connection,
|
| + DBusDispatchStatus status,
|
| + void *data) {
|
| + LOG(ERROR) << "is connected: "
|
| + << dbus_connection_get_is_connected(connection);
|
| + LOG(ERROR) << "new status: " << status;
|
| +}
|
| +
|
| +bool Bus::InitForAsync() {
|
| + if (!Init()) {
|
| + return false;
|
| + }
|
| + LOG(ERROR) << "@@ " << __PRETTY_FUNCTION__;
|
| + dbus_connection_set_watch_functions(connection_,
|
| + &Bus::OnAddWatch,
|
| + &Bus::OnRemoveWatch,
|
| + &Bus::OnToggleWatch,
|
| + this,
|
| + NULL);
|
| + dbus_connection_set_timeout_functions(connection_,
|
| + NULL,
|
| + NULL,
|
| + NULL,
|
| + NULL,
|
| + NULL);
|
| + dbus_connection_set_dispatch_status_function(connection_,
|
| + OnDispatchStatus,
|
| + connection_,
|
| + NULL);
|
| + return true;
|
| +}
|
| +
|
| +ObjectProxy* Bus::GetObjectProxy(const std::string& service_name,
|
| + const std::string& object_path) {
|
| + return new ObjectProxy(this, service_name, object_path);
|
| +}
|
| +
|
| +class Bus::IOThread : public base::Thread {
|
| + public:
|
| + IOThread() : base::Thread("Bus::IOThread") {
|
| + }
|
| +
|
| + ~IOThread() {
|
| + }
|
| +};
|
| +
|
| +
|
| +void Bus::StartIOThreadIfNeeded() {
|
| + if (io_thread_.get())
|
| + return;
|
| + base::Thread::Options thread_options;
|
| + thread_options.message_loop_type = MessageLoop::TYPE_IO;
|
| + io_thread_.reset(new IOThread);
|
| + io_thread_->StartWithOptions(thread_options);
|
| +}
|
| +
|
| +void Bus::PostTask(const tracked_objects::Location& from_here,
|
| + const base::Closure& task) {
|
| + io_thread_->message_loop()->PostTask(from_here, task);
|
| +}
|
| +
|
| +class Watch : public base::MessagePumpLibevent::Watcher {
|
| + public:
|
| + Watch(DBusWatch* watch, DBusConnection* connection)
|
| + : watch_(watch),
|
| + connection_(connection) {
|
| + dbus_watch_set_data(watch_, this, NULL);
|
| + }
|
| +
|
| + ~Watch() {
|
| + file_descriptor_watcher_.StopWatchingFileDescriptor();
|
| + dbus_watch_set_data(watch_, NULL, NULL);
|
| + }
|
| +
|
| + // Returns true if ready to watch.
|
| + bool IsEnabled() {
|
| + return dbus_watch_get_enabled(watch_);
|
| + }
|
| +
|
| + void StartWatching() {
|
| + LOG(ERROR) << "@@ " << __PRETTY_FUNCTION__;
|
| +
|
| + const int fd = dbus_watch_get_unix_fd(watch_);
|
| + LOG(ERROR) << "fd: " << fd;
|
| + const int flags = dbus_watch_get_flags(watch_);
|
| + LOG(ERROR) << "flags: " << flags;
|
| +
|
| + MessageLoopForIO::Mode mode;
|
| + if ((flags & DBUS_WATCH_READABLE) && (flags & DBUS_WATCH_WRITABLE))
|
| + mode = MessageLoopForIO::WATCH_READ_WRITE;
|
| + if (flags & DBUS_WATCH_READABLE)
|
| + mode = MessageLoopForIO::WATCH_READ;
|
| + if (flags & DBUS_WATCH_WRITABLE)
|
| + mode = MessageLoopForIO::WATCH_WRITE;
|
| +
|
| + const bool persistent = true; // Watch persistently.
|
| + const bool success = MessageLoopForIO::current()->WatchFileDescriptor(
|
| + fd,
|
| + persistent,
|
| + mode,
|
| + &file_descriptor_watcher_,
|
| + this);
|
| + DCHECK(success) << "Unable to allocate memory";
|
| + }
|
| +
|
| + // Implements MessagePumpLibevent::Watcher::OnFileCanReadWithoutBlocking.
|
| + virtual void OnFileCanReadWithoutBlocking(int fd) {
|
| + LOG(ERROR) << "@@ " << __PRETTY_FUNCTION__;
|
| +
|
| + int flags = 0;
|
| + flags |= DBUS_WATCH_READABLE;
|
| + flags |= DBUS_WATCH_WRITABLE;
|
| + LOG(ERROR) << "status: " <<
|
| + dbus_connection_get_dispatch_status(connection_);
|
| + const bool success = dbus_watch_handle(watch_, flags);
|
| + LOG(ERROR) << "status: " <<
|
| + dbus_connection_get_dispatch_status(connection_);
|
| + while (dbus_connection_dispatch(connection_) == DBUS_DISPATCH_DATA_REMAINS);
|
| +
|
| + DCHECK(success) << "Unable to allocate memory";
|
| + }
|
| +
|
| + // Implements MessagePumpLibevent::Watcher::OnFileCanWriteWithoutBlocking.
|
| + virtual void OnFileCanWriteWithoutBlocking(int fd) {
|
| + LOG(ERROR) << "@@ " << __PRETTY_FUNCTION__;
|
| +
|
| + const bool success = dbus_watch_handle(watch_, DBUS_WATCH_WRITABLE);
|
| + DCHECK(success) << "Unable to allocate memory";
|
| + }
|
| +
|
| + private:
|
| + DBusWatch* watch_;
|
| + DBusConnection* connection_;
|
| + base::MessagePumpLibevent::FileDescriptorWatcher file_descriptor_watcher_;
|
| +};
|
| +
|
| +dbus_bool_t Bus::OnAddWatch(DBusWatch* raw_watch, void* data) {
|
| + LOG(ERROR) << "@@ " << "watch: " << raw_watch;
|
| +
|
| + Bus* self = reinterpret_cast<Bus*>(data);
|
| + Watch* watch = new Watch(raw_watch, self->connection_);
|
| + LOG(ERROR) << "flags: " << dbus_watch_get_flags(raw_watch);
|
| + if (watch->IsEnabled()) {
|
| + watch->StartWatching();
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +void Bus::OnRemoveWatch(DBusWatch* raw_watch, void* data) {
|
| + LOG(ERROR) << "@@ " << __PRETTY_FUNCTION__;
|
| +
|
| + Watch* watch = reinterpret_cast<Watch*>(dbus_watch_get_data(raw_watch));
|
| + delete watch;
|
| +}
|
| +
|
| +void Bus::OnToggleWatch(DBusWatch* raw_watch, void* data) {
|
| + LOG(ERROR) << "@@ " << __PRETTY_FUNCTION__;
|
| +
|
| + Watch* watch = reinterpret_cast<Watch*>(dbus_watch_get_data(raw_watch));
|
| + if (watch->IsEnabled()) {
|
| + OnAddWatch(raw_watch, data);
|
| + } else {
|
| + OnRemoveWatch(raw_watch, data);
|
| + }
|
| +}
|
| +
|
| +//
|
| +// ObjectProxy implementation.
|
| +//
|
| +
|
| +ObjectProxy::ObjectProxy(Bus* bus,
|
| + const std::string& service_name,
|
| + const std::string& object_path)
|
| + : bus_(bus),
|
| + service_name_(service_name),
|
| + object_path_(object_path) {
|
| +}
|
| +
|
| +ObjectProxy::~ObjectProxy() {
|
| +}
|
| +
|
| +// Originally we tried to make |method_call| a const reference, but we
|
| +// gave up as dbus_connection_send_with_reply_and_block() takes a
|
| +// non-const pointer of DBusMessage as the second parameter.
|
| +bool ObjectProxy::CallMethodSync(MethodCall* method_call,
|
| + Response* response) {
|
| + base::ThreadRestrictions::AssertIOAllowed();
|
| + if (!bus_->Init())
|
| + return false;
|
| + method_call->SetServiceName(service_name_);
|
| + method_call->SetObjectPath(object_path_);
|
| + DBusMessage* request_message = method_call->raw_message();
|
| +
|
| + const int timeout_ms = -1; // Default timeout.
|
| + DBusError error = {};
|
| + dbus_error_init(&error);
|
| +
|
| + // Send the message synchronously.
|
| + DBusMessage* response_message = dbus_connection_send_with_reply_and_block(
|
| + bus_->connection(), request_message, timeout_ms, &error);
|
| +
|
| + if (!response_message) {
|
| + if (dbus_error_is_set(&error)) {
|
| + LOG(ERROR) << error.message;
|
| + }
|
| + return false;
|
| + }
|
| + response->reset_raw_message(response_message);
|
| +
|
| + return true;
|
| +}
|
| +
|
| +void ObjectProxy::CallMethodAsync(MethodCall* method_call,
|
| + ResponseCallback callback) {
|
| + bus_->StartIOThreadIfNeeded();
|
| +
|
| + method_call->SetServiceName(service_name_);
|
| + method_call->SetObjectPath(object_path_);
|
| + // This is a bit tricky but increment the reference count of the request
|
| + // message here so that we can keep using the message even if the
|
| + // MethodCall object at the caller is gone before the method call is
|
| + // complete.
|
| + DBusMessage* request_message = method_call->raw_message();
|
| + dbus_message_ref(request_message);
|
| +
|
| + // Bind() won't compile if we pass request_message as-is since
|
| + // DBusMessage is an opaque struct which Bind() does not like.
|
| + //
|
| + // /base/bind_helpers.h:145:
|
| + // error: invalid use of incomplete type 'struct DBusMessage'
|
| + //
|
| + // Hence we cast it to void* to workaround the issue.
|
| + base::Closure task = base::Bind(&ObjectProxy::StartAsyncMethodCall,
|
| + // Make this a ref-counted class?
|
| + base::Unretained(this),
|
| + reinterpret_cast<void*>(request_message),
|
| + MessageLoop::current(),
|
| + callback);
|
| + LOG(ERROR) << "CallMethodAsync: thread id: " << base::PlatformThread::CurrentId();
|
| + bus_->PostTask(FROM_HERE, task);
|
| +}
|
| +
|
| +void ObjectProxy::StartAsyncMethodCall(void* in_request_message,
|
| + MessageLoop* origin_loop,
|
| + ResponseCallback response_callback) {
|
| + LOG(ERROR) << "@@ " << __PRETTY_FUNCTION__;
|
| +
|
| + DBusMessage* request_message =
|
| + reinterpret_cast<DBusMessage*>(in_request_message);
|
| + if (bus_->InitForAsync()) {
|
| + const int timeout_ms = -1; // Default timeout.
|
| + DBusPendingCall* pending_call = NULL;
|
| + // This returns false only when unable to allocate memory.
|
| + bool success = false;
|
| + success = dbus_connection_send_with_reply(
|
| + bus_->connection(), request_message, &pending_call, timeout_ms);
|
| + dbus_pending_call_ref(pending_call);
|
| + DCHECK(success) << "Unable to allocate memory";
|
| +
|
| + OnPendingCallIsCompleteData* data =
|
| + new OnPendingCallIsCompleteData(origin_loop, response_callback);
|
| +
|
| + // This returns false only when unable to allocate memory.
|
| + success = dbus_pending_call_set_notify(
|
| + pending_call,
|
| + &ObjectProxy::OnPendingCallIsComplete,
|
| + data,
|
| + NULL);
|
| + DCHECK(success) << "Unable to allocate memory";
|
| + } else {
|
| + Response* response = NULL;
|
| + base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback,
|
| + response_callback,
|
| + response);
|
| + origin_loop->PostTask(FROM_HERE, task);
|
| + }
|
| + // It's now safe to unref the request message.
|
| + dbus_message_unref(request_message);
|
| +}
|
| +
|
| +void ObjectProxy::RunResponseCallback(ResponseCallback response_callback,
|
| + Response* response) {
|
| + LOG(ERROR) << "@@ " << __PRETTY_FUNCTION__;
|
| +
|
| + response_callback.Run(response);
|
| +}
|
| +
|
| +ObjectProxy::OnPendingCallIsCompleteData::OnPendingCallIsCompleteData(
|
| + MessageLoop* in_origin_loop,
|
| + ResponseCallback in_response_callback)
|
| + : origin_loop(in_origin_loop),
|
| + response_callback(in_response_callback) {
|
| +}
|
| +
|
| +void ObjectProxy::OnPendingCallIsComplete(DBusPendingCall* pending_call,
|
| + void* user_data) {
|
| + LOG(ERROR) << "@@ " << __PRETTY_FUNCTION__;
|
| +
|
| + OnPendingCallIsCompleteData* data =
|
| + reinterpret_cast<OnPendingCallIsCompleteData*>(user_data);
|
| +
|
| + DBusMessage* response_message = dbus_pending_call_steal_reply(pending_call);
|
| + CHECK(response_message) << "hoge";
|
| + // This will be deleted in the callback.
|
| + Response* response = new Response;
|
| + response->reset_raw_message(response_message);
|
| + base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback,
|
| + data->response_callback,
|
| + response);
|
| + data->origin_loop->PostTask(FROM_HERE, task);
|
| +
|
| + delete data;
|
| +}
|
| +
|
| +//
|
| +// Message implementation.
|
| +//
|
| +
|
| +Message::Message()
|
| + : raw_message_(NULL) {
|
| +}
|
| +
|
| +Message::~Message() {
|
| + if (raw_message_)
|
| + dbus_message_unref(raw_message_);
|
| +}
|
| +
|
| +void Message::reset_raw_message(DBusMessage* raw_message) {
|
| + if (raw_message_)
|
| + dbus_message_unref(raw_message_);
|
| + raw_message_ = raw_message;
|
| +}
|
| +
|
| +std::string Message::ToStringInternal(const std::string& indent,
|
| + MessageReader* reader) {
|
| + std::string output;
|
| + while (reader->HasMore()) {
|
| + const Type type = reader->GetType();
|
| + switch (type) {
|
| + case BYTE: {
|
| + uint8 value;
|
| + reader->PopByte(&value);
|
| + output += indent + "byte " + base::StringPrintf("%d", value) + "\n";
|
| + break;
|
| + }
|
| + case BOOL: {
|
| + bool value;
|
| + reader->PopBool(&value);
|
| + output += indent + "bool " + (value ? "true" : "false") + "\n";
|
| + break;
|
| + }
|
| + case INT16: {
|
| + int16 value;
|
| + reader->PopInt16(&value);
|
| + output += indent + "int16 " + base::StringPrintf("%d", value) + "\n";
|
| + break;
|
| + }
|
| + case UINT16: {
|
| + uint16 value;
|
| + reader->PopUint16(&value);
|
| + output += indent + "uint16 " + base::StringPrintf("%d", value) + "\n";
|
| + break;
|
| + }
|
| + case INT32: {
|
| + int32 value;
|
| + reader->PopInt32(&value);
|
| + output += indent + "int32 " + base::StringPrintf("%d", value) + "\n";
|
| + break;
|
| + }
|
| + case UINT32: {
|
| + uint32 value;
|
| + reader->PopUint32(&value);
|
| + output += indent + "uint32 " + base::StringPrintf("%u", value) + "\n";
|
| + break;
|
| + }
|
| + case INT64: {
|
| + int64 value;
|
| + reader->PopInt64(&value);
|
| + output += indent + "int64 " + base::StringPrintf("%ld", value) + "\n";
|
| + break;
|
| + }
|
| + case UINT64: {
|
| + uint64 value;
|
| + reader->PopUint64(&value);
|
| + output += indent + "uint64 " + base::StringPrintf("%lu", value) + "\n";
|
| + break;
|
| + }
|
| + case DOUBLE: {
|
| + double value;
|
| + reader->PopDouble(&value);
|
| + output += indent + "double " + base::StringPrintf("%f", value) + "\n";
|
| + break;
|
| + }
|
| + case STRING: {
|
| + std::string value;
|
| + reader->PopString(&value);
|
| + output += indent + "string \"" + value + "\"\n";
|
| + break;
|
| + }
|
| + case OBJECT_PATH: {
|
| + std::string value;
|
| + reader->PopObjectPath(&value);
|
| + output += indent + "object_path \"" + value + "\"\n";
|
| + break;
|
| + }
|
| + case ARRAY: {
|
| + MessageReader sub_reader(this);
|
| + reader->PopArray(&sub_reader);
|
| + output += indent + "array [\n";
|
| + output += ToStringInternal(indent + " ", &sub_reader);
|
| + output += indent + "]\n";
|
| + break;
|
| + }
|
| + case STRUCT: {
|
| + MessageReader sub_reader(this);
|
| + reader->PopStruct(&sub_reader);
|
| + output += indent + "struct {\n";
|
| + output += ToStringInternal(indent + " ", &sub_reader);
|
| + output += indent + "}\n";
|
| + break;
|
| + }
|
| + case DICT_ENTRY: {
|
| + MessageReader sub_reader(this);
|
| + reader->PopDictEntry(&sub_reader);
|
| + output += indent + "dict entry {\n";
|
| + output += ToStringInternal(indent + " ", &sub_reader);
|
| + output += indent + "}\n";
|
| + break;
|
| + }
|
| + case VARIANT: {
|
| + MessageReader sub_reader(this);
|
| + reader->PopVariant(&sub_reader);
|
| + output += indent + "variant ";
|
| + output += ToStringInternal(indent + " ", &sub_reader);
|
| + break;
|
| + }
|
| + default:
|
| + LOG(FATAL) << "Unknown type: " << type;
|
| + }
|
| + }
|
| + return output;
|
| +}
|
| +
|
| +std::string Message::ToString() {
|
| + std::string output;
|
| + MessageReader reader(this);
|
| + return ToStringInternal("", &reader);
|
| +}
|
| +
|
| +//
|
| +// MethodCall implementation.
|
| +//
|
| +
|
| +MethodCall::MethodCall(const std::string& interface_name,
|
| + const std::string& method_name)
|
| + : Message() {
|
| + reset_raw_message(dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_CALL));
|
| +
|
| + bool success = false;
|
| + success = dbus_message_set_interface(raw_message(), interface_name.c_str());
|
| + DCHECK(success) << "Unable to allocate memory";
|
| +
|
| + success = dbus_message_set_member(raw_message(), method_name.c_str());
|
| + DCHECK(success) << "Unable to allocate memory";
|
| +}
|
| +
|
| +void MethodCall::SetServiceName(const std::string& service_name) {
|
| + const bool success = dbus_message_set_destination(raw_message(),
|
| + service_name.c_str());
|
| + DCHECK(success) << "Unable to allocate memory";
|
| +}
|
| +
|
| +void MethodCall::SetObjectPath(const std::string& object_path) {
|
| + const bool success = dbus_message_set_path(raw_message(),
|
| + object_path.c_str());
|
| + DCHECK(success) << "Unable to allocate memory";
|
| +}
|
| +
|
| +//
|
| +// Response implementation.
|
| +//
|
| +
|
| +Response::Response() : Message() {
|
| +}
|
| +
|
| +//
|
| +// MessageWriter implementation.
|
| +//
|
| +
|
| +MessageWriter::MessageWriter(Message* message) :
|
| + message_(message) {
|
| + dbus_message_iter_init_append(message_->raw_message(), &raw_message_iter_);
|
| +}
|
| +
|
| +
|
| +MessageWriter::~MessageWriter() {
|
| +}
|
| +
|
| +void MessageWriter::AppendByte(uint8 value) {
|
| + const bool success = dbus_message_iter_append_basic(
|
| + &raw_message_iter_, DBUS_TYPE_BYTE, &value);
|
| + // dbus_message_iter_append_basic() fails only when there is not enough
|
| + // memory. We don't return this error as there is nothing we can do when
|
| + // it fails to allocate memory for a byte.
|
| + DCHECK(success) << "Unable to allocate memory";
|
| +}
|
| +
|
| +void MessageWriter::AppendBool(bool value) {
|
| + const bool success = dbus_message_iter_append_basic(
|
| + &raw_message_iter_, DBUS_TYPE_BOOLEAN, &value);
|
| + DCHECK(success) << "Unable to allocate memory";
|
| +}
|
| +
|
| +void MessageWriter::AppendInt16(int16 value) {
|
| + const bool success = dbus_message_iter_append_basic(
|
| + &raw_message_iter_, DBUS_TYPE_INT16, &value);
|
| + DCHECK(success) << "Unable to allocate memory";
|
| +}
|
| +
|
| +void MessageWriter::AppendUint16(uint16 value) {
|
| + const bool success = dbus_message_iter_append_basic(
|
| + &raw_message_iter_, DBUS_TYPE_UINT16, &value);
|
| + DCHECK(success) << "Unable to allocate memory";
|
| +}
|
| +
|
| +void MessageWriter::AppendInt32(int32 value) {
|
| + const bool success = dbus_message_iter_append_basic(
|
| + &raw_message_iter_, DBUS_TYPE_INT32, &value);
|
| + DCHECK(success) << "Unable to allocate memory";
|
| +}
|
| +
|
| +void MessageWriter::AppendUint32(uint32 value) {
|
| + const bool success = dbus_message_iter_append_basic(
|
| + &raw_message_iter_, DBUS_TYPE_UINT32, &value);
|
| + DCHECK(success) << "Unable to allocate memory";
|
| +}
|
| +
|
| +void MessageWriter::AppendInt64(int64 value) {
|
| + const bool success = dbus_message_iter_append_basic(
|
| + &raw_message_iter_, DBUS_TYPE_INT64, &value);
|
| + DCHECK(success) << "Unable to allocate memory";
|
| +}
|
| +
|
| +void MessageWriter::AppendUint64(uint64 value) {
|
| + const bool success = dbus_message_iter_append_basic(
|
| + &raw_message_iter_, DBUS_TYPE_UINT64, &value);
|
| + DCHECK(success) << "Unable to allocate memory";
|
| +}
|
| +
|
| +void MessageWriter::AppendDouble(double value) {
|
| + const bool success = dbus_message_iter_append_basic(
|
| + &raw_message_iter_, DBUS_TYPE_DOUBLE, &value);
|
| + DCHECK(success) << "Unable to allocate memory";
|
| +}
|
| +
|
| +void MessageWriter::AppendString(const std::string& value) {
|
| + const char* pointer = value.c_str();
|
| + const bool success = dbus_message_iter_append_basic(
|
| + &raw_message_iter_, DBUS_TYPE_STRING, &pointer);
|
| + // It may make sense to return an error here, as the input string can be
|
| + // large. If needed, we could add something like
|
| + // bool AppendStringWithErrorChecking().
|
| + DCHECK(success) << "Unable to allocate memory";
|
| +}
|
| +
|
| +void MessageWriter::AppendObjectPath(const std::string& value) {
|
| + const char* pointer = value.c_str();
|
| + const bool success = dbus_message_iter_append_basic(
|
| + &raw_message_iter_, DBUS_TYPE_OBJECT_PATH, &pointer);
|
| + DCHECK(success) << "Unable to allocate memory";
|
| +}
|
| +
|
| +void MessageWriter::OpenArray(const std::string& signature,
|
| + MessageWriter* writer) {
|
| + const bool success = dbus_message_iter_open_container(
|
| + &raw_message_iter_,
|
| + DBUS_TYPE_ARRAY,
|
| + signature.c_str(),
|
| + &writer->raw_message_iter_);
|
| + DCHECK(success) << "Unable to allocate memory";
|
| +}
|
| +
|
| +void MessageWriter::OpenVariant(const std::string& signature,
|
| + MessageWriter* writer) {
|
| + const bool success = dbus_message_iter_open_container(
|
| + &raw_message_iter_,
|
| + DBUS_TYPE_VARIANT,
|
| + signature.c_str(),
|
| + &writer->raw_message_iter_);
|
| + DCHECK(success) << "Unable to allocate memory";
|
| +}
|
| +
|
| +void MessageWriter::OpenStruct(MessageWriter* writer) {
|
| + const bool success = dbus_message_iter_open_container(
|
| + &raw_message_iter_,
|
| + DBUS_TYPE_STRUCT,
|
| + NULL, // Signature should be NULL.
|
| + &writer->raw_message_iter_);
|
| + DCHECK(success) << "Unable to allocate memory";
|
| +}
|
| +
|
| +void MessageWriter::OpenDictEntry(MessageWriter* writer) {
|
| + const bool success = dbus_message_iter_open_container(
|
| + &raw_message_iter_,
|
| + DBUS_TYPE_DICT_ENTRY,
|
| + NULL, // Signature should be NULL.
|
| + &writer->raw_message_iter_);
|
| + DCHECK(success) << "Unable to allocate memory";
|
| +}
|
| +
|
| +void MessageWriter::CloseContainer(MessageWriter* writer) {
|
| + const bool success = dbus_message_iter_close_container(
|
| + &raw_message_iter_, &writer->raw_message_iter_);
|
| + DCHECK(success) << "Unable to allocate memory";
|
| +}
|
| +
|
| +//
|
| +// MessageReader implementation.
|
| +//
|
| +
|
| +MessageReader::MessageReader(Message* message)
|
| + : message_(message) {
|
| + dbus_message_iter_init(message_->raw_message(), &raw_message_iter_);
|
| +}
|
| +
|
| +
|
| +MessageReader::~MessageReader() {
|
| +}
|
| +
|
| +bool MessageReader::HasMore() {
|
| + const int dbus_type = dbus_message_iter_get_arg_type(&raw_message_iter_);
|
| + return dbus_type != DBUS_TYPE_INVALID;
|
| +}
|
| +
|
| +bool MessageReader::PopByte(uint8* value) {
|
| + return PopBasic(DBUS_TYPE_BYTE, value);
|
| +}
|
| +
|
| +bool MessageReader::PopBool(bool* value) {
|
| + return PopBasic(DBUS_TYPE_BOOLEAN, value);
|
| +}
|
| +
|
| +bool MessageReader::PopInt16(int16* value) {
|
| + return PopBasic(DBUS_TYPE_INT16, value);
|
| +}
|
| +
|
| +bool MessageReader::PopUint16(uint16* value) {
|
| + return PopBasic(DBUS_TYPE_UINT16, value);
|
| +}
|
| +
|
| +bool MessageReader::PopInt32(int32* value) {
|
| + return PopBasic(DBUS_TYPE_INT32, value);
|
| +}
|
| +
|
| +bool MessageReader::PopUint32(uint32* value) {
|
| + return PopBasic(DBUS_TYPE_UINT32, value);
|
| +}
|
| +
|
| +bool MessageReader::PopInt64(int64* value) {
|
| + return PopBasic(DBUS_TYPE_INT64, value);
|
| +}
|
| +
|
| +bool MessageReader::PopUint64(uint64* value) {
|
| + return PopBasic(DBUS_TYPE_UINT64, value);
|
| +}
|
| +
|
| +bool MessageReader::PopDouble(double* value) {
|
| + return PopBasic(DBUS_TYPE_DOUBLE, value);
|
| +}
|
| +
|
| +bool MessageReader::PopString(std::string* value) {
|
| + char* tmp_value = NULL;
|
| + const bool success = PopBasic(DBUS_TYPE_STRING, &tmp_value);
|
| + if (success)
|
| + *value = tmp_value; // Copy the string.
|
| + return success;
|
| +}
|
| +
|
| +bool MessageReader::PopObjectPath(std::string* value) {
|
| + char* tmp_value = NULL;
|
| + const bool success = PopBasic(DBUS_TYPE_OBJECT_PATH, &tmp_value);
|
| + if (success)
|
| + *value = tmp_value; // Copy the string.
|
| + return success;
|
| +}
|
| +
|
| +bool MessageReader::PopArray(MessageReader* sub_reader) {
|
| + return PopContainer(DBUS_TYPE_ARRAY, sub_reader);
|
| +}
|
| +
|
| +bool MessageReader::PopStruct(MessageReader* sub_reader) {
|
| + return PopContainer(DBUS_TYPE_STRUCT, sub_reader);
|
| +}
|
| +
|
| +bool MessageReader::PopDictEntry(MessageReader* sub_reader) {
|
| + return PopContainer(DBUS_TYPE_DICT_ENTRY, sub_reader);
|
| +}
|
| +
|
| +bool MessageReader::PopVariant(MessageReader* sub_reader) {
|
| + return PopContainer(DBUS_TYPE_VARIANT, sub_reader);
|
| +}
|
| +
|
| +bool MessageReader::PopArrayOfBytes(
|
| + std::vector<uint8>* bytes) {
|
| + MessageReader array_reader(message_);
|
| + if (!PopArray(&array_reader))
|
| + return false;
|
| + if (!array_reader.CheckType(DBUS_TYPE_BYTE))
|
| + return false;
|
| + char* values = NULL;
|
| + int num_values = 0;
|
| + dbus_message_iter_get_fixed_array(&array_reader.raw_message_iter_,
|
| + &values, &num_values);
|
| + if (!values)
|
| + return false;
|
| +
|
| + bytes->assign(values, values + num_values); // Copy the data.
|
| + return true;
|
| +}
|
| +
|
| +bool MessageReader::PopArrayOfObjectPaths(
|
| + std::vector<std::string> *object_paths) {
|
| + MessageReader array_reader(message_);
|
| + if (!PopArray(&array_reader))
|
| + return false;
|
| + while (array_reader.HasMore()) {
|
| + std::string object_path;
|
| + if (!array_reader.PopObjectPath(&object_path))
|
| + return false;
|
| + object_paths->push_back(object_path);
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool MessageReader::PopVariantOfByte(uint8* value) {
|
| + return PopVariantOfBasic(DBUS_TYPE_BYTE, value);
|
| +}
|
| +
|
| +bool MessageReader::PopVariantOfBool(bool* value) {
|
| + return PopVariantOfBasic(DBUS_TYPE_BOOLEAN, value);
|
| +}
|
| +
|
| +bool MessageReader::PopVariantOfInt16(int16* value) {
|
| + return PopVariantOfBasic(DBUS_TYPE_INT16, value);
|
| +}
|
| +
|
| +bool MessageReader::PopVariantOfUint16(uint16* value) {
|
| + return PopVariantOfBasic(DBUS_TYPE_UINT16, value);
|
| +}
|
| +
|
| +bool MessageReader::PopVariantOfInt32(int32* value) {
|
| + return PopVariantOfBasic(DBUS_TYPE_INT32, value);
|
| +}
|
| +
|
| +bool MessageReader::PopVariantOfUint32(uint32* value) {
|
| + return PopVariantOfBasic(DBUS_TYPE_UINT32, value);
|
| +}
|
| +
|
| +bool MessageReader::PopVariantOfInt64(int64* value) {
|
| + return PopVariantOfBasic(DBUS_TYPE_INT64, value);
|
| +}
|
| +
|
| +bool MessageReader::PopVariantOfUint64(uint64* value) {
|
| + return PopVariantOfBasic(DBUS_TYPE_UINT64, value);
|
| +}
|
| +
|
| +bool MessageReader::PopVariantOfDouble(double* value) {
|
| + return PopVariantOfBasic(DBUS_TYPE_DOUBLE, value);
|
| +}
|
| +
|
| +bool MessageReader::PopVariantOfString(std::string* value) {
|
| + char* tmp_value = NULL;
|
| + const bool success = PopVariantOfBasic(DBUS_TYPE_STRING, &tmp_value);
|
| + if (success)
|
| + *value = tmp_value; // Copy the string.
|
| + return success;
|
| +}
|
| +
|
| +bool MessageReader::PopVariantOfObjectPath(std::string* value) {
|
| + char* tmp_value = NULL;
|
| + const bool success = PopVariantOfBasic(DBUS_TYPE_OBJECT_PATH, &tmp_value);
|
| + if (success)
|
| + *value = tmp_value; // Copy the string.
|
| + return success;
|
| +}
|
| +
|
| +Message::Type MessageReader::GetType() {
|
| + const int dbus_type = dbus_message_iter_get_arg_type(&raw_message_iter_);
|
| + return static_cast<Message::Type>(dbus_type);
|
| +}
|
| +
|
| +bool MessageReader::CheckType(int dbus_type) {
|
| + const int actual_type = dbus_message_iter_get_arg_type(&raw_message_iter_);
|
| + if (actual_type != dbus_type) {
|
| + VLOG(1) << "Type " << dbus_type << " is expected but got "
|
| + << actual_type;
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool MessageReader::PopBasic(int dbus_type, void* value) {
|
| + if (!CheckType(dbus_type))
|
| + return false;
|
| + dbus_message_iter_get_basic(&raw_message_iter_, value);
|
| + dbus_message_iter_next(&raw_message_iter_);
|
| + return true;
|
| +}
|
| +
|
| +bool MessageReader::PopContainer(int dbus_type, MessageReader* sub_reader) {
|
| + DCHECK_NE(this, sub_reader);
|
| +
|
| + if (!CheckType(dbus_type))
|
| + return false;
|
| + dbus_message_iter_recurse(&raw_message_iter_,
|
| + &sub_reader->raw_message_iter_);
|
| + dbus_message_iter_next(&raw_message_iter_);
|
| + return true;
|
| +}
|
| +
|
| +bool MessageReader::PopVariantOfBasic(int dbus_type, void* value) {
|
| + net::dbus::MessageReader variant_reader(message_);
|
| + if (!PopVariant(&variant_reader))
|
| + return false;
|
| + return variant_reader.PopBasic(dbus_type, value);
|
| +}
|
| +
|
| +} // namespace dbus
|
| +} // namespace net
|
|
|