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