2 * Copyright (c) 2019, The OpenThread Authors.
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.
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.
33 #include <dbus/dbus.h>
35 #include "common/logging.hpp"
36 #include "dbus/common/dbus_message_dump.hpp"
37 #include "dbus/server/dbus_object.hpp"
39 using std::placeholders::_1;
44 DBusObject::DBusObject(DBusConnection *aConnection, const std::string &aObjectPath)
45 : mConnection(aConnection)
46 , mObjectPath(aObjectPath)
50 otbrError DBusObject::Init(void)
52 otbrError error = OTBR_ERROR_NONE;
53 DBusObjectPathVTable vTable;
55 memset(&vTable, 0, sizeof(vTable));
57 vTable.message_function = DBusObject::sMessageHandler;
59 VerifyOrExit(dbus_connection_register_object_path(mConnection, mObjectPath.c_str(), &vTable, this),
60 error = OTBR_ERROR_DBUS);
61 RegisterMethod(DBUS_INTERFACE_PROPERTIES, DBUS_PROPERTY_GET_METHOD,
62 std::bind(&DBusObject::GetPropertyMethodHandler, this, _1));
63 RegisterMethod(DBUS_INTERFACE_PROPERTIES, DBUS_PROPERTY_SET_METHOD,
64 std::bind(&DBusObject::SetPropertyMethodHandler, this, _1));
65 RegisterMethod(DBUS_INTERFACE_PROPERTIES, DBUS_PROPERTY_GET_ALL_METHOD,
66 std::bind(&DBusObject::GetAllPropertiesMethodHandler, this, _1));
72 void DBusObject::RegisterMethod(const std::string & aInterfaceName,
73 const std::string & aMethodName,
74 const MethodHandlerType &aHandler)
76 std::string fullPath = aInterfaceName + "." + aMethodName;
78 assert(mMethodHandlers.find(fullPath) == mMethodHandlers.end());
79 mMethodHandlers.emplace(fullPath, aHandler);
82 void DBusObject::RegisterGetPropertyHandler(const std::string & aInterfaceName,
83 const std::string & aPropertyName,
84 const PropertyHandlerType &aHandler)
86 mGetPropertyHandlers[aInterfaceName].emplace(aPropertyName, aHandler);
89 void DBusObject::RegisterSetPropertyHandler(const std::string & aInterfaceName,
90 const std::string & aPropertyName,
91 const PropertyHandlerType &aHandler)
93 std::string fullPath = aInterfaceName + "." + aPropertyName;
95 assert(mSetPropertyHandlers.find(fullPath) == mSetPropertyHandlers.end());
96 mSetPropertyHandlers.emplace(fullPath, aHandler);
99 DBusHandlerResult DBusObject::sMessageHandler(DBusConnection *aConnection, DBusMessage *aMessage, void *aData)
101 DBusObject *server = reinterpret_cast<DBusObject *>(aData);
103 return server->MessageHandler(aConnection, aMessage);
106 DBusHandlerResult DBusObject::MessageHandler(DBusConnection *aConnection, DBusMessage *aMessage)
108 DBusHandlerResult handled = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
109 DBusRequest request(aConnection, aMessage);
110 std::string interface = dbus_message_get_interface(aMessage);
111 std::string memberName = interface + "." + dbus_message_get_member(aMessage);
112 auto iter = mMethodHandlers.find(memberName);
114 if (dbus_message_get_type(aMessage) == DBUS_MESSAGE_TYPE_METHOD_CALL && iter != mMethodHandlers.end())
116 otbrLog(OTBR_LOG_INFO, "Handling method %s", memberName.c_str());
117 if (otbrLogGetLevel() >= OTBR_LOG_DEBUG)
119 DumpDBusMessage(*aMessage);
121 (iter->second)(request);
122 handled = DBUS_HANDLER_RESULT_HANDLED;
128 void DBusObject::GetPropertyMethodHandler(DBusRequest &aRequest)
130 UniqueDBusMessage reply{dbus_message_new_method_return(aRequest.GetMessage())};
132 DBusMessageIter iter;
133 std::string interfaceName;
134 std::string propertyName;
135 otError error = OT_ERROR_NONE;
137 VerifyOrExit(reply != nullptr, error = OT_ERROR_NO_BUFS);
138 VerifyOrExit(dbus_message_iter_init(aRequest.GetMessage(), &iter), error = OT_ERROR_FAILED);
139 VerifyOrExit(DBusMessageExtract(&iter, interfaceName) == OTBR_ERROR_NONE, error = OT_ERROR_PARSE);
140 VerifyOrExit(DBusMessageExtract(&iter, propertyName) == OTBR_ERROR_NONE, error = OT_ERROR_PARSE);
142 auto propertyIter = mGetPropertyHandlers.find(interfaceName);
144 otbrLog(OTBR_LOG_INFO, "GetProperty %s.%s", interfaceName.c_str(), propertyName.c_str());
145 VerifyOrExit(propertyIter != mGetPropertyHandlers.end(), error = OT_ERROR_NOT_FOUND);
147 DBusMessageIter replyIter;
148 auto & interfaceHandlers = propertyIter->second;
149 auto interfaceIter = interfaceHandlers.find(propertyName);
151 VerifyOrExit(interfaceIter != interfaceHandlers.end(), error = OT_ERROR_NOT_FOUND);
152 dbus_message_iter_init_append(reply.get(), &replyIter);
153 SuccessOrExit(error = interfaceIter->second(replyIter));
157 if (error == OT_ERROR_NONE)
159 if (otbrLogGetLevel() >= OTBR_LOG_DEBUG)
161 otbrLog(OTBR_LOG_DEBUG, "GetProperty %s.%s reply:", interfaceName.c_str(), propertyName.c_str());
162 DumpDBusMessage(*reply);
165 dbus_connection_send(aRequest.GetConnection(), reply.get(), nullptr);
169 otbrLog(OTBR_LOG_WARNING, "GetProperty %s.%s error:%s", interfaceName.c_str(), propertyName.c_str(),
170 ConvertToDBusErrorName(error));
171 aRequest.ReplyOtResult(error);
175 void DBusObject::GetAllPropertiesMethodHandler(DBusRequest &aRequest)
177 UniqueDBusMessage reply{dbus_message_new_method_return(aRequest.GetMessage())};
178 DBusMessageIter iter, subIter, dictEntryIter;
179 std::string interfaceName;
180 auto args = std::tie(interfaceName);
181 otError error = OT_ERROR_NONE;
183 VerifyOrExit(reply != nullptr, error = OT_ERROR_NO_BUFS);
184 VerifyOrExit(DBusMessageToTuple(*aRequest.GetMessage(), args) == OTBR_ERROR_NONE, error = OT_ERROR_PARSE);
185 VerifyOrExit(mGetPropertyHandlers.find(interfaceName) != mGetPropertyHandlers.end(), error = OT_ERROR_NOT_FOUND);
186 dbus_message_iter_init_append(reply.get(), &iter);
188 for (auto &p : mGetPropertyHandlers.at(interfaceName))
190 VerifyOrExit(dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
191 "{" DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING "}",
193 error = OT_ERROR_FAILED);
194 VerifyOrExit(dbus_message_iter_open_container(&subIter, DBUS_TYPE_DICT_ENTRY, nullptr, &dictEntryIter),
195 error = OT_ERROR_FAILED);
196 VerifyOrExit(DBusMessageEncode(&dictEntryIter, p.first) == OTBR_ERROR_NONE, error = OT_ERROR_FAILED);
198 SuccessOrExit(error = p.second(dictEntryIter));
200 VerifyOrExit(dbus_message_iter_close_container(&subIter, &dictEntryIter), error = OT_ERROR_FAILED);
201 VerifyOrExit(dbus_message_iter_close_container(&iter, &subIter));
205 if (error == OT_ERROR_NONE)
207 dbus_connection_send(aRequest.GetConnection(), reply.get(), nullptr);
211 aRequest.ReplyOtResult(error);
215 void DBusObject::SetPropertyMethodHandler(DBusRequest &aRequest)
217 DBusMessageIter iter;
218 std::string interfaceName;
219 std::string propertyName;
220 std::string propertyFullPath;
221 otError error = OT_ERROR_NONE;
223 VerifyOrExit(dbus_message_iter_init(aRequest.GetMessage(), &iter), error = OT_ERROR_FAILED);
224 VerifyOrExit(DBusMessageExtract(&iter, interfaceName) == OTBR_ERROR_NONE, error = OT_ERROR_PARSE);
225 VerifyOrExit(DBusMessageExtract(&iter, propertyName) == OTBR_ERROR_NONE, error = OT_ERROR_PARSE);
227 propertyFullPath = interfaceName + "." + propertyName;
228 otbrLog(OTBR_LOG_INFO, "SetProperty %s", propertyFullPath.c_str());
230 auto handlerIter = mSetPropertyHandlers.find(propertyFullPath);
232 VerifyOrExit(handlerIter != mSetPropertyHandlers.end(), error = OT_ERROR_NOT_FOUND);
233 error = handlerIter->second(iter);
237 if (error != OT_ERROR_NONE)
239 otbrLog(OTBR_LOG_WARNING, "SetProperty %s.%s error:%s", interfaceName.c_str(), propertyName.c_str(),
240 ConvertToDBusErrorName(error));
242 aRequest.ReplyOtResult(error);
246 DBusObject::~DBusObject(void)