Updating trunk VERSION from 1129.0 to 1130.0
[chromium-blink-merge.git] / dbus / message.cc
blobd52591217e47bedadb04afcaf57dfcc5b3fcb435
1 // Copyright (c) 2012 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.
5 #include "dbus/message.h"
7 #include <string>
9 #include "base/basictypes.h"
10 #include "base/format_macros.h"
11 #include "base/logging.h"
12 #include "base/platform_file.h"
13 #include "base/stringprintf.h"
14 #include "dbus/object_path.h"
15 #include "third_party/protobuf/src/google/protobuf/message_lite.h"
17 namespace {
19 // Appends the header name and the value to |output|, if the value is
20 // not empty.
21 static void AppendStringHeader(const std::string& header_name,
22 const std::string& header_value,
23 std::string* output) {
24 if (!header_value.empty()) {
25 *output += header_name + ": " + header_value + "\n";
29 // Appends the header name and the value to |output|, if the value is
30 // nonzero.
31 static void AppendUint32Header(const std::string& header_name,
32 uint32 header_value,
33 std::string* output) {
34 if (header_value != 0) {
35 *output += (header_name + ": " + base::StringPrintf("%u", header_value) +
36 "\n");
40 } // namespace
42 namespace dbus {
44 Message::Message()
45 : raw_message_(NULL) {
48 Message::~Message() {
49 if (raw_message_)
50 dbus_message_unref(raw_message_);
53 void Message::Init(DBusMessage* raw_message) {
54 DCHECK(!raw_message_);
55 raw_message_ = raw_message;
58 Message::MessageType Message::GetMessageType() {
59 if (!raw_message_)
60 return MESSAGE_INVALID;
61 const int type = dbus_message_get_type(raw_message_);
62 return static_cast<Message::MessageType>(type);
65 std::string Message::GetMessageTypeAsString() {
66 switch (GetMessageType()) {
67 case MESSAGE_INVALID:
68 return "MESSAGE_INVALID";
69 case MESSAGE_METHOD_CALL:
70 return "MESSAGE_METHOD_CALL";
71 case MESSAGE_METHOD_RETURN:
72 return "MESSAGE_METHOD_RETURN";
73 case MESSAGE_SIGNAL:
74 return "MESSAGE_SIGNAL";
75 case MESSAGE_ERROR:
76 return "MESSAGE_ERROR";
78 NOTREACHED();
79 return "";
82 std::string Message::ToStringInternal(const std::string& indent,
83 MessageReader* reader) {
84 const char* kBrokenMessage = "[broken message]";
85 std::string output;
86 while (reader->HasMoreData()) {
87 const DataType type = reader->GetDataType();
88 switch (type) {
89 case BYTE: {
90 uint8 value = 0;
91 if (!reader->PopByte(&value))
92 return kBrokenMessage;
93 output += indent + "byte " + base::StringPrintf("%d", value) + "\n";
94 break;
96 case BOOL: {
97 bool value = false;
98 if (!reader->PopBool(&value))
99 return kBrokenMessage;
100 output += indent + "bool " + (value ? "true" : "false") + "\n";
101 break;
103 case INT16: {
104 int16 value = 0;
105 if (!reader->PopInt16(&value))
106 return kBrokenMessage;
107 output += indent + "int16 " + base::StringPrintf("%d", value) + "\n";
108 break;
110 case UINT16: {
111 uint16 value = 0;
112 if (!reader->PopUint16(&value))
113 return kBrokenMessage;
114 output += indent + "uint16 " + base::StringPrintf("%d", value) + "\n";
115 break;
117 case INT32: {
118 int32 value = 0;
119 if (!reader->PopInt32(&value))
120 return kBrokenMessage;
121 output += indent + "int32 " + base::StringPrintf("%d", value) + "\n";
122 break;
124 case UINT32: {
125 uint32 value = 0;
126 if (!reader->PopUint32(&value))
127 return kBrokenMessage;
128 output += indent + "uint32 " + base::StringPrintf("%u", value) + "\n";
129 break;
131 case INT64: {
132 int64 value = 0;
133 if (!reader->PopInt64(&value))
134 return kBrokenMessage;
135 output += (indent + "int64 " +
136 base::StringPrintf("%" PRId64, value) + "\n");
137 break;
139 case UINT64: {
140 uint64 value = 0;
141 if (!reader->PopUint64(&value))
142 return kBrokenMessage;
143 output += (indent + "uint64 " +
144 base::StringPrintf("%" PRIu64, value) + "\n");
145 break;
147 case DOUBLE: {
148 double value = 0;
149 if (!reader->PopDouble(&value))
150 return kBrokenMessage;
151 output += indent + "double " + base::StringPrintf("%f", value) + "\n";
152 break;
154 case STRING: {
155 std::string value;
156 if (!reader->PopString(&value))
157 return kBrokenMessage;
158 output += indent + "string \"" + value + "\"\n";
159 break;
161 case OBJECT_PATH: {
162 ObjectPath value;
163 if (!reader->PopObjectPath(&value))
164 return kBrokenMessage;
165 output += indent + "object_path \"" + value.value() + "\"\n";
166 break;
168 case ARRAY: {
169 MessageReader sub_reader(this);
170 if (!reader->PopArray(&sub_reader))
171 return kBrokenMessage;
172 output += indent + "array [\n";
173 output += ToStringInternal(indent + " ", &sub_reader);
174 output += indent + "]\n";
175 break;
177 case STRUCT: {
178 MessageReader sub_reader(this);
179 if (!reader->PopStruct(&sub_reader))
180 return kBrokenMessage;
181 output += indent + "struct {\n";
182 output += ToStringInternal(indent + " ", &sub_reader);
183 output += indent + "}\n";
184 break;
186 case DICT_ENTRY: {
187 MessageReader sub_reader(this);
188 if (!reader->PopDictEntry(&sub_reader))
189 return kBrokenMessage;
190 output += indent + "dict entry {\n";
191 output += ToStringInternal(indent + " ", &sub_reader);
192 output += indent + "}\n";
193 break;
195 case VARIANT: {
196 MessageReader sub_reader(this);
197 if (!reader->PopVariant(&sub_reader))
198 return kBrokenMessage;
199 output += indent + "variant ";
200 output += ToStringInternal(indent + " ", &sub_reader);
201 break;
203 case UNIX_FD: {
204 CHECK(kDBusTypeUnixFdIsSupported);
206 FileDescriptor file_descriptor;
207 if (!reader->PopFileDescriptor(&file_descriptor))
208 return kBrokenMessage;
209 output += indent + "fd#" +
210 base::StringPrintf("%d", file_descriptor.value()) + "\n";
211 break;
213 default:
214 LOG(FATAL) << "Unknown type: " << type;
217 return output;
220 // The returned string consists of message headers such as
221 // destination if any, followed by a blank line, and the message
222 // payload. For example, a MethodCall's ToString() will look like:
224 // destination: com.example.Service
225 // path: /com/example/Object
226 // interface: com.example.Interface
227 // member: SomeMethod
229 // string \"payload\"
230 // ...
231 std::string Message::ToString() {
232 if (!raw_message_)
233 return "";
235 // Generate headers first.
236 std::string headers;
237 AppendStringHeader("message_type", GetMessageTypeAsString(), &headers);
238 AppendStringHeader("destination", GetDestination(), &headers);
239 AppendStringHeader("path", GetPath().value(), &headers);
240 AppendStringHeader("interface", GetInterface(), &headers);
241 AppendStringHeader("member", GetMember(), &headers);
242 AppendStringHeader("error_name", GetErrorName(), &headers);
243 AppendStringHeader("sender", GetSender(), &headers);
244 AppendStringHeader("signature", GetSignature(), &headers);
245 AppendUint32Header("serial", GetSerial(), &headers);
246 AppendUint32Header("reply_serial", GetReplySerial(), &headers);
248 // Generate the payload.
249 MessageReader reader(this);
250 return headers + "\n" + ToStringInternal("", &reader);
253 void Message::SetDestination(const std::string& destination) {
254 const bool success = dbus_message_set_destination(raw_message_,
255 destination.c_str());
256 CHECK(success) << "Unable to allocate memory";
259 void Message::SetPath(const ObjectPath& path) {
260 const bool success = dbus_message_set_path(raw_message_,
261 path.value().c_str());
262 CHECK(success) << "Unable to allocate memory";
265 void Message::SetInterface(const std::string& interface) {
266 const bool success = dbus_message_set_interface(raw_message_,
267 interface.c_str());
268 CHECK(success) << "Unable to allocate memory";
271 void Message::SetMember(const std::string& member) {
272 const bool success = dbus_message_set_member(raw_message_,
273 member.c_str());
274 CHECK(success) << "Unable to allocate memory";
277 void Message::SetErrorName(const std::string& error_name) {
278 const bool success = dbus_message_set_error_name(raw_message_,
279 error_name.c_str());
280 CHECK(success) << "Unable to allocate memory";
283 void Message::SetSender(const std::string& sender) {
284 const bool success = dbus_message_set_sender(raw_message_,
285 sender.c_str());
286 CHECK(success) << "Unable to allocate memory";
289 void Message::SetSerial(uint32 serial) {
290 dbus_message_set_serial(raw_message_, serial);
293 void Message::SetReplySerial(uint32 reply_serial) {
294 dbus_message_set_reply_serial(raw_message_, reply_serial);
297 std::string Message::GetDestination() {
298 const char* destination = dbus_message_get_destination(raw_message_);
299 return destination ? destination : "";
302 ObjectPath Message::GetPath() {
303 const char* path = dbus_message_get_path(raw_message_);
304 return ObjectPath(path ? path : "");
307 std::string Message::GetInterface() {
308 const char* interface = dbus_message_get_interface(raw_message_);
309 return interface ? interface : "";
312 std::string Message::GetMember() {
313 const char* member = dbus_message_get_member(raw_message_);
314 return member ? member : "";
317 std::string Message::GetErrorName() {
318 const char* error_name = dbus_message_get_error_name(raw_message_);
319 return error_name ? error_name : "";
322 std::string Message::GetSender() {
323 const char* sender = dbus_message_get_sender(raw_message_);
324 return sender ? sender : "";
327 std::string Message::GetSignature() {
328 const char* signature = dbus_message_get_signature(raw_message_);
329 return signature ? signature : "";
332 uint32 Message::GetSerial() {
333 return dbus_message_get_serial(raw_message_);
336 uint32 Message::GetReplySerial() {
337 return dbus_message_get_reply_serial(raw_message_);
341 // MethodCall implementation.
344 MethodCall::MethodCall(const std::string& interface_name,
345 const std::string& method_name)
346 : Message() {
347 Init(dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_CALL));
349 SetInterface(interface_name);
350 SetMember(method_name);
353 MethodCall::MethodCall() : Message() {
356 MethodCall* MethodCall::FromRawMessage(DBusMessage* raw_message) {
357 DCHECK_EQ(DBUS_MESSAGE_TYPE_METHOD_CALL, dbus_message_get_type(raw_message));
359 MethodCall* method_call = new MethodCall;
360 method_call->Init(raw_message);
361 return method_call;
365 // Signal implementation.
367 Signal::Signal(const std::string& interface_name,
368 const std::string& method_name)
369 : Message() {
370 Init(dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL));
372 SetInterface(interface_name);
373 SetMember(method_name);
376 Signal::Signal() : Message() {
379 Signal* Signal::FromRawMessage(DBusMessage* raw_message) {
380 DCHECK_EQ(DBUS_MESSAGE_TYPE_SIGNAL, dbus_message_get_type(raw_message));
382 Signal* signal = new Signal;
383 signal->Init(raw_message);
384 return signal;
388 // Response implementation.
391 Response::Response() : Message() {
394 Response* Response::FromRawMessage(DBusMessage* raw_message) {
395 DCHECK_EQ(DBUS_MESSAGE_TYPE_METHOD_RETURN,
396 dbus_message_get_type(raw_message));
398 Response* response = new Response;
399 response->Init(raw_message);
400 return response;
403 Response* Response::FromMethodCall(MethodCall* method_call) {
404 Response* response = new Response;
405 response->Init(dbus_message_new_method_return(method_call->raw_message()));
406 return response;
409 Response* Response::CreateEmpty() {
410 Response* response = new Response;
411 response->Init(dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN));
412 return response;
415 // ErrorResponse implementation.
418 ErrorResponse::ErrorResponse() : Response() {
421 ErrorResponse* ErrorResponse::FromRawMessage(DBusMessage* raw_message) {
422 DCHECK_EQ(DBUS_MESSAGE_TYPE_ERROR, dbus_message_get_type(raw_message));
424 ErrorResponse* response = new ErrorResponse;
425 response->Init(raw_message);
426 return response;
429 ErrorResponse* ErrorResponse::FromMethodCall(
430 MethodCall* method_call,
431 const std::string& error_name,
432 const std::string& error_message) {
433 ErrorResponse* response = new ErrorResponse;
434 response->Init(dbus_message_new_error(method_call->raw_message(),
435 error_name.c_str(),
436 error_message.c_str()));
437 return response;
441 // MessageWriter implementation.
444 MessageWriter::MessageWriter(Message* message) :
445 message_(message),
446 container_is_open_(false) {
447 memset(&raw_message_iter_, 0, sizeof(raw_message_iter_));
448 if (message)
449 dbus_message_iter_init_append(message_->raw_message(), &raw_message_iter_);
452 MessageWriter::~MessageWriter() {
455 void MessageWriter::AppendByte(uint8 value) {
456 AppendBasic(DBUS_TYPE_BYTE, &value);
459 void MessageWriter::AppendBool(bool value) {
460 // The size of dbus_bool_t and the size of bool are different. The
461 // former is always 4 per dbus-types.h, whereas the latter is usually 1.
462 // dbus_message_iter_append_basic() used in AppendBasic() expects four
463 // bytes for DBUS_TYPE_BOOLEAN, so we must pass a dbus_bool_t, instead
464 // of a bool, to AppendBasic().
465 dbus_bool_t dbus_value = value;
466 AppendBasic(DBUS_TYPE_BOOLEAN, &dbus_value);
469 void MessageWriter::AppendInt16(int16 value) {
470 AppendBasic(DBUS_TYPE_INT16, &value);
473 void MessageWriter::AppendUint16(uint16 value) {
474 AppendBasic(DBUS_TYPE_UINT16, &value);
477 void MessageWriter::AppendInt32(int32 value) {
478 AppendBasic(DBUS_TYPE_INT32, &value);
481 void MessageWriter::AppendUint32(uint32 value) {
482 AppendBasic(DBUS_TYPE_UINT32, &value);
485 void MessageWriter::AppendInt64(int64 value) {
486 AppendBasic(DBUS_TYPE_INT64, &value);
489 void MessageWriter::AppendUint64(uint64 value) {
490 AppendBasic(DBUS_TYPE_UINT64, &value);
493 void MessageWriter::AppendDouble(double value) {
494 AppendBasic(DBUS_TYPE_DOUBLE, &value);
497 void MessageWriter::AppendString(const std::string& value) {
498 const char* pointer = value.c_str();
499 AppendBasic(DBUS_TYPE_STRING, &pointer);
500 // TODO(satorux): It may make sense to return an error here, as the
501 // input string can be large. If needed, we could add something like
502 // bool AppendStringWithErrorChecking().
505 void MessageWriter::AppendObjectPath(const ObjectPath& value) {
506 const char* pointer = value.value().c_str();
507 AppendBasic(DBUS_TYPE_OBJECT_PATH, &pointer);
510 // Ideally, client shouldn't need to supply the signature string, but
511 // the underlying D-Bus library requires us to supply this before
512 // appending contents to array and variant. It's technically possible
513 // for us to design API that doesn't require the signature but it will
514 // complicate the implementation so we decided to have the signature
515 // parameter. Hopefully, variants are less used in request messages from
516 // client side than response message from server side, so this should
517 // not be a big issue.
518 void MessageWriter::OpenArray(const std::string& signature,
519 MessageWriter* writer) {
520 DCHECK(!container_is_open_);
522 const bool success = dbus_message_iter_open_container(
523 &raw_message_iter_,
524 DBUS_TYPE_ARRAY,
525 signature.c_str(),
526 &writer->raw_message_iter_);
527 CHECK(success) << "Unable to allocate memory";
528 container_is_open_ = true;
531 void MessageWriter::OpenVariant(const std::string& signature,
532 MessageWriter* writer) {
533 DCHECK(!container_is_open_);
535 const bool success = dbus_message_iter_open_container(
536 &raw_message_iter_,
537 DBUS_TYPE_VARIANT,
538 signature.c_str(),
539 &writer->raw_message_iter_);
540 CHECK(success) << "Unable to allocate memory";
541 container_is_open_ = true;
544 void MessageWriter::OpenStruct(MessageWriter* writer) {
545 DCHECK(!container_is_open_);
547 const bool success = dbus_message_iter_open_container(
548 &raw_message_iter_,
549 DBUS_TYPE_STRUCT,
550 NULL, // Signature should be NULL.
551 &writer->raw_message_iter_);
552 CHECK(success) << "Unable to allocate memory";
553 container_is_open_ = true;
556 void MessageWriter::OpenDictEntry(MessageWriter* writer) {
557 DCHECK(!container_is_open_);
559 const bool success = dbus_message_iter_open_container(
560 &raw_message_iter_,
561 DBUS_TYPE_DICT_ENTRY,
562 NULL, // Signature should be NULL.
563 &writer->raw_message_iter_);
564 CHECK(success) << "Unable to allocate memory";
565 container_is_open_ = true;
568 void MessageWriter::CloseContainer(MessageWriter* writer) {
569 DCHECK(container_is_open_);
571 const bool success = dbus_message_iter_close_container(
572 &raw_message_iter_, &writer->raw_message_iter_);
573 CHECK(success) << "Unable to allocate memory";
574 container_is_open_ = false;
577 void MessageWriter::AppendArrayOfBytes(const uint8* values, size_t length) {
578 DCHECK(!container_is_open_);
579 MessageWriter array_writer(message_);
580 OpenArray("y", &array_writer);
581 const bool success = dbus_message_iter_append_fixed_array(
582 &(array_writer.raw_message_iter_),
583 DBUS_TYPE_BYTE,
584 &values,
585 static_cast<int>(length));
586 CHECK(success) << "Unable to allocate memory";
587 CloseContainer(&array_writer);
590 void MessageWriter::AppendArrayOfStrings(
591 const std::vector<std::string>& strings) {
592 DCHECK(!container_is_open_);
593 MessageWriter array_writer(message_);
594 OpenArray("s", &array_writer);
595 for (size_t i = 0; i < strings.size(); ++i) {
596 array_writer.AppendString(strings[i]);
598 CloseContainer(&array_writer);
601 void MessageWriter::AppendArrayOfObjectPaths(
602 const std::vector<ObjectPath>& object_paths) {
603 DCHECK(!container_is_open_);
604 MessageWriter array_writer(message_);
605 OpenArray("o", &array_writer);
606 for (size_t i = 0; i < object_paths.size(); ++i) {
607 array_writer.AppendObjectPath(object_paths[i]);
609 CloseContainer(&array_writer);
612 bool MessageWriter::AppendProtoAsArrayOfBytes(
613 const google::protobuf::MessageLite& protobuf) {
614 std::string serialized_proto;
615 if (!protobuf.SerializeToString(&serialized_proto)) {
616 LOG(ERROR) << "Unable to serialize supplied protocol buffer";
617 return false;
619 AppendArrayOfBytes(reinterpret_cast<const uint8*>(serialized_proto.data()),
620 serialized_proto.size());
621 return true;
624 void MessageWriter::AppendVariantOfByte(uint8 value) {
625 AppendVariantOfBasic(DBUS_TYPE_BYTE, &value);
628 void MessageWriter::AppendVariantOfBool(bool value) {
629 // See the comment at MessageWriter::AppendBool().
630 dbus_bool_t dbus_value = value;
631 AppendVariantOfBasic(DBUS_TYPE_BOOLEAN, &dbus_value);
634 void MessageWriter::AppendVariantOfInt16(int16 value) {
635 AppendVariantOfBasic(DBUS_TYPE_INT16, &value);
638 void MessageWriter::AppendVariantOfUint16(uint16 value) {
639 AppendVariantOfBasic(DBUS_TYPE_UINT16, &value);
642 void MessageWriter::AppendVariantOfInt32(int32 value) {
643 AppendVariantOfBasic(DBUS_TYPE_INT32, &value);
646 void MessageWriter::AppendVariantOfUint32(uint32 value) {
647 AppendVariantOfBasic(DBUS_TYPE_UINT32, &value);
650 void MessageWriter::AppendVariantOfInt64(int64 value) {
651 AppendVariantOfBasic(DBUS_TYPE_INT64, &value);
654 void MessageWriter::AppendVariantOfUint64(uint64 value) {
655 AppendVariantOfBasic(DBUS_TYPE_UINT64, &value);
658 void MessageWriter::AppendVariantOfDouble(double value) {
659 AppendVariantOfBasic(DBUS_TYPE_DOUBLE, &value);
662 void MessageWriter::AppendVariantOfString(const std::string& value) {
663 const char* pointer = value.c_str();
664 AppendVariantOfBasic(DBUS_TYPE_STRING, &pointer);
667 void MessageWriter::AppendVariantOfObjectPath(const ObjectPath& value) {
668 const char* pointer = value.value().c_str();
669 AppendVariantOfBasic(DBUS_TYPE_OBJECT_PATH, &pointer);
672 void MessageWriter::AppendBasic(int dbus_type, const void* value) {
673 DCHECK(!container_is_open_);
675 const bool success = dbus_message_iter_append_basic(
676 &raw_message_iter_, dbus_type, value);
677 // dbus_message_iter_append_basic() fails only when there is not enough
678 // memory. We don't return this error as there is nothing we can do when
679 // it fails to allocate memory for a byte etc.
680 CHECK(success) << "Unable to allocate memory";
683 void MessageWriter::AppendVariantOfBasic(int dbus_type, const void* value) {
684 const std::string signature = base::StringPrintf("%c", dbus_type);
685 MessageWriter variant_writer(message_);
686 OpenVariant(signature, &variant_writer);
687 variant_writer.AppendBasic(dbus_type, value);
688 CloseContainer(&variant_writer);
691 void MessageWriter::AppendFileDescriptor(const FileDescriptor& value) {
692 CHECK(kDBusTypeUnixFdIsSupported);
694 base::PlatformFileInfo info;
695 int fd = value.value();
696 bool ok = base::GetPlatformFileInfo(fd, &info);
697 if (!ok || info.is_directory) {
698 // NB: sending a directory potentially enables sandbox escape
699 LOG(FATAL) << "Attempt to pass invalid file descriptor";
701 AppendBasic(DBUS_TYPE_UNIX_FD, &fd);
705 // MessageReader implementation.
708 MessageReader::MessageReader(Message* message)
709 : message_(message) {
710 memset(&raw_message_iter_, 0, sizeof(raw_message_iter_));
711 if (message)
712 dbus_message_iter_init(message_->raw_message(), &raw_message_iter_);
716 MessageReader::~MessageReader() {
719 bool MessageReader::HasMoreData() {
720 const int dbus_type = dbus_message_iter_get_arg_type(&raw_message_iter_);
721 return dbus_type != DBUS_TYPE_INVALID;
724 bool MessageReader::PopByte(uint8* value) {
725 return PopBasic(DBUS_TYPE_BYTE, value);
728 bool MessageReader::PopBool(bool* value) {
729 // Like MessageWriter::AppendBool(), we should copy |value| to
730 // dbus_bool_t, as dbus_message_iter_get_basic() used in PopBasic()
731 // expects four bytes for DBUS_TYPE_BOOLEAN.
732 dbus_bool_t dbus_value = FALSE;
733 const bool success = PopBasic(DBUS_TYPE_BOOLEAN, &dbus_value);
734 *value = static_cast<bool>(dbus_value);
735 return success;
738 bool MessageReader::PopInt16(int16* value) {
739 return PopBasic(DBUS_TYPE_INT16, value);
742 bool MessageReader::PopUint16(uint16* value) {
743 return PopBasic(DBUS_TYPE_UINT16, value);
746 bool MessageReader::PopInt32(int32* value) {
747 return PopBasic(DBUS_TYPE_INT32, value);
750 bool MessageReader::PopUint32(uint32* value) {
751 return PopBasic(DBUS_TYPE_UINT32, value);
754 bool MessageReader::PopInt64(int64* value) {
755 return PopBasic(DBUS_TYPE_INT64, value);
758 bool MessageReader::PopUint64(uint64* value) {
759 return PopBasic(DBUS_TYPE_UINT64, value);
762 bool MessageReader::PopDouble(double* value) {
763 return PopBasic(DBUS_TYPE_DOUBLE, value);
766 bool MessageReader::PopString(std::string* value) {
767 char* tmp_value = NULL;
768 const bool success = PopBasic(DBUS_TYPE_STRING, &tmp_value);
769 if (success)
770 value->assign(tmp_value);
771 return success;
774 bool MessageReader::PopObjectPath(ObjectPath* value) {
775 char* tmp_value = NULL;
776 const bool success = PopBasic(DBUS_TYPE_OBJECT_PATH, &tmp_value);
777 if (success)
778 *value = ObjectPath(tmp_value);
779 return success;
782 bool MessageReader::PopArray(MessageReader* sub_reader) {
783 return PopContainer(DBUS_TYPE_ARRAY, sub_reader);
786 bool MessageReader::PopStruct(MessageReader* sub_reader) {
787 return PopContainer(DBUS_TYPE_STRUCT, sub_reader);
790 bool MessageReader::PopDictEntry(MessageReader* sub_reader) {
791 return PopContainer(DBUS_TYPE_DICT_ENTRY, sub_reader);
794 bool MessageReader::PopVariant(MessageReader* sub_reader) {
795 return PopContainer(DBUS_TYPE_VARIANT, sub_reader);
798 bool MessageReader::PopArrayOfBytes(uint8** bytes, size_t* length) {
799 MessageReader array_reader(message_);
800 if (!PopArray(&array_reader))
801 return false;
802 // An empty array is allowed.
803 if (!array_reader.HasMoreData()) {
804 *length = 0;
805 *bytes = NULL;
806 return true;
808 if (!array_reader.CheckDataType(DBUS_TYPE_BYTE))
809 return false;
810 int int_length = 0;
811 dbus_message_iter_get_fixed_array(&array_reader.raw_message_iter_,
812 bytes,
813 &int_length);
814 *length = static_cast<int>(int_length);
815 return true;
818 bool MessageReader::PopArrayOfStrings(
819 std::vector<std::string> *strings) {
820 MessageReader array_reader(message_);
821 if (!PopArray(&array_reader))
822 return false;
823 while (array_reader.HasMoreData()) {
824 std::string string;
825 if (!array_reader.PopString(&string))
826 return false;
827 strings->push_back(string);
829 return true;
832 bool MessageReader::PopArrayOfObjectPaths(
833 std::vector<ObjectPath> *object_paths) {
834 MessageReader array_reader(message_);
835 if (!PopArray(&array_reader))
836 return false;
837 while (array_reader.HasMoreData()) {
838 ObjectPath object_path;
839 if (!array_reader.PopObjectPath(&object_path))
840 return false;
841 object_paths->push_back(object_path);
843 return true;
846 bool MessageReader::PopArrayOfBytesAsProto(
847 google::protobuf::MessageLite* protobuf) {
848 DCHECK(protobuf != NULL);
849 char* serialized_buf = NULL;
850 size_t buf_size = 0;
851 if (!PopArrayOfBytes(reinterpret_cast<uint8**>(&serialized_buf), &buf_size)) {
852 LOG(ERROR) << "Error reading array of bytes";
853 return false;
855 if (!protobuf->ParseFromArray(serialized_buf, buf_size)) {
856 LOG(ERROR) << "Failed to parse protocol buffer from array";
857 return false;
859 return true;
862 bool MessageReader::PopVariantOfByte(uint8* value) {
863 return PopVariantOfBasic(DBUS_TYPE_BYTE, value);
866 bool MessageReader::PopVariantOfBool(bool* value) {
867 // See the comment at MessageReader::PopBool().
868 dbus_bool_t dbus_value = FALSE;
869 const bool success = PopVariantOfBasic(DBUS_TYPE_BOOLEAN, &dbus_value);
870 *value = static_cast<bool>(dbus_value);
871 return success;
874 bool MessageReader::PopVariantOfInt16(int16* value) {
875 return PopVariantOfBasic(DBUS_TYPE_INT16, value);
878 bool MessageReader::PopVariantOfUint16(uint16* value) {
879 return PopVariantOfBasic(DBUS_TYPE_UINT16, value);
882 bool MessageReader::PopVariantOfInt32(int32* value) {
883 return PopVariantOfBasic(DBUS_TYPE_INT32, value);
886 bool MessageReader::PopVariantOfUint32(uint32* value) {
887 return PopVariantOfBasic(DBUS_TYPE_UINT32, value);
890 bool MessageReader::PopVariantOfInt64(int64* value) {
891 return PopVariantOfBasic(DBUS_TYPE_INT64, value);
894 bool MessageReader::PopVariantOfUint64(uint64* value) {
895 return PopVariantOfBasic(DBUS_TYPE_UINT64, value);
898 bool MessageReader::PopVariantOfDouble(double* value) {
899 return PopVariantOfBasic(DBUS_TYPE_DOUBLE, value);
902 bool MessageReader::PopVariantOfString(std::string* value) {
903 char* tmp_value = NULL;
904 const bool success = PopVariantOfBasic(DBUS_TYPE_STRING, &tmp_value);
905 if (success)
906 value->assign(tmp_value);
907 return success;
910 bool MessageReader::PopVariantOfObjectPath(ObjectPath* value) {
911 char* tmp_value = NULL;
912 const bool success = PopVariantOfBasic(DBUS_TYPE_OBJECT_PATH, &tmp_value);
913 if (success)
914 *value = ObjectPath(tmp_value);
915 return success;
918 Message::DataType MessageReader::GetDataType() {
919 const int dbus_type = dbus_message_iter_get_arg_type(&raw_message_iter_);
920 return static_cast<Message::DataType>(dbus_type);
923 bool MessageReader::CheckDataType(int dbus_type) {
924 const int actual_type = dbus_message_iter_get_arg_type(&raw_message_iter_);
925 if (actual_type != dbus_type) {
926 VLOG(1) << "Type " << dbus_type << " is expected but got "
927 << actual_type;
928 return false;
930 return true;
933 bool MessageReader::PopBasic(int dbus_type, void* value) {
934 if (!CheckDataType(dbus_type))
935 return false;
936 // dbus_message_iter_get_basic() here should always work, as we have
937 // already checked the next item's data type in CheckDataType(). Note
938 // that dbus_message_iter_get_basic() is a void function.
939 dbus_message_iter_get_basic(&raw_message_iter_, value);
940 DCHECK(value);
941 dbus_message_iter_next(&raw_message_iter_);
942 return true;
945 bool MessageReader::PopContainer(int dbus_type, MessageReader* sub_reader) {
946 DCHECK_NE(this, sub_reader);
948 if (!CheckDataType(dbus_type))
949 return false;
950 dbus_message_iter_recurse(&raw_message_iter_,
951 &sub_reader->raw_message_iter_);
952 dbus_message_iter_next(&raw_message_iter_);
953 return true;
956 bool MessageReader::PopVariantOfBasic(int dbus_type, void* value) {
957 dbus::MessageReader variant_reader(message_);
958 if (!PopVariant(&variant_reader))
959 return false;
960 return variant_reader.PopBasic(dbus_type, value);
963 bool MessageReader::PopFileDescriptor(FileDescriptor* value) {
964 CHECK(kDBusTypeUnixFdIsSupported);
966 int fd = -1;
967 const bool success = PopBasic(DBUS_TYPE_UNIX_FD, &fd);
968 if (!success)
969 return false;
971 base::PlatformFileInfo info;
972 bool ok = base::GetPlatformFileInfo(fd, &info);
973 if (!ok || info.is_directory) {
974 base::ClosePlatformFile(fd);
975 // NB: receiving a directory potentially enables sandbox escape
976 LOG(FATAL) << "Attempt to receive invalid file descriptor";
977 return false; // NB: not reached
979 value->PutValue(fd);
980 return true;
983 } // namespace dbus