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