lokinet/llarp/service/context.cpp

284 lines
7.3 KiB
C++
Raw Normal View History

#include <service/context.hpp>
2018-12-12 01:12:59 +00:00
#include <handlers/null.hpp>
2018-12-12 02:15:08 +00:00
#include <handlers/tun.hpp>
#include <nodedb.hpp>
#include <router/abstractrouter.hpp>
2018-12-12 02:15:08 +00:00
#include <service/endpoint.hpp>
namespace llarp
{
namespace service
{
namespace
{
using EndpointConstructor = std::function<service::Endpoint_ptr(
const std::string&, AbstractRouter*, service::Context*)>;
using EndpointConstructors = std::map<std::string, EndpointConstructor>;
static EndpointConstructors endpointConstructors = {
{"tun",
[](const std::string& nick, AbstractRouter* r, service::Context* c)
-> service::Endpoint_ptr {
return std::make_shared<handlers::TunEndpoint>(nick, r, c, false);
}},
{"android",
[](const std::string& nick, AbstractRouter* r, service::Context* c)
-> service::Endpoint_ptr {
return std::make_shared<handlers::TunEndpoint>(nick, r, c, true);
}},
{"ios",
[](const std::string& nick, AbstractRouter* r, service::Context* c)
-> service::Endpoint_ptr {
return std::make_shared<handlers::TunEndpoint>(nick, r, c, true);
}},
{"null",
[](const std::string& nick, AbstractRouter* r, service::Context* c)
-> service::Endpoint_ptr {
return std::make_shared<handlers::NullEndpoint>(nick, r, c);
}}};
} // namespace
Context::Context(AbstractRouter* r) : m_Router(r)
{
}
2019-07-30 23:42:13 +00:00
Context::~Context() = default;
bool
Context::StopAll()
{
auto itr = m_Endpoints.begin();
while (itr != m_Endpoints.end())
{
itr->second->Stop();
m_Stopped.emplace_back(std::move(itr->second));
itr = m_Endpoints.erase(itr);
}
return true;
}
2019-02-11 17:14:43 +00:00
util::StatusObject
Context::ExtractStatus() const
2019-02-08 19:43:25 +00:00
{
2019-02-11 17:14:43 +00:00
util::StatusObject obj{};
2019-02-08 19:43:25 +00:00
auto itr = m_Endpoints.begin();
while (itr != m_Endpoints.end())
2019-02-08 19:43:25 +00:00
{
obj[itr->first] = itr->second->ExtractStatus();
2019-02-08 19:43:25 +00:00
++itr;
}
2019-02-11 17:14:43 +00:00
return obj;
2019-02-08 19:43:25 +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())
{
if (visit(itr->first, itr->second))
++itr;
else
return;
}
}
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
{
auto itr = m_Stopped.begin();
while (itr != m_Stopped.end())
{
if ((*itr)->ShouldRemove())
itr = m_Stopped.erase(itr);
else
++itr;
}
}
// tick active endpoints
for (const auto& item : m_Endpoints)
{
item.second->Tick(now);
}
}
bool
Context::hasEndpoints()
{
return m_Endpoints.size() ? true : false;
}
static const char*
DefaultEndpointType()
{
#ifdef ANDROID
return "android";
2019-10-30 13:33:23 +00:00
#else
#ifdef IOS
return "ios";
#else
return "tun";
2019-10-30 13:33:23 +00:00
#endif
#endif
}
bool
Context::AddDefaultEndpoint(const std::unordered_multimap<std::string, std::string>& opts)
{
2018-11-26 13:29:45 +00:00
Config::section_values_t configOpts;
configOpts.push_back({"type", DefaultEndpointType()});
// non reachable by default as this is the default endpoint
// but only if no keyfile option provided
if (opts.count("keyfile") == 0)
{
configOpts.push_back({"reachable", "false"});
}
2018-11-26 13:29:45 +00:00
{
auto itr = opts.begin();
while (itr != opts.end())
2018-11-26 13:29:45 +00:00
{
configOpts.push_back({itr->first, itr->second});
++itr;
}
}
return AddEndpoint({"default", configOpts});
}
bool
2018-11-11 13:14:19 +00:00
Context::StartAll()
{
auto itr = m_Endpoints.begin();
while (itr != m_Endpoints.end())
2018-11-11 13:14:19 +00:00
{
if (!itr->second->Start())
2018-11-11 13:14:19 +00:00
{
LogError(itr->first, " failed to start");
2018-11-11 13:14:19 +00:00
return false;
}
LogInfo(itr->first, " started");
2018-11-11 13:14:19 +00:00
++itr;
}
return true;
}
Endpoint_ptr
Context::GetEndpointByName(const std::string& name)
{
auto itr = m_Endpoints.find(name);
if (itr != m_Endpoints.end())
return itr->second;
return nullptr;
}
2020-02-28 16:29:15 +00:00
void
Context::InjectEndpoint(std::string name, std::shared_ptr<Endpoint> ep)
2020-02-28 16:29:15 +00:00
{
2020-02-28 18:44:27 +00:00
ep->LoadKeyFile();
if (ep->Start())
2020-02-28 16:29:15 +00:00
{
m_Endpoints.emplace(std::move(name), std::move(ep));
}
}
2018-11-11 13:14:19 +00:00
bool
Context::AddEndpoint(const Config::section_t& conf, bool autostart)
{
{
2018-08-23 14:07:53 +00:00
auto itr = m_Endpoints.find(conf.first);
if (itr != m_Endpoints.end())
2018-08-23 14:07:53 +00:00
{
LogError("cannot add hidden service with duplicate name: ", conf.first);
2018-08-23 14:07:53 +00:00
return false;
}
}
2018-08-23 14:07:53 +00:00
// extract type
std::string endpointType = DefaultEndpointType();
std::string keyfile;
for (const auto& option : conf.second)
2018-08-23 14:07:53 +00:00
{
if (option.first == "type")
2018-08-23 14:07:53 +00:00
endpointType = option.second;
if (option.first == "keyfile")
keyfile = option.second;
2018-08-23 14:07:53 +00:00
}
2019-04-23 16:13:22 +00:00
service::Endpoint_ptr service;
2018-08-23 14:07:53 +00:00
{
// detect type
const auto itr = endpointConstructors.find(endpointType);
if (itr == endpointConstructors.end())
2018-08-23 14:07:53 +00:00
{
LogError("no such endpoint type: ", endpointType);
2018-08-23 14:07:53 +00:00
return false;
}
// construct
service = itr->second(conf.first, m_Router, this);
if (service)
{
2019-04-23 16:13:22 +00:00
// if ephemeral, then we need to regen key
// if privkey file, then set it and load it
if (!keyfile.empty())
2019-04-23 16:13:22 +00:00
{
service->SetOption("keyfile", keyfile);
// load keyfile, so we have the correct name for logging
}
LogInfo("Establishing endpoint identity");
service->LoadKeyFile(); // only start endpoint not tun
// now Name() will be correct
}
2018-08-23 14:07:53 +00:00
}
if (service == nullptr)
2019-04-23 16:13:22 +00:00
return false;
2018-08-23 14:07:53 +00:00
// configure
for (const auto& option : conf.second)
{
auto& k = option.first;
if (k == "type")
2018-08-23 14:07:53 +00:00
continue;
auto& v = option.second;
if (!service->SetOption(k, v))
{
LogError("failed to set ", k, "=", v, " for hidden service endpoint ", conf.first);
return false;
}
}
if (autostart)
2018-11-11 13:14:19 +00:00
{
// start
if (service->Start())
2018-11-11 13:14:19 +00:00
{
LogInfo("autostarting hidden service endpoint ", service->Name());
2019-04-23 16:13:22 +00:00
m_Endpoints.emplace(conf.first, service);
2018-11-11 13:14:19 +00:00
return true;
}
LogError("failed to start hidden service endpoint ", conf.first);
2018-11-11 13:14:19 +00:00
return false;
}
2019-07-06 17:03:40 +00:00
LogInfo("added hidden service endpoint ", service->Name());
m_Endpoints.emplace(conf.first, service);
return true;
}
2018-07-17 04:37:50 +00:00
} // namespace service
} // namespace llarp