summaryrefslogtreecommitdiffstats
path: root/dbus/message.h
blob: 501f99ac7aa65f5603e1e6c1bb61dfa97778ed9b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef DBUS_MESSAGE_H_
#define DBUS_MESSAGE_H_
#pragma once

#include <string>
#include <vector>
#include <dbus/dbus.h>

#include "base/basictypes.h"

namespace dbus {

class MessageWriter;
class MessageReader;

// Message is the base class of D-Bus message types. Client code should
// usually use sub classes such as MethodCall and Response instead.
//
// The class name Message is very generic, but there should be no problem
// as the class is inside 'dbus' namespace. We chose to name this way, as
// libdbus defines lots of types starting with DBus, such as
// DBusMessage. We should avoid confusion and conflict with these types.
class Message {
 public:
  // The message type used in D-Bus.  Redefined here so client code
  // doesn't need to use raw D-Bus macros. DBUS_MESSAGE_TYPE_INVALID
  // etc. are #define macros. Having an enum type here makes code a bit
  // more type-safe.
  enum MessageType {
    MESSAGE_INVALID = DBUS_MESSAGE_TYPE_INVALID,
    MESSAGE_METHOD_CALL = DBUS_MESSAGE_TYPE_METHOD_CALL,
    MESSAGE_METHOD_RETURN = DBUS_MESSAGE_TYPE_METHOD_RETURN,
    MESSAGE_SIGNAL = DBUS_MESSAGE_TYPE_SIGNAL,
    MESSAGE_ERROR = DBUS_MESSAGE_TYPE_ERROR,
 };

  // The data type used in the D-Bus type system.  See the comment at
  // MessageType for why we are redefining data types here.
  enum DataType {
    INVALID_DATA = DBUS_TYPE_INVALID,
    BYTE = DBUS_TYPE_BYTE,
    BOOL = DBUS_TYPE_BOOLEAN,
    INT16 = DBUS_TYPE_INT16,
    UINT16 = DBUS_TYPE_UINT16,
    INT32 = DBUS_TYPE_INT32,
    UINT32 = DBUS_TYPE_UINT32,
    INT64 = DBUS_TYPE_INT64,
    UINT64 = DBUS_TYPE_UINT64,
    DOUBLE = DBUS_TYPE_DOUBLE,
    STRING = DBUS_TYPE_STRING,
    OBJECT_PATH = DBUS_TYPE_OBJECT_PATH,
    ARRAY = DBUS_TYPE_ARRAY,
    STRUCT = DBUS_TYPE_STRUCT,
    DICT_ENTRY = DBUS_TYPE_DICT_ENTRY,
    VARIANT = DBUS_TYPE_VARIANT,
  };

  // Creates a Message. The internal raw message is NULL until it's set
  // from outside by reset_raw_message().
  Message();
  virtual ~Message();

  // Returns the type of the message. Returns MESSAGE_INVALID if
  // raw_message_ is NULL.
  MessageType GetMessageType();

  DBusMessage* raw_message() { return raw_message_; }

  // Resets raw_message_ with the given raw message. Takes the ownership
  // of raw_message. raw_message_ will be unref'ed in the destructor.
  void reset_raw_message(DBusMessage* raw_message);

  // Returns the string representation of this message. Useful for
  // debugging.
  std::string ToString();

 private:
  // Helper function used in ToString().
  std::string ToStringInternal(const std::string& indent,
                               MessageReader* reader);

  DBusMessage* raw_message_;
  DISALLOW_COPY_AND_ASSIGN(Message);
};

// MessageCall is a type of message used for calling a method via D-Bus.
class MethodCall : public Message {
 public:
  // Creates a method call message for the specified interface name and
  // the method name.
  //
  // For instance, to call "Get" method of DBUS_INTERFACE_INTROSPECTABLE
  // interface ("org.freedesktop.DBus.Introspectable"), create a method
  // call like this:
  //
  //   MethodCall method_call(DBUS_INTERFACE_INTROSPECTABLE, "Get");
  //
  // The constructor creates the internal raw_message_, so the client
  // doesn't need to set this with reset_raw_message().
  MethodCall(const std::string& interface_name,
             const std::string& method_name);

