Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(290)

Unified Diff: dbus/object_proxy.cc

Issue 7491029: Implement Bus and ObjectProxy classes for our D-Bus library. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: another clang challenge Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « dbus/object_proxy.h ('k') | dbus/scoped_dbus_error.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: dbus/object_proxy.cc
diff --git a/dbus/object_proxy.cc b/dbus/object_proxy.cc
new file mode 100644
index 0000000000000000000000000000000000000000..24dbde227671b4f010a9f91a7b7324a9a7415b5a
--- /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
« no previous file with comments | « dbus/object_proxy.h ('k') | dbus/scoped_dbus_error.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698