summaryrefslogtreecommitdiffstats
path: root/dbus/object_proxy.cc
diff options
context:
space:
mode:
authorsatorux@chromium.org <satorux@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-17 20:58:12 +0000
committersatorux@chromium.org <satorux@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-17 20:58:12 +0000
commita510761104333ec7da3943399f059ff693839856 (patch)
tree2a9f81a60bccf4db3367ad1b8f71e9ea130efb7d /dbus/object_proxy.cc
parent07f93af15169ee054552a376ac4953abd1346cb2 (diff)
downloadchromium_src-a510761104333ec7da3943399f059ff693839856.zip
chromium_src-a510761104333ec7da3943399f059ff693839856.tar.gz
chromium_src-a510761104333ec7da3943399f059ff693839856.tar.bz2
Implement Bus and ObjectProxy classes for our D-Bus library.
ObjectProxy is used to access remote objects. ExportedObject is used to export objects to other D-Bus BUG=90036 TEST=run unit tests. The code is not yet used in Chrome. Review URL: http://codereview.chromium.org/7491029 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@97204 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'dbus/object_proxy.cc')
-rw-r--r--dbus/object_proxy.cc197
1 files changed, 197 insertions, 0 deletions
diff --git a/dbus/object_proxy.cc b/dbus/object_proxy.cc
new file mode 100644
index 0000000..24dbde2
--- /dev/null
+++ b/dbus/object_proxy.cc
@@ -0,0 +1,197 @@
+// 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 "dbus/bus.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_restrictions.h"
+#include "dbus/message.h"
+#include "dbus/object_proxy.h"
+#include "dbus/scoped_dbus_error.h"
+
+namespace dbus {
+
+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::CallMethodAndBlock(MethodCall* method_call,
+ int timeout_ms,
+ Response* response) {
+ bus_->AssertOnDBusThread();
+
+ if (!bus_->Connect())
+ return false;
+
+ method_call->SetDestination(service_name_);
+ method_call->SetPath(object_path_);
+ DBusMessage* request_message = method_call->raw_message();
+
+ ScopedDBusError error;
+
+ // Send the message synchronously.
+ DBusMessage* response_message =
+ bus_->SendWithReplyAndBlock(request_message, timeout_ms, error.get());
+
+ if (!response_message) {
+ LOG(ERROR) << "Failed to call method: "
+ << (error.is_set() ? error.message() : "");
+ return false;
+ }
+ response->reset_raw_message(response_message);
+
+ return true;
+}
+
+void ObjectProxy::CallMethod(MethodCall* method_call,
+ int timeout_ms,
+ ResponseCallback callback) {
+ bus_->AssertOnOriginThread();
+
+ method_call->SetDestination(service_name_);
+ method_call->SetPath(object_path_);
+ // Increment the reference count so we can safely reference the
+ // underlying request message until the method call is complete. This
+ // will be unref'ed in StartAsyncMethodCall().
+ 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() cannot handle.
+ // Hence we cast it to void* to workaround the issue.
+ base::Closure task = base::Bind(&ObjectProxy::StartAsyncMethodCall,
+ this,
+ timeout_ms,
+ static_cast<void*>(request_message),
+ callback);
+ // Wait for the response in the D-Bus thread.
+ bus_->PostTaskToDBusThread(FROM_HERE, task);
+}
+
+ObjectProxy::OnPendingCallIsCompleteData::OnPendingCallIsCompleteData(
+ ObjectProxy* in_object_proxy,
+ ResponseCallback in_response_callback)
+ : object_proxy(in_object_proxy),
+ response_callback(in_response_callback) {
+}
+
+ObjectProxy::OnPendingCallIsCompleteData::~OnPendingCallIsCompleteData() {
+}
+
+void ObjectProxy::StartAsyncMethodCall(int timeout_ms,
+ void* in_request_message,
+ ResponseCallback response_callback) {
+ bus_->AssertOnDBusThread();
+
+ if (!bus_->Connect() || !bus_->SetUpAsyncOperations()) {
+ // In case of a failure, run the callback with NULL response, that
+ // indicates a failure.
+ Response* response = NULL;
+ base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback,
+ this,
+ response_callback,
+ response);
+ bus_->PostTaskToOriginThread(FROM_HERE, task);
+ return;
+ }
+
+ DBusMessage* request_message =
+ static_cast<DBusMessage*>(in_request_message);
+ DBusPendingCall* pending_call = NULL;
+
+ bus_->SendWithReply(request_message, &pending_call, timeout_ms);
+
+ // Prepare the data we'll be passing to OnPendingCallIsCompleteThunk().
+ // The data will be deleted in OnPendingCallIsCompleteThunk().
+ OnPendingCallIsCompleteData* data =
+ new OnPendingCallIsCompleteData(this, response_callback);
+
+ // This returns false only when unable to allocate memory.
+ const bool success = dbus_pending_call_set_notify(
+ pending_call,
+ &ObjectProxy::OnPendingCallIsCompleteThunk,
+ data,
+ NULL);
+ CHECK(success) << "Unable to allocate memory";
+ dbus_pending_call_unref(pending_call);
+
+ // It's now safe to unref the request message.
+ dbus_message_unref(request_message);
+}
+
+void ObjectProxy::OnPendingCallIsComplete(DBusPendingCall* pending_call,
+ ResponseCallback response_callback) {
+ bus_->AssertOnDBusThread();
+
+ DBusMessage* response_message = dbus_pending_call_steal_reply(pending_call);
+
+ if (!response_message) {
+ // This shouldn't happen but just in case.
+ LOG(ERROR) << "The response message is not received for some reason";
+ Response* response = NULL;
+ base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback,
+ this,
+ response_callback,
+ response);
+ bus_->PostTaskToOriginThread(FROM_HERE, task);
+ return;
+ }
+
+ // The response message will be deleted in RunResponseCallback().
+ Response* response = new Response;
+ response->reset_raw_message(response_message);
+ base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback,
+ this,
+ response_callback,
+ response);
+ bus_->PostTaskToOriginThread(FROM_HERE, task);
+}
+
+void ObjectProxy::RunResponseCallback(ResponseCallback response_callback,
+ Response* response) {
+ bus_->AssertOnOriginThread();
+
+ if (!response) {
+ // The response is not received.
+ response_callback.Run(NULL);
+ } else if (response->GetMessageType() == Message::MESSAGE_ERROR) {
+ // Error message may contain the error message as string.
+ dbus::MessageReader reader(response);
+ std::string error_message;
+ reader.PopString(&error_message);
+ LOG(ERROR) << "Failed to call method: " << response->GetErrorName()
+ << ": " << error_message;
+ // We don't give the error message to the callback.
+ response_callback.Run(NULL);
+ } else {
+ // The response is successfuly received.
+ response_callback.Run(response);
+ }
+ delete response; // It's ok to delete NULL.
+}
+
+void ObjectProxy::OnPendingCallIsCompleteThunk(DBusPendingCall* pending_call,
+ void* user_data) {
+ OnPendingCallIsCompleteData* data =
+ reinterpret_cast<OnPendingCallIsCompleteData*>(user_data);
+ ObjectProxy* self = data->object_proxy;
+ self->OnPendingCallIsComplete(pending_call,
+ data->response_callback);
+ delete data;
+}
+
+} // namespace dbus