OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "dbus/bus.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/logging.h" | |
9 #include "base/message_loop.h" | |
10 #include "base/threading/thread.h" | |
11 #include "base/threading/thread_restrictions.h" | |
12 #include "dbus/error.h" | |
13 #include "dbus/message.h" | |
14 #include "dbus/object_proxy.h" | |
15 | |
16 namespace dbus { | |
17 | |
18 ObjectProxy::ObjectProxy(Bus* bus, | |
19 const std::string& service_name, | |
20 const std::string& object_path) | |
21 : bus_(bus), | |
22 service_name_(service_name), | |
23 object_path_(object_path) { | |
24 } | |
25 | |
26 ObjectProxy::~ObjectProxy() { | |
27 } | |
28 | |
29 // Originally we tried to make |method_call| a const reference, but we | |
30 // gave up as dbus_connection_send_with_reply_and_block() takes a | |
31 // non-const pointer of DBusMessage as the second parameter. | |
32 bool ObjectProxy::CallMethodAndBlock(MethodCall* method_call, | |
33 int timeout_ms, | |
34 Response* response) { | |
35 bus_->AssertOnDBusThread(); | |
36 | |
37 if (!bus_->Connect()) | |
38 return false; | |
39 | |
40 method_call->SetDestination(service_name_); | |
41 method_call->SetPath(object_path_); | |
42 DBusMessage* request_message = method_call->raw_message(); | |
43 | |
44 ScopedDBusError error; | |
45 | |
46 // Send the message synchronously. | |
47 DBusMessage* response_message = | |
48 bus_->SendWithReplyAndBlock(request_message, timeout_ms, error.get()); | |
49 | |
50 if (!response_message) { | |
51 LOG(ERROR) << "Failed to call method: " | |
52 << (error.is_set() ? error.message() : ""); | |
53 return false; | |
54 } | |
55 response->reset_raw_message(response_message); | |
56 | |
57 return true; | |
58 } | |
59 | |
60 void ObjectProxy::CallMethod(MethodCall* method_call, | |
61 int timeout_ms, | |
62 ResponseCallback callback) { | |
63 bus_->AssertOnOriginThread(); | |
64 | |
65 method_call->SetDestination(service_name_); | |
66 method_call->SetPath(object_path_); | |
67 // Increment the reference count so we can safely reference the | |
68 // underlying request message until the method call is complete. This | |
69 // will be unref'ed in StartAsyncMethodCall(). | |
70 DBusMessage* request_message = method_call->raw_message(); | |
71 dbus_message_ref(request_message); | |
72 | |
73 // Bind() won't compile if we pass request_message as-is since | |
74 // DBusMessage is an opaque struct which Bind() cannot handle. | |
75 // Hence we cast it to void* to workaround the issue. | |
76 base::Closure task = base::Bind(&ObjectProxy::StartAsyncMethodCall, | |
77 this, | |
78 timeout_ms, | |
79 static_cast<void*>(request_message), | |
80 callback); | |
81 // Wait for the response in the D-Bus thread. | |
82 bus_->PostTaskToDBusThread(FROM_HERE, task); | |
83 } | |
84 | |
85 ObjectProxy::OnPendingCallIsCompleteData::OnPendingCallIsCompleteData( | |
86 ObjectProxy* in_object_proxy, | |
87 ResponseCallback in_response_callback) | |
88 : object_proxy(in_object_proxy), | |
89 response_callback(in_response_callback) { | |
90 } | |
91 | |
92 void ObjectProxy::StartAsyncMethodCall(int timeout_ms, | |
93 void* in_request_message, | |
94 ResponseCallback response_callback) { | |
95 bus_->AssertOnDBusThread(); | |
96 | |
97 if (!bus_->Connect() || !bus_->SetUpAsyncOperations()) { | |
98 Response* response = NULL; | |
99 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback, | |
100 this, | |
101 response_callback, | |
102 response); | |
103 bus_->PostTaskToOriginThread(FROM_HERE, task); | |
104 return; | |
105 } | |
106 | |
107 DBusMessage* request_message = | |
108 static_cast<DBusMessage*>(in_request_message); | |
109 DBusPendingCall* pending_call = NULL; | |
110 | |
111 // This returns false only when unable to allocate memory. | |
112 bus_->SendWithReply(request_message, | |
113 &pending_call, | |
114 timeout_ms); | |
stevenjb
2011/08/10 19:40:07
nit: alignment
satorux1
2011/08/10 21:40:55
Done.
| |
115 | |
116 // Prepare the data we'll be passing to OnPendingCallIsCompleteThunk(). | |
117 // The data will be deleted in OnPendingCallIsCompleteThunk(). | |
118 OnPendingCallIsCompleteData* data = | |
119 new OnPendingCallIsCompleteData(this, response_callback); | |
120 | |
121 // This returns false only when unable to allocate memory. | |
122 const bool success = dbus_pending_call_set_notify( | |
123 pending_call, | |
124 &ObjectProxy::OnPendingCallIsCompleteThunk, | |
125 data, | |
126 NULL); | |
127 CHECK(success) << "Unable to allocate memory"; | |
128 dbus_pending_call_unref(pending_call); | |
129 | |
130 // It's now safe to unref the request message. | |
131 dbus_message_unref(request_message); | |
132 } | |
133 | |
134 void ObjectProxy::OnPendingCallIsComplete(DBusPendingCall* pending_call, | |
135 ResponseCallback response_callback) { | |
136 bus_->AssertOnDBusThread(); | |
137 | |
138 DBusMessage* response_message = dbus_pending_call_steal_reply(pending_call); | |
139 | |
140 if (!response_message) { | |
141 // This shouldn't happen but just in case. | |
142 LOG(ERROR) << "The response message is not received for some reason"; | |
143 Response* response = NULL; | |
144 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback, | |
145 this, | |
146 response_callback, | |
147 response); | |
148 bus_->PostTaskToOriginThread(FROM_HERE, task); | |
149 return; | |
150 } | |
151 | |
152 // The response message will be deleted in the callback. | |
153 Response* response = new Response; | |
154 response->reset_raw_message(response_message); | |
155 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback, | |
156 this, | |
157 response_callback, | |
158 response); | |
159 bus_->PostTaskToOriginThread(FROM_HERE, task); | |
160 } | |
161 | |
162 void ObjectProxy::RunResponseCallback(ResponseCallback response_callback, | |
163 Response* response) { | |
164 bus_->AssertOnOriginThread(); | |
165 | |
166 if (!response) { | |
167 // The response is not received. | |
168 response_callback.Run(NULL); | |
169 } else if (response->GetMessageType() == Message::MESSAGE_ERROR) { | |
170 // Error message may contain the error message as string. | |
171 dbus::MessageReader reader(response); | |
172 std::string error_message; | |
173 reader.PopString(&error_message); | |
174 LOG(ERROR) << "Failed to call method: " << response->GetErrorName() | |
175 << ": " << error_message; | |
176 // We don't give the error message to the callback. | |
177 delete response; | |
178 response_callback.Run(NULL); | |
179 } else { | |
180 // The response is successfuly received. | |
181 response_callback.Run(response); | |
182 } | |
183 } | |
184 | |
185 void ObjectProxy::OnPendingCallIsCompleteThunk(DBusPendingCall* pending_call, | |
186 void* user_data) { | |
187 OnPendingCallIsCompleteData* data = | |
188 reinterpret_cast<OnPendingCallIsCompleteData*>(user_data); | |
189 ObjectProxy* self = data->object_proxy; | |
190 self->OnPendingCallIsComplete(pending_call, | |
191 data->response_callback); | |
192 delete data; | |
193 } | |
194 | |
195 } // namespace dbus | |
OLD | NEW |