• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     otbrError            error = OTBR_ERROR_NONE;
55     DBusObjectPathVTable vTable;
56 
57     memset(&vTable, 0, sizeof(vTable));
58 
59     vTable.message_function = DBusObject::sMessageHandler;
60 
61     VerifyOrExit(dbus_connection_register_object_path(mConnection, mObjectPath.c_str(), &vTable, this),
62                  error = OTBR_ERROR_DBUS);
63     RegisterMethod(DBUS_INTERFACE_PROPERTIES, DBUS_PROPERTY_GET_METHOD,
64                    std::bind(&DBusObject::GetPropertyMethodHandler, this, _1));
65     RegisterMethod(DBUS_INTERFACE_PROPERTIES, DBUS_PROPERTY_SET_METHOD,
66                    std::bind(&DBusObject::SetPropertyMethodHandler, this, _1));
67     RegisterMethod(DBUS_INTERFACE_PROPERTIES, DBUS_PROPERTY_GET_ALL_METHOD,
68                    std::bind(&DBusObject::GetAllPropertiesMethodHandler, this, _1));
69 
70 exit:
71     return error;
72 }
73 
RegisterMethod(const std::string & aInterfaceName,const std::string & aMethodName,const MethodHandlerType & aHandler)74 void DBusObject::RegisterMethod(const std::string &      aInterfaceName,
75                                 const std::string &      aMethodName,
76                                 const MethodHandlerType &aHandler)
77 {
78     std::string fullPath = aInterfaceName + "." + aMethodName;
79 
80     assert(mMethodHandlers.find(fullPath) == mMethodHandlers.end());
81     mMethodHandlers.emplace(fullPath, aHandler);
82 }
83 
RegisterGetPropertyHandler(const std::string & aInterfaceName,const std::string & aPropertyName,const PropertyHandlerType & aHandler)84 void DBusObject::RegisterGetPropertyHandler(const std::string &        aInterfaceName,
85                                             const std::string &        aPropertyName,
86                                             const PropertyHandlerType &aHandler)
87 {
88     mGetPropertyHandlers[aInterfaceName].emplace(aPropertyName, aHandler);
89 }
90 
RegisterSetPropertyHandler(const std::string & aInterfaceName,const std::string & aPropertyName,const PropertyHandlerType & aHandler)91 void DBusObject::RegisterSetPropertyHandler(const std::string &        aInterfaceName,
92                                             const std::string &        aPropertyName,
93                                             const PropertyHandlerType &aHandler)
94 {
95     std::string fullPath = aInterfaceName + "." + aPropertyName;
96 
97     assert(mSetPropertyHandlers.find(fullPath) == mSetPropertyHandlers.end());
98     mSetPropertyHandlers.emplace(fullPath, aHandler);
99 }
100 
sMessageHandler(DBusConnection * aConnection,DBusMessage * aMessage,void * aData)101 DBusHandlerResult DBusObject::sMessageHandler(DBusConnection *aConnection, DBusMessage *aMessage, void *aData)
102 {
103     DBusObject *server = reinterpret_cast<DBusObject *>(aData);
104 
105     return server->MessageHandler(aConnection, aMessage);
106 }
107 
MessageHandler(DBusConnection * aConnection,DBusMessage * aMessage)108 DBusHandlerResult DBusObject::MessageHandler(DBusConnection *aConnection, DBusMessage *aMessage)
109 {
110     DBusHandlerResult handled = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
111     DBusRequest       request(aConnection, aMessage);
112     std::string       interface  = dbus_message_get_interface(aMessage);
113     std::string       memberName = interface + "." + dbus_message_get_member(aMessage);
114     auto              iter       = mMethodHandlers.find(memberName);
115 
116     if (dbus_message_get_type(aMessage) == DBUS_MESSAGE_TYPE_METHOD_CALL && iter != mMethodHandlers.end())
117     {
118         otbrLogInfo("Handling method %s", memberName.c_str());
119         if (otbrLogGetLevel() >= OTBR_LOG_DEBUG)
120         {
121             DumpDBusMessage(*aMessage);
122         }
123         (iter->second)(request);
124         handled = DBUS_HANDLER_RESULT_HANDLED;
125     }
126 
127     return handled;
128 }
129 
GetPropertyMethodHandler(DBusRequest & aRequest)130 void DBusObject::GetPropertyMethodHandler(DBusRequest &aRequest)
131 {
132     UniqueDBusMessage reply{dbus_message_new_method_return(aRequest.GetMessage())};
133 
134     DBusMessageIter iter;
135     std::string     interfaceName;
136     std::string     propertyName;
137     otError         error      = OT_ERROR_NONE;
138     otError         replyError = OT_ERROR_NONE;
139 
140     VerifyOrExit(reply != nullptr, error = OT_ERROR_NO_BUFS);
141     VerifyOrExit(dbus_message_iter_init(aRequest.GetMessage(), &iter), error = OT_ERROR_FAILED);
142     VerifyOrExit(DBusMessageExtract(&iter, interfaceName) == OTBR_ERROR_NONE, error = OT_ERROR_PARSE);
143     VerifyOrExit(DBusMessageExtract(&iter, propertyName) == OTBR_ERROR_NONE, error = OT_ERROR_PARSE);
144     {
145         auto propertyIter = mGetPropertyHandlers.find(interfaceName);
146 
147         otbrLogInfo("GetProperty %s.%s", interfaceName.c_str(), propertyName.c_str());
148         VerifyOrExit(propertyIter != mGetPropertyHandlers.end(), error = OT_ERROR_NOT_FOUND);
149         {
150             DBusMessageIter replyIter;
151             auto &          interfaceHandlers = propertyIter->second;
152             auto            interfaceIter     = interfaceHandlers.find(propertyName);
153 
154             VerifyOrExit(interfaceIter != interfaceHandlers.end(), error = OT_ERROR_NOT_FOUND);
155             dbus_message_iter_init_append(reply.get(), &replyIter);
156             SuccessOrExit(replyError = interfaceIter->second(replyIter));
157         }
158     }
159 exit:
160     if (error == OT_ERROR_NONE && replyError == OT_ERROR_NONE)
161     {
162         if (otbrLogGetLevel() >= OTBR_LOG_DEBUG)
163         {
164             otbrLogDebug("GetProperty %s.%s reply:", interfaceName.c_str(), propertyName.c_str());
165             DumpDBusMessage(*reply);
166         }
167 
168         dbus_connection_send(aRequest.GetConnection(), reply.get(), nullptr);
169     }
170     else if (error == OT_ERROR_NONE)
171     {
172         otbrLogInfo("GetProperty %s.%s reply:%s", interfaceName.c_str(), propertyName.c_str(),
173                     ConvertToDBusErrorName(replyError));
174         aRequest.ReplyOtResult(replyError);
175     }
176     else
177     {
178         otbrLogWarning("GetProperty %s.%s error:%s", interfaceName.c_str(), propertyName.c_str(),
179                        ConvertToDBusErrorName(error));
180         aRequest.ReplyOtResult(error);
181     }
182 }
183 
GetAllPropertiesMethodHandler(DBusRequest & aRequest)184 void DBusObject::GetAllPropertiesMethodHandler(DBusRequest &aRequest)
185 {
186     UniqueDBusMessage reply{dbus_message_new_method_return(aRequest.GetMessage())};
187     DBusMessageIter   iter, subIter, dictEntryIter;
188     std::string       interfaceName;
189     auto              args  = std::tie(interfaceName);
190     otError           error = OT_ERROR_NONE;
191 
192     VerifyOrExit(reply != nullptr, error = OT_ERROR_NO_BUFS);
193     VerifyOrExit(DBusMessageToTuple(*aRequest.GetMessage(), args) == OTBR_ERROR_NONE, error = OT_ERROR_PARSE);
194     VerifyOrExit(mGetPropertyHandlers.find(interfaceName) != mGetPropertyHandlers.end(), error = OT_ERROR_NOT_FOUND);
195     dbus_message_iter_init_append(reply.get(), &iter);
196 
197     for (auto &p : mGetPropertyHandlers.at(interfaceName))
198     {
199         VerifyOrExit(dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
200                                                       "{" DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING "}",
201                                                       &subIter),
202                      error = OT_ERROR_FAILED);
203         VerifyOrExit(dbus_message_iter_open_container(&subIter, DBUS_TYPE_DICT_ENTRY, nullptr, &dictEntryIter),
204                      error = OT_ERROR_FAILED);
205         VerifyOrExit(DBusMessageEncode(&dictEntryIter, p.first) == OTBR_ERROR_NONE, error = OT_ERROR_FAILED);
206 
207         SuccessOrExit(error = p.second(dictEntryIter));
208 
209         VerifyOrExit(dbus_message_iter_close_container(&subIter, &dictEntryIter), error = OT_ERROR_FAILED);
210         VerifyOrExit(dbus_message_iter_close_container(&iter, &subIter));
211     }
212 
213 exit:
214     if (error == OT_ERROR_NONE)
215     {
216         dbus_connection_send(aRequest.GetConnection(), reply.get(), nullptr);
217     }
218     else
219     {
220         aRequest.ReplyOtResult(error);
221     }
222 }
223 
SetPropertyMethodHandler(DBusRequest & aRequest)224 void DBusObject::SetPropertyMethodHandler(DBusRequest &aRequest)
225 {
226     DBusMessageIter iter;
227     std::string     interfaceName;
228     std::string     propertyName;
229     std::string     propertyFullPath;
230     otError         error = OT_ERROR_NONE;
231 
232     VerifyOrExit(dbus_message_iter_init(aRequest.GetMessage(), &iter), error = OT_ERROR_FAILED);
233     VerifyOrExit(DBusMessageExtract(&iter, interfaceName) == OTBR_ERROR_NONE, error = OT_ERROR_PARSE);
234     VerifyOrExit(DBusMessageExtract(&iter, propertyName) == OTBR_ERROR_NONE, error = OT_ERROR_PARSE);
235 
236     propertyFullPath = interfaceName + "." + propertyName;
237     otbrLogInfo("SetProperty %s", propertyFullPath.c_str());
238     {
239         auto handlerIter = mSetPropertyHandlers.find(propertyFullPath);
240 
241         VerifyOrExit(handlerIter != mSetPropertyHandlers.end(), error = OT_ERROR_NOT_FOUND);
242         error = handlerIter->second(iter);
243     }
244 
245 exit:
246     if (error != OT_ERROR_NONE)
247     {
248         otbrLogWarning("SetProperty %s.%s error:%s", interfaceName.c_str(), propertyName.c_str(),
249                        ConvertToDBusErrorName(error));
250     }
251     aRequest.ReplyOtResult(error);
252     return;
253 }
254 
~DBusObject(void)255 DBusObject::~DBusObject(void)
256 {
257 }
258 
NewSignalMessage(const std::string & aInterfaceName,const std::string & aSignalName)259 UniqueDBusMessage DBusObject::NewSignalMessage(const std::string &aInterfaceName, const std::string &aSignalName)
260 {
261     return UniqueDBusMessage(dbus_message_new_signal(mObjectPath.c_str(), aInterfaceName.c_str(), aSignalName.c_str()));
262 }
263 
264 } // namespace DBus
265 } // namespace otbr
266