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

Side by Side Diff: dbus/message.cc

Issue 7492029: Implement classes used for manipulating D-Bus messages. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: improve ToString() Created 9 years, 5 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « dbus/message.h ('k') | dbus/message_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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/message.h"
6
7 #include "base/basictypes.h"
8 #include "base/format_macros.h"
9 #include "base/logging.h"
10 #include "base/stringprintf.h"
11
12 namespace dbus {
13
14 Message::Message()
15 : raw_message_(NULL) {
16 }
17
18 Message::~Message() {
19 if (raw_message_)
20 dbus_message_unref(raw_message_);
21 }
22
23 Message::MessageType Message::GetMessageType() {
24 if (!raw_message_)
25 return MESSAGE_INVALID;
26 const int type = dbus_message_get_type(raw_message_);
27 return static_cast<Message::MessageType>(type);
28 }
29
30 void Message::reset_raw_message(DBusMessage* raw_message) {
31 if (raw_message_)
32 dbus_message_unref(raw_message_);
33 raw_message_ = raw_message;
34 }
35
36 std::string Message::ToStringInternal(const std::string& indent,
37 MessageReader* reader) {
38 std::string output;
39 while (reader->HasMoreData()) {
40 const DataType type = reader->GetDataType();
41 switch (type) {
42 case BYTE: {
43 uint8 value = 0;
44 if (!reader->PopByte(&value))
45 return "[broken message]";
stevenjb 2011/07/27 22:08:52 use kBrokenMessage for all of these
satorux1 2011/07/27 22:22:58 Done.
46 output += indent + "byte " + base::StringPrintf("%d", value) + "\n";
47 break;
48 }
49 case BOOL: {
50 bool value = false;
51 if (!reader->PopBool(&value))
52 return "[broken message]";
53 output += indent + "bool " + (value ? "true" : "false") + "\n";
54 break;
55 }
56 case INT16: {
57 int16 value = 0;
58 if (!reader->PopInt16(&value))
59 return "[broken message]";
60 output += indent + "int16 " + base::StringPrintf("%d", value) + "\n";
61 break;
62 }
63 case UINT16: {
64 uint16 value = 0;
65 if (!reader->PopUint16(&value))
66 return "[broken message]";
67 output += indent + "uint16 " + base::StringPrintf("%d", value) + "\n";
68 break;
69 }
70 case INT32: {
71 int32 value = 0;
72 if (!reader->PopInt32(&value))
73 return "[broken message]";
74 output += indent + "int32 " + base::StringPrintf("%d", value) + "\n";
75 break;
76 }
77 case UINT32: {
78 uint32 value = 0;
79 if (!reader->PopUint32(&value))
80 return "[broken message]";
81 output += indent + "uint32 " + base::StringPrintf("%u", value) + "\n";
82 break;
83 }
84 case INT64: {
85 int64 value = 0;
86 if (!reader->PopInt64(&value))
87 return "[broken message]";
88 output += (indent + "int64 " +
89 base::StringPrintf("%" PRId64, value) + "\n");
90 break;
91 }
92 case UINT64: {
93 uint64 value = 0;
94 if (!reader->PopUint64(&value))
95 return "[broken message]";
96 output += (indent + "uint64 " +
97 base::StringPrintf("%" PRIu64, value) + "\n");
98 break;
99 }
100 case DOUBLE: {
101 double value = 0;
102 if (!reader->PopDouble(&value))
103 return "[broken message]";
104 output += indent + "double " + base::StringPrintf("%f", value) + "\n";
105 break;
106 }
107 case STRING: {
108 std::string value;
109 if (!reader->PopString(&value))
110 return "[broken message]";
111 output += indent + "string \"" + value + "\"\n";
112 break;
113 }
114 case OBJECT_PATH: {
115 std::string value;
116 if (!reader->PopObjectPath(&value))
117 return "[broken message]";
118 output += indent + "object_path \"" + value + "\"\n";
119 break;
120 }
121 case ARRAY: {
122 MessageReader sub_reader(this);
123 if (!reader->PopArray(&sub_reader))
124 return "[broken message]";
125 output += indent + "array [\n";
126 output += ToStringInternal(indent + " ", &sub_reader);
127 output += indent + "]\n";
128 break;
129 }
130 case STRUCT: {
131 MessageReader sub_reader(this);
132 if (!reader->PopStruct(&sub_reader))
133 return "[broken message]";
134 output += indent + "struct {\n";
135 output += ToStringInternal(indent + " ", &sub_reader);
136 output += indent + "}\n";
137 break;
138 }
139 case DICT_ENTRY: {
140 MessageReader sub_reader(this);
141 if (!reader->PopDictEntry(&sub_reader))
142 return "[broken message]";
143 output += indent + "dict entry {\n";
144 output += ToStringInternal(indent + " ", &sub_reader);
145 output += indent + "}\n";
146 break;
147 }
148 case VARIANT: {
149 MessageReader sub_reader(this);
150 if (!reader->PopVariant(&sub_reader))
151 return "[broken message]";
152 output += indent + "variant ";
153 output += ToStringInternal(indent + " ", &sub_reader);
154 break;
155 }
156 default:
157 LOG(FATAL) << "Unknown type: " << type;
158 }
159 }
160 return output;
161 }
162
163 std::string Message::ToString() {
164 if (!raw_message_)
165 return "";
stevenjb 2011/07/27 22:08:52 nit: return std::string()
satorux1 2011/07/27 22:22:58 "" is used in some other places, and I'd slightly
166
167 // Generate headers first.
168 std::string headers;
169 const char* destination = dbus_message_get_destination(raw_message_);
170 if (destination)
171 headers += base::StringPrintf("destination: %s\n", destination);
172 const char* path = dbus_message_get_path(raw_message_);
173 if (path)
174 headers += base::StringPrintf("path: %s\n", path);
175 const char* interface = dbus_message_get_interface(raw_message_);
176 if (interface)
177 headers += base::StringPrintf("interface: %s\n", interface);
178 const char* member = dbus_message_get_member(raw_message_);
179 if (member)
180 headers += base::StringPrintf("member: %s\n", member);
181
182 // Generate the payload.
183 MessageReader reader(this);
184 return headers + "\n" + ToStringInternal("", &reader);
185 }
186
187 //
188 // MethodCall implementation.
189 //
190
191 MethodCall::MethodCall(const std::string& interface_name,
192 const std::string& method_name)
193 : Message(),
194 interface_name_(interface_name),
195 method_name_(method_name) {
196 reset_raw_message(dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_CALL));
197
198 bool success = dbus_message_set_interface(raw_message(),
199 interface_name.c_str());
200 CHECK(success) << "Unable to allocate memory";
201
202 success = dbus_message_set_member(raw_message(), method_name.c_str());
203 CHECK(success) << "Unable to allocate memory";
204 }
205
206 void MethodCall::SetServiceName(const std::string& service_name) {
207 const bool success = dbus_message_set_destination(raw_message(),
208 service_name.c_str());
209 CHECK(success) << "Unable to allocate memory";
210 }
211
212 void MethodCall::SetObjectPath(const std::string& object_path) {
213 const bool success = dbus_message_set_path(raw_message(),
214 object_path.c_str());
215 CHECK(success) << "Unable to allocate memory";
216 }
217
218 //
219 // Response implementation.
220 //
221
222 Response::Response() : Message() {
223 }
224
225 //
226 // MessageWriter implementation.
227 //
228
229 MessageWriter::MessageWriter(Message* message) :
230 message_(message),
231 container_is_open_(false) {
232 dbus_message_iter_init_append(message_->raw_message(), &raw_message_iter_);
233 }
234
235 MessageWriter::~MessageWriter() {
236 }
237
238 void MessageWriter::AppendByte(uint8 value) {
239 AppendBasic(DBUS_TYPE_BYTE, &value);
240 }
241
242 void MessageWriter::AppendBool(bool value) {
243 AppendBasic(DBUS_TYPE_BOOLEAN, &value);
244 }
245
246 void MessageWriter::AppendInt16(int16 value) {
247 AppendBasic(DBUS_TYPE_INT16, &value);
248 }
249
250 void MessageWriter::AppendUint16(uint16 value) {
251 AppendBasic(DBUS_TYPE_UINT16, &value);
252 }
253
254 void MessageWriter::AppendInt32(int32 value) {
255 AppendBasic(DBUS_TYPE_INT32, &value);
256 }
257
258 void MessageWriter::AppendUint32(uint32 value) {
259 AppendBasic(DBUS_TYPE_UINT32, &value);
260 }
261
262 void MessageWriter::AppendInt64(int64 value) {
263 AppendBasic(DBUS_TYPE_INT64, &value);
264 }
265
266 void MessageWriter::AppendUint64(uint64 value) {
267 AppendBasic(DBUS_TYPE_UINT64, &value);
268 }
269
270 void MessageWriter::AppendDouble(double value) {
271 AppendBasic(DBUS_TYPE_DOUBLE, &value);
272 }
273
274 void MessageWriter::AppendString(const std::string& value) {
275 const char* pointer = value.c_str();
276 AppendBasic(DBUS_TYPE_STRING, &pointer);
277 // It may make sense to return an error here, as the input string can be
278 // large. If needed, we could add something like
279 // bool AppendStringWithErrorChecking().
280 }
281
282 void MessageWriter::AppendObjectPath(const std::string& value) {
283 const char* pointer = value.c_str();
284 AppendBasic(DBUS_TYPE_OBJECT_PATH, &pointer);
285 }
286
287 void MessageWriter::OpenArray(const std::string& signature,
288 MessageWriter* writer) {
289 DCHECK(!container_is_open_);
290
291 const bool success = dbus_message_iter_open_container(
292 &raw_message_iter_,
293 DBUS_TYPE_ARRAY,
294 signature.c_str(),
295 &writer->raw_message_iter_);
296 CHECK(success) << "Unable to allocate memory";
297 container_is_open_ = true;
298 }
299
300 void MessageWriter::OpenVariant(const std::string& signature,
301 MessageWriter* writer) {
302 DCHECK(!container_is_open_);
303
304 const bool success = dbus_message_iter_open_container(
305 &raw_message_iter_,
306 DBUS_TYPE_VARIANT,
307 signature.c_str(),
308 &writer->raw_message_iter_);
309 CHECK(success) << "Unable to allocate memory";
310 container_is_open_ = true;
311 }
312
313 void MessageWriter::OpenStruct(MessageWriter* writer) {
314 DCHECK(!container_is_open_);
315
316 const bool success = dbus_message_iter_open_container(
317 &raw_message_iter_,
318 DBUS_TYPE_STRUCT,
319 NULL, // Signature should be NULL.
320 &writer->raw_message_iter_);
321 CHECK(success) << "Unable to allocate memory";
322 container_is_open_ = true;
323 }
324
325 void MessageWriter::OpenDictEntry(MessageWriter* writer) {
326 DCHECK(!container_is_open_);
327
328 const bool success = dbus_message_iter_open_container(
329 &raw_message_iter_,
330 DBUS_TYPE_DICT_ENTRY,
331 NULL, // Signature should be NULL.
332 &writer->raw_message_iter_);
333 CHECK(success) << "Unable to allocate memory";
334 container_is_open_ = true;
335 }
336
337 void MessageWriter::CloseContainer(MessageWriter* writer) {
338 DCHECK(container_is_open_);
339
340 const bool success = dbus_message_iter_close_container(
341 &raw_message_iter_, &writer->raw_message_iter_);
342 CHECK(success) << "Unable to allocate memory";
343 container_is_open_ = false;
344 }
345
346 void MessageWriter::AppendArrayOfBytes(const uint8* values, size_t length) {
347 DCHECK(!container_is_open_);
348 MessageWriter array_writer(message_);
349 OpenArray("y", &array_writer);
350 const bool success = dbus_message_iter_append_fixed_array(
351 &(array_writer.raw_message_iter_),
352 DBUS_TYPE_BYTE,
353 &values,
354 // |length| is size_t so that client code can easily pass STL
355 // a container like AppendArrayOfBytes(str.data(), str.size());
stevenjb 2011/07/27 22:08:52 I would put this comment in the header, or omit it
satorux1 2011/07/27 22:22:58 Removed.
356 static_cast<int>(length));
357 CHECK(success) << "Unable to allocate memory";
358 CloseContainer(&array_writer);
359 }
360
361 void MessageWriter::AppendVariantOfByte(uint8 value) {
362 AppendVariantOfBasic(DBUS_TYPE_BYTE, &value);
363 }
364
365 void MessageWriter::AppendVariantOfBool(bool value) {
366 AppendVariantOfBasic(DBUS_TYPE_BOOLEAN, &value);
367 }
368
369 void MessageWriter::AppendVariantOfInt16(int16 value) {
370 AppendVariantOfBasic(DBUS_TYPE_INT16, &value);
371 }
372
373 void MessageWriter::AppendVariantOfUint16(uint16 value) {
374 AppendVariantOfBasic(DBUS_TYPE_UINT16, &value);
375 }
376
377 void MessageWriter::AppendVariantOfInt32(int32 value) {
378 AppendVariantOfBasic(DBUS_TYPE_INT32, &value);
379 }
380
381 void MessageWriter::AppendVariantOfUint32(uint32 value) {
382 AppendVariantOfBasic(DBUS_TYPE_UINT32, &value);
383 }
384
385 void MessageWriter::AppendVariantOfInt64(int64 value) {
386 AppendVariantOfBasic(DBUS_TYPE_INT64, &value);
387 }
388
389 void MessageWriter::AppendVariantOfUint64(uint64 value) {
390 AppendVariantOfBasic(DBUS_TYPE_UINT64, &value);
391 }
392
393 void MessageWriter::AppendVariantOfDouble(double value) {
394 AppendVariantOfBasic(DBUS_TYPE_DOUBLE, &value);
395 }
396
397 void MessageWriter::AppendVariantOfString(const std::string& value) {
398 const char* pointer = value.c_str();
399 AppendVariantOfBasic(DBUS_TYPE_STRING, &pointer);
400 }
401
402 void MessageWriter::AppendVariantOfObjectPath(const std::string& value) {
403 const char* pointer = value.c_str();
404 AppendVariantOfBasic(DBUS_TYPE_OBJECT_PATH, &pointer);
405 }
406
407 void MessageWriter::AppendBasic(int dbus_type, const void* value) {
408 DCHECK(!container_is_open_);
409
410 const bool success = dbus_message_iter_append_basic(
411 &raw_message_iter_, dbus_type, value);
412 // dbus_message_iter_append_basic() fails only when there is not enough
413 // memory. We don't return this error as there is nothing we can do when
414 // it fails to allocate memory for a byte etc.
415 CHECK(success) << "Unable to allocate memory";
416 }
417
418 void MessageWriter::AppendVariantOfBasic(int dbus_type, const void* value) {
419 const std::string signature = base::StringPrintf("%c", dbus_type);
420 MessageWriter variant_writer(message_);
421 OpenVariant(signature, &variant_writer);
422 variant_writer.AppendBasic(dbus_type, value);
423 CloseContainer(&variant_writer);
424 }
425
426 //
427 // MessageReader implementation.
428 //
429
430 MessageReader::MessageReader(Message* message)
431 : message_(message) {
432 dbus_message_iter_init(message_->raw_message(), &raw_message_iter_);
433 }
434
435
436 MessageReader::~MessageReader() {
437 }
438
439 bool MessageReader::HasMoreData() {
440 const int dbus_type = dbus_message_iter_get_arg_type(&raw_message_iter_);
441 return dbus_type != DBUS_TYPE_INVALID;
442 }
443
444 bool MessageReader::PopByte(uint8* value) {
445 return PopBasic(DBUS_TYPE_BYTE, value);
446 }
447
448 bool MessageReader::PopBool(bool* value) {
449 return PopBasic(DBUS_TYPE_BOOLEAN, value);
450 }
451
452 bool MessageReader::PopInt16(int16* value) {
453 return PopBasic(DBUS_TYPE_INT16, value);
454 }
455
456 bool MessageReader::PopUint16(uint16* value) {
457 return PopBasic(DBUS_TYPE_UINT16, value);
458 }
459
460 bool MessageReader::PopInt32(int32* value) {
461 return PopBasic(DBUS_TYPE_INT32, value);
462 }
463
464 bool MessageReader::PopUint32(uint32* value) {
465 return PopBasic(DBUS_TYPE_UINT32, value);
466 }
467
468 bool MessageReader::PopInt64(int64* value) {
469 return PopBasic(DBUS_TYPE_INT64, value);
470 }
471
472 bool MessageReader::PopUint64(uint64* value) {
473 return PopBasic(DBUS_TYPE_UINT64, value);
474 }
475
476 bool MessageReader::PopDouble(double* value) {
477 return PopBasic(DBUS_TYPE_DOUBLE, value);
478 }
479
480 bool MessageReader::PopString(std::string* value) {
481 char* tmp_value = NULL;
482 const bool success = PopBasic(DBUS_TYPE_STRING, &tmp_value);
483 if (success)
484 value->assign(tmp_value);
485 return success;
486 }
487
488 bool MessageReader::PopObjectPath(std::string* value) {
489 char* tmp_value = NULL;
490 const bool success = PopBasic(DBUS_TYPE_OBJECT_PATH, &tmp_value);
491 if (success)
492 value->assign(tmp_value);
493 return success;
494 }
495
496 bool MessageReader::PopArray(MessageReader* sub_reader) {
497 return PopContainer(DBUS_TYPE_ARRAY, sub_reader);
498 }
499
500 bool MessageReader::PopStruct(MessageReader* sub_reader) {
501 return PopContainer(DBUS_TYPE_STRUCT, sub_reader);
502 }
503
504 bool MessageReader::PopDictEntry(MessageReader* sub_reader) {
505 return PopContainer(DBUS_TYPE_DICT_ENTRY, sub_reader);
506 }
507
508 bool MessageReader::PopVariant(MessageReader* sub_reader) {
509 return PopContainer(DBUS_TYPE_VARIANT, sub_reader);
510 }
511
512 bool MessageReader::PopArrayOfBytes(
513 std::vector<uint8>* bytes) {
514 MessageReader array_reader(message_);
515 if (!PopArray(&array_reader))
516 return false;
517 if (!array_reader.CheckDataType(DBUS_TYPE_BYTE))
518 return false;
519 char* values = NULL;
520 int num_values = 0;
521 dbus_message_iter_get_fixed_array(&array_reader.raw_message_iter_,
522 &values, &num_values);
523 if (!values)
524 return false;
525
526 bytes->assign(values, values + num_values); // Copy the data.
527 return true;
528 }
529
530 bool MessageReader::PopArrayOfObjectPaths(
531 std::vector<std::string> *object_paths) {
532 MessageReader array_reader(message_);
533 if (!PopArray(&array_reader))
534 return false;
535 while (array_reader.HasMoreData()) {
536 std::string object_path;
537 if (!array_reader.PopObjectPath(&object_path))
538 return false;
539 object_paths->push_back(object_path);
540 }
541 return true;
542 }
543
544 bool MessageReader::PopVariantOfByte(uint8* value) {
545 return PopVariantOfBasic(DBUS_TYPE_BYTE, value);
546 }
547
548 bool MessageReader::PopVariantOfBool(bool* value) {
549 return PopVariantOfBasic(DBUS_TYPE_BOOLEAN, value);
550 }
551
552 bool MessageReader::PopVariantOfInt16(int16* value) {
553 return PopVariantOfBasic(DBUS_TYPE_INT16, value);
554 }
555
556 bool MessageReader::PopVariantOfUint16(uint16* value) {
557 return PopVariantOfBasic(DBUS_TYPE_UINT16, value);
558 }
559
560 bool MessageReader::PopVariantOfInt32(int32* value) {
561 return PopVariantOfBasic(DBUS_TYPE_INT32, value);
562 }
563
564 bool MessageReader::PopVariantOfUint32(uint32* value) {
565 return PopVariantOfBasic(DBUS_TYPE_UINT32, value);
566 }
567
568 bool MessageReader::PopVariantOfInt64(int64* value) {
569 return PopVariantOfBasic(DBUS_TYPE_INT64, value);
570 }
571
572 bool MessageReader::PopVariantOfUint64(uint64* value) {
573 return PopVariantOfBasic(DBUS_TYPE_UINT64, value);
574 }
575
576 bool MessageReader::PopVariantOfDouble(double* value) {
577 return PopVariantOfBasic(DBUS_TYPE_DOUBLE, value);
578 }
579
580 bool MessageReader::PopVariantOfString(std::string* value) {
581 char* tmp_value = NULL;
582 const bool success = PopVariantOfBasic(DBUS_TYPE_STRING, &tmp_value);
583 if (success)
584 value->assign(tmp_value);
585 return success;
586 }
587
588 bool MessageReader::PopVariantOfObjectPath(std::string* value) {
589 char* tmp_value = NULL;
590 const bool success = PopVariantOfBasic(DBUS_TYPE_OBJECT_PATH, &tmp_value);
591 if (success)
592 value->assign(tmp_value);
593 return success;
594 }
595
596 Message::DataType MessageReader::GetDataType() {
597 const int dbus_type = dbus_message_iter_get_arg_type(&raw_message_iter_);
598 return static_cast<Message::DataType>(dbus_type);
599 }
600
601 bool MessageReader::CheckDataType(int dbus_type) {
602 const int actual_type = dbus_message_iter_get_arg_type(&raw_message_iter_);
603 if (actual_type != dbus_type) {
604 VLOG(1) << "Type " << dbus_type << " is expected but got "
605 << actual_type;
606 return false;
607 }
608 return true;
609 }
610
611 bool MessageReader::PopBasic(int dbus_type, void* value) {
612 if (!CheckDataType(dbus_type))
613 return false;
614 // dbus_message_iter_get_basic() here should always work, as we have
615 // already checked the next item's data type in CheckDataType(). Note
616 // that dbus_message_iter_get_basic() is a void function.
617 dbus_message_iter_get_basic(&raw_message_iter_, value);
618 DCHECK(value);
619 dbus_message_iter_next(&raw_message_iter_);
620 return true;
621 }
622
623 bool MessageReader::PopContainer(int dbus_type, MessageReader* sub_reader) {
624 DCHECK_NE(this, sub_reader);
625
626 if (!CheckDataType(dbus_type))
627 return false;
628 dbus_message_iter_recurse(&raw_message_iter_,
629 &sub_reader->raw_message_iter_);
630 dbus_message_iter_next(&raw_message_iter_);
631 return true;
632 }
633
634 bool MessageReader::PopVariantOfBasic(int dbus_type, void* value) {
635 dbus::MessageReader variant_reader(message_);
636 if (!PopVariant(&variant_reader))
637 return false;
638 return variant_reader.PopBasic(dbus_type, value);
639 }
640
641 } // namespace dbus
OLDNEW
« no previous file with comments | « dbus/message.h ('k') | dbus/message_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698