xref: /aosp_15_r20/external/ot-br-posix/src/agent/application.cpp (revision 4a64e381480ef79f0532b2421e44e6ee336b8e0d)
1 /*
2  *    Copyright (c) 2021, 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 /**
30  * @file
31  *   The file implements the OTBR Agent.
32  */
33 
34 #define OTBR_LOG_TAG "APP"
35 
36 #ifdef HAVE_LIBSYSTEMD
37 #include <systemd/sd-daemon.h>
38 #endif
39 
40 #include "agent/application.hpp"
41 #include "common/code_utils.hpp"
42 #include "common/mainloop_manager.hpp"
43 #include "utils/infra_link_selector.hpp"
44 
45 namespace otbr {
46 
47 std::atomic_bool     Application::sShouldTerminate(false);
48 const struct timeval Application::kPollTimeout = {10, 0};
49 
Application(const std::string & aInterfaceName,const std::vector<const char * > & aBackboneInterfaceNames,const std::vector<const char * > & aRadioUrls,bool aEnableAutoAttach,const std::string & aRestListenAddress,int aRestListenPort)50 Application::Application(const std::string               &aInterfaceName,
51                          const std::vector<const char *> &aBackboneInterfaceNames,
52                          const std::vector<const char *> &aRadioUrls,
53                          bool                             aEnableAutoAttach,
54                          const std::string               &aRestListenAddress,
55                          int                              aRestListenPort)
56     : mInterfaceName(aInterfaceName)
57 #if __linux__
58     , mInfraLinkSelector(aBackboneInterfaceNames)
59     , mBackboneInterfaceName(mInfraLinkSelector.Select())
60 #else
61     , mBackboneInterfaceName(aBackboneInterfaceNames.empty() ? "" : aBackboneInterfaceNames.front())
62 #endif
63     , mHost(Ncp::ThreadHost::Create(mInterfaceName.c_str(),
64                                     aRadioUrls,
65                                     mBackboneInterfaceName,
66                                     /* aDryRun */ false,
67                                     aEnableAutoAttach))
68 #if OTBR_ENABLE_MDNS
69     , mPublisher(Mdns::Publisher::Create([this](Mdns::Publisher::State aState) { this->HandleMdnsState(aState); }))
70 #endif
71 #if OTBR_ENABLE_DBUS_SERVER && OTBR_ENABLE_BORDER_AGENT
72     , mDBusAgent(MakeUnique<DBus::DBusAgent>(*mHost, *mPublisher))
73 #endif
74 {
75     if (mHost->GetCoprocessorType() == OT_COPROCESSOR_RCP)
76     {
77         CreateRcpMode(aRestListenAddress, aRestListenPort);
78     }
79 }
80 
Init(void)81 void Application::Init(void)
82 {
83     mHost->Init();
84 
85     switch (mHost->GetCoprocessorType())
86     {
87     case OT_COPROCESSOR_RCP:
88         InitRcpMode();
89         break;
90     case OT_COPROCESSOR_NCP:
91         InitNcpMode();
92         break;
93     default:
94         DieNow("Unknown coprocessor type!");
95         break;
96     }
97 
98     otbrLogInfo("Co-processor version: %s", mHost->GetCoprocessorVersion());
99 }
100 
Deinit(void)101 void Application::Deinit(void)
102 {
103     switch (mHost->GetCoprocessorType())
104     {
105     case OT_COPROCESSOR_RCP:
106         DeinitRcpMode();
107         break;
108     case OT_COPROCESSOR_NCP:
109         DeinitNcpMode();
110         break;
111     default:
112         DieNow("Unknown coprocessor type!");
113         break;
114     }
115 
116     mHost->Deinit();
117 }
118 
Run(void)119 otbrError Application::Run(void)
120 {
121     otbrError error = OTBR_ERROR_NONE;
122 
123     otbrLogInfo("Thread Border Router started on AIL %s.", mBackboneInterfaceName);
124 
125 #ifdef HAVE_LIBSYSTEMD
126     if (getenv("SYSTEMD_EXEC_PID") != nullptr)
127     {
128         otbrLogInfo("Notify systemd the service is ready.");
129 
130         // Ignored return value as systemd recommends.
131         // See https://www.freedesktop.org/software/systemd/man/sd_notify.html
132         sd_notify(0, "READY=1");
133     }
134 #endif
135 
136 #if OTBR_ENABLE_NOTIFY_UPSTART
137     if (getenv("UPSTART_JOB") != nullptr)
138     {
139         otbrLogInfo("Notify Upstart the service is ready.");
140         if (raise(SIGSTOP))
141         {
142             otbrLogWarning("Failed to notify Upstart.");
143         }
144     }
145 #endif
146 
147     // allow quitting elegantly
148     signal(SIGTERM, HandleSignal);
149 
150     while (!sShouldTerminate)
151     {
152         otbr::MainloopContext mainloop;
153         int                   rval;
154 
155         mainloop.mMaxFd   = -1;
156         mainloop.mTimeout = kPollTimeout;
157 
158         FD_ZERO(&mainloop.mReadFdSet);
159         FD_ZERO(&mainloop.mWriteFdSet);
160         FD_ZERO(&mainloop.mErrorFdSet);
161 
162         MainloopManager::GetInstance().Update(mainloop);
163 
164         rval = select(mainloop.mMaxFd + 1, &mainloop.mReadFdSet, &mainloop.mWriteFdSet, &mainloop.mErrorFdSet,
165                       &mainloop.mTimeout);
166 
167         if (rval >= 0)
168         {
169             MainloopManager::GetInstance().Process(mainloop);
170 
171 #if __linux__
172             {
173                 const char *newInfraLink = mInfraLinkSelector.Select();
174 
175                 if (mBackboneInterfaceName != newInfraLink)
176                 {
177                     error = OTBR_ERROR_INFRA_LINK_CHANGED;
178                     break;
179                 }
180             }
181 #endif
182         }
183         else if (errno != EINTR)
184         {
185             error = OTBR_ERROR_ERRNO;
186             otbrLogErr("select() failed: %s", strerror(errno));
187             break;
188         }
189     }
190 
191     return error;
192 }
193 
HandleMdnsState(Mdns::Publisher::State aState)194 void Application::HandleMdnsState(Mdns::Publisher::State aState)
195 {
196     OTBR_UNUSED_VARIABLE(aState);
197 
198 #if OTBR_ENABLE_BORDER_AGENT
199     mBorderAgent->HandleMdnsState(aState);
200 #endif
201 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
202     mAdvertisingProxy->HandleMdnsState(aState);
203 #endif
204 #if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY
205     mDiscoveryProxy->HandleMdnsState(aState);
206 #endif
207 #if OTBR_ENABLE_TREL
208     mTrelDnssd->HandleMdnsState(aState);
209 #endif
210 }
211 
HandleSignal(int aSignal)212 void Application::HandleSignal(int aSignal)
213 {
214     sShouldTerminate = true;
215     signal(aSignal, SIG_DFL);
216 }
217 
CreateRcpMode(const std::string & aRestListenAddress,int aRestListenPort)218 void Application::CreateRcpMode(const std::string &aRestListenAddress, int aRestListenPort)
219 {
220     otbr::Ncp::RcpHost &rcpHost = static_cast<otbr::Ncp::RcpHost &>(*mHost);
221 #if OTBR_ENABLE_BORDER_AGENT
222     mBorderAgent = MakeUnique<BorderAgent>(rcpHost, *mPublisher);
223 #endif
224 #if OTBR_ENABLE_BACKBONE_ROUTER
225     mBackboneAgent = MakeUnique<BackboneRouter::BackboneAgent>(rcpHost, mInterfaceName, mBackboneInterfaceName);
226 #endif
227 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
228     mAdvertisingProxy = MakeUnique<AdvertisingProxy>(rcpHost, *mPublisher);
229 #endif
230 #if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY
231     mDiscoveryProxy = MakeUnique<Dnssd::DiscoveryProxy>(rcpHost, *mPublisher);
232 #endif
233 #if OTBR_ENABLE_TREL
234     mTrelDnssd = MakeUnique<TrelDnssd::TrelDnssd>(rcpHost, *mPublisher);
235 #endif
236 #if OTBR_ENABLE_OPENWRT
237     mUbusAgent = MakeUnique<ubus::UBusAgent>(rcpHost);
238 #endif
239 #if OTBR_ENABLE_REST_SERVER
240     mRestWebServer = MakeUnique<rest::RestWebServer>(rcpHost, aRestListenAddress, aRestListenPort);
241 #endif
242 #if OTBR_ENABLE_VENDOR_SERVER
243     mVendorServer = vendor::VendorServer::newInstance(*this);
244 #endif
245 
246     OT_UNUSED_VARIABLE(aRestListenAddress);
247     OT_UNUSED_VARIABLE(aRestListenPort);
248 }
249 
InitRcpMode(void)250 void Application::InitRcpMode(void)
251 {
252 #if OTBR_ENABLE_MDNS
253     mPublisher->Start();
254 #endif
255 #if OTBR_ENABLE_BORDER_AGENT
256 // This is for delaying publishing the MeshCoP service until the correct
257 // vendor name and OUI etc. are correctly set by BorderAgent::SetMeshCopServiceValues()
258 #if OTBR_STOP_BORDER_AGENT_ON_INIT
259     mBorderAgent->SetEnabled(false);
260 #else
261     mBorderAgent->SetEnabled(true);
262 #endif
263 #endif
264 #if OTBR_ENABLE_BACKBONE_ROUTER
265     mBackboneAgent->Init();
266 #endif
267 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
268     mAdvertisingProxy->SetEnabled(true);
269 #endif
270 #if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY
271     mDiscoveryProxy->SetEnabled(true);
272 #endif
273 #if OTBR_ENABLE_OPENWRT
274     mUbusAgent->Init();
275 #endif
276 #if OTBR_ENABLE_REST_SERVER
277     mRestWebServer->Init();
278 #endif
279 #if OTBR_ENABLE_DBUS_SERVER
280     mDBusAgent->Init(*mBorderAgent);
281 #endif
282 #if OTBR_ENABLE_VENDOR_SERVER
283     mVendorServer->Init();
284 #endif
285 }
286 
DeinitRcpMode(void)287 void Application::DeinitRcpMode(void)
288 {
289 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
290     mAdvertisingProxy->SetEnabled(false);
291 #endif
292 #if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY
293     mDiscoveryProxy->SetEnabled(false);
294 #endif
295 #if OTBR_ENABLE_BORDER_AGENT
296     mBorderAgent->SetEnabled(false);
297 #endif
298 #if OTBR_ENABLE_MDNS
299     mPublisher->Stop();
300 #endif
301 }
302 
InitNcpMode(void)303 void Application::InitNcpMode(void)
304 {
305 #if OTBR_ENABLE_DBUS_SERVER
306     mDBusAgent->Init(*mBorderAgent);
307 #endif
308 }
309 
DeinitNcpMode(void)310 void Application::DeinitNcpMode(void)
311 {
312     /* empty */
313 }
314 
315 } // namespace otbr
316