lokinet/llarp/service/context.cpp

218 lines
5.1 KiB
C++
Raw Normal View History

#include "context.hpp"
#include "endpoint.hpp"
#include <llarp/handlers/null.hpp>
#include <llarp/handlers/tun.hpp>
#include <stdexcept>
2023-10-19 21:59:57 +00:00
2023-10-23 22:58:58 +00:00
namespace llarp::service
{
2023-10-23 22:58:58 +00:00
static auto logcat = log::Cat("service");
namespace
{
2023-10-23 22:58:58 +00:00
using EndpointConstructor = std::function<service::Endpoint_ptr(Router*, service::Context*)>;
using EndpointConstructors = std::map<std::string, EndpointConstructor>;
static EndpointConstructors endpointConstructors = {
{"tun",
[](Router* r, service::Context* c) {
return std::make_shared<handlers::TunEndpoint>(r, c);
}},
{"android",
[](Router* r, service::Context* c) {
return std::make_shared<handlers::TunEndpoint>(r, c);
}},
{"ios",
[](Router* r, service::Context* c) {
return std::make_shared<handlers::TunEndpoint>(r, c);
}},
{"null", [](Router* r, service::Context* c) {
return std::make_shared<handlers::NullEndpoint>(r, c);
}}};
} // namespace
Context::Context(Router* r) : m_Router(r)
{}
Context::~Context() = default;
bool
Context::StopAll()
{
auto itr = m_Endpoints.begin();
while (itr != m_Endpoints.end())
{
2023-10-23 22:58:58 +00:00
log::debug(logcat, "Stopping endpoint {}.", itr->first);
itr->second->Stop();
log::debug(logcat, "Endpoint {} stopped.", itr->first);
m_Stopped.emplace_back(std::move(itr->second));
itr = m_Endpoints.erase(itr);
}
2023-10-23 22:58:58 +00:00
return true;
}
2023-10-23 22:58:58 +00:00
util::StatusObject
Context::ExtractStatus() const
{
util::StatusObject obj{};
auto itr = m_Endpoints.begin();
while (itr != m_Endpoints.end())
{
2023-10-23 22:58:58 +00:00
obj[itr->first] = itr->second->ExtractStatus();
++itr;
}
2023-10-23 22:58:58 +00:00
return obj;
}
2023-10-23 22:58:58 +00:00
void
Context::ForEachService(
std::function<bool(const std::string&, const std::shared_ptr<Endpoint>&)> visit) const
{
auto itr = m_Endpoints.begin();
while (itr != m_Endpoints.end())
{
2023-10-23 22:58:58 +00:00
if (visit(itr->first, itr->second))
++itr;
else
return;
}
2023-10-23 22:58:58 +00:00
}
2023-10-23 22:58:58 +00:00
void
Context::Pump()
{
auto now = time_now_ms();
for (auto& [name, endpoint] : m_Endpoints)
endpoint->Pump(now);
}
2023-10-23 22:58:58 +00:00
bool
Context::RemoveEndpoint(const std::string& name)
{
auto itr = m_Endpoints.find(name);
if (itr == m_Endpoints.end())
return false;
std::shared_ptr<Endpoint> ep = std::move(itr->second);
m_Endpoints.erase(itr);
ep->Stop();
m_Stopped.emplace_back(std::move(ep));
return true;
}
void
Context::Tick(llarp_time_t now)
{
// erase stopped endpoints that are done
{
2023-10-23 22:58:58 +00:00
auto itr = m_Stopped.begin();
while (itr != m_Stopped.end())
{
2023-10-23 22:58:58 +00:00
if ((*itr)->ShouldRemove())
itr = m_Stopped.erase(itr);
else
++itr;
}
}
2023-10-23 22:58:58 +00:00
// tick active endpoints
for (const auto& item : m_Endpoints)
{
2023-10-23 22:58:58 +00:00
item.second->Tick(now);
}
2023-10-23 22:58:58 +00:00
}
2023-10-23 22:58:58 +00:00
bool
Context::hasEndpoints()
{
return m_Endpoints.size() ? true : false;
}
static const char*
DefaultEndpointType()
{
#ifdef ANDROID
2023-10-23 22:58:58 +00:00
return "android";
2019-10-30 13:33:23 +00:00
#else
#ifdef IOS
2023-10-23 22:58:58 +00:00
return "ios";
#else
2023-10-23 22:58:58 +00:00
return "tun";
2019-10-30 13:33:23 +00:00
#endif
#endif
2023-10-23 22:58:58 +00:00
}
2023-10-23 22:58:58 +00:00
bool
Context::StartAll()
{
auto itr = m_Endpoints.begin();
while (itr != m_Endpoints.end())
2018-11-11 13:14:19 +00:00
{
2023-10-23 22:58:58 +00:00
if (!itr->second->Start())
2018-11-11 13:14:19 +00:00
{
2023-10-23 22:58:58 +00:00
LogError(itr->first, " failed to start");
return false;
2018-11-11 13:14:19 +00:00
}
2023-10-23 22:58:58 +00:00
LogInfo(itr->first, " started");
++itr;
}
2023-10-23 22:58:58 +00:00
return true;
}
2023-10-23 22:58:58 +00:00
Endpoint_ptr
Context::GetEndpointByName(const std::string& name) const
{
auto itr = m_Endpoints.find(name);
if (itr != m_Endpoints.end())
return itr->second;
return nullptr;
}
void
Context::InjectEndpoint(std::string name, std::shared_ptr<Endpoint> ep)
{
ep->LoadKeyFile();
if (ep->Start())
2020-02-28 16:29:15 +00:00
{
2023-10-23 22:58:58 +00:00
m_Endpoints.emplace(std::move(name), std::move(ep));
2020-02-28 16:29:15 +00:00
}
2023-10-23 22:58:58 +00:00
}
2020-02-28 16:29:15 +00:00
2023-10-23 22:58:58 +00:00
void
Context::AddEndpoint(const Config& conf, bool autostart)
{
constexpr auto endpointName = "default";
2023-10-23 22:58:58 +00:00
if (m_Endpoints.find(endpointName) != m_Endpoints.end())
throw std::invalid_argument("service::Context only supports one endpoint now");
2020-04-22 20:04:47 +00:00
2023-11-03 13:40:14 +00:00
const auto& endpointType = conf.network.endpoint_type;
2023-10-23 22:58:58 +00:00
// use factory to create endpoint
const auto itr = endpointConstructors.find(endpointType);
if (itr == endpointConstructors.end())
throw std::invalid_argument{fmt::format("Endpoint type {} does not exist", endpointType)};
2020-04-22 20:04:47 +00:00
2023-10-23 22:58:58 +00:00
auto service = itr->second(m_Router, this);
if (not service)
throw std::runtime_error{
fmt::format("Failed to construct endpoint of type {}", endpointType)};
2020-04-22 20:04:47 +00:00
2023-10-23 22:58:58 +00:00
// pass conf to service
service->Configure(conf.network, conf.dns);
2023-10-23 22:58:58 +00:00
if (not service->LoadKeyFile())
throw std::runtime_error("Endpoint's keyfile could not be loaded");
2019-07-06 17:03:40 +00:00
2023-10-23 22:58:58 +00:00
// autostart if requested
if (autostart)
{
if (service->Start())
LogInfo("autostarting hidden service endpoint ", service->Name());
else
throw std::runtime_error("failed to start hidden service endpoint");
}
2023-10-23 22:58:58 +00:00
m_Endpoints.emplace(endpointName, service);
}
} // namespace llarp::service