xref: /aosp_15_r20/external/ot-br-posix/src/dbus/server/dbus_object.cpp (revision 4a64e381480ef79f0532b2421e44e6ee336b8e0d)
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