  const std::string& interface_name() { return interface_name_; }
  const std::string& method_name() { return method_name_; }

  // Sets the service name. This will be handled by the object proxy.
  void SetServiceName(const std::string& service_name);
  // Sets the object path. This will be handled by the object proxy.
  void SetObjectPath(const std::string& object_path);

  std::string interface_name_;
  std::string method_name_;

  DISALLOW_COPY_AND_ASSIGN(MethodCall);
};

// Response is a type of message used for receiving a response from a
// method via D-Bus.
class Response : public Message {
 public:
  // Creates a Response message. The internal raw message is NULL.
  // Classes that implment method calls need to set the raw message once a
  // response is received from the server. See object_proxy.h.
  Response();

 private:
  DISALLOW_COPY_AND_ASSIGN(Response);
};

// MessageWriter is used to write outgoing messages for calling methods
// and sending signals.
//
// The main design goal of MessageReader and MessageWriter classes is to
// provide a type safe API. In the past, there was a Chrome OS blocker
// bug, that took days to fix, that would have been prevented if the API
// was type-safe.
//
// For instance, instead of doing something like:
//
//   // We shouldn't add '&' to str here, but it compiles with '&' added.
//   dbus_g_proxy_call(..., G_TYPE_STRING, str, G_TYPE_INVALID, ...)
//
// We want to do something like:
//
//   writer.AppendString(str);
//
class MessageWriter {
 public:
  // Data added with Append* will be written to |message|.
  MessageWriter(Message* message);
  ~MessageWriter();

  // Appends a byte to the message.
  void AppendByte(uint8 value);
  void AppendBool(bool value);
  void AppendInt16(int16 value);
  void AppendUint16(uint16 value);
  void AppendInt32(int32 value);
  void AppendUint32(uint32 value);
  void AppendInt64(int64 value);
  void AppendUint64(uint64 value);
  void AppendDouble(double value);
  void AppendString(const std::string& value);
  void AppendObjectPath(const std::string& value);

  // Opens an array. The array contents can be added to the array with
  // |sub_writer|. The client code must close the array with
  // CloseContainer(), once all contents are added.
  //
  // |signature| parameter is used to supply the D-Bus type signature of
  // the array contents. For instance, if you want an array of strings,
  // then you pass "s" as the signature.
  //
  // See the spec for details about the type signatures.
  // http://dbus.freedesktop.org/doc/dbus-specification.html
  // #message-protocol-signatures
  //
  void OpenArray(const std::string& signature, MessageWriter* sub_writer);
  // Do the same for a variant.
  void OpenVariant(const std::string& signature, MessageWriter* sub_writer);
  // Do the same for Struct and dict entry. They don't need the signature.
  void OpenStruct(MessageWriter* sub_writer);
  void OpenDictEntry(MessageWriter* sub_writer);

  // Close the container for a array/variant/struct/dict entry.
  void CloseContainer(MessageWriter* sub_writer);

  // Appends the array of bytes. Arrays of bytes are often used for
  // exchanging binary blobs hence it's worth having a specialized
  // function.
  void AppendArrayOfBytes(const uint8* values, size_t length);

  // Appends the byte wrapped in a variant data container. Variants are
  // widely used in D-Bus services so it's worth having a specialized
  // function. For instance, The third parameter of
  // "org.freedesktop.DBus.Properties.Set" is a variant.
  void AppendVariantOfByte(uint8 value);
  void AppendVariantOfBool(bool value);
  void AppendVariantOfInt16(int16 value);
  void AppendVariantOfUint16(uint16 value);
  void AppendVariantOfInt32(int32 value);
  void AppendVariantOfUint32(uint32 value);
  void AppendVariantOfInt64(int64 value);
  void AppendVariantOfUint64(uint64 value);
  void AppendVariantOfDouble(double value);
  void AppendVariantOfString(const std::string& value);
  void AppendVariantOfObjectPath(const std::string& value);

 private:
  // Helper function used to implement AppendByte etc.
  void AppendBasic(int dbus_type, const void* value);

