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

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

Powered by Google App Engine
This is Rietveld 408576698