lokinet/llarp/service/context.cpp

389 lines
9.9 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
{
Context::Context(AbstractRouter *r) : m_Router(r)
{
}
Context::~Context()
{
}
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-11 17:14:43 +00:00
obj.Put(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::unique_ptr< Endpoint > &) >
visit)
{
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::unique_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
{
auto itr = m_Endpoints.begin();
while(itr != m_Endpoints.end())
{
itr->second->Tick(now);
++itr;
}
}
2019-02-08 13:04:12 +00:00
auto ep = getFirstEndpoint();
if(!ep)
return;
std::vector< RouterID > expired;
m_Router->nodedb()->visit([&](const RouterContact &rc) -> bool {
2018-12-19 17:48:29 +00:00
if(rc.IsExpired(now))
2019-02-08 13:04:12 +00:00
expired.emplace_back(rc.pubkey);
2018-12-19 17:48:29 +00:00
return true;
});
2019-02-08 13:05:09 +00:00
// TODO: we need to stop looking up service nodes that are gone forever
// how do?
2019-02-08 13:04:12 +00:00
for(const auto &k : expired)
ep->LookupRouterAnon(k);
}
bool
Context::hasEndpoints()
{
return m_Endpoints.size() ? true : false;
}
service::Endpoint *
2018-09-22 10:23:23 +00:00
Context::getFirstEndpoint()
{
2018-09-22 10:23:23 +00:00
if(!m_Endpoints.size())
{
LogError("No endpoints found");
return nullptr;
}
auto itr = m_Endpoints.begin();
if(itr == m_Endpoints.end())
return nullptr;
return itr->second.get();
2018-09-22 10:23:23 +00:00
}
bool
Context::iterate(struct endpoint_iter &i)
{
if(!m_Endpoints.size())
{
LogError("No endpoints found");
return false;
}
i.index = 0;
// util::Lock lock(access);
auto itr = m_Endpoints.begin();
while(itr != m_Endpoints.end())
{
i.endpoint = itr->second.get();
if(!i.visit(&i))
return false;
// advance
i.index++;
itr++;
}
return true;
}
handlers::TunEndpoint *
2018-09-22 10:23:23 +00:00
Context::getFirstTun()
{
service::Endpoint *endpointer = this->getFirstEndpoint();
2018-09-22 10:23:23 +00:00
if(!endpointer)
{
return nullptr;
}
handlers::TunEndpoint *tunEndpoint =
static_cast< handlers::TunEndpoint * >(endpointer);
return tunEndpoint;
}
llarp_tun_io *
Context::getRange()
{
handlers::TunEndpoint *tunEndpoint = this->getFirstTun();
2018-09-22 10:23:23 +00:00
if(!tunEndpoint)
{
LogError("No tunnel endpoint found");
return nullptr;
}
return &tunEndpoint->tunif;
}
2018-10-23 21:28:01 +00:00
bool
Context::FindBestAddressFor(const AlignedBuffer< 32 > &addr, bool isSNode,
huint32_t &ip)
{
auto itr = m_Endpoints.begin();
while(itr != m_Endpoints.end())
{
2018-11-29 14:01:13 +00:00
if(itr->second->HasAddress(addr))
{
2018-11-29 14:01:13 +00:00
ip = itr->second->ObtainIPForAddr(addr, isSNode);
2018-10-23 21:28:01 +00:00
return true;
}
++itr;
}
2018-10-23 21:28:01 +00:00
itr = m_Endpoints.find("default");
if(itr != m_Endpoints.end())
{
2018-11-29 14:01:13 +00:00
ip = itr->second->ObtainIPForAddr(addr, isSNode);
2018-10-23 21:28:01 +00:00
return true;
}
return false;
}
2018-09-21 12:53:20 +00:00
bool
Context::Prefetch(const service::Address &addr)
2018-09-21 12:53:20 +00:00
{
handlers::TunEndpoint *tunEndpoint = this->getFirstTun();
2018-09-22 10:23:23 +00:00
if(!tunEndpoint)
2018-09-21 12:53:20 +00:00
{
LogError("No tunnel endpoint found");
2018-09-21 12:53:20 +00:00
return false;
}
2018-09-22 10:23:23 +00:00
// HiddenServiceAddresslookup *lookup = new
// HiddenServiceEndpoint(tunEndpoint, callback, addr,
// tunEndpoint->GenTXID());
return tunEndpoint->EnsurePathToService(
addr,
[](__attribute__((unused)) Address addr,
__attribute__((unused)) void *ctx) {},
10000);
2018-09-21 12:53:20 +00:00
}
bool
MapAddressAllIter(struct Context::endpoint_iter *endpointCfg)
{
Context::mapAddressAll_context *context =
(Context::mapAddressAll_context *)endpointCfg->user;
handlers::TunEndpoint *tunEndpoint =
(handlers::TunEndpoint *)endpointCfg->endpoint;
if(!tunEndpoint)
{
LogError("No tunnel endpoint found");
return true; // still continue
}
return tunEndpoint->MapAddress(
context->serviceAddr, context->localPrivateIpAddr.xtohl(), false);
}
bool
Context::MapAddressAll(const service::Address &addr,
Addr &localPrivateIpAddr)
{
struct Context::mapAddressAll_context context;
context.serviceAddr = addr;
context.localPrivateIpAddr = localPrivateIpAddr;
struct Context::endpoint_iter i;
i.user = &context;
i.index = 0;
i.visit = &MapAddressAllIter;
return this->iterate(i);
}
bool
2018-11-26 13:29:45 +00:00
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", "tun"});
{
auto itr = opts.begin();
while(itr != opts.end())
{
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())
{
if(!itr->second->Start())
{
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;
}
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())
{
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 = "tun";
std::string keyfile = "";
2018-08-23 14:07:53 +00:00
for(const auto &option : conf.second)
{
if(option.first == "type")
endpointType = option.second;
if(option.first == "keyfile")
keyfile = option.second;
2018-08-23 14:07:53 +00:00
}
std::unique_ptr< service::Endpoint > service;
static std::map<
std::string,
std::function< std::unique_ptr< service::Endpoint >(
const std::string &, AbstractRouter *, service::Context *) > >
2018-08-23 14:07:53 +00:00
endpointConstructors = {
{"tun",
[](const std::string &nick, AbstractRouter *r,
service::Context *c) -> std::unique_ptr< service::Endpoint > {
return std::make_unique< handlers::TunEndpoint >(nick, r, c);
2018-08-23 14:07:53 +00:00
}},
{"null",
[](const std::string &nick, AbstractRouter *r,
service::Context *c) -> std::unique_ptr< service::Endpoint > {
return std::make_unique< handlers::NullEndpoint >(nick, r, c);
2018-08-23 14:07:53 +00:00
}}};
2018-08-23 14:07:53 +00:00
{
// detect type
auto itr = endpointConstructors.find(endpointType);
if(itr == endpointConstructors.end())
{
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 ephemeral, then we need to regen key
// if privkey file, then set it and load it
if(keyfile != "")
{
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
}
// configure
for(const auto &option : conf.second)
{
auto &k = option.first;
2018-08-23 14:07:53 +00:00
if(k == "type")
continue;
auto &v = option.second;
if(!service->SetOption(k, v))
{
LogError("failed to set ", k, "=", v, " for hidden service endpoint ",
conf.first);
return false;
}
}
2018-11-11 13:14:19 +00:00
if(autostart)
{
// start
if(service->Start())
{
LogInfo("autostarting hidden service endpoint ", service->Name());
m_Endpoints.emplace(conf.first, std::move(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;
}
else
{
LogInfo("added hidden service endpoint ", service->Name());
m_Endpoints.emplace(conf.first, std::move(service));
return true;
}
}
2018-07-17 04:37:50 +00:00
} // namespace service
} // namespace llarp