| /* |
| * Copyright (c) 2021, The OpenThread Authors. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. Neither the name of the copyright holder nor the |
| * names of its contributors may be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| /** |
| * @file |
| * The file implements the OTBR Agent. |
| */ |
| |
| #define OTBR_LOG_TAG "APP" |
| |
| #ifdef HAVE_LIBSYSTEMD |
| #include <systemd/sd-daemon.h> |
| #endif |
| |
| #include "agent/application.hpp" |
| #include "common/code_utils.hpp" |
| #include "common/mainloop_manager.hpp" |
| #include "utils/infra_link_selector.hpp" |
| |
| namespace otbr { |
| |
| std::atomic_bool Application::sShouldTerminate(false); |
| const struct timeval Application::kPollTimeout = {10, 0}; |
| |
| Application::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) |
| : mInterfaceName(aInterfaceName) |
| #if __linux__ |
| , mInfraLinkSelector(aBackboneInterfaceNames) |
| , mBackboneInterfaceName(mInfraLinkSelector.Select()) |
| #else |
| , mBackboneInterfaceName(aBackboneInterfaceNames.empty() ? "" : aBackboneInterfaceNames.front()) |
| #endif |
| , mNcp(mInterfaceName.c_str(), aRadioUrls, mBackboneInterfaceName, /* aDryRun */ false, aEnableAutoAttach) |
| #if OTBR_ENABLE_BORDER_AGENT |
| , mBorderAgent(mNcp) |
| #endif |
| #if OTBR_ENABLE_BACKBONE_ROUTER |
| , mBackboneAgent(mNcp, aInterfaceName, mBackboneInterfaceName) |
| #endif |
| #if OTBR_ENABLE_OPENWRT |
| , mUbusAgent(mNcp) |
| #endif |
| #if OTBR_ENABLE_REST_SERVER |
| , mRestWebServer(mNcp, aRestListenAddress, aRestListenPort) |
| #endif |
| #if OTBR_ENABLE_DBUS_SERVER && OTBR_ENABLE_BORDER_AGENT |
| , mDBusAgent(mNcp, mBorderAgent.GetPublisher()) |
| #endif |
| #if OTBR_ENABLE_ANDROID_OTDAEMON_SERVER |
| , mOtDaemonServer(ndk::SharedRefBase::make<Android::OtDaemonServer>()) |
| #endif |
| { |
| OTBR_UNUSED_VARIABLE(aRestListenAddress); |
| OTBR_UNUSED_VARIABLE(aRestListenPort); |
| } |
| |
| void Application::Init(void) |
| { |
| mNcp.Init(); |
| |
| #if OTBR_ENABLE_BORDER_AGENT |
| mBorderAgent.Init(); |
| #endif |
| #if OTBR_ENABLE_BACKBONE_ROUTER |
| mBackboneAgent.Init(); |
| #endif |
| #if OTBR_ENABLE_OPENWRT |
| mUbusAgent.Init(); |
| #endif |
| #if OTBR_ENABLE_REST_SERVER |
| mRestWebServer.Init(); |
| #endif |
| #if OTBR_ENABLE_DBUS_SERVER |
| mDBusAgent.Init(); |
| #endif |
| #if OTBR_ENABLE_ANDROID_OTDAEMON_SERVER |
| mOtDaemonServer->InitOrDie(&mNcp); |
| #endif |
| } |
| |
| void Application::Deinit(void) |
| { |
| #if OTBR_ENABLE_BORDER_AGENT |
| mBorderAgent.Deinit(); |
| #endif |
| |
| mNcp.Deinit(); |
| } |
| |
| otbrError Application::Run(void) |
| { |
| otbrError error = OTBR_ERROR_NONE; |
| |
| otbrLogInfo("Thread Border Router started on AIL %s.", mBackboneInterfaceName); |
| |
| #ifdef HAVE_LIBSYSTEMD |
| if (getenv("SYSTEMD_EXEC_PID") != nullptr) |
| { |
| otbrLogInfo("Notify systemd the service is ready."); |
| |
| // Ignored return value as systemd recommends. |
| // See https://www.freedesktop.org/software/systemd/man/sd_notify.html |
| sd_notify(0, "READY=1"); |
| } |
| #endif |
| |
| #if OTBR_ENABLE_NOTIFY_UPSTART |
| if (getenv("UPSTART_JOB") != nullptr) |
| { |
| otbrLogInfo("Notify Upstart the service is ready."); |
| if (raise(SIGSTOP)) |
| { |
| otbrLogWarning("Failed to notify Upstart."); |
| } |
| } |
| #endif |
| |
| // allow quitting elegantly |
| signal(SIGTERM, HandleSignal); |
| |
| while (!sShouldTerminate) |
| { |
| otbr::MainloopContext mainloop; |
| int rval; |
| |
| mainloop.mMaxFd = -1; |
| mainloop.mTimeout = kPollTimeout; |
| |
| FD_ZERO(&mainloop.mReadFdSet); |
| FD_ZERO(&mainloop.mWriteFdSet); |
| FD_ZERO(&mainloop.mErrorFdSet); |
| |
| MainloopManager::GetInstance().Update(mainloop); |
| |
| rval = select(mainloop.mMaxFd + 1, &mainloop.mReadFdSet, &mainloop.mWriteFdSet, &mainloop.mErrorFdSet, |
| &mainloop.mTimeout); |
| |
| if (rval >= 0) |
| { |
| MainloopManager::GetInstance().Process(mainloop); |
| |
| #if __linux__ |
| { |
| const char *newInfraLink = mInfraLinkSelector.Select(); |
| |
| if (mBackboneInterfaceName != newInfraLink) |
| { |
| error = OTBR_ERROR_INFRA_LINK_CHANGED; |
| break; |
| } |
| } |
| #endif |
| } |
| else if (errno != EINTR) |
| { |
| error = OTBR_ERROR_ERRNO; |
| otbrLogErr("select() failed: %s", strerror(errno)); |
| break; |
| } |
| } |
| |
| return error; |
| } |
| |
| void Application::HandleSignal(int aSignal) |
| { |
| sShouldTerminate = true; |
| signal(aSignal, SIG_DFL); |
| } |
| |
| } // namespace otbr |