xref: /aosp_15_r20/external/ot-br-posix/src/dbus/server/dbus_agent.cpp (revision 4a64e381480ef79f0532b2421e44e6ee336b8e0d)
1 /*
2  *    Copyright (c) 2020, 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 "dbus/server/dbus_agent.hpp"
32 
33 #include <chrono>
34 #include <thread>
35 #include <unistd.h>
36 
37 #include "common/logging.hpp"
38 #include "dbus/common/constants.hpp"
39 #include "dbus/server/dbus_thread_object_ncp.hpp"
40 #include "dbus/server/dbus_thread_object_rcp.hpp"
41 #include "mdns/mdns.hpp"
42 
43 namespace otbr {
44 namespace DBus {
45 
46 const struct timeval           DBusAgent::kPollTimeout = {0, 0};
47 constexpr std::chrono::seconds DBusAgent::kDBusWaitAllowance;
48 
DBusAgent(otbr::Ncp::ThreadHost & aHost,Mdns::Publisher & aPublisher)49 DBusAgent::DBusAgent(otbr::Ncp::ThreadHost &aHost, Mdns::Publisher &aPublisher)
50     : mInterfaceName(aHost.GetInterfaceName())
51     , mHost(aHost)
52     , mPublisher(aPublisher)
53 {
54 }
55 
Init(otbr::BorderAgent & aBorderAgent)56 void DBusAgent::Init(otbr::BorderAgent &aBorderAgent)
57 {
58     otbrError error = OTBR_ERROR_NONE;
59 
60     auto connection_deadline = Clock::now() + kDBusWaitAllowance;
61 
62     while ((mConnection = PrepareDBusConnection()) == nullptr && Clock::now() < connection_deadline)
63     {
64         otbrLogWarning("Failed to setup DBus connection, will retry after 1 second");
65         std::this_thread::sleep_for(std::chrono::seconds(1));
66     }
67 
68     VerifyOrDie(mConnection != nullptr, "Failed to get DBus connection");
69 
70     switch (mHost.GetCoprocessorType())
71     {
72     case OT_COPROCESSOR_RCP:
73         mThreadObject = MakeUnique<DBusThreadObjectRcp>(*mConnection, mInterfaceName,
74                                                         static_cast<Ncp::RcpHost &>(mHost), &mPublisher, aBorderAgent);
75         break;
76 
77     case OT_COPROCESSOR_NCP:
78         mThreadObject =
79             MakeUnique<DBusThreadObjectNcp>(*mConnection, mInterfaceName, static_cast<Ncp::NcpHost &>(mHost));
80         break;
81 
82     default:
83         DieNow("Unknown coprocessor type!");
84         break;
85     }
86 
87     error = mThreadObject->Init();
88     VerifyOrDie(error == OTBR_ERROR_NONE, "Failed to initialize DBus Agent");
89 }
90 
PrepareDBusConnection(void)91 DBusAgent::UniqueDBusConnection DBusAgent::PrepareDBusConnection(void)
92 {
93     DBusError            dbusError;
94     DBusConnection      *conn = nullptr;
95     UniqueDBusConnection uniqueConn;
96     int                  requestReply;
97     std::string          serverName = OTBR_DBUS_SERVER_PREFIX + mInterfaceName;
98 
99     dbus_error_init(&dbusError);
100 
101     conn = dbus_bus_get(DBUS_BUS_SYSTEM, &dbusError);
102 
103     uniqueConn = UniqueDBusConnection(conn, [](DBusConnection *aConnection) { dbus_connection_unref(aConnection); });
104 
105     VerifyOrExit(uniqueConn != nullptr,
106                  otbrLogWarning("Failed to get DBus connection: %s: %s", dbusError.name, dbusError.message));
107     dbus_bus_register(uniqueConn.get(), &dbusError);
108 
109     requestReply =
110         dbus_bus_request_name(uniqueConn.get(), serverName.c_str(), DBUS_NAME_FLAG_REPLACE_EXISTING, &dbusError);
111     VerifyOrExit(requestReply == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER ||
112                      requestReply == DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER,
113                  {
114                      otbrLogWarning("Failed to request DBus name: %s: %s", dbusError.name, dbusError.message);
115                      uniqueConn = nullptr;
116                  });
117     VerifyOrExit(
118         dbus_connection_set_watch_functions(uniqueConn.get(), AddDBusWatch, RemoveDBusWatch, nullptr, this, nullptr),
119         uniqueConn = nullptr);
120 
121 exit:
122     dbus_error_free(&dbusError);
123 
124     return uniqueConn;
125 }
126 
AddDBusWatch(struct DBusWatch * aWatch,void * aContext)127 dbus_bool_t DBusAgent::AddDBusWatch(struct DBusWatch *aWatch, void *aContext)
128 {
129     static_cast<DBusAgent *>(aContext)->mWatches.insert(aWatch);
130     return TRUE;
131 }
132 
RemoveDBusWatch(struct DBusWatch * aWatch,void * aContext)133 void DBusAgent::RemoveDBusWatch(struct DBusWatch *aWatch, void *aContext)
134 {
135     static_cast<DBusAgent *>(aContext)->mWatches.erase(aWatch);
136 }
137 
Update(MainloopContext & aMainloop)138 void DBusAgent::Update(MainloopContext &aMainloop)
139 {
140     unsigned int flags;
141     int          fd;
142     uint8_t      fdSetMask = MainloopContext::kErrorFdSet;
143 
144     if (dbus_connection_get_dispatch_status(mConnection.get()) == DBUS_DISPATCH_DATA_REMAINS)
145     {
146         aMainloop.mTimeout = {0, 0};
147     }
148 
149     for (const auto &watch : mWatches)
150     {
151         if (!dbus_watch_get_enabled(watch))
152         {
153             continue;
154         }
155 
156         flags = dbus_watch_get_flags(watch);
157         fd    = dbus_watch_get_unix_fd(watch);
158 
159         if (fd < 0)
160         {
161             continue;
162         }
163 
164         if (flags & DBUS_WATCH_READABLE)
165         {
166             fdSetMask |= MainloopContext::kReadFdSet;
167         }
168 
169         if ((flags & DBUS_WATCH_WRITABLE))
170         {
171             fdSetMask |= MainloopContext::kWriteFdSet;
172         }
173 
174         aMainloop.AddFdToSet(fd, fdSetMask);
175     }
176 }
177 
Process(const MainloopContext & aMainloop)178 void DBusAgent::Process(const MainloopContext &aMainloop)
179 {
180     unsigned int flags;
181     int          fd;
182 
183     for (const auto &watch : mWatches)
184     {
185         if (!dbus_watch_get_enabled(watch))
186         {
187             continue;
188         }
189 
190         flags = dbus_watch_get_flags(watch);
191         fd    = dbus_watch_get_unix_fd(watch);
192 
193         if (fd < 0)
194         {
195             continue;
196         }
197 
198         if ((flags & DBUS_WATCH_READABLE) && !FD_ISSET(fd, &aMainloop.mReadFdSet))
199         {
200             flags &= static_cast<unsigned int>(~DBUS_WATCH_READABLE);
201         }
202 
203         if ((flags & DBUS_WATCH_WRITABLE) && !FD_ISSET(fd, &aMainloop.mWriteFdSet))
204         {
205             flags &= static_cast<unsigned int>(~DBUS_WATCH_WRITABLE);
206         }
207 
208         if (FD_ISSET(fd, &aMainloop.mErrorFdSet))
209         {
210             flags |= DBUS_WATCH_ERROR;
211         }
212 
213         dbus_watch_handle(watch, flags);
214     }
215 
216     while (DBUS_DISPATCH_DATA_REMAINS == dbus_connection_dispatch(mConnection.get()))
217         ;
218 }
219 
220 } // namespace DBus
221 } // namespace otbr
222