Skip to content

Commit

Permalink
[application] refactor to decouple Application with InfraLinkSelector (
Browse files Browse the repository at this point in the history
…#2574)

This commit refactors the `Application` class.

In specific:
1. Decouple `Application` with `InfraLinkSelector` by moving
   `InfraLinkSelector` out of the `Application` class. The current
   dependency causes that we cannot move the creation of `ThreadHost`
   instance out of the constructor of the `Application` class.
2. Move `Ncp::ThreadHost::Create` out of the `Application`
   constructor.

This change solves the fuzzer test issue in Android: When we create an
`Application` object, we have to initlialize the radio which will
cause error in the fuzz environment. With this change, we can pass a
FuzzThreadHost object to the `Application`.
  • Loading branch information
Irving-cl authored Nov 6, 2024
1 parent 7a79c99 commit 10756a6
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 50 deletions.
51 changes: 18 additions & 33 deletions src/agent/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,43 +51,33 @@ namespace otbr {
std::atomic_bool Application::sShouldTerminate(false);
const struct timeval Application::kPollTimeout = {OTBR_MAINLOOP_POLL_TIMEOUT_SEC, 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)
Application::Application(Ncp::ThreadHost &aHost,
const std::string &aInterfaceName,
const std::string &aBackboneInterfaceName,
const std::string &aRestListenAddress,
int aRestListenPort)
: mInterfaceName(aInterfaceName)
#if __linux__
, mInfraLinkSelector(aBackboneInterfaceNames)
, mBackboneInterfaceName(mInfraLinkSelector.Select())
#else
, mBackboneInterfaceName(aBackboneInterfaceNames.empty() ? "" : aBackboneInterfaceNames.front())
#endif
, mHost(Ncp::ThreadHost::Create(mInterfaceName.c_str(),
aRadioUrls,
mBackboneInterfaceName,
/* aDryRun */ false,
aEnableAutoAttach))
, mBackboneInterfaceName(aBackboneInterfaceName.c_str())
, mHost(aHost)
#if OTBR_ENABLE_MDNS
, mPublisher(
Mdns::Publisher::Create([this](Mdns::Publisher::State aState) { mMdnsStateSubject.UpdateState(aState); }))
#endif
#if OTBR_ENABLE_DBUS_SERVER && OTBR_ENABLE_BORDER_AGENT
, mDBusAgent(MakeUnique<DBus::DBusAgent>(*mHost, *mPublisher))
, mDBusAgent(MakeUnique<DBus::DBusAgent>(mHost, *mPublisher))
#endif
{
if (mHost->GetCoprocessorType() == OT_COPROCESSOR_RCP)
if (mHost.GetCoprocessorType() == OT_COPROCESSOR_RCP)
{
CreateRcpMode(aRestListenAddress, aRestListenPort);
}
}

void Application::Init(void)
{
mHost->Init();
mHost.Init();

switch (mHost->GetCoprocessorType())
switch (mHost.GetCoprocessorType())
{
case OT_COPROCESSOR_RCP:
InitRcpMode();
Expand All @@ -100,12 +90,12 @@ void Application::Init(void)
break;
}

otbrLogInfo("Co-processor version: %s", mHost->GetCoprocessorVersion());
otbrLogInfo("Co-processor version: %s", mHost.GetCoprocessorVersion());
}

void Application::Deinit(void)
{
switch (mHost->GetCoprocessorType())
switch (mHost.GetCoprocessorType())
{
case OT_COPROCESSOR_RCP:
DeinitRcpMode();
Expand All @@ -118,15 +108,13 @@ void Application::Deinit(void)
break;
}

mHost->Deinit();
mHost.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)
{
Expand Down Expand Up @@ -173,17 +161,14 @@ otbrError Application::Run(void)
{
MainloopManager::GetInstance().Process(mainloop);

#if __linux__
if (mErrorCondition)
{
const char *newInfraLink = mInfraLinkSelector.Select();

if (mBackboneInterfaceName != newInfraLink)
error = mErrorCondition();
if (error != OTBR_ERROR_NONE)
{
error = OTBR_ERROR_INFRA_LINK_CHANGED;
break;
}
}
#endif
}
else if (errno != EINTR)
{
Expand All @@ -204,7 +189,7 @@ void Application::HandleSignal(int aSignal)

void Application::CreateRcpMode(const std::string &aRestListenAddress, int aRestListenPort)
{
otbr::Ncp::RcpHost &rcpHost = static_cast<otbr::Ncp::RcpHost &>(*mHost);
otbr::Ncp::RcpHost &rcpHost = static_cast<otbr::Ncp::RcpHost &>(mHost);
#if OTBR_ENABLE_BORDER_AGENT
mBorderAgent = MakeUnique<BorderAgent>(rcpHost, *mPublisher);
#endif
Expand Down
38 changes: 23 additions & 15 deletions src/agent/application.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,22 +87,22 @@ class VendorServer;
class Application : private NonCopyable
{
public:
typedef std::function<otbrError(void)> ErrorCondition;

/**
* This constructor initializes the Application instance.
*
* @param[in] aHost A reference to the ThreadHost object.
* @param[in] aInterfaceName Name of the Thread network interface.
* @param[in] aBackboneInterfaceName Name of the backbone network interface.
* @param[in] aRadioUrls The radio URLs (can be IEEE802.15.4 or TREL radio).
* @param[in] aEnableAutoAttach Whether or not to automatically attach to the saved network.
* @param[in] aRestListenAddress Network address to listen on.
* @param[in] aRestListenPort Network port to listen on.
*/
explicit 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);
explicit Application(Ncp::ThreadHost &aHost,
const std::string &aInterfaceName,
const std::string &aBackboneInterfaceName,
const std::string &aRestListenAddress,
int aRestListenPort);

/**
* This method initializes the Application instance.
Expand All @@ -114,6 +114,16 @@ class Application : private NonCopyable
*/
void Deinit(void);

/**
* This method sets an error condition for the application.
*
* If the error condition returns an error other than 'OTBR_ERROR_NONE', the application will
* exit the loop in `Run`.
*
* @param[in] aErrorCondition The error condition.
*/
void SetErrorCondition(ErrorCondition aErrorCondition) { mErrorCondition = aErrorCondition; }

/**
* This method runs the application until exit.
*
Expand All @@ -127,7 +137,7 @@ class Application : private NonCopyable
*
* @returns The OpenThread controller object.
*/
Ncp::ThreadHost &GetHost(void) { return *mHost; }
Ncp::ThreadHost &GetHost(void) { return mHost; }

#if OTBR_ENABLE_MDNS
/**
Expand Down Expand Up @@ -250,12 +260,9 @@ class Application : private NonCopyable
void InitNcpMode(void);
void DeinitNcpMode(void);

std::string mInterfaceName;
#if __linux__
otbr::Utils::InfraLinkSelector mInfraLinkSelector;
#endif
const char *mBackboneInterfaceName;
std::unique_ptr<Ncp::ThreadHost> mHost;
std::string mInterfaceName;
const char *mBackboneInterfaceName;
Ncp::ThreadHost &mHost;
#if OTBR_ENABLE_MDNS
Mdns::StateSubject mMdnsStateSubject;
std::unique_ptr<Mdns::Publisher> mPublisher;
Expand Down Expand Up @@ -289,6 +296,7 @@ class Application : private NonCopyable
#endif

static std::atomic_bool sShouldTerminate;
ErrorCondition mErrorCondition;
};

/**
Expand Down
19 changes: 17 additions & 2 deletions src/agent/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -319,11 +319,26 @@ static int realmain(int argc, char *argv[])
}

{
otbr::Application app(interfaceName, backboneInterfaceNames, radioUrls, enableAutoAttach, restListenAddress,
restListenPort);
#if __linux__
otbr::Utils::InfraLinkSelector infraLinkSelector(backboneInterfaceNames);
const std::string backboneInterfaceName = infraLinkSelector.Select();
otbr::Application::ErrorCondition errorCondition = [&backboneInterfaceName, &infraLinkSelector](void) {
return std::string(infraLinkSelector.Select()) == backboneInterfaceName ? OTBR_ERROR_NONE
: OTBR_ERROR_INFRA_LINK_CHANGED;
};
#else
const std::string backboneInterfaceName = backboneInterfaceNames.empty() ? "" : backboneInterfaceNames.front();
#endif
std::unique_ptr<otbr::Ncp::ThreadHost> host = otbr::Ncp::ThreadHost::Create(
interfaceName, radioUrls, backboneInterfaceName.c_str(), /* aDryRun */ false, enableAutoAttach);

otbr::Application app(*host, interfaceName, backboneInterfaceName, restListenAddress, restListenPort);

gApp = &app;
app.Init();
#if __linux__
app.SetErrorCondition(errorCondition);
#endif

ret = app.Run();

Expand Down

0 comments on commit 10756a6

Please sign in to comment.