2021-03-09 23:24:35 +01:00
|
|
|
#include "link_manager.hpp"
|
2023-09-15 16:55:32 +02:00
|
|
|
#include "connection.hpp"
|
2019-06-26 23:39:29 +02:00
|
|
|
|
2023-09-14 16:54:51 +02:00
|
|
|
#include <llarp/router/router.hpp>
|
2023-09-13 21:57:18 +02:00
|
|
|
#include <llarp/router/rc_lookup_handler.hpp>
|
2023-08-28 22:50:06 +02:00
|
|
|
#include <llarp/nodedb.hpp>
|
2019-06-26 23:39:29 +02:00
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include <set>
|
|
|
|
|
|
|
|
namespace llarp
|
|
|
|
{
|
2023-09-15 16:55:32 +02:00
|
|
|
namespace link
|
|
|
|
{
|
|
|
|
std::shared_ptr<link::Connection>
|
|
|
|
Endpoint::get_conn(const RouterContact& rc) const
|
|
|
|
{
|
2023-09-18 23:50:07 +02:00
|
|
|
if (auto itr = conns.find(rc.pubkey); itr != conns.end())
|
|
|
|
return itr->second;
|
2023-09-15 16:55:32 +02:00
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2023-09-21 16:20:49 +02:00
|
|
|
std::shared_ptr<link::Connection>
|
|
|
|
Endpoint::get_conn(const RouterID& rid) const
|
|
|
|
{
|
|
|
|
if (auto itr = conns.find(rid); itr != conns.end())
|
|
|
|
return itr->second;
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2023-09-15 16:55:32 +02:00
|
|
|
bool
|
|
|
|
Endpoint::have_conn(const RouterID& remote, bool client_only) const
|
|
|
|
{
|
|
|
|
if (auto itr = conns.find(remote); itr != conns.end())
|
|
|
|
{
|
|
|
|
if (not(itr->second->remote_is_relay and client_only))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2023-09-19 22:09:18 +02:00
|
|
|
Endpoint::deregister_peer(RouterID _rid)
|
2023-09-15 16:55:32 +02:00
|
|
|
{
|
2023-09-19 22:09:18 +02:00
|
|
|
if (auto itr = conns.find(_rid); itr != conns.end())
|
2023-09-15 16:55:32 +02:00
|
|
|
{
|
2023-09-19 22:09:18 +02:00
|
|
|
auto& c = itr->second;
|
|
|
|
auto& _scid = c->conn->scid();
|
|
|
|
|
|
|
|
link_manager.router.loop()->call([this, scid = _scid, rid = _rid]() {
|
|
|
|
endpoint->close_connection(scid);
|
|
|
|
|
|
|
|
conns.erase(rid);
|
|
|
|
connid_map.erase(scid);
|
|
|
|
});
|
|
|
|
|
2023-09-15 16:55:32 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t
|
|
|
|
Endpoint::num_connected(bool clients_only) const
|
|
|
|
{
|
|
|
|
size_t count = 0;
|
|
|
|
|
|
|
|
for (const auto& c : conns)
|
|
|
|
{
|
|
|
|
if (not(c.second->remote_is_relay and clients_only))
|
|
|
|
count += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
Endpoint::get_random_connection(RouterContact& router) const
|
|
|
|
{
|
|
|
|
if (const auto size = conns.size(); size)
|
|
|
|
{
|
|
|
|
auto itr = conns.begin();
|
|
|
|
std::advance(itr, randint() % size);
|
|
|
|
router = itr->second->remote_rc;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
log::warning(quic_cat, "Error: failed to fetch random connection");
|
|
|
|
return false;
|
|
|
|
}
|
2023-09-19 22:09:18 +02:00
|
|
|
|
|
|
|
void
|
|
|
|
Endpoint::for_each_connection(std::function<void(link::Connection&)> func)
|
|
|
|
{
|
|
|
|
for (const auto& [rid, conn] : conns)
|
|
|
|
func(*conn);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Endpoint::close_connection(RouterID _rid)
|
|
|
|
{
|
|
|
|
if (auto itr = conns.find(_rid); itr != conns.end())
|
|
|
|
{
|
|
|
|
auto& c = itr->second;
|
|
|
|
auto& _scid = c->conn->scid();
|
|
|
|
|
|
|
|
link_manager.router.loop()->call([this, scid = _scid, rid = _rid]() {
|
|
|
|
endpoint->close_connection(scid);
|
|
|
|
|
|
|
|
conns.erase(rid);
|
|
|
|
connid_map.erase(scid);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-15 16:55:32 +02:00
|
|
|
} // namespace link
|
2023-09-14 16:54:51 +02:00
|
|
|
|
2023-09-19 22:09:18 +02:00
|
|
|
void
|
|
|
|
LinkManager::for_each_connection(std::function<void(link::Connection&)> func)
|
|
|
|
{
|
|
|
|
if (is_stopping)
|
|
|
|
return;
|
|
|
|
|
|
|
|
return ep.for_each_connection(func);
|
|
|
|
}
|
|
|
|
|
2023-09-27 16:09:48 +02:00
|
|
|
void
|
|
|
|
LinkManager::register_commands(std::shared_ptr<oxen::quic::BTRequestStream>& s)
|
|
|
|
{
|
|
|
|
for (const auto& [name, func] : rpc_commands)
|
|
|
|
{
|
|
|
|
s->register_command(name, [this, f = func](oxen::quic::message m) {
|
|
|
|
router.loop()->call([this, func = f, msg = std::move(m)]() mutable {
|
|
|
|
std::invoke(func, this, std::move(msg));
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-21 16:20:49 +02:00
|
|
|
std::shared_ptr<oxen::quic::Endpoint>
|
|
|
|
LinkManager::startup_endpoint()
|
|
|
|
{
|
|
|
|
/** Parameters:
|
|
|
|
- local bind address
|
|
|
|
- conection open callback
|
|
|
|
- connection close callback
|
|
|
|
- stream constructor callback
|
|
|
|
- will return a BTRequestStream on the first call to get_new_stream<BTRequestStream>
|
|
|
|
*/
|
|
|
|
return quic->endpoint(
|
|
|
|
router.public_ip(),
|
|
|
|
[this](oxen::quic::connection_interface& ci) { return on_conn_open(ci); },
|
|
|
|
[this](oxen::quic::connection_interface& ci, uint64_t ec) {
|
|
|
|
return on_conn_closed(ci, ec);
|
|
|
|
},
|
|
|
|
[this](oxen::quic::dgram_interface& di, bstring dgram) { recv_data_message(di, dgram); },
|
|
|
|
[&](oxen::quic::Connection& c,
|
|
|
|
oxen::quic::Endpoint& e,
|
|
|
|
std::optional<int64_t> id) -> std::shared_ptr<oxen::quic::Stream> {
|
|
|
|
if (id && id == 0)
|
|
|
|
{
|
2023-09-27 16:09:48 +02:00
|
|
|
auto s = std::make_shared<oxen::quic::BTRequestStream>();
|
|
|
|
register_commands(s);
|
|
|
|
return s;
|
2023-09-21 16:20:49 +02:00
|
|
|
}
|
|
|
|
return std::make_shared<oxen::quic::Stream>(c, e);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-09-14 16:54:51 +02:00
|
|
|
LinkManager::LinkManager(Router& r)
|
|
|
|
: router{r}
|
|
|
|
, quic{std::make_unique<oxen::quic::Network>()}
|
|
|
|
, tls_creds{oxen::quic::GNUTLSCreds::make_from_ed_keys(
|
2023-09-15 16:55:32 +02:00
|
|
|
{reinterpret_cast<const char*>(router.identity().data()), size_t{32}},
|
|
|
|
{reinterpret_cast<const char*>(router.identity().toPublic().data()), size_t{32}})}
|
2023-09-21 16:20:49 +02:00
|
|
|
, ep{startup_endpoint(), *this}
|
2023-09-14 16:54:51 +02:00
|
|
|
{}
|
|
|
|
|
2019-06-26 23:39:29 +02:00
|
|
|
bool
|
2023-09-21 16:20:49 +02:00
|
|
|
LinkManager::send_control_message(
|
2023-09-27 16:09:48 +02:00
|
|
|
const RouterID& remote,
|
|
|
|
std::string endpoint,
|
|
|
|
std::string body,
|
|
|
|
std::function<void(oxen::quic::message)> func)
|
2019-06-26 23:39:29 +02:00
|
|
|
{
|
2023-09-19 22:09:18 +02:00
|
|
|
if (is_stopping)
|
2019-06-26 23:39:29 +02:00
|
|
|
return false;
|
|
|
|
|
2023-09-21 16:20:49 +02:00
|
|
|
if (auto conn = ep.get_conn(remote); conn)
|
2019-06-26 23:39:29 +02:00
|
|
|
{
|
2023-09-27 16:09:48 +02:00
|
|
|
conn->control_stream->command(endpoint, body, std::move(func));
|
2023-09-21 16:20:49 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
router.loop()->call([&]() {
|
2023-09-27 16:09:48 +02:00
|
|
|
auto pending = PendingControlMessage(body, endpoint, func);
|
2023-09-18 23:50:07 +02:00
|
|
|
|
|
|
|
auto [itr, b] = pending_conn_msg_queue.emplace(remote, MessageQueue());
|
2023-09-21 16:20:49 +02:00
|
|
|
itr->second.push_back(std::move(pending));
|
2023-09-18 23:50:07 +02:00
|
|
|
|
|
|
|
rc_lookup->get_rc(
|
|
|
|
remote,
|
|
|
|
[this](
|
|
|
|
[[maybe_unused]] const RouterID& rid,
|
|
|
|
const RouterContact* const rc,
|
|
|
|
const RCRequestResult res) {
|
|
|
|
if (res == RCRequestResult::Success)
|
|
|
|
connect_to(*rc);
|
|
|
|
else
|
|
|
|
log::warning(quic_cat, "Do something intelligent here for error handling");
|
|
|
|
});
|
2023-09-21 16:20:49 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2023-09-18 23:50:07 +02:00
|
|
|
|
2023-09-21 16:20:49 +02:00
|
|
|
bool
|
|
|
|
LinkManager::send_data_message(const RouterID& remote, std::string body)
|
|
|
|
{
|
|
|
|
if (is_stopping)
|
2019-06-26 23:39:29 +02:00
|
|
|
return false;
|
2023-09-21 16:20:49 +02:00
|
|
|
|
|
|
|
if (auto conn = ep.get_conn(remote); conn)
|
|
|
|
{
|
|
|
|
conn->conn->send_datagram(std::move(body));
|
|
|
|
return true;
|
2019-06-26 23:39:29 +02:00
|
|
|
}
|
|
|
|
|
2023-09-21 16:20:49 +02:00
|
|
|
router.loop()->call([&]() {
|
|
|
|
auto pending = PendingDataMessage(body);
|
|
|
|
|
|
|
|
auto [itr, b] = pending_conn_msg_queue.emplace(remote, MessageQueue());
|
|
|
|
itr->second.push_back(std::move(pending));
|
|
|
|
|
|
|
|
rc_lookup->get_rc(
|
|
|
|
remote,
|
|
|
|
[this](
|
|
|
|
[[maybe_unused]] const RouterID& rid,
|
|
|
|
const RouterContact* const rc,
|
|
|
|
const RCRequestResult res) {
|
|
|
|
if (res == RCRequestResult::Success)
|
|
|
|
connect_to(*rc);
|
|
|
|
else
|
|
|
|
log::warning(quic_cat, "Do something intelligent here for error handling");
|
|
|
|
});
|
|
|
|
});
|
2023-09-18 23:50:07 +02:00
|
|
|
|
2023-08-28 22:50:06 +02:00
|
|
|
return false;
|
2019-06-26 23:39:29 +02:00
|
|
|
}
|
|
|
|
|
2023-09-18 23:50:07 +02:00
|
|
|
void
|
2023-09-19 22:09:18 +02:00
|
|
|
LinkManager::close_connection(RouterID rid)
|
|
|
|
{
|
|
|
|
return ep.close_connection(rid);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
LinkManager::connect_to(RouterID rid)
|
2023-09-18 23:50:07 +02:00
|
|
|
{
|
|
|
|
rc_lookup->get_rc(
|
2023-09-19 22:09:18 +02:00
|
|
|
rid,
|
2023-09-18 23:50:07 +02:00
|
|
|
[this](
|
|
|
|
[[maybe_unused]] const RouterID& rid,
|
|
|
|
const RouterContact* const rc,
|
|
|
|
const RCRequestResult res) {
|
|
|
|
if (res == RCRequestResult::Success)
|
|
|
|
connect_to(*rc);
|
|
|
|
/* TODO:
|
|
|
|
else
|
|
|
|
RC lookup failure callback here
|
|
|
|
*/
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// This function assumes the RC has already had its signature verified and connection is allowed.
|
|
|
|
void
|
|
|
|
LinkManager::connect_to(RouterContact rc)
|
|
|
|
{
|
2023-09-21 16:20:49 +02:00
|
|
|
if (auto conn = ep.get_conn(rc.pubkey); conn)
|
2023-09-18 23:50:07 +02:00
|
|
|
{
|
2023-09-21 16:20:49 +02:00
|
|
|
// TODO: should implement some connection failed logic, but not the same logic that
|
|
|
|
// would be executed for another failure case
|
2023-09-18 23:50:07 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto& remote_addr = rc.addr;
|
|
|
|
|
|
|
|
// TODO: confirm remote end is using the expected pubkey (RouterID).
|
|
|
|
// TODO: ALPN for "client" vs "relay" (could just be set on endpoint creation)
|
2023-09-21 16:20:49 +02:00
|
|
|
if (auto rv = ep.establish_connection(remote_addr, rc, tls_creds); rv)
|
2023-09-18 23:50:07 +02:00
|
|
|
{
|
|
|
|
log::info(quic_cat, "Connection to {} successfully established!", remote_addr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
log::warning(quic_cat, "Connection to {} successfully established!", remote_addr);
|
|
|
|
}
|
|
|
|
|
2023-09-19 22:09:18 +02:00
|
|
|
// TODO: should we add routes here now that Router::SessionOpen is gone?
|
2023-09-18 23:50:07 +02:00
|
|
|
void
|
|
|
|
LinkManager::on_conn_open(oxen::quic::connection_interface& ci)
|
|
|
|
{
|
2023-09-19 22:09:18 +02:00
|
|
|
router.loop()->call([this, &conn_interface = ci]() {
|
|
|
|
const auto& scid = conn_interface.scid();
|
|
|
|
const auto& rid = ep.connid_map[scid];
|
2023-09-18 23:50:07 +02:00
|
|
|
|
2023-09-21 16:20:49 +02:00
|
|
|
// check to see if this connection was established while we were attempting to queue
|
|
|
|
// messages to the remote
|
2023-09-19 22:09:18 +02:00
|
|
|
if (auto itr = pending_conn_msg_queue.find(rid); itr != pending_conn_msg_queue.end())
|
|
|
|
{
|
|
|
|
auto& que = itr->second;
|
2023-09-18 23:50:07 +02:00
|
|
|
|
2023-09-19 22:09:18 +02:00
|
|
|
while (not que.empty())
|
|
|
|
{
|
2023-09-21 16:20:49 +02:00
|
|
|
auto& m = que.front();
|
|
|
|
|
|
|
|
if (m.is_control)
|
|
|
|
{
|
|
|
|
auto& msg = reinterpret_cast<PendingControlMessage&>(m);
|
2023-09-27 16:09:48 +02:00
|
|
|
ep.conns[rid]->control_stream->command(msg.endpoint, msg.body, msg.func);
|
2023-09-21 16:20:49 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
auto& msg = reinterpret_cast<PendingDataMessage&>(m);
|
|
|
|
conn_interface.send_datagram(std::move(msg.body));
|
|
|
|
}
|
2023-09-18 23:50:07 +02:00
|
|
|
|
2023-09-21 16:20:49 +02:00
|
|
|
que.pop_front();
|
2023-09-19 22:09:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
LinkManager::on_conn_closed(oxen::quic::connection_interface& ci, uint64_t ec)
|
|
|
|
{
|
|
|
|
router.loop()->call([this, &conn_interface = ci, error_code = ec]() {
|
|
|
|
const auto& scid = conn_interface.scid();
|
|
|
|
|
|
|
|
log::debug(quic_cat, "Purging quic connection CID:{} (ec: {})", scid, error_code);
|
|
|
|
|
|
|
|
if (const auto& c_itr = ep.connid_map.find(scid); c_itr != ep.connid_map.end())
|
2023-09-18 23:50:07 +02:00
|
|
|
{
|
2023-09-19 22:09:18 +02:00
|
|
|
const auto& rid = c_itr->second;
|
2023-09-18 23:50:07 +02:00
|
|
|
|
2023-09-19 22:09:18 +02:00
|
|
|
if (auto p_itr = pending_conn_msg_queue.find(rid); p_itr != pending_conn_msg_queue.end())
|
|
|
|
pending_conn_msg_queue.erase(p_itr);
|
2023-09-18 23:50:07 +02:00
|
|
|
|
2023-09-19 22:09:18 +02:00
|
|
|
if (auto m_itr = ep.conns.find(rid); m_itr != ep.conns.end())
|
|
|
|
ep.conns.erase(m_itr);
|
|
|
|
|
|
|
|
ep.connid_map.erase(c_itr);
|
|
|
|
|
|
|
|
log::debug(quic_cat, "Quic connection CID:{} purged successfully", scid);
|
2023-09-18 23:50:07 +02:00
|
|
|
}
|
2023-09-19 22:09:18 +02:00
|
|
|
});
|
|
|
|
}
|
2023-09-18 23:50:07 +02:00
|
|
|
|
2019-06-26 23:39:29 +02:00
|
|
|
bool
|
2023-09-14 16:54:51 +02:00
|
|
|
LinkManager::have_connection_to(const RouterID& remote, bool client_only) const
|
2021-06-08 00:31:57 +02:00
|
|
|
{
|
2023-09-14 16:54:51 +02:00
|
|
|
return ep.have_conn(remote, client_only);
|
2021-06-08 00:31:57 +02:00
|
|
|
}
|
|
|
|
|
2023-08-28 22:50:06 +02:00
|
|
|
bool
|
2023-09-14 16:54:51 +02:00
|
|
|
LinkManager::have_client_connection_to(const RouterID& remote) const
|
2023-08-28 22:50:06 +02:00
|
|
|
{
|
2023-09-14 16:54:51 +02:00
|
|
|
return ep.have_conn(remote, true);
|
2023-08-28 22:50:06 +02:00
|
|
|
}
|
|
|
|
|
2020-11-10 15:24:58 +01:00
|
|
|
void
|
2023-09-14 16:54:51 +02:00
|
|
|
LinkManager::deregister_peer(RouterID remote)
|
2020-11-10 15:24:58 +01:00
|
|
|
{
|
2023-09-14 16:54:51 +02:00
|
|
|
if (auto rv = ep.deregister_peer(remote); rv)
|
2020-11-10 15:24:58 +01:00
|
|
|
{
|
2023-09-14 16:54:51 +02:00
|
|
|
persisting_conns.erase(remote);
|
2023-09-18 23:50:07 +02:00
|
|
|
log::info(logcat, "Peer {} successfully de-registered", remote);
|
2020-11-10 15:24:58 +01:00
|
|
|
}
|
2023-09-14 16:54:51 +02:00
|
|
|
else
|
2023-09-18 23:50:07 +02:00
|
|
|
log::warning(logcat, "Peer {} not found for de-registration!", remote);
|
2019-06-26 23:39:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2023-09-14 16:54:51 +02:00
|
|
|
LinkManager::stop()
|
2019-06-26 23:39:29 +02:00
|
|
|
{
|
2023-09-19 22:09:18 +02:00
|
|
|
if (is_stopping)
|
2019-06-26 23:39:29 +02:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-09-15 16:55:32 +02:00
|
|
|
util::Lock l(m);
|
2019-06-26 23:39:29 +02:00
|
|
|
|
|
|
|
LogInfo("stopping links");
|
2023-09-19 22:09:18 +02:00
|
|
|
is_stopping = true;
|
2019-06-26 23:39:29 +02:00
|
|
|
|
2023-08-28 16:56:44 +02:00
|
|
|
quic.reset();
|
2019-06-26 23:39:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2023-09-14 16:54:51 +02:00
|
|
|
LinkManager::set_conn_persist(const RouterID& remote, llarp_time_t until)
|
2019-06-26 23:39:29 +02:00
|
|
|
{
|
2023-09-19 22:09:18 +02:00
|
|
|
if (is_stopping)
|
2019-06-26 23:39:29 +02:00
|
|
|
return;
|
|
|
|
|
2023-09-15 16:55:32 +02:00
|
|
|
util::Lock l(m);
|
2021-06-06 16:51:29 +02:00
|
|
|
|
2023-09-14 16:54:51 +02:00
|
|
|
persisting_conns[remote] = std::max(until, persisting_conns[remote]);
|
|
|
|
if (have_client_connection_to(remote))
|
2021-06-07 14:39:38 +02:00
|
|
|
{
|
2023-08-28 16:56:44 +02:00
|
|
|
// mark this as a client so we don't try to back connect
|
2023-09-14 16:54:51 +02:00
|
|
|
clients.Upsert(remote);
|
2021-06-07 14:39:38 +02:00
|
|
|
}
|
2019-06-26 23:39:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t
|
2023-09-14 16:54:51 +02:00
|
|
|
LinkManager::get_num_connected(bool clients_only) const
|
2019-06-26 23:39:29 +02:00
|
|
|
{
|
2023-09-15 16:55:32 +02:00
|
|
|
return ep.num_connected(clients_only);
|
2019-06-26 23:39:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t
|
2023-09-14 16:54:51 +02:00
|
|
|
LinkManager::get_num_connected_clients() const
|
2019-06-26 23:39:29 +02:00
|
|
|
{
|
2023-09-14 16:54:51 +02:00
|
|
|
return get_num_connected(true);
|
2019-12-03 18:03:19 +01:00
|
|
|
}
|
|
|
|
|
2019-06-26 23:39:29 +02:00
|
|
|
bool
|
2023-09-14 16:54:51 +02:00
|
|
|
LinkManager::get_random_connected(RouterContact& router) const
|
2019-06-26 23:39:29 +02:00
|
|
|
{
|
2023-09-15 16:55:32 +02:00
|
|
|
return ep.get_random_connection(router);
|
2019-06-26 23:39:29 +02:00
|
|
|
}
|
|
|
|
|
2023-08-29 16:26:59 +02:00
|
|
|
// TODO: this? perhaps no longer necessary in the same way?
|
2019-06-26 23:39:29 +02:00
|
|
|
void
|
2023-09-14 16:54:51 +02:00
|
|
|
LinkManager::check_persisting_conns(llarp_time_t)
|
2019-06-26 23:39:29 +02:00
|
|
|
{
|
2023-09-19 22:09:18 +02:00
|
|
|
if (is_stopping)
|
2019-06-26 23:39:29 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-08-29 16:26:59 +02:00
|
|
|
// TODO: do we still need this concept?
|
2020-06-04 18:00:30 +02:00
|
|
|
void
|
2023-09-14 16:54:51 +02:00
|
|
|
LinkManager::update_peer_db(std::shared_ptr<PeerDb>)
|
2023-08-29 16:26:59 +02:00
|
|
|
{}
|
2020-06-04 18:00:30 +02:00
|
|
|
|
2023-08-29 16:26:59 +02:00
|
|
|
// TODO: this
|
2019-06-26 23:39:29 +02:00
|
|
|
util::StatusObject
|
2023-09-15 16:55:32 +02:00
|
|
|
LinkManager::extract_status() const
|
2019-06-26 23:39:29 +02:00
|
|
|
{
|
2023-08-28 16:56:44 +02:00
|
|
|
return {};
|
2019-06-26 23:39:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2023-09-14 16:54:51 +02:00
|
|
|
LinkManager::init(RCLookupHandler* rcLookup)
|
2019-06-26 23:39:29 +02:00
|
|
|
{
|
2023-09-19 22:09:18 +02:00
|
|
|
is_stopping = false;
|
2023-09-15 16:55:32 +02:00
|
|
|
rc_lookup = rcLookup;
|
|
|
|
node_db = router.node_db();
|
2019-06-26 23:39:29 +02:00
|
|
|
}
|
|
|
|
|
2023-08-28 16:56:44 +02:00
|
|
|
void
|
2023-09-15 16:55:32 +02:00
|
|
|
LinkManager::connect_to_random(int num_conns)
|
2023-08-28 16:56:44 +02:00
|
|
|
{
|
|
|
|
std::set<RouterID> exclude;
|
2023-09-15 16:55:32 +02:00
|
|
|
auto remainder = num_conns;
|
|
|
|
|
2023-08-28 16:56:44 +02:00
|
|
|
do
|
2019-06-26 23:39:29 +02:00
|
|
|
{
|
2023-08-28 16:56:44 +02:00
|
|
|
auto filter = [exclude](const auto& rc) -> bool { return exclude.count(rc.pubkey) == 0; };
|
|
|
|
|
2023-09-15 16:55:32 +02:00
|
|
|
if (auto maybe_other = node_db->GetRandom(filter))
|
2019-06-26 23:39:29 +02:00
|
|
|
{
|
2023-09-15 16:55:32 +02:00
|
|
|
exclude.insert(maybe_other->pubkey);
|
2023-08-28 16:56:44 +02:00
|
|
|
|
2023-09-15 16:55:32 +02:00
|
|
|
if (not rc_lookup->is_session_allowed(maybe_other->pubkey))
|
|
|
|
continue;
|
2023-08-28 16:56:44 +02:00
|
|
|
|
2023-09-15 16:55:32 +02:00
|
|
|
connect_to(*maybe_other);
|
|
|
|
--remainder;
|
|
|
|
}
|
|
|
|
} while (remainder > 0);
|
2023-08-28 16:56:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2023-09-14 16:54:51 +02:00
|
|
|
LinkManager::recv_data_message(oxen::quic::dgram_interface&, bstring)
|
2023-08-28 16:56:44 +02:00
|
|
|
{
|
2023-08-29 16:26:59 +02:00
|
|
|
// TODO: this
|
2023-08-28 16:56:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2023-09-27 16:09:48 +02:00
|
|
|
LinkManager::handle_find_name(oxen::quic::message m)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
oxenc::bt_dict_consumer btdp{m.body()};
|
|
|
|
std::string name_hash, tx_id;
|
|
|
|
|
|
|
|
if (btdp.skip_until("H"))
|
|
|
|
name_hash = btdp.consume_string();
|
|
|
|
|
|
|
|
if (btdp.skip_until("T"))
|
|
|
|
tx_id = btdp.consume_string();
|
|
|
|
|
|
|
|
router.rpc_client()->LookupLNSNameHash(name_hash, [](auto /* maybe */) {
|
|
|
|
|
|
|
|
});
|
|
|
|
}
|
|
|
|
catch (const std::exception& e)
|
|
|
|
{
|
|
|
|
log::warning(link_cat, "Exception: {}", e.what());
|
|
|
|
m.respond("ERROR", true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
LinkManager::handle_find_router(oxen::quic::message)
|
|
|
|
{}
|
|
|
|
|
|
|
|
void
|
|
|
|
LinkManager::handle_publish_intro(oxen::quic::message m)
|
2023-08-28 16:56:44 +02:00
|
|
|
{
|
2023-09-27 16:09:48 +02:00
|
|
|
std::string introset, tx_id, derived_signing_key, sig;
|
|
|
|
uint64_t is_relayed, relay_order;
|
|
|
|
std::chrono::milliseconds signed_at;
|
|
|
|
|
|
|
|
try
|
2023-09-21 16:20:49 +02:00
|
|
|
{
|
2023-09-27 16:09:48 +02:00
|
|
|
oxenc::bt_dict_consumer btdc_a{m.body()};
|
|
|
|
|
|
|
|
if (btdc_a.skip_until("I"))
|
|
|
|
introset = btdc_a.consume_string();
|
|
|
|
|
|
|
|
if (btdc_a.skip_until("O"))
|
|
|
|
relay_order = btdc_a.consume_integer<uint64_t>();
|
2023-09-21 16:20:49 +02:00
|
|
|
|
2023-09-27 16:09:48 +02:00
|
|
|
if (btdc_a.skip_until("R"))
|
|
|
|
is_relayed = btdc_a.consume_integer<uint64_t>();
|
|
|
|
|
|
|
|
if (btdc_a.skip_until("T"))
|
|
|
|
tx_id = btdc_a.consume_string();
|
|
|
|
|
|
|
|
oxenc::bt_dict_consumer btdc_b{introset};
|
|
|
|
|
|
|
|
if (btdc_b.skip_until("d"))
|
|
|
|
derived_signing_key = btdc_b.consume_string();
|
|
|
|
|
|
|
|
if (btdc_b.skip_until("s"))
|
|
|
|
signed_at = std::chrono::milliseconds{btdc_b.consume_integer<int64_t>()};
|
|
|
|
|
|
|
|
if (btdc_b.skip_until("z"))
|
|
|
|
sig = btdc_b.consume_string();
|
|
|
|
}
|
|
|
|
catch (const std::exception& e)
|
|
|
|
{
|
|
|
|
log::warning(link_cat, "Exception: {}", e.what());
|
|
|
|
m.respond("ERROR", true);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto now = router.now();
|
|
|
|
const auto addr = dht::Key_t{reinterpret_cast<uint8_t*>(derived_signing_key.data())};
|
|
|
|
const auto local_key = router.rc().pubkey;
|
|
|
|
|
|
|
|
if (not service::EncryptedIntroSet::verify(introset, derived_signing_key, sig))
|
|
|
|
{
|
|
|
|
log::error(link_cat, "Received PublishIntroMessage with invalid introset: {}", introset);
|
|
|
|
m.respond("INVALID INTROSET", true);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (now + service::MAX_INTROSET_TIME_DELTA > signed_at + path::DEFAULT_LIFETIME)
|
|
|
|
{
|
|
|
|
log::error(link_cat, "Received PublishIntroMessage with expired introset: {}", introset);
|
|
|
|
m.respond("EXPIRED INTROSET", true);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto closest_rcs = router.node_db()->FindManyClosestTo(addr, INTROSET_STORAGE_REDUNDANCY);
|
|
|
|
|
|
|
|
if (closest_rcs.size() != INTROSET_STORAGE_REDUNDANCY)
|
|
|
|
{
|
|
|
|
log::error(
|
|
|
|
link_cat, "Received PublishIntroMessage but only know {} nodes", closest_rcs.size());
|
|
|
|
m.respond("INSUFFICIENT NODES", true);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_relayed)
|
|
|
|
{
|
|
|
|
if (relay_order >= INTROSET_STORAGE_REDUNDANCY)
|
2023-09-21 16:20:49 +02:00
|
|
|
{
|
2023-09-27 16:09:48 +02:00
|
|
|
log::error(
|
|
|
|
link_cat, "Received PublishIntroMessage with invalide relay order: {}", relay_order);
|
|
|
|
m.respond("INVALID ORDER", true);
|
|
|
|
return;
|
|
|
|
}
|
2023-09-21 16:20:49 +02:00
|
|
|
|
2023-09-27 16:09:48 +02:00
|
|
|
log::info(link_cat, "Relaying PublishIntroMessage for {} (TXID: {})", addr, tx_id);
|
|
|
|
|
|
|
|
const auto& peer_rc = closest_rcs[relay_order];
|
|
|
|
const auto& peer_key = peer_rc.pubkey;
|
|
|
|
|
|
|
|
if (peer_key == local_key)
|
|
|
|
{
|
|
|
|
log::info(
|
|
|
|
link_cat,
|
|
|
|
"Received PublishIntroMessage in which we are peer index {}.. storing introset",
|
|
|
|
relay_order);
|
|
|
|
|
|
|
|
// TODO: replace this concept
|
|
|
|
// dht->services()->PutNode(introset);
|
|
|
|
|
|
|
|
// TODO: should this be a call to send_control_message instead?
|
|
|
|
m.respond("got_intro");
|
2023-09-21 16:20:49 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-09-27 16:09:48 +02:00
|
|
|
log::info(
|
|
|
|
link_cat, "Received PublishIntroMessage; propagating to peer index {}", relay_order);
|
|
|
|
|
|
|
|
send_control_message(
|
|
|
|
peer_key, "publish_intro", std::move(introset), [this](oxen::quic::message m) {
|
|
|
|
return handle_got_intro(std::move(m));
|
|
|
|
});
|
2023-09-21 16:20:49 +02:00
|
|
|
}
|
2023-09-27 16:09:48 +02:00
|
|
|
|
|
|
|
return;
|
2023-09-21 16:20:49 +02:00
|
|
|
}
|
2023-09-27 16:09:48 +02:00
|
|
|
|
|
|
|
int rc_index = -1, index = 0;
|
|
|
|
|
|
|
|
for (const auto& rc : closest_rcs)
|
|
|
|
{
|
|
|
|
if (rc.pubkey == local_key)
|
|
|
|
{
|
|
|
|
rc_index = index;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
++index;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rc_index >= 0)
|
2023-09-21 16:20:49 +02:00
|
|
|
{
|
2023-09-27 16:09:48 +02:00
|
|
|
log::info(link_cat, "Received PublishIntroMessage for {} (TXID: {}); we are candidate {}");
|
|
|
|
|
|
|
|
// TODO: should this be a call to send_control_message instead?
|
|
|
|
m.respond("got_intro");
|
2023-09-21 16:20:49 +02:00
|
|
|
}
|
2023-09-27 16:09:48 +02:00
|
|
|
else
|
|
|
|
log::warning(
|
|
|
|
link_cat,
|
|
|
|
"Received non-relayed PublishIntroMessage from {}; we are not the candidate",
|
|
|
|
addr);
|
2019-06-26 23:39:29 +02:00
|
|
|
}
|
|
|
|
|
2023-09-27 16:09:48 +02:00
|
|
|
void
|
|
|
|
LinkManager::handle_find_intro(oxen::quic::message)
|
|
|
|
{}
|
|
|
|
|
|
|
|
void
|
|
|
|
LinkManager::handle_path_confirm(oxen::quic::message)
|
|
|
|
{}
|
|
|
|
|
|
|
|
void
|
|
|
|
LinkManager::handle_path_latency(oxen::quic::message)
|
|
|
|
{}
|
|
|
|
|
|
|
|
void
|
|
|
|
LinkManager::handle_update_exit(oxen::quic::message)
|
|
|
|
{}
|
|
|
|
|
|
|
|
void
|
|
|
|
LinkManager::handle_obtain_exit(oxen::quic::message)
|
|
|
|
{}
|
|
|
|
|
|
|
|
void
|
|
|
|
LinkManager::handle_close_exit(oxen::quic::message)
|
|
|
|
{}
|
|
|
|
|
|
|
|
void
|
|
|
|
LinkManager::handle_got_intro(oxen::quic::message)
|
|
|
|
{}
|
|
|
|
|
|
|
|
void
|
|
|
|
LinkManager::handle_got_name(oxen::quic::message)
|
|
|
|
{}
|
|
|
|
|
|
|
|
void
|
|
|
|
LinkManager::handle_got_router(oxen::quic::message)
|
|
|
|
{}
|
2019-06-26 23:39:29 +02:00
|
|
|
} // namespace llarp
|