1 /*
2 * Copyright (c) 2019, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #define OTBR_LOG_TAG "DBUS"
30
31 #include <assert.h>
32 #include <stdio.h>
33 #include <string.h>
34
35 #include <dbus/dbus.h>
36
37 #include "common/logging.hpp"
38 #include "dbus/common/dbus_message_dump.hpp"
39 #include "dbus/server/dbus_object.hpp"
40
41 using std::placeholders::_1;
42
43 namespace otbr {
44 namespace DBus {
45
DBusObject(DBusConnection * aConnection,const std::string & aObjectPath)46 DBusObject::DBusObject(DBusConnection *aConnection, const std::string &aObjectPath)
47 : mConnection(aConnection)
48 , mObjectPath(aObjectPath)
49 {
50 }
51
Init(void)52 otbrError DBusObject::Init(void)
53 {
54 return Initialize(/* aIsAsyncPropertyHandler */ false);
55 }
56
Initialize(bool aIsAsyncPropertyHandler)57 otbrError DBusObject::Initialize(bool aIsAsyncPropertyHandler)
58 {
59 otbrError error = OTBR_ERROR_NONE;
60 DBusObjectPathVTable vTable;
61
62 memset(&vTable, 0, sizeof(vTable));
63
64 vTable.message_function = DBusObject::sMessageHandler;
65
66 VerifyOrExit(dbus_connection_register_object_path(mConnection, mObjectPath.c_str(), &vTable, this),
67 error = OTBR_ERROR_DBUS);
68
69 if (aIsAsyncPropertyHandler)
70 {
71 RegisterMethod(DBUS_INTERFACE_PROPERTIES, DBUS_PROPERTY_GET_METHOD,
72 std::bind(&DBusObject::AsyncGetPropertyMethodHandler, this, _1));
73 }
74 else
75 {
76 RegisterMethod(DBUS_INTERFACE_PROPERTIES, DBUS_PROPERTY_GET_METHOD,
77 std::bind(&DBusObject::GetPropertyMethodHandler, this, _1));
78 RegisterMethod(DBUS_INTERFACE_PROPERTIES, DBUS_PROPERTY_SET_METHOD,
79 std::bind(&DBusObject::SetPropertyMethodHandler, this, _1));
80 RegisterMethod(DBUS_INTERFACE_PROPERTIES, DBUS_PROPERTY_GET_ALL_METHOD,
81 std::bind(&DBusObject::GetAllPropertiesMethodHandler, this, _1));
82 }
83
84 exit:
85 return error;
86 }
87
RegisterMethod(const std::string & aInterfaceName,const std::string & aMethodName,const MethodHandlerType & aHandler)88 void DBusObject::RegisterMethod(const std::string &aInterfaceName,
89 const std::string &aMethodName,
90 const MethodHandlerType &aHandler)
91 {
92 std::string fullPath = aInterfaceName + "." + aMethodName;
93
94 assert(mMethodHandlers.find(fullPath) == mMethodHandlers.end());
95 mMethodHandlers.emplace(fullPath, aHandler);
96 }
97
RegisterGetPropertyHandler(const std::string & aInterfaceName,const std::string & aPropertyName,const PropertyHandlerType & aHandler)98 void DBusObject::RegisterGetPropertyHandler(const std::string &aInterfaceName,
99 const std::string &aPropertyName,
100 const PropertyHandlerType &aHandler)
101 {
102 mGetPropertyHandlers[aInterfaceName].emplace(aPropertyName, aHandler);
103 }
104
RegisterSetPropertyHandler(const std::string & aInterfaceName,const std::string & aPropertyName,const PropertyHandlerType & aHandler)105 void DBusObject::RegisterSetPropertyHandler(const std::string &aInterfaceName,
106 const std::string &aPropertyName,
107 const PropertyHandlerType &aHandler)
108 {
109 std::string fullPath = aInterfaceName + "." + aPropertyName;
110
111 assert(mSetPropertyHandlers.find(fullPath) == mSetPropertyHandlers.end());
112 mSetPropertyHandlers.emplace(fullPath, aHandler);
113 }
114
RegisterAsyncGetPropertyHandler(const std::string & aInterfaceName,const std::string & aPropertyName,const AsyncPropertyHandlerType & aHandler)115 void DBusObject::RegisterAsyncGetPropertyHandler(const std::string &aInterfaceName,
116 const std::string &aPropertyName,
117 const AsyncPropertyHandlerType &aHandler)
118 {
119 mAsyncGetPropertyHandlers[aInterfaceName].emplace(aPropertyName, aHandler);
120 }
121
sMessageHandler(DBusConnection * aConnection,DBusMessage * aMessage,void * aData)122 DBusHandlerResult DBusObject::sMessageHandler(DBusConnection *aConnection, DBusMessage *aMessage, void *aData)
123 {
124 DBusObject *server = reinterpret_cast<DBusObject *>(aData);
125
126 return server->MessageHandler(aConnection, aMessage);
127 }
128
MessageHandler(DBusConnection * aConnection,DBusMessage * aMessage)129 DBusHandlerResult DBusObject::MessageHandler(DBusConnection *aConnection, DBusMessage *aMessage)
130 {
131 DBusHandlerResult handled = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
132 DBusRequest request(aConnection, aMessage);
133 std::string interface = dbus_message_get_interface(aMessage);
134 std::string memberName = interface + "." + dbus_message_get_member(aMessage);
135 auto iter = mMethodHandlers.find(memberName);
136
137 if (dbus_message_get_type(aMessage) == DBUS_MESSAGE_TYPE_METHOD_CALL && iter != mMethodHandlers.end())
138 {
139 otbrLogDebug("Handling method %s", memberName.c_str());
140 if (otbrLogGetLevel() >= OTBR_LOG_DEBUG)
141 {
142 DumpDBusMessage(*aMessage);
143 }
144 (iter->second)(request);
145 handled = DBUS_HANDLER_RESULT_HANDLED;
146 }
147
148 return handled;
149 }
150
GetPropertyMethodHandler(DBusRequest & aRequest)151 void DBusObject::GetPropertyMethodHandler(DBusRequest &aRequest)
152 {
153 UniqueDBusMessage reply{dbus_message_new_method_return(aRequest.GetMessage())};
154
155 DBusMessageIter iter;
156 std::string interfaceName;
157 std::string propertyName;
158 otError error = OT_ERROR_NONE;
159 otError replyError = OT_ERROR_NONE;
160
161 VerifyOrExit(reply != nullptr, error = OT_ERROR_NO_BUFS);
162 VerifyOrExit(dbus_message_iter_init(aRequest.GetMessage(), &iter), error = OT_ERROR_FAILED);
163 VerifyOrExit(DBusMessageExtract(&iter, interfaceName) == OTBR_ERROR_NONE, error = OT_ERROR_PARSE);
164 VerifyOrExit(DBusMessageExtract(&iter, propertyName) == OTBR_ERROR_NONE, error = OT_ERROR_PARSE);
165 {
166 auto propertyIter = mGetPropertyHandlers.find(interfaceName);
167
168 otbrLogDebug("GetProperty %s.%s", interfaceName.c_str(), propertyName.c_str());
169 VerifyOrExit(propertyIter != mGetPropertyHandlers.end(), error = OT_ERROR_NOT_FOUND);
170 {
171 DBusMessageIter replyIter;
172 auto &interfaceHandlers = propertyIter->second;
173 auto interfaceIter = interfaceHandlers.find(propertyName);
174
175 VerifyOrExit(interfaceIter != interfaceHandlers.end(), error = OT_ERROR_NOT_FOUND);
176 dbus_message_iter_init_append(reply.get(), &replyIter);
177 SuccessOrExit(replyError = interfaceIter->second(replyIter));
178 }
179 }
180 exit:
181 if (error == OT_ERROR_NONE && replyError == OT_ERROR_NONE)
182 {
183 if (otbrLogGetLevel() >= OTBR_LOG_DEBUG)
184 {
185 otbrLogDebug("GetProperty %s.%s reply:", interfaceName.c_str(), propertyName.c_str());
186 DumpDBusMessage(*reply);
187 }
188
189 dbus_connection_send(aRequest.GetConnection(), reply.get(), nullptr);
190 }
191 else if (error == OT_ERROR_NONE)
192 {
193 otbrLogInfo("GetProperty %s.%s reply:%s", interfaceName.c_str(), propertyName.c_str(),
194 ConvertToDBusErrorName(replyError));
195 aRequest.ReplyOtResult(replyError);
196 }
197 else
198 {
199 otbrLogWarning("GetProperty %s.%s error:%s", interfaceName.c_str(), propertyName.c_str(),
200 ConvertToDBusErrorName(error));
201 aRequest.ReplyOtResult(error);
202 }
203 }
204
GetAllPropertiesMethodHandler(DBusRequest & aRequest)205 void DBusObject::GetAllPropertiesMethodHandler(DBusRequest &aRequest)
206 {
207 UniqueDBusMessage reply{dbus_message_new_method_return(aRequest.GetMessage())};
208 DBusMessageIter iter, subIter, dictEntryIter;
209 std::string interfaceName;
210 auto args = std::tie(interfaceName);
211 otError error = OT_ERROR_NONE;
212
213 VerifyOrExit(reply != nullptr, error = OT_ERROR_NO_BUFS);
214 VerifyOrExit(DBusMessageToTuple(*aRequest.GetMessage(), args) == OTBR_ERROR_NONE, error = OT_ERROR_PARSE);
215 VerifyOrExit(mGetPropertyHandlers.find(interfaceName) != mGetPropertyHandlers.end(), error = OT_ERROR_NOT_FOUND);
216 dbus_message_iter_init_append(reply.get(), &iter);
217
218 for (auto &p : mGetPropertyHandlers.at(interfaceName))
219 {
220 VerifyOrExit(dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
221 "{" DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING "}",
222 &subIter),
223 error = OT_ERROR_FAILED);
224 VerifyOrExit(dbus_message_iter_open_container(&subIter, DBUS_TYPE_DICT_ENTRY, nullptr, &dictEntryIter),
225 error = OT_ERROR_FAILED);
226 VerifyOrExit(DBusMessageEncode(&dictEntryIter, p.first) == OTBR_ERROR_NONE, error = OT_ERROR_FAILED);
227
228 SuccessOrExit(error = p.second(dictEntryIter));
229
230 VerifyOrExit(dbus_message_iter_close_container(&subIter, &dictEntryIter), error = OT_ERROR_FAILED);
231 VerifyOrExit(dbus_message_iter_close_container(&iter, &subIter));
232 }
233
234 exit:
235 if (error == OT_ERROR_NONE)
236 {
237 dbus_connection_send(aRequest.GetConnection(), reply.get(), nullptr);
238 }
239 else
240 {
241 aRequest.ReplyOtResult(error);
242 }
243 }
244
SetPropertyMethodHandler(DBusRequest & aRequest)245 void DBusObject::SetPropertyMethodHandler(DBusRequest &aRequest)
246 {
247 DBusMessageIter iter;
248 std::string interfaceName;
249 std::string propertyName;
250 std::string propertyFullPath;
251 otError error = OT_ERROR_NONE;
252
253 VerifyOrExit(dbus_message_iter_init(aRequest.GetMessage(), &iter), error = OT_ERROR_FAILED);
254 VerifyOrExit(DBusMessageExtract(&iter, interfaceName) == OTBR_ERROR_NONE, error = OT_ERROR_PARSE);
255 VerifyOrExit(DBusMessageExtract(&iter, propertyName) == OTBR_ERROR_NONE, error = OT_ERROR_PARSE);
256
257 propertyFullPath = interfaceName + "." + propertyName;
258 otbrLogInfo("SetProperty %s", propertyFullPath.c_str());
259 {
260 auto handlerIter = mSetPropertyHandlers.find(propertyFullPath);
261
262 VerifyOrExit(handlerIter != mSetPropertyHandlers.end(), error = OT_ERROR_NOT_FOUND);
263 error = handlerIter->second(iter);
264 }
265
266 exit:
267 if (error != OT_ERROR_NONE)
268 {
269 otbrLogWarning("SetProperty %s.%s error:%s", interfaceName.c_str(), propertyName.c_str(),
270 ConvertToDBusErrorName(error));
271 }
272 aRequest.ReplyOtResult(error);
273 return;
274 }
275
AsyncGetPropertyMethodHandler(DBusRequest & aRequest)276 void DBusObject::AsyncGetPropertyMethodHandler(DBusRequest &aRequest)
277 {
278 DBusMessageIter iter;
279 std::string interfaceName;
280 otError error = OT_ERROR_NONE;
281 std::string propertyName;
282
283 VerifyOrExit(dbus_message_iter_init(aRequest.GetMessage(), &iter), error = OT_ERROR_FAILED);
284 SuccessOrExit(error = OtbrErrorToOtError(DBusMessageExtract(&iter, interfaceName)));
285 SuccessOrExit(error = OtbrErrorToOtError(DBusMessageExtract(&iter, propertyName)));
286
287 {
288 auto propertyIter = mAsyncGetPropertyHandlers.find(interfaceName);
289
290 otbrLogDebug("AsyncGetProperty %s.%s", interfaceName.c_str(), propertyName.c_str());
291 VerifyOrExit(propertyIter != mAsyncGetPropertyHandlers.end(), error = OT_ERROR_NOT_FOUND);
292 {
293 auto &interfaceHandlers = propertyIter->second;
294 auto interfaceIter = interfaceHandlers.find(propertyName);
295
296 VerifyOrExit(interfaceIter != interfaceHandlers.end(), error = OT_ERROR_NOT_FOUND);
297 (interfaceIter->second)(aRequest);
298 }
299 }
300
301 exit:
302 if (error != OT_ERROR_NONE)
303 {
304 otbrLogWarning("GetProperty %s.%s error:%s", interfaceName.c_str(), propertyName.c_str(),
305 ConvertToDBusErrorName(error));
306 aRequest.ReplyOtResult(error);
307 }
308 }
309
~DBusObject(void)310 DBusObject::~DBusObject(void)
311 {
312 }
313
NewSignalMessage(const std::string & aInterfaceName,const std::string & aSignalName)314 UniqueDBusMessage DBusObject::NewSignalMessage(const std::string &aInterfaceName, const std::string &aSignalName)
315 {
316 return UniqueDBusMessage(dbus_message_new_signal(mObjectPath.c_str(), aInterfaceName.c_str(), aSignalName.c_str()));
317 }
318
Flush(void)319 void DBusObject::Flush(void)
320 {
321 dbus_connection_flush(mConnection);
322 }
323
324 } // namespace DBus
325 } // namespace otbr
326