  // Helper function used to implement AppendVariantOfByte() etc.
  void AppendVariantOfBasic(int dbus_type, const void* value);

  Message* message_;
  DBusMessageIter raw_message_iter_;
  bool container_is_open_;

  DISALLOW_COPY_AND_ASSIGN(MessageWriter);
};

// MessageReader is used to read incoming messages such as responses for
// method calls.
//
// MessageReader manages an internal iterator to read data. All functions
// starting with Pop advance the iterator on success.
class MessageReader {
 public:
  // The data will be read from the given message.
  MessageReader(Message* message);
  ~MessageReader();

  // Returns true if the reader has more data to read. The function is
  // used to iterate contents in a container like:
  //
  //   while (reader.HasMoreData())
  //     reader.PopString(&value);
  bool HasMoreData();

  // Gets the byte at the current iterator position.
  // Returns true and advances the iterator on success.
  // Returns false if the data type is not a byte.
  bool PopByte(uint8* value);
  bool PopBool(bool* value);
  bool PopInt16(int16* value);
  bool PopUint16(uint16* value);
  bool PopInt32(int32* value);
  bool PopUint32(uint32* value);
  bool PopInt64(int64* value);
  bool PopUint64(uint64* value);
  bool PopDouble(double* value);
  bool PopString(std::string* value);
  bool PopObjectPath(std::string* value);

  // Sets up the given message reader to read an array at the current
  // iterator position.
  // Returns true and advances the iterator on success.
  // Returns false if the data type is not an array
  bool PopArray(MessageReader* sub_reader);
  bool PopStruct(MessageReader* sub_reader);
  bool PopDictEntry(MessageReader* sub_reader);
  bool PopVariant(MessageReader* sub_reader);

  // Gets the array of bytes at the current iterator position.
  // Returns true and advances the iterator on success.
  //
  // Arrays of bytes are often used for exchanging binary blobs hence it's
  // worth having a specialized function.
  //
  // |bytes| must be copied if the contents will be referenced after the
  // |MessageReader is destroyed.
  bool PopArrayOfBytes(uint8** bytes, size_t* length);

  // Gets the array of object paths at the current iterator position.
  // Returns true and advances the iterator on success.
  //
  // Arrays of object paths are often used to communicate with D-Bus
  // services like NetworkManager, hence it's worth having a specialized
  // function.
  bool PopArrayOfObjectPaths(std::vector<std::string>* object_paths);

  // Gets the byte from the variant data container at the current iterator
  // position.
  // Returns true and advances the iterator on success.
  //
  // Variants are widely used in D-Bus services so it's worth having a
  // specialized function. For instance, The return value type of
  // "org.freedesktop.DBus.Properties.Get" is a variant.
  bool PopVariantOfByte(uint8* value);
  bool PopVariantOfBool(bool* value);
  bool PopVariantOfInt16(int16* value);
  bool PopVariantOfUint16(uint16* value);
  bool PopVariantOfInt32(int32* value);
  bool PopVariantOfUint32(uint32* value);
  bool PopVariantOfInt64(int64* value);
  bool PopVariantOfUint64(uint64* value);
  bool PopVariantOfDouble(double* value);
  bool PopVariantOfString(std::string* value);
  bool PopVariantOfObjectPath(std::string* value);

  // Get the data type of the value at the current iterator
  // position. INVALID_DATA will be returned if the iterator points to the
  // end of the message.
  Message::DataType GetDataType();

 private:
  // Returns true if the data type at the current iterator position
  // matches the given D-Bus type, such as DBUS_TYPE_BYTE.
  bool CheckDataType(int dbus_type);

  // Helper function used to implement PopByte() etc.
  bool PopBasic(int dbus_type, void *value);

  // Helper function used to implement PopArray() etc.
  bool PopContainer(int dbus_type, MessageReader* sub_reader);

  // Helper function used to implement PopVariantOfByte() etc.
  bool PopVariantOfBasic(int dbus_type, void* value);

  Message* message_;
  DBusMessageIter raw_message_iter_;

  DISALLOW_COPY_AND_ASSIGN(MessageReader);
};

}  // namespace dbus

#endif  // DBUS_MESSAGE_H_