• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "mdns/mdns.hpp"
40 
41 namespace otbr {
42 namespace DBus {
43 
44 const struct timeval           DBusAgent::kPollTimeout = {0, 0};
45 constexpr std::chrono::seconds DBusAgent::kDBusWaitAllowance;
46 
DBusAgent(otbr::Ncp::ControllerOpenThread & aNcp,Mdns::Publisher & aPublisher)47 DBusAgent::DBusAgent(otbr::Ncp::ControllerOpenThread &aNcp, Mdns::Publisher &aPublisher)
48     : mInterfaceName(aNcp.GetInterfaceName())
49     , mNcp(aNcp)
50     , mPublisher(aPublisher)
51 {
52 }
53 
Init(void)54 void DBusAgent::Init(void)
55 {
56     otbrError error = OTBR_ERROR_NONE;
57 
58     auto connection_deadline = Clock::now() + kDBusWaitAllowance;
59 
60     while ((mConnection = PrepareDBusConnection()) == nullptr && Clock::now() < connection_deadline)
61     {
62         otbrLogWarning("Failed to setup DBus connection, will retry after 1 second");
63         std::this_thread::sleep_for(std::chrono::seconds(1));
64     }
65 
66     VerifyOrDie(mConnection != nullptr, "Failed to get DBus connection");
67 
68     mThreadObject =
69         std::unique_ptr<DBusThreadObject>(new DBusThreadObject(mConnection.get(), mInterfaceName, &mNcp, &mPublisher));
70     error = mThreadObject->Init();
71     VerifyOrDie(error == OTBR_ERROR_NONE, "Failed to initialize DBus Agent");
72 }
73 
PrepareDBusConnection(void)74 DBusAgent::UniqueDBusConnection DBusAgent::PrepareDBusConnection(void)
75 {
76     DBusError            dbusError;
77     DBusConnection *     conn = nullptr;
78     UniqueDBusConnection uniqueConn;
79     int                  requestReply;
80     std::string          serverName = OTBR_DBUS_SERVER_PREFIX + mInterfaceName;
81 
82     dbus_error_init(&dbusError);
83 
84     conn = dbus_bus_get(DBUS_BUS_SYSTEM, &dbusError);
85 
86     uniqueConn = UniqueDBusConnection(conn, [](DBusConnection *aConnection) { dbus_connection_unref(aConnection); });
87 
88     VerifyOrExit(uniqueConn != nullptr,
89                  otbrLogWarning("Failed to get DBus connection: %s: %s", dbusError.name, dbusError.message));
90     dbus_bus_register(uniqueConn.get(), &dbusError);
91 
92     requestReply =
93         dbus_bus_request_name(uniqueConn.get(), serverName.c_str(), DBUS_NAME_FLAG_REPLACE_EXISTING, &dbusError);
94     VerifyOrExit(requestReply == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER ||
95                      requestReply == DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER,
96                  {
97                      otbrLogWarning("Failed to request DBus name: %s: %s", dbusError.name, dbusError.message);
98                      uniqueConn = nullptr;
99                  });
100     VerifyOrExit(
101         dbus_connection_set_watch_functions(uniqueConn.get(), AddDBusWatch, RemoveDBusWatch, nullptr, this, nullptr),
102         uniqueConn = nullptr);
103 
104 exit:
105     dbus_error_free(&dbusError);
106 
107     return uniqueConn;
108 }
109 
AddDBusWatch(struct DBusWatch * aWatch,void * aContext)110 dbus_bool_t DBusAgent::AddDBusWatch(struct DBusWatch *aWatch, void *aContext)
111 {
112     static_cast<DBusAgent *>(aContext)->mWatches.insert(aWatch);
113     return TRUE;
114 }
115 
RemoveDBusWatch(struct DBusWatch * aWatch,void * aContext)116 void DBusAgent::RemoveDBusWatch(struct DBusWatch *aWatch, void *aContext)
117 {
118     static_cast<DBusAgent *>(aContext)->mWatches.erase(aWatch);
119 }
120 
Update(MainloopContext & aMainloop)121 void DBusAgent::Update(MainloopContext &aMainloop)
122 {
123     unsigned int flags;
124     int          fd;
125 
126     if (dbus_connection_get_dispatch_status(mConnection.get()) == DBUS_DISPATCH_DATA_REMAINS)
127     {
128         aMainloop.mTimeout = {0, 0};
129     }
130 
131     for (const auto &watch : mWatches)
132     {
133         if (!dbus_watch_get_enabled(watch))
134         {
135             continue;
136         }
137 
138         flags = dbus_watch_get_flags(watch);
139         fd    = dbus_watch_get_unix_fd(watch);
140 
141         if (fd < 0)
142         {
143             continue;
144         }
145 
146         if (flags & DBUS_WATCH_READABLE)
147         {
148             FD_SET(fd, &aMainloop.mReadFdSet);
149         }
150 
151         if ((flags & DBUS_WATCH_WRITABLE))
152         {
153             FD_SET(fd, &aMainloop.mWriteFdSet);
154         }
155 
156         FD_SET(fd, &aMainloop.mErrorFdSet);
157 
158         aMainloop.mMaxFd = std::max(aMainloop.mMaxFd, fd);
159     }
160 }
161 
Process(const MainloopContext & aMainloop)162 void DBusAgent::Process(const MainloopContext &aMainloop)
163 {
164     unsigned int flags;
165     int          fd;
166 
167     for (const auto &watch : mWatches)
168     {
169         if (!dbus_watch_get_enabled(watch))
170         {
171             continue;
172         }
173 
174         flags = dbus_watch_get_flags(watch);
175         fd    = dbus_watch_get_unix_fd(watch);
176 
177         if (fd < 0)
178         {
179             continue;
180         }
181 
182         if ((flags & DBUS_WATCH_READABLE) && !FD_ISSET(fd, &aMainloop.mReadFdSet))
183         {
184             flags &= static_cast<unsigned int>(~DBUS_WATCH_READABLE);
185         }
186 
187         if ((flags & DBUS_WATCH_WRITABLE) && !FD_ISSET(fd, &aMainloop.mWriteFdSet))
188         {
189             flags &= static_cast<unsigned int>(~DBUS_WATCH_WRITABLE);
190         }
191 
192         if (FD_ISSET(fd, &aMainloop.mErrorFdSet))
193         {
194             flags |= DBUS_WATCH_ERROR;
195         }
196 
197         dbus_watch_handle(watch, flags);
198     }
199 
200     while (DBUS_DISPATCH_DATA_REMAINS == dbus_connection_dispatch(mConnection.get()))
201         ;
202 }
203 
204 } // namespace DBus
205 } // namespace otbr
206