• 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 "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     , mNcp(mInterfaceName.c_str(), aRadioUrls, mBackboneInterfaceName, /* aDryRun */ false, aEnableAutoAttach)
64 #if OTBR_ENABLE_MDNS
65     , mPublisher(Mdns::Publisher::Create([this](Mdns::Publisher::State aState) { this->HandleMdnsState(aState); }))
66 #endif
67 #if OTBR_ENABLE_BORDER_AGENT
68     , mBorderAgent(mNcp, *mPublisher)
69 #endif
70 #if OTBR_ENABLE_BACKBONE_ROUTER
71     , mBackboneAgent(mNcp, aInterfaceName, mBackboneInterfaceName)
72 #endif
73 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
74     , mAdvertisingProxy(mNcp, *mPublisher)
75 #endif
76 #if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY
77     , mDiscoveryProxy(mNcp, *mPublisher)
78 #endif
79 #if OTBR_ENABLE_TREL
80     , mTrelDnssd(mNcp, *mPublisher)
81 #endif
82 #if OTBR_ENABLE_OPENWRT
83     , mUbusAgent(mNcp)
84 #endif
85 #if OTBR_ENABLE_REST_SERVER
86     , mRestWebServer(mNcp, aRestListenAddress, aRestListenPort)
87 #endif
88 #if OTBR_ENABLE_DBUS_SERVER && OTBR_ENABLE_BORDER_AGENT
89     , mDBusAgent(mNcp, *mPublisher)
90 #endif
91 #if OTBR_ENABLE_VENDOR_SERVER
92     , mVendorServer(vendor::VendorServer::newInstance(*this))
93 #endif
94 {
95     OTBR_UNUSED_VARIABLE(aRestListenAddress);
96     OTBR_UNUSED_VARIABLE(aRestListenPort);
97 }
98 
Init(void)99 void Application::Init(void)
100 {
101     mNcp.Init();
102 
103 #if OTBR_ENABLE_MDNS
104     mPublisher->Start();
105 #endif
106 #if OTBR_ENABLE_BORDER_AGENT
107 // This is for delaying publishing the MeshCoP service until the correct
108 // vendor name and OUI etc. are correctly set by BorderAgent::SetMeshCopServiceValues()
109 #if OTBR_STOP_BORDER_AGENT_ON_INIT
110     mBorderAgent.SetEnabled(false);
111 #else
112     mBorderAgent.SetEnabled(true);
113 #endif
114 #endif
115 #if OTBR_ENABLE_BACKBONE_ROUTER
116     mBackboneAgent.Init();
117 #endif
118 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
119     mAdvertisingProxy.SetEnabled(true);
120 #endif
121 #if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY
122     mDiscoveryProxy.SetEnabled(true);
123 #endif
124 #if OTBR_ENABLE_OPENWRT
125     mUbusAgent.Init();
126 #endif
127 #if OTBR_ENABLE_REST_SERVER
128     mRestWebServer.Init();
129 #endif
130 #if OTBR_ENABLE_DBUS_SERVER
131     mDBusAgent.Init();
132 #endif
133 #if OTBR_ENABLE_VENDOR_SERVER
134     mVendorServer->Init();
135 #endif
136 }
137 
Deinit(void)138 void Application::Deinit(void)
139 {
140 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
141     mAdvertisingProxy.SetEnabled(false);
142 #endif
143 #if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY
144     mDiscoveryProxy.SetEnabled(false);
145 #endif
146 #if OTBR_ENABLE_BORDER_AGENT
147     mBorderAgent.SetEnabled(false);
148 #endif
149 #if OTBR_ENABLE_MDNS
150     mPublisher->Stop();
151 #endif
152 
153     mNcp.Deinit();
154 }
155 
Run(void)156 otbrError Application::Run(void)
157 {
158     otbrError error = OTBR_ERROR_NONE;
159 
160     otbrLogInfo("Thread Border Router started on AIL %s.", mBackboneInterfaceName);
161 
162 #ifdef HAVE_LIBSYSTEMD
163     if (getenv("SYSTEMD_EXEC_PID") != nullptr)
164     {
165         otbrLogInfo("Notify systemd the service is ready.");
166 
167         // Ignored return value as systemd recommends.
168         // See https://www.freedesktop.org/software/systemd/man/sd_notify.html
169         sd_notify(0, "READY=1");
170     }
171 #endif
172 
173 #if OTBR_ENABLE_NOTIFY_UPSTART
174     if (getenv("UPSTART_JOB") != nullptr)
175     {
176         otbrLogInfo("Notify Upstart the service is ready.");
177         if (raise(SIGSTOP))
178         {
179             otbrLogWarning("Failed to notify Upstart.");
180         }
181     }
182 #endif
183 
184     // allow quitting elegantly
185     signal(SIGTERM, HandleSignal);
186 
187     while (!sShouldTerminate)
188     {
189         otbr::MainloopContext mainloop;
190         int                   rval;
191 
192         mainloop.mMaxFd   = -1;
193         mainloop.mTimeout = kPollTimeout;
194 
195         FD_ZERO(&mainloop.mReadFdSet);
196         FD_ZERO(&mainloop.mWriteFdSet);
197         FD_ZERO(&mainloop.mErrorFdSet);
198 
199         MainloopManager::GetInstance().Update(mainloop);
200 
201         rval = select(mainloop.mMaxFd + 1, &mainloop.mReadFdSet, &mainloop.mWriteFdSet, &mainloop.mErrorFdSet,
202                       &mainloop.mTimeout);
203 
204         if (rval >= 0)
205         {
206             MainloopManager::GetInstance().Process(mainloop);
207 
208 #if __linux__
209             {
210                 const char *newInfraLink = mInfraLinkSelector.Select();
211 
212                 if (mBackboneInterfaceName != newInfraLink)
213                 {
214                     error = OTBR_ERROR_INFRA_LINK_CHANGED;
215                     break;
216                 }
217             }
218 #endif
219         }
220         else if (errno != EINTR)
221         {
222             error = OTBR_ERROR_ERRNO;
223             otbrLogErr("select() failed: %s", strerror(errno));
224             break;
225         }
226     }
227 
228     return error;
229 }
230 
HandleMdnsState(Mdns::Publisher::State aState)231 void Application::HandleMdnsState(Mdns::Publisher::State aState)
232 {
233     OTBR_UNUSED_VARIABLE(aState);
234 
235 #if OTBR_ENABLE_BORDER_AGENT
236     mBorderAgent.HandleMdnsState(aState);
237 #endif
238 #if OTBR_ENABLE_SRP_ADVERTISING_PROXY
239     mAdvertisingProxy.HandleMdnsState(aState);
240 #endif
241 #if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY
242     mDiscoveryProxy.HandleMdnsState(aState);
243 #endif
244 #if OTBR_ENABLE_TREL
245     mTrelDnssd.HandleMdnsState(aState);
246 #endif
247 }
248 
HandleSignal(int aSignal)249 void Application::HandleSignal(int aSignal)
250 {
251     sShouldTerminate = true;
252     signal(aSignal, SIG_DFL);
253 }
254 
255 } // namespace otbr
256