1 // Copyright 2014 The Chromium OS 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 <brillo/dbus/data_serialization.h>
6
7 #include <base/logging.h>
8 #include <brillo/any.h>
9 #include <brillo/variant_dictionary.h>
10
11 namespace brillo {
12 namespace dbus_utils {
13
AppendValueToWriter(dbus::MessageWriter * writer,bool value)14 void AppendValueToWriter(dbus::MessageWriter* writer, bool value) {
15 writer->AppendBool(value);
16 }
17
AppendValueToWriter(dbus::MessageWriter * writer,uint8_t value)18 void AppendValueToWriter(dbus::MessageWriter* writer, uint8_t value) {
19 writer->AppendByte(value);
20 }
21
AppendValueToWriter(dbus::MessageWriter * writer,int16_t value)22 void AppendValueToWriter(dbus::MessageWriter* writer, int16_t value) {
23 writer->AppendInt16(value);
24 }
25
AppendValueToWriter(dbus::MessageWriter * writer,uint16_t value)26 void AppendValueToWriter(dbus::MessageWriter* writer, uint16_t value) {
27 writer->AppendUint16(value);
28 }
29
AppendValueToWriter(dbus::MessageWriter * writer,int32_t value)30 void AppendValueToWriter(dbus::MessageWriter* writer, int32_t value) {
31 writer->AppendInt32(value);
32 }
33
AppendValueToWriter(dbus::MessageWriter * writer,uint32_t value)34 void AppendValueToWriter(dbus::MessageWriter* writer, uint32_t value) {
35 writer->AppendUint32(value);
36 }
37
AppendValueToWriter(dbus::MessageWriter * writer,int64_t value)38 void AppendValueToWriter(dbus::MessageWriter* writer, int64_t value) {
39 writer->AppendInt64(value);
40 }
41
AppendValueToWriter(dbus::MessageWriter * writer,uint64_t value)42 void AppendValueToWriter(dbus::MessageWriter* writer, uint64_t value) {
43 writer->AppendUint64(value);
44 }
45
AppendValueToWriter(dbus::MessageWriter * writer,double value)46 void AppendValueToWriter(dbus::MessageWriter* writer, double value) {
47 writer->AppendDouble(value);
48 }
49
AppendValueToWriter(dbus::MessageWriter * writer,const std::string & value)50 void AppendValueToWriter(dbus::MessageWriter* writer,
51 const std::string& value) {
52 writer->AppendString(value);
53 }
54
AppendValueToWriter(dbus::MessageWriter * writer,const char * value)55 void AppendValueToWriter(dbus::MessageWriter* writer, const char* value) {
56 AppendValueToWriter(writer, std::string(value));
57 }
58
AppendValueToWriter(dbus::MessageWriter * writer,const dbus::ObjectPath & value)59 void AppendValueToWriter(dbus::MessageWriter* writer,
60 const dbus::ObjectPath& value) {
61 writer->AppendObjectPath(value);
62 }
63
AppendValueToWriter(dbus::MessageWriter * writer,const base::ScopedFD & value)64 void AppendValueToWriter(dbus::MessageWriter* writer,
65 const base::ScopedFD& value) {
66 writer->AppendFileDescriptor(value.get());
67 }
68
AppendValueToWriter(dbus::MessageWriter * writer,const brillo::Any & value)69 void AppendValueToWriter(dbus::MessageWriter* writer,
70 const brillo::Any& value) {
71 value.AppendToDBusMessageWriter(writer);
72 }
73
74 ///////////////////////////////////////////////////////////////////////////////
75
PopValueFromReader(dbus::MessageReader * reader,bool * value)76 bool PopValueFromReader(dbus::MessageReader* reader, bool* value) {
77 dbus::MessageReader variant_reader(nullptr);
78 return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
79 reader->PopBool(value);
80 }
81
PopValueFromReader(dbus::MessageReader * reader,uint8_t * value)82 bool PopValueFromReader(dbus::MessageReader* reader, uint8_t* value) {
83 dbus::MessageReader variant_reader(nullptr);
84 return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
85 reader->PopByte(value);
86 }
87
PopValueFromReader(dbus::MessageReader * reader,int16_t * value)88 bool PopValueFromReader(dbus::MessageReader* reader, int16_t* value) {
89 dbus::MessageReader variant_reader(nullptr);
90 return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
91 reader->PopInt16(value);
92 }
93
PopValueFromReader(dbus::MessageReader * reader,uint16_t * value)94 bool PopValueFromReader(dbus::MessageReader* reader, uint16_t* value) {
95 dbus::MessageReader variant_reader(nullptr);
96 return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
97 reader->PopUint16(value);
98 }
99
PopValueFromReader(dbus::MessageReader * reader,int32_t * value)100 bool PopValueFromReader(dbus::MessageReader* reader, int32_t* value) {
101 dbus::MessageReader variant_reader(nullptr);
102 return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
103 reader->PopInt32(value);
104 }
105
PopValueFromReader(dbus::MessageReader * reader,uint32_t * value)106 bool PopValueFromReader(dbus::MessageReader* reader, uint32_t* value) {
107 dbus::MessageReader variant_reader(nullptr);
108 return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
109 reader->PopUint32(value);
110 }
111
PopValueFromReader(dbus::MessageReader * reader,int64_t * value)112 bool PopValueFromReader(dbus::MessageReader* reader, int64_t* value) {
113 dbus::MessageReader variant_reader(nullptr);
114 return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
115 reader->PopInt64(value);
116 }
117
PopValueFromReader(dbus::MessageReader * reader,uint64_t * value)118 bool PopValueFromReader(dbus::MessageReader* reader, uint64_t* value) {
119 dbus::MessageReader variant_reader(nullptr);
120 return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
121 reader->PopUint64(value);
122 }
123
PopValueFromReader(dbus::MessageReader * reader,double * value)124 bool PopValueFromReader(dbus::MessageReader* reader, double* value) {
125 dbus::MessageReader variant_reader(nullptr);
126 return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
127 reader->PopDouble(value);
128 }
129
PopValueFromReader(dbus::MessageReader * reader,std::string * value)130 bool PopValueFromReader(dbus::MessageReader* reader, std::string* value) {
131 dbus::MessageReader variant_reader(nullptr);
132 return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
133 reader->PopString(value);
134 }
135
PopValueFromReader(dbus::MessageReader * reader,dbus::ObjectPath * value)136 bool PopValueFromReader(dbus::MessageReader* reader, dbus::ObjectPath* value) {
137 dbus::MessageReader variant_reader(nullptr);
138 return details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
139 reader->PopObjectPath(value);
140 }
141
PopValueFromReader(dbus::MessageReader * reader,base::ScopedFD * value)142 bool PopValueFromReader(dbus::MessageReader* reader,
143 base::ScopedFD* value) {
144 dbus::MessageReader variant_reader(nullptr);
145 bool ok = details::DescendIntoVariantIfPresent(&reader, &variant_reader) &&
146 reader->PopFileDescriptor(value);
147 return ok;
148 }
149
150 namespace {
151
152 // Helper methods for PopValueFromReader(dbus::MessageReader*, Any*)
153 // implementation. Pops a value of particular type from |reader| and assigns
154 // it to |value| of type Any.
155 template<typename T>
PopTypedValueFromReader(dbus::MessageReader * reader,brillo::Any * value)156 bool PopTypedValueFromReader(dbus::MessageReader* reader,
157 brillo::Any* value) {
158 T data{};
159 if (!PopValueFromReader(reader, &data))
160 return false;
161 *value = std::move(data);
162 return true;
163 }
164
165 // std::vector<T> overload.
166 template<typename T>
PopTypedArrayFromReader(dbus::MessageReader * reader,brillo::Any * value)167 bool PopTypedArrayFromReader(dbus::MessageReader* reader,
168 brillo::Any* value) {
169 return PopTypedValueFromReader<std::vector<T>>(reader, value);
170 }
171
172 // std::map<KEY, VALUE> overload.
173 template<typename KEY, typename VALUE>
PopTypedMapFromReader(dbus::MessageReader * reader,brillo::Any * value)174 bool PopTypedMapFromReader(dbus::MessageReader* reader, brillo::Any* value) {
175 return PopTypedValueFromReader<std::map<KEY, VALUE>>(reader, value);
176 }
177
178 // Helper methods for reading common ARRAY signatures into a Variant.
179 // Note that only common types are supported. If an additional specific
180 // type signature is required, feel free to add support for it.
PopArrayValueFromReader(dbus::MessageReader * reader,brillo::Any * value)181 bool PopArrayValueFromReader(dbus::MessageReader* reader,
182 brillo::Any* value) {
183 std::string signature = reader->GetDataSignature();
184 if (signature == "ab")
185 return PopTypedArrayFromReader<bool>(reader, value);
186 else if (signature == "ay")
187 return PopTypedArrayFromReader<uint8_t>(reader, value);
188 else if (signature == "an")
189 return PopTypedArrayFromReader<int16_t>(reader, value);
190 else if (signature == "aq")
191 return PopTypedArrayFromReader<uint16_t>(reader, value);
192 else if (signature == "ai")
193 return PopTypedArrayFromReader<int32_t>(reader, value);
194 else if (signature == "au")
195 return PopTypedArrayFromReader<uint32_t>(reader, value);
196 else if (signature == "ax")
197 return PopTypedArrayFromReader<int64_t>(reader, value);
198 else if (signature == "at")
199 return PopTypedArrayFromReader<uint64_t>(reader, value);
200 else if (signature == "ad")
201 return PopTypedArrayFromReader<double>(reader, value);
202 else if (signature == "as")
203 return PopTypedArrayFromReader<std::string>(reader, value);
204 else if (signature == "ao")
205 return PopTypedArrayFromReader<dbus::ObjectPath>(reader, value);
206 else if (signature == "av")
207 return PopTypedArrayFromReader<brillo::Any>(reader, value);
208 else if (signature == "a{ss}")
209 return PopTypedMapFromReader<std::string, std::string>(reader, value);
210 else if (signature == "a{sv}")
211 return PopTypedValueFromReader<brillo::VariantDictionary>(reader, value);
212 else if (signature == "aa{ss}")
213 return PopTypedArrayFromReader<
214 std::map<std::string, std::string>>(reader, value);
215 else if (signature == "aa{sv}")
216 return PopTypedArrayFromReader<brillo::VariantDictionary>(reader, value);
217 else if (signature == "a{sa{ss}}")
218 return PopTypedMapFromReader<
219 std::string, std::map<std::string, std::string>>(reader, value);
220 else if (signature == "a{sa{sv}}")
221 return PopTypedMapFromReader<
222 std::string, brillo::VariantDictionary>(reader, value);
223 else if (signature == "a{say}")
224 return PopTypedMapFromReader<
225 std::string, std::vector<uint8_t>>(reader, value);
226 else if (signature == "a{uv}")
227 return PopTypedMapFromReader<uint32_t, brillo::Any>(reader, value);
228 else if (signature == "a(su)")
229 return PopTypedArrayFromReader<
230 std::tuple<std::string, uint32_t>>(reader, value);
231 else if (signature == "a{uu}")
232 return PopTypedMapFromReader<uint32_t, uint32_t>(reader, value);
233 else if (signature == "a(uu)")
234 return PopTypedArrayFromReader<
235 std::tuple<uint32_t, uint32_t>>(reader, value);
236
237 // When a use case for particular array signature is found, feel free
238 // to add handing for it here.
239 LOG(ERROR) << "Variant de-serialization of array containing data of "
240 << "type '" << signature << "' is not yet supported";
241 return false;
242 }
243
244 // Helper methods for reading common STRUCT signatures into a Variant.
245 // Note that only common types are supported. If an additional specific
246 // type signature is required, feel free to add support for it.
PopStructValueFromReader(dbus::MessageReader * reader,brillo::Any * value)247 bool PopStructValueFromReader(dbus::MessageReader* reader,
248 brillo::Any* value) {
249 std::string signature = reader->GetDataSignature();
250 if (signature == "(ii)")
251 return PopTypedValueFromReader<std::tuple<int, int>>(reader, value);
252 else if (signature == "(ss)")
253 return PopTypedValueFromReader<std::tuple<std::string, std::string>>(reader,
254 value);
255 else if (signature == "(ub)")
256 return PopTypedValueFromReader<std::tuple<uint32_t, bool>>(reader, value);
257 else if (signature == "(uu)")
258 return PopTypedValueFromReader<std::tuple<uint32_t, uint32_t>>(reader,
259 value);
260
261 // When a use case for particular struct signature is found, feel free
262 // to add handing for it here.
263 LOG(ERROR) << "Variant de-serialization of structs of type '" << signature
264 << "' is not yet supported";
265 return false;
266 }
267
268 } // anonymous namespace
269
PopValueFromReader(dbus::MessageReader * reader,brillo::Any * value)270 bool PopValueFromReader(dbus::MessageReader* reader, brillo::Any* value) {
271 dbus::MessageReader variant_reader(nullptr);
272 if (!details::DescendIntoVariantIfPresent(&reader, &variant_reader))
273 return false;
274
275 switch (reader->GetDataType()) {
276 case dbus::Message::BYTE:
277 return PopTypedValueFromReader<uint8_t>(reader, value);
278 case dbus::Message::BOOL:
279 return PopTypedValueFromReader<bool>(reader, value);
280 case dbus::Message::INT16:
281 return PopTypedValueFromReader<int16_t>(reader, value);
282 case dbus::Message::UINT16:
283 return PopTypedValueFromReader<uint16_t>(reader, value);
284 case dbus::Message::INT32:
285 return PopTypedValueFromReader<int32_t>(reader, value);
286 case dbus::Message::UINT32:
287 return PopTypedValueFromReader<uint32_t>(reader, value);
288 case dbus::Message::INT64:
289 return PopTypedValueFromReader<int64_t>(reader, value);
290 case dbus::Message::UINT64:
291 return PopTypedValueFromReader<uint64_t>(reader, value);
292 case dbus::Message::DOUBLE:
293 return PopTypedValueFromReader<double>(reader, value);
294 case dbus::Message::STRING:
295 return PopTypedValueFromReader<std::string>(reader, value);
296 case dbus::Message::OBJECT_PATH:
297 return PopTypedValueFromReader<dbus::ObjectPath>(reader, value);
298 case dbus::Message::ARRAY:
299 return PopArrayValueFromReader(reader, value);
300 case dbus::Message::STRUCT:
301 return PopStructValueFromReader(reader, value);
302 case dbus::Message::DICT_ENTRY:
303 LOG(ERROR) << "Variant of DICT_ENTRY is invalid";
304 return false;
305 case dbus::Message::VARIANT:
306 LOG(ERROR) << "Variant containing a variant is invalid";
307 return false;
308 case dbus::Message::UNIX_FD:
309 CHECK(dbus::IsDBusTypeUnixFdSupported()) << "UNIX_FD data not supported";
310 // base::ScopedFD is not a copyable type. Cannot be returned via
311 // brillo::Any. Fail here.
312 LOG(ERROR) << "Cannot return FileDescriptor via Any";
313 return false;
314 default:
315 LOG(FATAL) << "Unknown D-Bus data type: " << variant_reader.GetDataType();
316 return false;
317 }
318 return true;
319 }
320
321 } // namespace dbus_utils
322 } // namespace brillo
323