lokinet/llarp/rpc/rpc.cpp

493 lines
13 KiB
C++
Raw Normal View History

#include <rpc/rpc.hpp>
2019-10-02 20:27:34 +00:00
#include <constants/version.hpp>
#include <router/abstractrouter.hpp>
#include <service/context.hpp>
2019-09-01 12:10:49 +00:00
#include <util/logging/logger.hpp>
#include <router_id.hpp>
#include <exit/context.hpp>
2018-10-19 11:41:36 +00:00
#include <util/encode.hpp>
2019-09-01 12:38:03 +00:00
#include <util/meta/memfn.hpp>
#include <libabyss.hpp>
2019-07-30 23:42:13 +00:00
#include <utility>
2018-10-19 11:41:36 +00:00
namespace llarp
{
namespace rpc
{
2018-11-01 12:47:14 +00:00
struct CallerHandler : public ::abyss::http::IRPCClientHandler
{
CallerImpl* m_Parent;
CallerHandler(::abyss::http::ConnImpl* impl, CallerImpl* parent)
: ::abyss::http::IRPCClientHandler(impl), m_Parent(parent)
2018-11-01 12:47:14 +00:00
{
}
2019-07-30 23:42:13 +00:00
~CallerHandler() override = default;
2018-11-01 12:47:14 +00:00
2018-11-21 17:46:33 +00:00
virtual bool
HandleJSONResult(const nlohmann::json& val) = 0;
2018-11-21 17:46:33 +00:00
bool
2019-07-30 23:42:13 +00:00
HandleResponse(::abyss::http::RPC_Response response) override
2018-11-21 17:46:33 +00:00
{
if(!response.is_object())
2018-11-21 17:46:33 +00:00
{
return HandleJSONResult({});
}
const auto itr = response.find("result");
if(itr == response.end())
2018-11-21 17:46:33 +00:00
{
return HandleJSONResult({});
}
2019-07-06 17:03:40 +00:00
if(itr.value().is_object())
{
return HandleJSONResult(itr.value());
}
2019-07-06 17:03:40 +00:00
return false;
2018-11-21 17:46:33 +00:00
}
2018-11-01 12:47:14 +00:00
void
2019-07-30 23:42:13 +00:00
PopulateReqHeaders(abyss::http::Headers_t& hdr) override;
2018-11-01 12:47:14 +00:00
};
2019-11-27 18:11:15 +00:00
struct LokiPingHandler final : public CallerHandler
{
~LokiPingHandler() override = default;
LokiPingHandler(::abyss::http::ConnImpl* impl, CallerImpl* parent)
: CallerHandler(impl, parent)
{
}
bool
HandleJSONResult(const nlohmann::json& result) override
{
if(not result.is_object())
{
LogError("invalid result from lokid ping, not an object");
return false;
}
const auto itr = result.find("status");
if(itr == result.end())
{
LogError("invalid result from lokid ping, no result");
return false;
}
if(not itr->is_string())
{
LogError("invalid result from lokid ping, status not an string");
return false;
}
const auto status = itr->get< std::string >();
if(status != "OK")
{
LogError("lokid ping failed: '", status, "'");
return false;
}
LogInfo("lokid ping: '", status, "'");
return true;
}
void
HandleError() override
{
LogError("Failed to ping lokid");
}
};
struct GetServiceNodeListHandler final : public CallerHandler
2018-11-01 12:47:14 +00:00
{
using PubkeyList_t = std::vector< RouterID >;
using Callback_t = std::function< void(const PubkeyList_t&, bool) >;
2018-11-01 12:47:14 +00:00
2019-07-30 23:42:13 +00:00
~GetServiceNodeListHandler() override = default;
Callback_t handler;
2018-11-01 12:47:14 +00:00
GetServiceNodeListHandler(::abyss::http::ConnImpl* impl,
CallerImpl* parent, Callback_t h)
2019-07-30 23:42:13 +00:00
: CallerHandler(impl, parent), handler(std::move(h))
2018-11-01 12:47:14 +00:00
{
}
bool
HandleJSONResult(const nlohmann::json& result) override
2018-11-01 12:47:14 +00:00
{
PubkeyList_t keys;
2019-10-14 15:38:34 +00:00
if(not result.is_object())
2018-11-21 17:46:33 +00:00
{
2019-02-28 16:02:36 +00:00
LogWarn("Invalid result: not an object");
2018-11-21 17:46:33 +00:00
handler({}, false);
return false;
}
2019-10-14 15:38:34 +00:00
const auto itr = result.find("service_node_states");
if(itr == result.end())
2018-11-21 17:46:33 +00:00
{
2019-10-14 15:38:34 +00:00
LogWarn("Invalid result: no service_node_states member");
2018-11-21 17:46:33 +00:00
handler({}, false);
return false;
}
2019-10-14 15:38:34 +00:00
if(not itr.value().is_array())
2018-11-21 17:46:33 +00:00
{
2019-10-14 15:38:34 +00:00
LogWarn("Invalid result: service_node_states is not an array");
2018-11-21 17:46:33 +00:00
handler({}, false);
return false;
}
for(const auto item : itr.value())
2018-11-21 17:46:33 +00:00
{
2019-10-14 15:38:34 +00:00
if(not item.is_object())
continue;
if(not item.value("active", false))
continue;
if(not item.value("funded", false))
continue;
2019-10-22 15:00:48 +00:00
const std::string pk = item.value("pubkey_ed25519", "");
if(pk.empty())
continue;
2019-10-14 15:38:34 +00:00
PubKey k;
2019-10-22 15:00:48 +00:00
if(k.FromString(pk))
2019-10-14 15:38:34 +00:00
keys.emplace_back(std::move(k));
2018-11-21 17:46:33 +00:00
}
2019-10-22 15:00:48 +00:00
handler(keys, not keys.empty());
2018-11-01 12:47:14 +00:00
return true;
}
void
2018-11-21 21:59:16 +00:00
HandleError() override
2018-11-01 12:47:14 +00:00
{
handler({}, false);
2018-11-01 12:47:14 +00:00
}
};
struct CallerImpl : public ::abyss::http::JSONRPC
{
AbstractRouter* router;
llarp_time_t m_NextKeyUpdate = 0;
2019-11-27 18:11:15 +00:00
llarp_time_t m_NextPing = 0;
const llarp_time_t KeyUpdateInterval = 5000;
2019-11-27 18:11:15 +00:00
const llarp_time_t PingInterval = 60 * 5 * 1000;
using PubkeyList_t = GetServiceNodeListHandler::PubkeyList_t;
CallerImpl(AbstractRouter* r) : ::abyss::http::JSONRPC(), router(r)
2018-11-01 12:47:14 +00:00
{
}
void
2018-11-21 17:46:33 +00:00
Tick(llarp_time_t now)
2018-11-01 12:47:14 +00:00
{
2019-11-27 18:11:15 +00:00
if(not router->IsRunning())
return;
if(now >= m_NextKeyUpdate)
{
AsyncUpdatePubkeyList();
m_NextKeyUpdate = now + KeyUpdateInterval;
}
2019-11-27 18:11:15 +00:00
if(now >= m_NextPing)
{
AsyncLokiPing();
m_NextPing = now + PingInterval;
}
2018-11-01 12:47:14 +00:00
Flush();
}
void
SetAuth(const std::string& user, const std::string& passwd)
{
username = user;
password = passwd;
}
2019-11-27 18:11:15 +00:00
void
AsyncLokiPing()
{
LogInfo("Pinging Lokid");
nlohmann::json version(llarp::VERSION);
2019-12-10 14:04:33 +00:00
nlohmann::json params({{"version", version}});
2019-11-27 18:11:15 +00:00
QueueRPC("lokinet_ping", std::move(params),
util::memFn(&CallerImpl::NewLokinetPingConn, this));
}
void
AsyncUpdatePubkeyList()
{
LogInfo("Updating service node list");
2019-10-14 15:38:34 +00:00
nlohmann::json params = {
2019-10-22 15:00:48 +00:00
{"fields",
{{"pubkey_ed25519", true}, {"active", true}, {"funded", true}}}};
QueueRPC("get_n_service_nodes", std::move(params),
2019-06-02 21:19:10 +00:00
util::memFn(&CallerImpl::NewAsyncUpdatePubkeyListConn, this));
}
2018-11-01 12:47:14 +00:00
bool
Start(const std::string& remote)
{
return RunAsync(router->netloop(), remote);
2018-11-01 12:47:14 +00:00
}
2019-11-27 18:11:15 +00:00
abyss::http::IRPCClientHandler*
NewLokinetPingConn(abyss::http::ConnImpl* impl)
{
return new LokiPingHandler(impl, this);
}
2018-11-01 12:47:14 +00:00
abyss::http::IRPCClientHandler*
NewAsyncUpdatePubkeyListConn(abyss::http::ConnImpl* impl)
2018-11-01 12:47:14 +00:00
{
return new GetServiceNodeListHandler(
impl, this,
2019-06-02 21:19:10 +00:00
util::memFn(&CallerImpl::HandleServiceNodeListUpdated, this));
2018-11-01 12:47:14 +00:00
}
void
HandleServiceNodeListUpdated(const PubkeyList_t& list, bool updated)
{
if(updated)
{
router->SetRouterWhitelist(list);
}
else
LogError("service node list not updated");
2018-11-01 12:47:14 +00:00
}
2019-07-30 23:42:13 +00:00
~CallerImpl() = default;
2018-11-01 12:47:14 +00:00
};
void
CallerHandler::PopulateReqHeaders(abyss::http::Headers_t& hdr)
{
hdr.emplace("User-Agent", "lokinet rpc (YOLO)");
}
2018-11-01 12:47:14 +00:00
struct Handler : public ::abyss::httpd::IRPCHandler
2018-10-19 11:41:36 +00:00
{
AbstractRouter* router;
std::unordered_map< absl::string_view, std::function< Response() >,
absl::Hash< absl::string_view > >
m_dispatch;
Handler(::abyss::httpd::ConnImpl* conn, AbstractRouter* r)
: ::abyss::httpd::IRPCHandler(conn)
, router(r)
, m_dispatch{
{"llarp.admin.wakeup", [=]() { return StartRouter(); }},
{"llarp.admin.link.neighbor",
[=]() { return ListNeighbors(); }},
{"llarp.admin.exit.list", [=]() { return ListExitLevels(); }},
{"llarp.admin.dumpstate", [=]() { return DumpState(); }},
{"llarp.admin.status", [=]() { return DumpStatus(); }},
{"llarp.our.addresses", [=]() { return OurAddresses(); }},
{"llarp.version", [=]() { return DumpVersion(); }}}
2018-10-23 11:29:37 +00:00
{
}
2018-10-19 11:41:36 +00:00
2019-07-30 23:42:13 +00:00
~Handler() override = default;
2018-10-19 11:41:36 +00:00
Response
StartRouter() const
{
const bool rc = router->Run();
return Response{{"status", rc}};
}
Response
DumpState() const
2019-02-08 19:43:25 +00:00
{
return router->ExtractStatus();
2019-02-08 19:43:25 +00:00
}
Response
ListExitLevels() const
2018-11-14 18:02:27 +00:00
{
exit::Context::TrafficStats stats;
router->exitContext().CalculateExitTraffic(stats);
Response resp;
for(const auto& stat : stats)
2018-11-14 18:02:27 +00:00
{
resp.emplace_back(Response{
{"ident", stat.first.ToHex()},
{"tx", stat.second.first},
{"rx", stat.second.second},
});
2018-11-14 18:02:27 +00:00
}
return resp;
2018-11-14 18:02:27 +00:00
}
Response
ListNeighbors() const
{
Response resp = Response::array();
router->ForEachPeer(
[&](const ILinkSession* session, bool outbound) {
resp.emplace_back(
Response{{"ident", RouterID(session->GetPubKey()).ToString()},
{"svcnode", session->GetRemoteRC().IsPublicRouter()},
{"outbound", outbound}});
},
false);
return resp;
}
Response
DumpStatus() const
{
size_t numServices = 0;
size_t numServicesReady = 0;
Response services = Response::array();
auto visitor =
[&](const std::string& name,
const std::shared_ptr< service::Endpoint >& ptr) -> bool {
numServices++;
if(ptr->IsReady())
numServicesReady++;
const Response status{{"ready", ptr->IsReady()},
{"stopped", ptr->IsStopped()},
{"stale", ptr->IntrosetIsStale()}};
services.emplace_back(Response{name, status});
return true;
};
router->hiddenServiceContext().ForEachService(visitor);
const Response resp{{"uptime", router->Uptime()},
{"servicesTotal", numServices},
{"servicesReady", numServicesReady},
{"services", services}};
return resp;
}
Response
OurAddresses() const
{
Response services;
router->hiddenServiceContext().ForEachService(
[&](const std::string&,
const std::shared_ptr< service::Endpoint >& service) {
const service::Address addr = service->GetIdentity().pub.Addr();
services.push_back(addr.ToString());
return true;
});
return Response{{"services", services}};
}
2019-10-02 20:27:34 +00:00
Response
DumpVersion() const
{
const Response resp{{"version", llarp::VERSION_FULL}};
2019-10-02 20:27:34 +00:00
return resp;
}
absl::optional< Response >
HandleJSONRPC(Method_t method,
2019-07-30 23:42:13 +00:00
ABSL_ATTRIBUTE_UNUSED const Params& params) override
2018-10-19 11:41:36 +00:00
{
auto it = m_dispatch.find(method);
if(it != m_dispatch.end())
{
return it->second();
2019-10-02 20:27:34 +00:00
}
2018-10-19 11:41:36 +00:00
return false;
}
};
2018-11-01 12:47:14 +00:00
struct ReqHandlerImpl : public ::abyss::httpd::BaseReqHandler
2018-10-23 11:29:37 +00:00
{
ReqHandlerImpl(AbstractRouter* r, llarp_time_t reqtimeout)
2018-11-01 12:47:14 +00:00
: ::abyss::httpd::BaseReqHandler(reqtimeout), router(r)
2018-10-23 11:29:37 +00:00
{
}
AbstractRouter* router;
2018-11-01 12:47:14 +00:00
::abyss::httpd::IRPCHandler*
2019-07-30 23:42:13 +00:00
CreateHandler(::abyss::httpd::ConnImpl* conn) override
2018-10-23 11:29:37 +00:00
{
return new Handler(conn, router);
}
};
struct ServerImpl
{
AbstractRouter* router;
2018-10-23 11:29:37 +00:00
ReqHandlerImpl _handler;
ServerImpl(AbstractRouter* r) : router(r), _handler(r, 2000)
2018-10-23 11:29:37 +00:00
{
}
2019-07-30 23:42:13 +00:00
~ServerImpl() = default;
2018-10-23 11:29:37 +00:00
void
Stop()
{
_handler.Close();
}
2018-10-23 11:29:37 +00:00
bool
Start(const std::string& addr)
{
2018-10-25 19:06:16 +00:00
uint16_t port = 0;
auto idx = addr.find_first_of(':');
Addr netaddr;
2018-10-25 19:06:16 +00:00
if(idx != std::string::npos)
{
port = std::stoi(addr.substr(1 + idx));
netaddr = Addr(addr.substr(0, idx));
2018-10-25 19:06:16 +00:00
}
sockaddr_in saddr;
saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
saddr.sin_family = AF_INET;
saddr.sin_port = htons(port);
return _handler.ServeAsync(router->netloop(), router->logic(),
2018-10-25 19:06:16 +00:00
(const sockaddr*)&saddr);
2018-10-23 11:29:37 +00:00
}
};
Caller::Caller(AbstractRouter* r)
: m_Impl(std::make_unique< CallerImpl >(r))
2018-11-01 12:47:14 +00:00
{
}
2019-07-30 23:42:13 +00:00
Caller::~Caller() = default;
2018-11-01 12:47:14 +00:00
void
Caller::Stop()
{
m_Impl->Stop();
}
2018-11-01 12:47:14 +00:00
bool
Caller::Start(const std::string& addr)
{
return m_Impl->Start(addr);
}
void
2018-11-21 17:46:33 +00:00
Caller::Tick(llarp_time_t now)
2018-11-01 12:47:14 +00:00
{
2018-11-21 17:46:33 +00:00
m_Impl->Tick(now);
2018-11-01 12:47:14 +00:00
}
void
Caller::SetAuth(const std::string& user, const std::string& passwd)
{
m_Impl->SetAuth(user, passwd);
}
Server::Server(AbstractRouter* r)
: m_Impl(std::make_unique< ServerImpl >(r))
2018-10-19 11:41:36 +00:00
{
}
2019-07-30 23:42:13 +00:00
Server::~Server() = default;
2018-10-19 11:41:36 +00:00
void
Server::Stop()
{
m_Impl->Stop();
}
2018-10-19 11:41:36 +00:00
bool
Server::Start(const std::string& addr)
{
return m_Impl->Start(addr);
}
} // namespace rpc
} // namespace llarp