• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "host/posix/dnssd.hpp"
44 #include "utils/infra_link_selector.hpp"
45 
46 namespace otbr {
47 
48 #ifndef OTBR_MAINLOOP_POLL_TIMEOUT_SEC
49 #define OTBR_MAINLOOP_POLL_TIMEOUT_SEC 10
50 #endif
51 
52 std::atomic_bool     Application::sShouldTerminate(false);
53 const struct timeval Application::kPollTimeout = {OTBR_MAINLOOP_POLL_TIMEOUT_SEC, 0};
54 
Application(Host::ThreadHost & aHost,const std::string & aInterfaceName,const std::string & aBackboneInterfaceName,const std::string & aRestListenAddress,int aRestListenPort)55 Application::Application(Host::ThreadHost  &aHost,
56                          const std::string &aInterfaceName,
57                          const std::string &aBackboneInterfaceName,
58                          const std::string &aRestListenAddress,
59                          int                aRestListenPort)
60     : mInterfaceName(aInterfaceName)
61     , mBackboneInterfaceName(aBackboneInterfaceName.c_str())
62     , mHost(aHost)
63 #if OTBR_ENABLE_MDNS
64     , mPublisher(
65           Mdns::Publisher::Create([this](Mdns::Publisher::State aState) { mMdnsStateSubject.UpdateState(aState); }))
66 #endif
67 #if OTBR_ENABLE_DNSSD_PLAT
68     , mDnssdPlatform(*mPublisher)
69 #endif
70 #if OTBR_ENABLE_DBUS_SERVER && OTBR_ENABLE_BORDER_AGENT
71     , mDBusAgent(MakeUnique<DBus::DBusAgent>(mHost, *mPublisher))
72 #endif
73 {
74     if (mHost.GetCoprocessorType() == OT_COPROCESSOR_RCP)
75     {
76         CreateRcpMode(aRestListenAddress, aRestListenPort);
77     }
78 }
79 
Init(void)80 void Application::Init(void)
81 {
82     mHost.Init();
83 
84     switch (mHost.GetCoprocessorType())
85     {
86     case OT_COPROCESSOR_RCP:
87         InitRcpMode();
88         break;
89     case OT_COPROCESSOR_NCP:
90         InitNcpMode();
91         break;
92     default:
93         DieNow("Unknown coprocessor type!");
94         break;
95     }
96 
97     otbrLogInfo("Co-processor version: %s", mHost.GetCoprocessorVersion());
98 }
99 
Deinit(void)100 void Application::Deinit(void)
101 {
102     switch (mHost.GetCoprocessorType())
103     {
104     case OT_COPROCESSOR_RCP:
105         DeinitRcpMode();
106         break;
107     case OT_COPROCESSOR_NCP:
108         DeinitNcpMode();
109         break;
110     default:
111         DieNow("Unknown coprocessor type!");
112         break;
113     }
114 
115     mHost.Deinit();
116 }
117 
Run(void)118 otbrError Application::Run(void)
119 {
120     otbrError error = OTBR_ERROR_NONE;
121 
122 #ifdef HAVE_LIBSYSTEMD
123     if (getenv("SYSTEMD_EXEC_PID") != nullptr)
124     {
125         otbrLogInfo("Notify systemd the service is ready.");
126 
127         // Ignored return value as systemd recommends.
128         // See https://www.freedesktop.org/software/systemd/man/sd_notify.html
129         sd_notify(0, "READY=1");
130     }
131 #endif
132 
133 #if OTBR_ENABLE_NOTIFY_UPSTART
134     if (getenv("UPSTART_JOB") != nullptr)
135     {
136         otbrLogInfo("Notify Upstart the service is ready.");
137         if (raise(SIGSTOP))
138         {
139             otbrLogWarning("Failed to notify Upstart.");
140         }
141     }
142 #endif
143 
144     // allow quitting elegantly
145     signal(SIGTERM, HandleSignal);
146 
147     // avoid exiting on SIGPIPE
148     signal(SIGPIPE, SIG_IGN);
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 (mErrorCondition)
172             {
173                 error = mErrorCondition();
174                 if (error != OTBR_ERROR_NONE)
175                 {
176                     break;
177                 }
178             }
179         }
180         else if (errno != EINTR)
181         {
182             error = OTBR_ERROR_ERRNO;
183             otbrLogErr("select() failed: %s", strerror(errno));
184             break;
185         }
186     }
187 
188     return error;
189 }
190 
HandleSignal(int aSignal)191 void Application::HandleSignal(int aSignal)
192 {
193     sShouldTerminate = true;
194     signal(aSignal, SIG_DFL);
195 }
196 
CreateRcpMode(const std::string & aRestListenAddress,int aRestListenPort)197 void Application::CreateRcpMode(const std::string &aRestListenAddress, int aRestListenPort)
198 {
199     otbr::Host::RcpHost &rcpHost = static_cast<otbr::Host::RcpHost &>(mHost);
200 #if OTBR_ENABLE_BORDER_AGENT
201     mBorderAgent = MakeUnique<BorderAgent>(rcpHost, *mPublisher);
202 #endif
203 #if OTBR_ENABLE_BACKBONE_ROUTER
204     mBackboneAgent = MakeUnique<BackboneRouter::BackboneAgent>(rcpHost, mInterfaceName, mBackboneInterfaceName);
205 #endif
206 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
207     mAdvertisingProxy = MakeUnique<AdvertisingProxy>(rcpHost, *mPublisher);
208 #endif
209 #if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY
210     mDiscoveryProxy = MakeUnique<Dnssd::DiscoveryProxy>(rcpHost, *mPublisher);
211 #endif
212 #if OTBR_ENABLE_TREL
213     mTrelDnssd = MakeUnique<TrelDnssd::TrelDnssd>(rcpHost, *mPublisher);
214 #endif
215 #if OTBR_ENABLE_OPENWRT
216     mUbusAgent = MakeUnique<ubus::UBusAgent>(rcpHost);
217 #endif
218 #if OTBR_ENABLE_REST_SERVER
219     mRestWebServer = MakeUnique<rest::RestWebServer>(rcpHost, aRestListenAddress, aRestListenPort);
220 #endif
221 #if OTBR_ENABLE_VENDOR_SERVER
222     mVendorServer = vendor::VendorServer::newInstance(*this);
223 #endif
224 
225     OT_UNUSED_VARIABLE(aRestListenAddress);
226     OT_UNUSED_VARIABLE(aRestListenPort);
227 }
228 
InitRcpMode(void)229 void Application::InitRcpMode(void)
230 {
231     Host::RcpHost &rcpHost = static_cast<otbr::Host::RcpHost &>(mHost);
232     OTBR_UNUSED_VARIABLE(rcpHost);
233 
234 #if OTBR_ENABLE_BORDER_AGENT
235     mMdnsStateSubject.AddObserver(*mBorderAgent);
236 #endif
237 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
238     mMdnsStateSubject.AddObserver(*mAdvertisingProxy);
239 #endif
240 #if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY
241     mMdnsStateSubject.AddObserver(*mDiscoveryProxy);
242 #endif
243 #if OTBR_ENABLE_TREL
244     mMdnsStateSubject.AddObserver(*mTrelDnssd);
245 #endif
246 #if OTBR_ENABLE_DNSSD_PLAT
247     mMdnsStateSubject.AddObserver(mDnssdPlatform);
248     mDnssdPlatform.SetDnssdStateChangedCallback(([&rcpHost](otPlatDnssdState aState) {
249         OTBR_UNUSED_VARIABLE(aState);
250         otPlatDnssdStateHandleStateChange(rcpHost.GetInstance());
251     }));
252 #endif
253 
254 #if OTBR_ENABLE_MDNS
255     mPublisher->Start();
256 #endif
257 #if OTBR_ENABLE_BORDER_AGENT
258     mBorderAgent->Init();
259 // This is for delaying publishing the MeshCoP service until the correct
260 // vendor name and OUI etc. are correctly set by BorderAgent::SetMeshCopServiceValues()
261 #if OTBR_STOP_BORDER_AGENT_ON_INIT
262     mBorderAgent->SetEnabled(false);
263 #else
264     mBorderAgent->SetEnabled(true);
265 #endif
266 #endif
267 #if OTBR_ENABLE_BACKBONE_ROUTER
268     mBackboneAgent->Init();
269 #endif
270 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
271     mAdvertisingProxy->SetEnabled(true);
272 #endif
273 #if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY
274     mDiscoveryProxy->SetEnabled(true);
275 #endif
276 #if OTBR_ENABLE_OPENWRT
277     mUbusAgent->Init();
278 #endif
279 #if OTBR_ENABLE_REST_SERVER
280     mRestWebServer->Init();
281 #endif
282 #if OTBR_ENABLE_DBUS_SERVER
283     mDBusAgent->Init(*mBorderAgent);
284 #endif
285 #if OTBR_ENABLE_VENDOR_SERVER
286     mVendorServer->Init();
287 #endif
288 #if OTBR_ENABLE_DNSSD_PLAT
289     mDnssdPlatform.Start();
290 #endif
291 }
292 
DeinitRcpMode(void)293 void Application::DeinitRcpMode(void)
294 {
295 #if OTBR_ENABLE_DNSSD_PLAT
296     mDnssdPlatform.Stop();
297 #endif
298 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
299     mAdvertisingProxy->SetEnabled(false);
300 #endif
301 #if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY
302     mDiscoveryProxy->SetEnabled(false);
303 #endif
304 #if OTBR_ENABLE_BORDER_AGENT
305     mBorderAgent->SetEnabled(false);
306     mBorderAgent->Deinit();
307 #endif
308 #if OTBR_ENABLE_MDNS
309     mMdnsStateSubject.Clear();
310     mPublisher->Stop();
311 #endif
312 }
313 
InitNcpMode(void)314 void Application::InitNcpMode(void)
315 {
316 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
317     otbr::Host::NcpHost &ncpHost = static_cast<otbr::Host::NcpHost &>(mHost);
318     ncpHost.SetMdnsPublisher(mPublisher.get());
319     mMdnsStateSubject.AddObserver(ncpHost);
320     mPublisher->Start();
321 #endif
322 #if OTBR_ENABLE_DBUS_SERVER
323     mDBusAgent->Init(*mBorderAgent);
324 #endif
325 }
326 
DeinitNcpMode(void)327 void Application::DeinitNcpMode(void)
328 {
329 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
330     mPublisher->Stop();
331 #endif
332 }
333 
334 } // namespace otbr
335