| 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 "net/dbus/dbus.h" |
| 6 |
| 7 #include "base/bind.h" |
| 8 #include "base/logging.h" |
| 9 #include "base/message_loop.h" |
| 10 |
| 11 namespace net { |
| 12 namespace dbus { |
| 13 |
| 14 // |
| 15 // Bus implementation. |
| 16 // |
| 17 |
| 18 Bus::Bus(const Options& options) |
| 19 : bus_type_(options.bus_type), |
| 20 connection_type_(options.connection_type), |
| 21 connection_(NULL) { |
| 22 } |
| 23 |
| 24 Bus::~Bus() { |
| 25 // Private connection should be closed. |
| 26 if (connection_ && connection_type_ == PRIVATE) { |
| 27 dbus_connection_close(connection_); |
| 28 } |
| 29 } |
| 30 |
| 31 bool Bus::Init() { |
| 32 // Check if it's already initialized. |
| 33 if (connection_) |
| 34 return true; |
| 35 |
| 36 DBusError error = {}; |
| 37 dbus_error_init(&error); |
| 38 const DBusBusType dbus_bus_type = static_cast<DBusBusType>(bus_type_); |
| 39 if (connection_type_ == PRIVATE) { |
| 40 connection_ = dbus_bus_get_private(dbus_bus_type, &error); |
| 41 } else { |
| 42 connection_ = dbus_bus_get(dbus_bus_type, &error); |
| 43 } |
| 44 if (!connection_) { |
| 45 if (dbus_error_is_set(&error)) { |
| 46 LOG(ERROR) << error.message; |
| 47 } |
| 48 return false; |
| 49 } |
| 50 |
| 51 return true; |
| 52 } |
| 53 |
| 54 ObjectProxy* Bus::GetObjectProxy(const std::string& service_name, |
| 55 const std::string& object_path) { |
| 56 DCHECK(connection_) << "Connection not yet established"; |
| 57 return new ObjectProxy(this, service_name, object_path); |
| 58 } |
| 59 |
| 60 // |
| 61 // ObjectProxy implementation. |
| 62 // |
| 63 |
| 64 ObjectProxy::ObjectProxy(Bus* bus, |
| 65 const std::string& service_name, |
| 66 const std::string& object_path) |
| 67 : bus_(bus), |
| 68 service_name_(service_name), |
| 69 object_path_(object_path) { |
| 70 } |
| 71 |
| 72 ObjectProxy::~ObjectProxy() { |
| 73 } |
| 74 |
| 75 // Originally we tried to make |method_call| a const reference, but we |
| 76 // gave up as dbus_connection_send_with_reply_and_block() takes a |
| 77 // non-const pointer of DBusMessage as the second parameter. |
| 78 bool ObjectProxy::CallMethodSync(MethodCall* method_call, |
| 79 Response* response) { |
| 80 if (!bus_->Init()) |
| 81 return false; |
| 82 method_call->SetServiceName(service_name_); |
| 83 method_call->SetObjectPath(object_path_); |
| 84 DBusMessage* request_message = method_call->raw_message(); |
| 85 |
| 86 const int timeout_ms = -1; // Default timeout. |
| 87 DBusError error = {}; |
| 88 dbus_error_init(&error); |
| 89 |
| 90 // Send the message synchronously. |
| 91 DBusMessage* response_message = dbus_connection_send_with_reply_and_block( |
| 92 bus_->connection(), request_message, timeout_ms, &error); |
| 93 |
| 94 if (!response_message) { |
| 95 if (dbus_error_is_set(&error)) { |
| 96 LOG(ERROR) << error.message; |
| 97 } |
| 98 return false; |
| 99 } |
| 100 response->reset_raw_message(response_message); |
| 101 |
| 102 return true; |
| 103 } |
| 104 |
| 105 void ObjectProxy::CallMethodAsync(MethodCall* method_call, |
| 106 ResponseCallback callback) { |
| 107 method_call->SetServiceName(service_name_); |
| 108 method_call->SetObjectPath(object_path_); |
| 109 // This is a bit tricky but increment the reference count of the request |
| 110 // message here so that we can keep using the message even if the |
| 111 // MethodCall object at the caller is gone before the method call is |
| 112 // complete. |
| 113 DBusMessage* request_message = method_call->raw_message(); |
| 114 dbus_message_ref(request_message); |
| 115 |
| 116 // Bind() won't compile if we pass request_message as-is since |
| 117 // DBusMessage is an opaque struct which Bind() does not like. |
| 118 // |
| 119 // /base/bind_helpers.h:145: |
| 120 // error: invalid use of incomplete type 'struct DBusMessage' |
| 121 // |
| 122 // Hence we cast it to void* to workaround the issue. |
| 123 base::Closure task = base::Bind(&ObjectProxy::StartAsyncMethodCall, |
| 124 // Make this a ref-counted class? |
| 125 base::Unretained(this), |
| 126 reinterpret_cast<void*>(request_message), |
| 127 MessageLoop::current(), |
| 128 callback); |
| 129 MessageLoopForIO::current()->PostTask(FROM_HERE, task); |
| 130 } |
| 131 |
| 132 void ObjectProxy::StartAsyncMethodCall(void* in_request_message, |
| 133 MessageLoop* origin_loop, |
| 134 ResponseCallback response_callback) { |
| 135 LOG(ERROR) << "@@ " << __PRETTY_FUNCTION__; |
| 136 |
| 137 DBusMessage* request_message = |
| 138 reinterpret_cast<DBusMessage*>(in_request_message); |
| 139 if (bus_->Init()) { |
| 140 const int timeout_ms = -1; // Default timeout. |
| 141 DBusPendingCall* pending_call = NULL; |
| 142 // This returns false only when unable to allocate memory. |
| 143 bool success = false; |
| 144 success = dbus_connection_send_with_reply( |
| 145 bus_->connection(), request_message, &pending_call, timeout_ms); |
| 146 DCHECK(success) << "Unable to allocate memory"; |
| 147 |
| 148 OnPendingCallIsCompleteData* data = |
| 149 new OnPendingCallIsCompleteData(origin_loop, response_callback); |
| 150 |
| 151 // This returns false only when unable to allocate memory. |
| 152 success = dbus_pending_call_set_notify( |
| 153 pending_call, |
| 154 &ObjectProxy::OnPendingCallIsComplete, |
| 155 data, |
| 156 NULL); |
| 157 DCHECK(success) << "Unable to allocate memory"; |
| 158 } else { |
| 159 Response* response = NULL; |
| 160 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback, |
| 161 response_callback, |
| 162 response); |
| 163 origin_loop->PostTask(FROM_HERE, task); |
| 164 } |
| 165 // It's now safe to unref the request message. |
| 166 dbus_message_unref(request_message); |
| 167 } |
| 168 |
| 169 void ObjectProxy::RunResponseCallback(ResponseCallback response_callback, |
| 170 Response* response) { |
| 171 LOG(ERROR) << "@@ " << __PRETTY_FUNCTION__; |
| 172 |
| 173 response_callback.Run(response); |
| 174 } |
| 175 |
| 176 ObjectProxy::OnPendingCallIsCompleteData::OnPendingCallIsCompleteData( |
| 177 MessageLoop* in_origin_loop, |
| 178 ResponseCallback in_response_callback) |
| 179 : origin_loop(in_origin_loop), |
| 180 response_callback(in_response_callback) { |
| 181 } |
| 182 |
| 183 void ObjectProxy::OnPendingCallIsComplete(DBusPendingCall* pending_call, |
| 184 void* user_data) { |
| 185 OnPendingCallIsCompleteData* data = |
| 186 reinterpret_cast<OnPendingCallIsCompleteData*>(user_data); |
| 187 |
| 188 DBusMessage* response_message = dbus_pending_call_steal_reply(pending_call); |
| 189 CHECK(response_message) << "hoge"; |
| 190 // This will be deleted in the callback. |
| 191 Response* response = new Response; |
| 192 response->reset_raw_message(response_message); |
| 193 base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback, |
| 194 data->response_callback, |
| 195 response); |
| 196 data->origin_loop->PostTask(FROM_HERE, task); |
| 197 |
| 198 delete data; |
| 199 } |
| 200 |
| 201 // |
| 202 // Message implementation. |
| 203 // |
| 204 |
| 205 Message::Message() |
| 206 : raw_message_(NULL) { |
| 207 } |
| 208 |
| 209 Message::~Message() { |
| 210 if (raw_message_) |
| 211 dbus_message_unref(raw_message_); |
| 212 } |
| 213 |
| 214 void Message::reset_raw_message(DBusMessage* raw_message) { |
| 215 if (raw_message_) |
| 216 dbus_message_unref(raw_message_); |
| 217 raw_message_ = raw_message; |
| 218 } |
| 219 |
| 220 // |
| 221 // MethodCall implementation. |
| 222 // |
| 223 |
| 224 MethodCall::MethodCall(const std::string& interface_name, |
| 225 const std::string& method_name) |
| 226 : Message() { |
| 227 reset_raw_message(dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_CALL)); |
| 228 |
| 229 bool success = false; |
| 230 success = dbus_message_set_interface(raw_message(), interface_name.c_str()); |
| 231 DCHECK(success) << "Unable to allocate memory"; |
| 232 |
| 233 success = dbus_message_set_member(raw_message(), method_name.c_str()); |
| 234 DCHECK(success) << "Unable to allocate memory"; |
| 235 } |
| 236 |
| 237 void MethodCall::SetServiceName(const std::string& service_name) { |
| 238 const bool success = dbus_message_set_destination(raw_message(), |
| 239 service_name.c_str()); |
| 240 DCHECK(success) << "Unable to allocate memory"; |
| 241 } |
| 242 |
| 243 void MethodCall::SetObjectPath(const std::string& object_path) { |
| 244 const bool success = dbus_message_set_path(raw_message(), |
| 245 object_path.c_str()); |
| 246 DCHECK(success) << "Unable to allocate memory"; |
| 247 } |
| 248 |
| 249 // |
| 250 // Response implementation. |
| 251 // |
| 252 |
| 253 Response::Response() : Message() { |
| 254 } |
| 255 |
| 256 // |
| 257 // MessageWriter implementation. |
| 258 // |
| 259 |
| 260 MessageWriter::MessageWriter(Message* message) : |
| 261 message_(message) { |
| 262 dbus_message_iter_init_append(message_->raw_message(), &raw_message_iter_); |
| 263 } |
| 264 |
| 265 |
| 266 MessageWriter::~MessageWriter() { |
| 267 } |
| 268 |
| 269 void MessageWriter::AppendByte(uint8 value) { |
| 270 const bool success = dbus_message_iter_append_basic( |
| 271 &raw_message_iter_, DBUS_TYPE_BYTE, &value); |
| 272 // dbus_message_iter_append_basic() fails only when there is not enough |
| 273 // memory. We don't return this error as there is nothing we can do when |
| 274 // it fails to allocate memory for a byte. |
| 275 DCHECK(success) << "Unable to allocate memory"; |
| 276 } |
| 277 |
| 278 void MessageWriter::AppendBool(bool value) { |
| 279 const bool success = dbus_message_iter_append_basic( |
| 280 &raw_message_iter_, DBUS_TYPE_BOOLEAN, &value); |
| 281 DCHECK(success) << "Unable to allocate memory"; |
| 282 } |
| 283 |
| 284 void MessageWriter::AppendInt16(int16 value) { |
| 285 const bool success = dbus_message_iter_append_basic( |
| 286 &raw_message_iter_, DBUS_TYPE_INT16, &value); |
| 287 DCHECK(success) << "Unable to allocate memory"; |
| 288 } |
| 289 |
| 290 void MessageWriter::AppendUint16(uint16 value) { |
| 291 const bool success = dbus_message_iter_append_basic( |
| 292 &raw_message_iter_, DBUS_TYPE_UINT16, &value); |
| 293 DCHECK(success) << "Unable to allocate memory"; |
| 294 } |
| 295 |
| 296 void MessageWriter::AppendInt32(int32 value) { |
| 297 const bool success = dbus_message_iter_append_basic( |
| 298 &raw_message_iter_, DBUS_TYPE_INT32, &value); |
| 299 DCHECK(success) << "Unable to allocate memory"; |
| 300 } |
| 301 |
| 302 void MessageWriter::AppendUint32(uint32 value) { |
| 303 const bool success = dbus_message_iter_append_basic( |
| 304 &raw_message_iter_, DBUS_TYPE_UINT32, &value); |
| 305 DCHECK(success) << "Unable to allocate memory"; |
| 306 } |
| 307 |
| 308 void MessageWriter::AppendInt64(int64 value) { |
| 309 const bool success = dbus_message_iter_append_basic( |
| 310 &raw_message_iter_, DBUS_TYPE_INT64, &value); |
| 311 DCHECK(success) << "Unable to allocate memory"; |
| 312 } |
| 313 |
| 314 void MessageWriter::AppendUint64(uint64 value) { |
| 315 const bool success = dbus_message_iter_append_basic( |
| 316 &raw_message_iter_, DBUS_TYPE_UINT64, &value); |
| 317 DCHECK(success) << "Unable to allocate memory"; |
| 318 } |
| 319 |
| 320 void MessageWriter::AppendDouble(double value) { |
| 321 const bool success = dbus_message_iter_append_basic( |
| 322 &raw_message_iter_, DBUS_TYPE_DOUBLE, &value); |
| 323 DCHECK(success) << "Unable to allocate memory"; |
| 324 } |
| 325 |
| 326 void MessageWriter::AppendString(const std::string& value) { |
| 327 const char* pointer = value.c_str(); |
| 328 const bool success = dbus_message_iter_append_basic( |
| 329 &raw_message_iter_, DBUS_TYPE_STRING, &pointer); |
| 330 // It may make sense to return an error here, as the input string can be |
| 331 // large. If needed, we could add something like |
| 332 // bool AppendStringWithErrorChecking(). |
| 333 DCHECK(success) << "Unable to allocate memory"; |
| 334 } |
| 335 |
| 336 void MessageWriter::AppendObjectPath(const std::string& value) { |
| 337 const char* pointer = value.c_str(); |
| 338 const bool success = dbus_message_iter_append_basic( |
| 339 &raw_message_iter_, DBUS_TYPE_OBJECT_PATH, &pointer); |
| 340 DCHECK(success) << "Unable to allocate memory"; |
| 341 } |
| 342 |
| 343 // |
| 344 // MessageReader implementation. |
| 345 // |
| 346 |
| 347 MessageReader::MessageReader(Message* message) |
| 348 : message_(message) { |
| 349 dbus_message_iter_init(message_->raw_message(), &raw_message_iter_); |
| 350 } |
| 351 |
| 352 |
| 353 MessageReader::~MessageReader() { |
| 354 } |
| 355 |
| 356 bool MessageReader::HasMore() { |
| 357 const int dbus_type = dbus_message_iter_get_arg_type(&raw_message_iter_); |
| 358 return dbus_type != DBUS_TYPE_INVALID; |
| 359 } |
| 360 |
| 361 bool MessageReader::PopByte(uint8* value) { |
| 362 return PopBasic(DBUS_TYPE_BYTE, value); |
| 363 } |
| 364 |
| 365 bool MessageReader::PopBool(bool* value) { |
| 366 return PopBasic(DBUS_TYPE_BOOLEAN, value); |
| 367 } |
| 368 |
| 369 bool MessageReader::PopInt16(int16* value) { |
| 370 return PopBasic(DBUS_TYPE_INT16, value); |
| 371 } |
| 372 |
| 373 bool MessageReader::PopUint16(uint16* value) { |
| 374 return PopBasic(DBUS_TYPE_UINT16, value); |
| 375 } |
| 376 |
| 377 bool MessageReader::PopInt32(int32* value) { |
| 378 return PopBasic(DBUS_TYPE_INT32, value); |
| 379 } |
| 380 |
| 381 bool MessageReader::PopUint32(uint32* value) { |
| 382 return PopBasic(DBUS_TYPE_UINT32, value); |
| 383 } |
| 384 |
| 385 bool MessageReader::PopInt64(int64* value) { |
| 386 return PopBasic(DBUS_TYPE_INT64, value); |
| 387 } |
| 388 |
| 389 bool MessageReader::PopUint64(uint64* value) { |
| 390 return PopBasic(DBUS_TYPE_UINT64, value); |
| 391 } |
| 392 |
| 393 bool MessageReader::PopDouble(double* value) { |
| 394 return PopBasic(DBUS_TYPE_DOUBLE, value); |
| 395 } |
| 396 |
| 397 bool MessageReader::PopString(std::string* value) { |
| 398 char* tmp_value = NULL; |
| 399 const bool success = PopBasic(DBUS_TYPE_STRING, &tmp_value); |
| 400 if (success) |
| 401 *value = tmp_value; // Copy the string. |
| 402 return success; |
| 403 } |
| 404 |
| 405 bool MessageReader::PopObjectPath(std::string* value) { |
| 406 char* tmp_value = NULL; |
| 407 const bool success = PopBasic(DBUS_TYPE_OBJECT_PATH, &tmp_value); |
| 408 if (success) |
| 409 *value = tmp_value; // Copy the string. |
| 410 return success; |
| 411 } |
| 412 |
| 413 bool MessageReader::PopArray(MessageReader* array_reader) { |
| 414 return PopContainer(DBUS_TYPE_ARRAY, array_reader); |
| 415 } |
| 416 |
| 417 bool MessageReader::PopStruct(MessageReader* struct_reader) { |
| 418 return PopContainer(DBUS_TYPE_STRUCT, struct_reader); |
| 419 } |
| 420 |
| 421 bool MessageReader::PopDictEntry(MessageReader* dict_entry_reader) { |
| 422 return PopContainer(DBUS_TYPE_DICT_ENTRY, dict_entry_reader); |
| 423 } |
| 424 |
| 425 bool MessageReader::PopVariant(MessageReader* variant_reader) { |
| 426 return PopContainer(DBUS_TYPE_VARIANT, variant_reader); |
| 427 } |
| 428 |
| 429 bool MessageReader::PopArrayOfBytes( |
| 430 std::vector<uint8>* bytes) { |
| 431 MessageReader array_reader(message_); |
| 432 if (!PopArray(&array_reader)) |
| 433 return false; |
| 434 if (!array_reader.CheckType(DBUS_TYPE_BYTE)) |
| 435 return false; |
| 436 char* values = NULL; |
| 437 int num_values = 0; |
| 438 dbus_message_iter_get_fixed_array(&array_reader.raw_message_iter_, |
| 439 &values, &num_values); |
| 440 if (!values) |
| 441 return false; |
| 442 |
| 443 bytes->assign(values, values + num_values); // Copy the data. |
| 444 return true; |
| 445 } |
| 446 |
| 447 bool MessageReader::PopArrayOfObjectPaths( |
| 448 std::vector<std::string> *object_paths) { |
| 449 MessageReader array_reader(message_); |
| 450 if (!PopArray(&array_reader)) |
| 451 return false; |
| 452 while (array_reader.HasMore()) { |
| 453 std::string object_path; |
| 454 if (!array_reader.PopObjectPath(&object_path)) |
| 455 return false; |
| 456 object_paths->push_back(object_path); |
| 457 } |
| 458 return true; |
| 459 } |
| 460 |
| 461 bool MessageReader::PopVariantOfByte(uint8* value) { |
| 462 return PopVariantOfBasic(DBUS_TYPE_BYTE, value); |
| 463 } |
| 464 |
| 465 bool MessageReader::PopVariantOfBool(bool* value) { |
| 466 return PopVariantOfBasic(DBUS_TYPE_BOOLEAN, value); |
| 467 } |
| 468 |
| 469 bool MessageReader::PopVariantOfInt16(int16* value) { |
| 470 return PopVariantOfBasic(DBUS_TYPE_INT16, value); |
| 471 } |
| 472 |
| 473 bool MessageReader::PopVariantOfUint16(uint16* value) { |
| 474 return PopVariantOfBasic(DBUS_TYPE_UINT16, value); |
| 475 } |
| 476 |
| 477 bool MessageReader::PopVariantOfInt32(int32* value) { |
| 478 return PopVariantOfBasic(DBUS_TYPE_INT32, value); |
| 479 } |
| 480 |
| 481 bool MessageReader::PopVariantOfUint32(uint32* value) { |
| 482 return PopVariantOfBasic(DBUS_TYPE_UINT32, value); |
| 483 } |
| 484 |
| 485 bool MessageReader::PopVariantOfInt64(int64* value) { |
| 486 return PopVariantOfBasic(DBUS_TYPE_INT64, value); |
| 487 } |
| 488 |
| 489 bool MessageReader::PopVariantOfUint64(uint64* value) { |
| 490 return PopVariantOfBasic(DBUS_TYPE_UINT64, value); |
| 491 } |
| 492 |
| 493 bool MessageReader::PopVariantOfDouble(double* value) { |
| 494 return PopVariantOfBasic(DBUS_TYPE_DOUBLE, value); |
| 495 } |
| 496 |
| 497 bool MessageReader::PopVariantOfString(std::string* value) { |
| 498 char* tmp_value = NULL; |
| 499 const bool success = PopVariantOfBasic(DBUS_TYPE_STRING, &tmp_value); |
| 500 if (success) |
| 501 *value = tmp_value; // Copy the string. |
| 502 return success; |
| 503 } |
| 504 |
| 505 bool MessageReader::PopVariantOfObjectPath(std::string* value) { |
| 506 char* tmp_value = NULL; |
| 507 const bool success = PopVariantOfBasic(DBUS_TYPE_OBJECT_PATH, &tmp_value); |
| 508 if (success) |
| 509 *value = tmp_value; // Copy the string. |
| 510 return success; |
| 511 } |
| 512 |
| 513 bool MessageReader::CheckType(int dbus_type) { |
| 514 const int actual_type = dbus_message_iter_get_arg_type(&raw_message_iter_); |
| 515 if (actual_type != dbus_type) { |
| 516 VLOG(1) << "Type " << dbus_type << " is expected but got " |
| 517 << actual_type; |
| 518 return false; |
| 519 } |
| 520 return true; |
| 521 } |
| 522 |
| 523 bool MessageReader::PopBasic(int dbus_type, void* value) { |
| 524 if (!CheckType(dbus_type)) |
| 525 return false; |
| 526 dbus_message_iter_get_basic(&raw_message_iter_, value); |
| 527 dbus_message_iter_next(&raw_message_iter_); |
| 528 return true; |
| 529 } |
| 530 |
| 531 bool MessageReader::PopContainer(int dbus_type, MessageReader* sub_reader) { |
| 532 DCHECK_NE(this, sub_reader); |
| 533 |
| 534 if (!CheckType(dbus_type)) |
| 535 return false; |
| 536 dbus_message_iter_recurse(&raw_message_iter_, |
| 537 &sub_reader->raw_message_iter_); |
| 538 dbus_message_iter_next(&raw_message_iter_); |
| 539 return true; |
| 540 } |
| 541 |
| 542 bool MessageReader::PopVariantOfBasic(int dbus_type, void* value) { |
| 543 net::dbus::MessageReader variant_reader(message_); |
| 544 if (!PopVariant(&variant_reader)) |
| 545 return false; |
| 546 return variant_reader.PopBasic(dbus_type, value); |
| 547 } |
| 548 |
| 549 } // namespace dbus |
| 550 } // namespace net |
| OLD | NEW |