mirror of
https://github.com/oxen-io/lokinet.git
synced 2024-11-13 01:10:24 +00:00
9844d358e6
- Make the main PumpLL also pump hidden services, rather than using separate wakers in each TunEndpoint. It seems there is some interactions that just one or the other is not enough. - Eliminate TunEndpoint send queue -- it isn't needed as we can just send directly.
218 lines
5.4 KiB
C++
218 lines
5.4 KiB
C++
#include "context.hpp"
|
|
|
|
#include <llarp/handlers/null.hpp>
|
|
#include <llarp/handlers/tun.hpp>
|
|
#include <llarp/nodedb.hpp>
|
|
#include <llarp/router/abstractrouter.hpp>
|
|
#include "endpoint.hpp"
|
|
#include <stdexcept>
|
|
|
|
namespace llarp
|
|
{
|
|
namespace service
|
|
{
|
|
namespace
|
|
{
|
|
using EndpointConstructor =
|
|
std::function<service::Endpoint_ptr(AbstractRouter*, service::Context*)>;
|
|
using EndpointConstructors = std::map<std::string, EndpointConstructor>;
|
|
|
|
static EndpointConstructors endpointConstructors = {
|
|
{"tun",
|
|
[](AbstractRouter* r, service::Context* c) {
|
|
return std::make_shared<handlers::TunEndpoint>(r, c);
|
|
}},
|
|
{"android",
|
|
[](AbstractRouter* r, service::Context* c) {
|
|
return std::make_shared<handlers::TunEndpoint>(r, c);
|
|
}},
|
|
{"ios",
|
|
[](AbstractRouter* r, service::Context* c) {
|
|
return std::make_shared<handlers::TunEndpoint>(r, c);
|
|
}},
|
|
{"null", [](AbstractRouter* r, service::Context* c) {
|
|
return std::make_shared<handlers::NullEndpoint>(r, c);
|
|
}}};
|
|
|
|
} // namespace
|
|
Context::Context(AbstractRouter* r) : m_Router(r)
|
|
{}
|
|
|
|
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;
|
|
}
|
|
|
|
util::StatusObject
|
|
Context::ExtractStatus() const
|
|
{
|
|
util::StatusObject obj{};
|
|
auto itr = m_Endpoints.begin();
|
|
while (itr != m_Endpoints.end())
|
|
{
|
|
obj[itr->first] = itr->second->ExtractStatus();
|
|
++itr;
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
void
|
|
Context::Pump()
|
|
{
|
|
auto now = time_now_ms();
|
|
for (auto& [name, endpoint] : m_Endpoints)
|
|
endpoint->Pump(now);
|
|
}
|
|
|
|
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";
|
|
#else
|
|
#ifdef IOS
|
|
return "ios";
|
|
#else
|
|
return "tun";
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
bool
|
|
Context::StartAll()
|
|
{
|
|
auto itr = m_Endpoints.begin();
|
|
while (itr != m_Endpoints.end())
|
|
{
|
|
if (!itr->second->Start())
|
|
{
|
|
LogError(itr->first, " failed to start");
|
|
return false;
|
|
}
|
|
LogInfo(itr->first, " started");
|
|
++itr;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
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())
|
|
{
|
|
m_Endpoints.emplace(std::move(name), std::move(ep));
|
|
}
|
|
}
|
|
|
|
void
|
|
Context::AddEndpoint(const Config& conf, bool autostart)
|
|
{
|
|
constexpr auto endpointName = "default";
|
|
|
|
if (m_Endpoints.find(endpointName) != m_Endpoints.end())
|
|
throw std::invalid_argument("service::Context only supports one endpoint now");
|
|
|
|
const auto& endpointType = conf.network.m_endpointType;
|
|
// use factory to create endpoint
|
|
const auto itr = endpointConstructors.find(endpointType);
|
|
if (itr == endpointConstructors.end())
|
|
throw std::invalid_argument(stringify("Endpoint type ", endpointType, " does not exist"));
|
|
|
|
auto service = itr->second(m_Router, this);
|
|
if (not service)
|
|
throw std::runtime_error(stringify("Failed to construct endpoint of type ", endpointType));
|
|
|
|
// pass conf to service
|
|
service->Configure(conf.network, conf.dns);
|
|
|
|
if (not service->LoadKeyFile())
|
|
throw std::runtime_error("Endpoint's keyfile could not be loaded");
|
|
|
|
// 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");
|
|
}
|
|
|
|
m_Endpoints.emplace(endpointName, service);
|
|
}
|
|
} // namespace service
|
|
} // namespace llarp
|