From c1f33bb1acca23e3892b4279b1f5f478b8c055c5 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Wed, 7 Aug 2019 12:33:29 -0400 Subject: [PATCH 01/20] initial mempipe implementation --- include/tuntap.h | 2 +- llarp/CMakeLists.txt | 2 + llarp/config/config.cpp | 21 +- llarp/config/config.hpp | 26 +- llarp/ev/ev_libuv.cpp | 21 +- llarp/link/factory.cpp | 52 +++ llarp/link/factory.hpp | 43 ++ llarp/link/server.hpp | 14 +- llarp/mempipe/mempipe.cpp | 534 +++++++++++++++++++++++ llarp/mempipe/mempipe.hpp | 25 ++ llarp/path/path.cpp | 4 +- llarp/path/path_context.cpp | 17 +- llarp/router/router.cpp | 113 +++-- llarp/router/router.hpp | 3 + llarp/service/endpoint.cpp | 2 +- llarp/service/protocol.cpp | 3 +- llarp/utp/utp.cpp | 14 +- llarp/utp/utp.hpp | 16 +- test/config/test_llarp_config_config.cpp | 6 +- test/link/test_llarp_link.cpp | 27 +- 20 files changed, 830 insertions(+), 115 deletions(-) create mode 100644 llarp/link/factory.cpp create mode 100644 llarp/link/factory.hpp create mode 100644 llarp/mempipe/mempipe.cpp create mode 100644 llarp/mempipe/mempipe.hpp diff --git a/include/tuntap.h b/include/tuntap.h index 8a56eb28e..6cc444a70 100644 --- a/include/tuntap.h +++ b/include/tuntap.h @@ -147,7 +147,7 @@ extern "C" int flags; /* ifr.ifr_flags on Unix */ char if_name[IF_NAMESIZE]; #if defined(Windows) - int idx; /* needed to set ipv6 address */ + int idx; /* needed to set ipv6 address */ #endif #if defined(FreeBSD) int mode; diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index 36510c0e1..a05435ba5 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -178,10 +178,12 @@ set(LIB_SRC iwp/linklayer.cpp iwp/outermessage.cpp iwp/iwp.cpp + link/factory.cpp link/i_link_manager.cpp link/link_manager.cpp link/server.cpp link/session.cpp + mempipe/mempipe.cpp messages/dht_immediate.cpp messages/discard.cpp messages/link_intro.cpp diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp index bf10ff91d..c68204354 100644 --- a/llarp/config/config.cpp +++ b/llarp/config/config.cpp @@ -33,6 +33,11 @@ namespace llarp void RouterConfig::fromSection(string_view key, string_view val) { + if(key == "default-protocol") + { + m_DefaultLinkProto = tostr(val); + LogInfo("overriding default link protocol to '", val, "'"); + } if(key == "netid") { if(val.size() <= NetID::size()) @@ -194,9 +199,8 @@ namespace llarp } void - IwpConfig::fromSection(string_view key, string_view val) + LinksConfig::fromSection(string_view key, string_view val) { - // try IPv4 first uint16_t proto = 0; std::set< std::string > parsed_opts; @@ -215,7 +219,7 @@ namespace llarp parsed_opts.insert(v); } } while(idx != std::string::npos); - + std::set< std::string > opts; /// for each option for(const auto &item : parsed_opts) { @@ -229,15 +233,20 @@ namespace llarp proto = port; } } + else + { + opts.insert(item); + } } if(key == "*") { - m_OutboundPort = proto; + m_OutboundLink = {"*", AF_INET, fromEnv(proto, "OUTBOUND_PORT"), + std::move(opts)}; } else { - m_servers.emplace_back(tostr(key), AF_INET, proto); + m_InboundLinks.emplace_back(tostr(key), AF_INET, proto, std::move(opts)); } } @@ -434,7 +443,7 @@ namespace llarp connect = find_section< ConnectConfig >(parser, "connect"); netdb = find_section< NetdbConfig >(parser, "netdb"); dns = find_section< DnsConfig >(parser, "dns"); - iwp_links = find_section< IwpConfig >(parser, "bind"); + links = find_section< LinksConfig >(parser, "bind"); services = find_section< ServicesConfig >(parser, "services"); system = find_section< SystemConfig >(parser, "system"); metrics = find_section< MetricsConfig >(parser, "metrics"); diff --git a/llarp/config/config.hpp b/llarp/config/config.hpp index 6ed3ee297..916144cee 100644 --- a/llarp/config/config.hpp +++ b/llarp/config/config.hpp @@ -128,6 +128,8 @@ namespace llarp int m_workerThreads = 1; int m_numNetThreads = 1; + std::string m_DefaultLinkProto = "utp"; + public: // clang-format off size_t minConnectedRouters() const { return fromEnv(m_minConnectedRouters, "MIN_CONNECTED_ROUTERS"); } @@ -143,6 +145,7 @@ namespace llarp const AddressInfo& addrInfo() const { return m_addrInfo; } int workerThreads() const { return fromEnv(m_workerThreads, "WORKER_THREADS"); } int numNetThreads() const { return fromEnv(m_numNetThreads, "NUM_NET_THREADS"); } + std::string defaultLinkProto() const { return fromEnv(m_DefaultLinkProto, "LINK_PROTO"); } // clang-format on void @@ -194,20 +197,27 @@ namespace llarp fromSection(string_view key, string_view val); }; - class IwpConfig + class LinksConfig { public: - using Servers = std::vector< std::tuple< std::string, int, uint16_t > >; + static constexpr int Interface = 0; + static constexpr int AddressFamily = 1; + static constexpr int Port = 2; + static constexpr int Options = 3; - private: - uint16_t m_OutboundPort = 0; + using ServerOptions = std::set< std::string >; + using LinkInfo = std::tuple< std::string, int, uint16_t, ServerOptions >; + using Links = std::vector< LinkInfo >; - Servers m_servers; + private: + LinkInfo m_OutboundLink; + Links m_InboundLinks; public: // clang-format off - uint16_t outboundPort() const { return fromEnv(m_OutboundPort, "OUTBOUND_PORT"); } - const Servers& servers() const { return m_servers; } + const LinkInfo& outboundLink() const { return m_OutboundLink; } + + const Links& inboundLinks() const { return m_InboundLinks; } // clang-format on void @@ -306,7 +316,7 @@ namespace llarp ConnectConfig connect; NetdbConfig netdb; DnsConfig dns; - IwpConfig iwp_links; + LinksConfig links; ServicesConfig services; SystemConfig system; MetricsConfig metrics; diff --git a/llarp/ev/ev_libuv.cpp b/llarp/ev/ev_libuv.cpp index feb6221c6..224f0a1aa 100644 --- a/llarp/ev/ev_libuv.cpp +++ b/llarp/ev/ev_libuv.cpp @@ -633,16 +633,17 @@ namespace libuv Loop::CloseAll() { llarp::LogInfo("Closing all handles"); - uv_walk(m_Impl.get(), - [](uv_handle_t* h, void*) { - if(uv_is_closing(h)) - return; - if(h->data && uv_is_active(h)) - { - static_cast< glue* >(h->data)->Close(); - } - }, - nullptr); + uv_walk( + m_Impl.get(), + [](uv_handle_t* h, void*) { + if(uv_is_closing(h)) + return; + if(h->data && uv_is_active(h)) + { + static_cast< glue* >(h->data)->Close(); + } + }, + nullptr); } void diff --git a/llarp/link/factory.cpp b/llarp/link/factory.cpp new file mode 100644 index 000000000..ba71f9a1d --- /dev/null +++ b/llarp/link/factory.cpp @@ -0,0 +1,52 @@ +#include +#include +#include + +namespace llarp +{ + LinkFactory::LinkType + LinkFactory::TypeFromName(string_view str) + { + if(str == "utp") + return LinkType::eLinkUTP; + if(str == "iwp") + return LinkType::eLinkIWP; + if(str == "mempipe") + return LinkType::eLinkMempipe; + return LinkType::eLinkUnknown; + } + + std::string + LinkFactory::NameFromType(LinkFactory::LinkType tp) + { + switch(tp) + { + case LinkType::eLinkUTP: + return "utp"; + case LinkType::eLinkIWP: + return "iwp"; + case LinkType::eLinkMempipe: + return "mempipe"; + default: + return "unspec"; + } + } + + LinkFactory::Factory + LinkFactory::Obtain(LinkFactory::LinkType tp, bool permitInbound) + { + switch(tp) + { + case LinkType::eLinkUTP: + if(permitInbound) + return llarp::utp::NewInboundLink; + return llarp::utp::NewOutboundLink; + case LinkType::eLinkMempipe: + if(permitInbound) + return llarp::mempipe::NewInboundLink; + return llarp::mempipe::NewOutboundLink; + default: + return nullptr; + } + } +} // namespace llarp \ No newline at end of file diff --git a/llarp/link/factory.hpp b/llarp/link/factory.hpp new file mode 100644 index 000000000..5acf3063e --- /dev/null +++ b/llarp/link/factory.hpp @@ -0,0 +1,43 @@ +#ifndef LLARP_LINK_FACTORY_HPP +#define LLARP_LINK_FACTORY_HPP +#include +#include + +#include + +namespace llarp +{ + /// LinkFactory is responsible for returning std::functions that create the + /// link layer types + struct LinkFactory + { + enum class LinkType + { + eLinkUTP, + eLinkIWP, + eLinkMempipe, + eLinkUnknown + }; + + using Factory = std::function< LinkLayer_ptr( + const SecretKey&, GetRCFunc, LinkMessageHandler, SignBufferFunc, + SessionEstablishedHandler, SessionRenegotiateHandler, TimeoutHandler, + SessionClosedHandler) >; + + /// get link type by name string + /// if invalid returns eLinkUnspec + static LinkType + TypeFromName(string_view name); + + /// turns a link type into a string representation + static std::string + NameFromType(LinkType t); + + /// obtain a link factory of a certain type + static Factory + Obtain(LinkType t, bool permitInbound); + }; + +} // namespace llarp + +#endif \ No newline at end of file diff --git a/llarp/link/server.hpp b/llarp/link/server.hpp index 74f3cf3cf..3f12f455d 100644 --- a/llarp/link/server.hpp +++ b/llarp/link/server.hpp @@ -103,7 +103,7 @@ namespace llarp llarp_ev_udp_sendto(&m_udp, to, pkt); } - bool + virtual bool Configure(llarp_ev_loop_ptr loop, const std::string& ifname, int af, uint16_t port); @@ -125,7 +125,7 @@ namespace llarp virtual bool Start(std::shared_ptr< llarp::Logic > l); - void + virtual void Stop(); virtual const char* @@ -140,11 +140,11 @@ namespace llarp void KeepAliveSessionTo(const RouterID& remote); - bool + virtual bool SendTo(const RouterID& remote, const llarp_buffer_t& buf, ILinkSession::CompletionHandler completed); - bool + virtual bool GetOurAddressInfo(AddressInfo& addr) const; bool @@ -200,6 +200,12 @@ namespace llarp SessionClosedHandler SessionClosed; SessionRenegotiateHandler SessionRenegotiate; + std::shared_ptr< Logic > + logic() + { + return m_Logic; + } + bool operator<(const ILinkLayer& other) const { diff --git a/llarp/mempipe/mempipe.cpp b/llarp/mempipe/mempipe.cpp new file mode 100644 index 000000000..58a0a3696 --- /dev/null +++ b/llarp/mempipe/mempipe.cpp @@ -0,0 +1,534 @@ +#include +#include +#include +#include + +namespace llarp +{ + namespace mempipe + { + struct MemLink; + struct MemSession; + + struct MempipeContext + { + using Nodes_t = + std::unordered_map< RouterID, LinkLayer_ptr, RouterID::Hash >; + Nodes_t _nodes; + using SendEvent = std::tuple< RouterID, RouterID, std::vector< byte_t >, + ILinkSession::CompletionHandler >; + + std::deque< SendEvent > _sendQueue; + + /// (src, dst, session, hook) + using NodeConnection_t = std::tuple< RouterID, RouterID >; + + struct NodeConnectionHash + { + size_t + operator()(const NodeConnection_t con) const + { + const auto& a = std::get< 0 >(con); + const auto& b = std::get< 1 >(con); + auto op = std::bit_xor< size_t >(); + return std::accumulate(a.begin(), a.end(), + std::accumulate(b.begin(), b.end(), 0, op), + op); + } + }; + + using NodeConnections_t = + std::unordered_map< NodeConnection_t, std::shared_ptr< MemSession >, + NodeConnectionHash >; + + NodeConnections_t _connections; + + mutable util::Mutex _access; + + void + AddNode(LinkLayer_ptr ptr) LOCKS_EXCLUDED(_access); + + void + RemoveNode(LinkLayer_ptr ptr) LOCKS_EXCLUDED(_access); + + LinkLayer_ptr + FindNode(const RouterID pk) LOCKS_EXCLUDED(_access); + + /// connect src to dst + void + ConnectNode(const RouterID src, const RouterID dst, + const std::shared_ptr< MemSession >& ptr) + LOCKS_EXCLUDED(_access); + + /// remote both src and dst as connected + void + DisconnectNode(const RouterID src, const RouterID dst) + LOCKS_EXCLUDED(_access); + + bool + HasConnection(const RouterID src, const RouterID dst) const + LOCKS_EXCLUDED(_access); + + void + InboundConnection(const RouterID to, + const std::shared_ptr< MemSession >& obsession); + + void + CallLater(std::function< void(void) > f) + { + m_Logic->call_later(10, f); + } + + bool + SendTo(const RouterID src, const RouterID dst, + const std::vector< byte_t > msg, + ILinkSession::CompletionHandler delivery) LOCKS_EXCLUDED(_access); + + void + Pump() LOCKS_EXCLUDED(_access); + + void + Start() + { + m_Run.store(true); + m_Thread = new std::thread{[&]() { + m_Logic = std::make_shared< Logic >(); + while(m_Run.load()) + { + Pump(); + m_Logic->tick(time_now_ms()); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + m_Logic = nullptr; + }}; + } + + ~MempipeContext() + { + m_Run.store(false); + if(m_Thread) + { + m_Thread->join(); + delete m_Thread; + } + } + + std::atomic< bool > m_Run; + std::shared_ptr< Logic > m_Logic = nullptr; + std::thread* m_Thread = nullptr; + }; + + using Globals_ptr = std::unique_ptr< MempipeContext >; + + Globals_ptr _globals; + + struct MemSession : public ILinkSession, + public std::enable_shared_from_this< MemSession > + { + MemSession(LinkLayer_ptr _local, LinkLayer_ptr _remote) + : remote(std::move(_remote)), parent(std::move(_local)) + { + } + + LinkLayer_ptr remote; + LinkLayer_ptr parent; + + util::Mutex _access; + + std::deque< std::vector< byte_t > > m_recvQueue; + std::deque< std::tuple< std::vector< byte_t >, CompletionHandler > > + m_sendQueue; + + llarp_time_t lastRecv = 0; + + PubKey + GetPubKey() const override + { + return remote->GetOurRC().pubkey; + } + + bool + SendKeepAlive() override + { + std::array< byte_t, 128 > pkt; + DiscardMessage msg; + llarp_buffer_t buf{pkt}; + if(!msg.BEncode(&buf)) + return false; + buf.sz = buf.cur - buf.base; + buf.cur = buf.base; + return SendMessageBuffer(buf, nullptr); + } + + void + Recv(const std::vector< byte_t > msg) LOCKS_EXCLUDED(_access) + { + util::Lock lock(&_access); + m_recvQueue.emplace_back(std::move(msg)); + lastRecv = parent->Now(); + } + + void + OnLinkEstablished(ILinkLayer*) override + { + return; + } + + bool + TimedOut(llarp_time_t now) const override + { + return now >= lastRecv && now - lastRecv > 5000; + } + + void + PumpWrite() LOCKS_EXCLUDED(_access) + { + std::deque< std::tuple< std::vector< byte_t >, CompletionHandler > > q; + { + util::Lock lock(&_access); + if(m_sendQueue.size()) + q = std::move(m_sendQueue); + } + const RouterID src = parent->GetOurRC().pubkey; + const RouterID dst = GetPubKey(); + while(q.size()) + { + const auto& f = q.front(); + _globals->SendTo(src, dst, std::get< 0 >(f), std::get< 1 >(f)); + q.pop_front(); + } + } + + void + PumpRead() LOCKS_EXCLUDED(_access) + { + std::deque< std::vector< byte_t > > q; + { + util::Lock lock(&_access); + if(m_recvQueue.size()) + q = std::move(m_recvQueue); + } + while(q.size()) + { + const llarp_buffer_t buf{q.front()}; + parent->HandleMessage(this, buf); + q.pop_front(); + } + } + + void Tick(llarp_time_t) override + { + } + + void + Pump() override + { + PumpRead(); + PumpWrite(); + } + + void + Close() override + { + auto self = shared_from_this(); + _globals->CallLater([=]() { self->Disconnected(); }); + } + + RouterContact + GetRemoteRC() const override + { + return remote->GetOurRC(); + } + + bool + ShouldPing() const override + { + return true; + } + + bool + SendMessageBuffer(const llarp_buffer_t& pkt, + ILinkSession::CompletionHandler completed) override + { + if(completed == nullptr) + completed = [](ILinkSession::DeliveryStatus) {}; + auto self = shared_from_this(); + std::vector< byte_t > buf(pkt.sz); + std::copy_n(pkt.base, pkt.sz, buf.begin()); + return _globals->SendTo(parent->GetOurRC().pubkey, GetRemoteRC().pubkey, + buf, [=](ILinkSession::DeliveryStatus status) { + self->parent->logic()->call_later( + 10, std::bind(completed, status)); + }); + } + + void + Start() override + { + auto self = shared_from_this(); + _globals->CallLater( + [=]() { _globals->InboundConnection(self->GetPubKey(), self); }); + } + + bool + IsEstablished() const override + { + return _globals->HasConnection(parent->GetOurRC().pubkey, GetPubKey()); + } + + void + Disconnected() + { + _globals->DisconnectNode(parent->GetOurRC().pubkey, GetPubKey()); + } + + bool + RenegotiateSession() override + { + return true; + } + + ILinkLayer* + GetLinkLayer() const override + { + return parent.get(); + } + + util::StatusObject + ExtractStatus() const override + { + return {}; + } + + llarp::Addr + GetRemoteEndpoint() const override + { + return {}; + } + + size_t + SendQueueBacklog() const override + { + return m_sendQueue.size(); + } + }; + + struct MemLink : public ILinkLayer, + public std::enable_shared_from_this< MemLink > + { + MemLink(const SecretKey& routerEncSecret, GetRCFunc getrc, + LinkMessageHandler h, SignBufferFunc sign, + SessionEstablishedHandler est, SessionRenegotiateHandler reneg, + TimeoutHandler timeout, SessionClosedHandler closed, + bool permitInbound) + : ILinkLayer(routerEncSecret, getrc, h, sign, est, reneg, timeout, + closed) + , allowInbound(permitInbound) + { + } + + const bool allowInbound; + + bool + KeyGen(SecretKey& k) override + { + k.Zero(); + return true; + } + + const char* + Name() const override + { + return "mempipe"; + } + + uint16_t + Rank() const override + { + return 100; + } + + void + RecvFrom(const llarp::Addr&, const void*, size_t) override + { + } + + bool + Configure(llarp_ev_loop_ptr, const std::string&, int, uint16_t) override + { + if(_globals == nullptr) + _globals = std::make_unique< MempipeContext >(); + return _globals != nullptr; + } + + std::shared_ptr< ILinkSession > + NewOutboundSession(const RouterContact& rc, + const AddressInfo& ai) override + { + if(ai.dialect != Name()) + return nullptr; + auto remote = _globals->FindNode(rc.pubkey); + if(remote == nullptr) + return nullptr; + return std::make_shared< MemSession >(shared_from_this(), remote); + } + + bool + Start(std::shared_ptr< Logic > l) override + { + if(!ILinkLayer::Start(l)) + return false; + _globals->AddNode(shared_from_this()); + return true; + } + + void + Stop() override + { + _globals->RemoveNode(shared_from_this()); + } + }; + + LinkLayer_ptr + NewOutboundLink(const SecretKey& routerEncSecret, GetRCFunc getrc, + LinkMessageHandler h, SignBufferFunc sign, + SessionEstablishedHandler est, + SessionRenegotiateHandler reneg, TimeoutHandler timeout, + SessionClosedHandler closed) + { + return std::make_shared< MemLink >(routerEncSecret, getrc, h, sign, est, + reneg, timeout, closed, false); + } + + LinkLayer_ptr + NewInboundLink(const SecretKey& routerEncSecret, GetRCFunc getrc, + LinkMessageHandler h, SignBufferFunc sign, + SessionEstablishedHandler est, + SessionRenegotiateHandler reneg, TimeoutHandler timeout, + SessionClosedHandler closed) + { + return std::make_shared< MemLink >(routerEncSecret, getrc, h, sign, est, + reneg, timeout, closed, true); + } + + void + MempipeContext::AddNode(LinkLayer_ptr ptr) + { + util::Lock lock(&_access); + _nodes.emplace(RouterID(ptr->GetOurRC().pubkey), ptr); + } + + bool + MempipeContext::SendTo(const RouterID src, const RouterID dst, + const std::vector< byte_t > msg, + ILinkSession::CompletionHandler delivery) + { + util::Lock lock(&_access); + _sendQueue.emplace_back(std::move(src), std::move(dst), std::move(msg), + std::move(delivery)); + return true; + } + + void + MempipeContext::InboundConnection(const RouterID to, + const std::shared_ptr< MemSession >& ob) + { + std::shared_ptr< MemSession > other; + { + util::Lock lock(&_access); + auto itr = _nodes.find(to); + if(itr != _nodes.end()) + { + other = std::make_shared< MemSession >(itr->second, ob->parent); + } + } + if(other) + { + ConnectNode(other->GetPubKey(), ob->GetPubKey(), other); + ConnectNode(ob->GetPubKey(), other->GetPubKey(), ob); + } + else + { + ob->Disconnected(); + } + } + + void + MempipeContext::ConnectNode(const RouterID src, const RouterID dst, + const std::shared_ptr< MemSession >& session) + { + util::Lock lock(&_access); + _connections.emplace(std::make_pair(std::make_tuple(src, dst), session)); + } + + void + MempipeContext::DisconnectNode(const RouterID src, const RouterID dst) + { + util::Lock lock(&_access); + _connections.erase({src, dst}); + } + + LinkLayer_ptr + MempipeContext::FindNode(const RouterID rid) + { + util::Lock lock(&_access); + auto itr = _nodes.find(rid); + if(itr == _nodes.end()) + return nullptr; + return itr->second; + } + + bool + MempipeContext::HasConnection(const RouterID src, const RouterID dst) const + { + util::Lock lock(&_access); + return _connections.find({src, dst}) != _connections.end(); + } + + void + MempipeContext::RemoveNode(LinkLayer_ptr node) + { + util::Lock lock(&_access); + const RouterID pk = node->GetOurRC().pubkey; + _nodes.erase(pk); + auto itr = _connections.begin(); + while(itr != _connections.end()) + { + if(std::get< 0 >(itr->first) == pk || std::get< 1 >(itr->first) == pk) + { + auto s = itr->second->shared_from_this(); + itr->second->GetLinkLayer()->logic()->call_later( + 1, [s]() { s->Disconnected(); }); + } + ++itr; + } + } + + void + MempipeContext::Pump() + { + std::deque< SendEvent > q; + { + util::Lock lock(&_access); + q = std::move(_sendQueue); + } + while(q.size()) + { + const auto& f = q.front(); + { + util::Lock lock(&_access); + auto itr = _connections.find({std::get< 0 >(f), std::get< 1 >(f)}); + ILinkSession::DeliveryStatus status = + ILinkSession::DeliveryStatus::eDeliveryDropped; + if(itr != _connections.end()) + { + status = ILinkSession::DeliveryStatus::eDeliverySuccess; + itr->second->Recv(std::get< 2 >(f)); + } + CallLater(std::bind(std::get< 3 >(f), status)); + } + q.pop_front(); + } + } + } // namespace mempipe +} // namespace llarp \ No newline at end of file diff --git a/llarp/mempipe/mempipe.hpp b/llarp/mempipe/mempipe.hpp new file mode 100644 index 000000000..91094602a --- /dev/null +++ b/llarp/mempipe/mempipe.hpp @@ -0,0 +1,25 @@ +#ifndef LLARP_MEMPIPE_MEMPIPE_HPP +#define LLARP_MEMPIPE_MEMPIPE_HPP +#include +#include + +namespace llarp +{ + namespace mempipe + { + LinkLayer_ptr + NewInboundLink(const SecretKey& routerEncSecret, GetRCFunc getrc, + LinkMessageHandler h, SignBufferFunc sign, + SessionEstablishedHandler est, + SessionRenegotiateHandler reneg, TimeoutHandler timeout, + SessionClosedHandler closed); + LinkLayer_ptr + NewOutboundLink(const SecretKey& routerEncSecret, GetRCFunc getrc, + LinkMessageHandler h, SignBufferFunc sign, + SessionEstablishedHandler est, + SessionRenegotiateHandler reneg, TimeoutHandler timeout, + SessionClosedHandler closed); + } // namespace mempipe +} // namespace llarp + +#endif \ No newline at end of file diff --git a/llarp/path/path.cpp b/llarp/path/path.cpp index 97f69d3fe..c3585cff1 100644 --- a/llarp/path/path.cpp +++ b/llarp/path/path.cpp @@ -103,8 +103,8 @@ namespace llarp } bool - Path::HandleLRSM(uint64_t status, - std::array< EncryptedFrame, 8 >& frames, AbstractRouter* r) + Path::HandleLRSM(uint64_t status, std::array< EncryptedFrame, 8 >& frames, + AbstractRouter* r) { uint64_t currentStatus = status; diff --git a/llarp/path/path_context.cpp b/llarp/path/path_context.cpp index b2460f84b..84a19f575 100644 --- a/llarp/path/path_context.cpp +++ b/llarp/path/path_context.cpp @@ -164,14 +164,15 @@ namespace llarp HopHandler_ptr PathContext::GetByUpstream(const RouterID& remote, const PathID_t& id) { - auto own = MapGet(m_OurPaths, id, - [](const PathSet_ptr) -> bool { - // TODO: is this right? - return true; - }, - [remote, id](PathSet_ptr p) -> HopHandler_ptr { - return p->GetByUpstream(remote, id); - }); + auto own = MapGet( + m_OurPaths, id, + [](const PathSet_ptr) -> bool { + // TODO: is this right? + return true; + }, + [remote, id](PathSet_ptr p) -> HopHandler_ptr { + return p->GetByUpstream(remote, id); + }); if(own) return own; diff --git a/llarp/router/router.cpp b/llarp/router/router.cpp index 686e44d1a..c0207304a 100644 --- a/llarp/router/router.cpp +++ b/llarp/router/router.cpp @@ -368,9 +368,17 @@ namespace llarp // reset netid in our rc _rc.netID = llarp::NetID(); } + const auto linktypename = conf->router.defaultLinkProto(); + _defaultLinkType = LinkFactory::TypeFromName(linktypename); + if(_defaultLinkType == LinkFactory::LinkType::eLinkUnknown) + { + LogError("failed to set link type to '", linktypename, + "' as that is invalid"); + return false; + } // IWP config - m_OutboundPort = conf->iwp_links.outboundPort(); + m_OutboundPort = std::get< LinksConfig::Port >(conf->links.outboundLink()); // Router config _rc.SetNick(conf->router.nickname()); maxConnectedRouters = conf->router.maxConnectedRouters(); @@ -391,7 +399,7 @@ namespace llarp lokidRPCPassword = conf->lokid.lokidRPCPassword; // TODO: add config flag for "is service node" - if(conf->iwp_links.servers().size()) + if(conf->links.inboundLinks().size()) { m_isServiceNode = true; } @@ -479,15 +487,34 @@ namespace llarp } // create inbound links, if we are a service node - for(const auto &serverConfig : conf->iwp_links.servers()) + for(const auto &serverConfig : conf->links.inboundLinks()) { - auto server = llarp::utp::NewInboundLink( + // get default factory + auto inboundLinkFactory = LinkFactory::Obtain(_defaultLinkType, true); + // for each option if provided ... + for(const auto &opt : std::get< LinksConfig::Options >(serverConfig)) + { + // try interpreting it as a link type + const auto linktype = LinkFactory::TypeFromName(opt); + if(linktype != LinkFactory::LinkType::eLinkUnknown) + { + // override link factory if it's a valid link type + auto factory = LinkFactory::Obtain(linktype, true); + if(factory) + { + inboundLinkFactory = std::move(factory); + break; + } + } + } + + auto server = inboundLinkFactory( encryption(), util::memFn(&AbstractRouter::rc, this), util::memFn(&AbstractRouter::HandleRecvLinkMessageBuffer, this), + util::memFn(&AbstractRouter::Sign, this), util::memFn(&IOutboundSessionMaker::OnSessionEstablished, &_outboundSessionMaker), util::memFn(&AbstractRouter::CheckRenegotiateValid, this), - util::memFn(&AbstractRouter::Sign, this), util::memFn(&IOutboundSessionMaker::OnConnectTimeout, &_outboundSessionMaker), util::memFn(&AbstractRouter::SessionClosed, this)); @@ -498,9 +525,9 @@ namespace llarp return false; } - const auto &key = std::get< 0 >(serverConfig); - int af = std::get< 1 >(serverConfig); - uint16_t port = std::get< 2 >(serverConfig); + const auto &key = std::get< LinksConfig::Interface >(serverConfig); + int af = std::get< LinksConfig::AddressFamily >(serverConfig); + uint16_t port = std::get< LinksConfig::Port >(serverConfig); if(!server->Configure(netloop(), key, af, port)) { LogError("failed to bind inbound link on ", key, " port ", port); @@ -1059,48 +1086,44 @@ namespace llarp bool Router::InitOutboundLinks() { - using LinkFactory = std::function< LinkLayer_ptr( - const SecretKey &, GetRCFunc, LinkMessageHandler, - SessionEstablishedHandler, SessionRenegotiateHandler, SignBufferFunc, - TimeoutHandler, SessionClosedHandler) >; + const auto linkTypeName = LinkFactory::NameFromType(_defaultLinkType); + LogInfo("initialize outbound link: ", linkTypeName); + auto factory = LinkFactory::Obtain(_defaultLinkType, false); + if(factory == nullptr) + { + LogError("cannot initialize outbound link of type '", linkTypeName, + "' as it has no implementation"); + return false; + } + auto link = + factory(encryption(), util::memFn(&AbstractRouter::rc, this), + util::memFn(&AbstractRouter::HandleRecvLinkMessageBuffer, this), + util::memFn(&AbstractRouter::Sign, this), + util::memFn(&IOutboundSessionMaker::OnSessionEstablished, + &_outboundSessionMaker), + util::memFn(&AbstractRouter::CheckRenegotiateValid, this), + util::memFn(&IOutboundSessionMaker::OnConnectTimeout, + &_outboundSessionMaker), + util::memFn(&AbstractRouter::SessionClosed, this)); + + if(!link) + return false; + if(!link->EnsureKeys(transport_keyfile.string().c_str())) + { + LogError("failed to load ", transport_keyfile); + return false; + } - static std::list< LinkFactory > linkFactories = {utp::NewOutboundLink, - iwp::NewServer}; + const auto afs = {AF_INET, AF_INET6}; - bool addedAtLeastOne = false; - for(const auto &factory : linkFactories) + for(const auto af : afs) { - auto link = factory( - encryption(), util::memFn(&AbstractRouter::rc, this), - util::memFn(&AbstractRouter::HandleRecvLinkMessageBuffer, this), - util::memFn(&IOutboundSessionMaker::OnSessionEstablished, - &_outboundSessionMaker), - util::memFn(&AbstractRouter::CheckRenegotiateValid, this), - util::memFn(&AbstractRouter::Sign, this), - util::memFn(&IOutboundSessionMaker::OnConnectTimeout, - &_outboundSessionMaker), - util::memFn(&AbstractRouter::SessionClosed, this)); - - if(!link) + if(!link->Configure(netloop(), "*", af, m_OutboundPort)) continue; - if(!link->EnsureKeys(transport_keyfile.string().c_str())) - { - LogError("failed to load ", transport_keyfile); - continue; - } - - const auto afs = {AF_INET, AF_INET6}; - - for(const auto af : afs) - { - if(!link->Configure(netloop(), "*", af, m_OutboundPort)) - continue; - _linkManager.AddLink(std::move(link), false); - addedAtLeastOne = true; - break; - } + _linkManager.AddLink(std::move(link), false); + return true; } - return addedAtLeastOne; + return false; } bool diff --git a/llarp/router/router.hpp b/llarp/router/router.hpp index 2b6b2df86..e4f2fb4d0 100644 --- a/llarp/router/router.hpp +++ b/llarp/router/router.hpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -175,6 +176,8 @@ namespace llarp struct sockaddr_in ip4addr; AddressInfo addrInfo; + LinkFactory::LinkType _defaultLinkType; + llarp_ev_loop_ptr _netloop; std::shared_ptr< llarp::thread::ThreadPool > cryptoworker; std::shared_ptr< Logic > _logic; diff --git a/llarp/service/endpoint.cpp b/llarp/service/endpoint.cpp index f00fb9e9d..f70194c50 100644 --- a/llarp/service/endpoint.cpp +++ b/llarp/service/endpoint.cpp @@ -510,7 +510,7 @@ namespace llarp { auto msg = std::make_shared< routing::DHTMessage >(); msg->M.emplace_back( - std::make_unique< dht::PublishIntroMessage >(m_IntroSet, txid, 1)); + std::make_unique< dht::PublishIntroMessage >(m_IntroSet, txid, 5)); return msg; } diff --git a/llarp/service/protocol.cpp b/llarp/service/protocol.cpp index a42d24aba..31dab271e 100644 --- a/llarp/service/protocol.cpp +++ b/llarp/service/protocol.cpp @@ -309,7 +309,8 @@ namespace llarp if(self->frame.T != self->msg->tag) { - LogError("convotag missmatch: ", self->frame.T, " != ", self->msg->tag); + LogError("convotag missmatch: ", self->frame.T, + " != ", self->msg->tag); self->msg.reset(); delete self; return; diff --git a/llarp/utp/utp.cpp b/llarp/utp/utp.cpp index 01d47502d..911fdc309 100644 --- a/llarp/utp/utp.cpp +++ b/llarp/utp/utp.cpp @@ -10,9 +10,10 @@ namespace llarp { LinkLayer_ptr NewOutboundLink(const SecretKey& routerEncSecret, GetRCFunc getrc, - LinkMessageHandler h, SessionEstablishedHandler est, - SessionRenegotiateHandler reneg, SignBufferFunc sign, - TimeoutHandler timeout, SessionClosedHandler closed) + LinkMessageHandler h, SignBufferFunc sign, + SessionEstablishedHandler est, + SessionRenegotiateHandler reneg, TimeoutHandler timeout, + SessionClosedHandler closed) { return std::make_shared< LinkLayer >(routerEncSecret, getrc, h, sign, est, reneg, timeout, closed, false); @@ -20,9 +21,10 @@ namespace llarp LinkLayer_ptr NewInboundLink(const SecretKey& routerEncSecret, GetRCFunc getrc, - LinkMessageHandler h, SessionEstablishedHandler est, - SessionRenegotiateHandler reneg, SignBufferFunc sign, - TimeoutHandler timeout, SessionClosedHandler closed) + LinkMessageHandler h, SignBufferFunc sign, + SessionEstablishedHandler est, + SessionRenegotiateHandler reneg, TimeoutHandler timeout, + SessionClosedHandler closed) { return std::make_shared< LinkLayer >(routerEncSecret, getrc, h, sign, est, reneg, timeout, closed, true); diff --git a/llarp/utp/utp.hpp b/llarp/utp/utp.hpp index 10857b796..d368065e2 100644 --- a/llarp/utp/utp.hpp +++ b/llarp/utp/utp.hpp @@ -6,20 +6,20 @@ namespace llarp { - struct AbstractRouter; - namespace utp { LinkLayer_ptr NewInboundLink(const SecretKey& routerEncSecret, GetRCFunc getrc, - LinkMessageHandler h, SessionEstablishedHandler est, - SessionRenegotiateHandler reneg, SignBufferFunc sign, - TimeoutHandler timeout, SessionClosedHandler closed); + LinkMessageHandler h, SignBufferFunc sign, + SessionEstablishedHandler est, + SessionRenegotiateHandler reneg, TimeoutHandler timeout, + SessionClosedHandler closed); LinkLayer_ptr NewOutboundLink(const SecretKey& routerEncSecret, GetRCFunc getrc, - LinkMessageHandler h, SessionEstablishedHandler est, - SessionRenegotiateHandler reneg, SignBufferFunc sign, - TimeoutHandler timeout, SessionClosedHandler closed); + LinkMessageHandler h, SignBufferFunc sign, + SessionEstablishedHandler est, + SessionRenegotiateHandler reneg, TimeoutHandler timeout, + SessionClosedHandler closed); /// shim const auto NewServer = NewInboundLink; } // namespace utp diff --git a/test/config/test_llarp_config_config.cpp b/test/config/test_llarp_config_config.cpp index 55eadeb3c..a31a7ed79 100644 --- a/test/config/test_llarp_config_config.cpp +++ b/test/config/test_llarp_config_config.cpp @@ -102,10 +102,10 @@ metric-tank-host=52.80.56.123:2003 ASSERT_FALSE(config.metrics.disableMetrics); { - using kv = IwpConfig::Servers::value_type; + using kv = LinksConfig::Links::value_type; - ASSERT_THAT(config.iwp_links.servers(), - UnorderedElementsAre(kv("eth0", AF_INET, 5501))); + ASSERT_THAT(config.links.inboundLinks(), + UnorderedElementsAre(kv("eth0", AF_INET, 5501, {}))); } ASSERT_THAT(config.bootstrap.routers, diff --git a/test/link/test_llarp_link.cpp b/test/link/test_llarp_link.cpp index 3c83b5050..63aec45f2 100644 --- a/test/link/test_llarp_link.cpp +++ b/test/link/test_llarp_link.cpp @@ -193,14 +193,15 @@ TEST_F(LinkLayerTest, TestUTPAliceRenegWithBob) return true; } }, + [&](Signature& sig, const llarp_buffer_t& buf) -> bool { + return m_crypto.sign(sig, Alice.signingKey, buf); + }, [&](ILinkSession* s) -> bool { const auto rc = s->GetRemoteRC(); return rc.pubkey == Bob.GetRC().pubkey; }, [&](RouterContact, RouterContact) -> bool { return true; }, - [&](Signature& sig, const llarp_buffer_t& buf) -> bool { - return m_crypto.sign(sig, Alice.signingKey, buf); - }, + [&](ILinkSession* session) { ASSERT_FALSE(session->IsEstablished()); Stop(); @@ -231,6 +232,10 @@ TEST_F(LinkLayerTest, TestUTPAliceRenegWithBob) Bob.gotLIM = true; return sendDiscardMessage(s); }, + + [&](Signature& sig, const llarp_buffer_t& buf) -> bool { + return m_crypto.sign(sig, Bob.signingKey, buf); + }, [&](ILinkSession* s) -> bool { if(s->GetRemoteRC().pubkey != Alice.GetRC().pubkey) return false; @@ -242,9 +247,6 @@ TEST_F(LinkLayerTest, TestUTPAliceRenegWithBob) success = newrc.pubkey == oldrc.pubkey; return true; }, - [&](Signature& sig, const llarp_buffer_t& buf) -> bool { - return m_crypto.sign(sig, Bob.signingKey, buf); - }, [&](ILinkSession* session) { ASSERT_FALSE(session->IsEstablished()); }, [&](RouterID router) { ASSERT_EQ(router, Alice.GetRouterID()); }); @@ -280,6 +282,9 @@ TEST_F(LinkLayerTest, TestUTPAliceConnectToBob) return false; } return AliceGotMessage(buf); + }, + [&](Signature& sig, const llarp_buffer_t& buf) -> bool { + return m_crypto.sign(sig, Alice.signingKey, buf); }, [&](ILinkSession* s) -> bool { if(s->GetRemoteRC().pubkey != Bob.GetRC().pubkey) @@ -288,9 +293,7 @@ TEST_F(LinkLayerTest, TestUTPAliceConnectToBob) return true; }, [&](RouterContact, RouterContact) -> bool { return true; }, - [&](Signature& sig, const llarp_buffer_t& buf) -> bool { - return m_crypto.sign(sig, Alice.signingKey, buf); - }, + [&](ILinkSession* session) { ASSERT_FALSE(session->IsEstablished()); Stop(); @@ -312,6 +315,9 @@ TEST_F(LinkLayerTest, TestUTPAliceConnectToBob) return false; } return true; + }, + [&](Signature& sig, const llarp_buffer_t& buf) -> bool { + return m_crypto.sign(sig, Bob.signingKey, buf); }, [&](ILinkSession* s) -> bool { if(s->GetRemoteRC().pubkey != Alice.GetRC().pubkey) @@ -332,9 +338,6 @@ TEST_F(LinkLayerTest, TestUTPAliceConnectToBob) return true; }, [&](RouterContact, RouterContact) -> bool { return true; }, - [&](Signature& sig, const llarp_buffer_t& buf) -> bool { - return m_crypto.sign(sig, Bob.signingKey, buf); - }, [&](ILinkSession* session) { ASSERT_FALSE(session->IsEstablished()); }, [&](RouterID router) { ASSERT_EQ(router, Alice.GetRouterID()); }); From aea4542edd9e7f47f190c4eb9b6fe25824eed85f Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Thu, 22 Aug 2019 07:18:05 -0400 Subject: [PATCH 02/20] more --- llarp/ev/ev.hpp | 5 ++ llarp/ev/ev_libuv.cpp | 81 ++++++++++++++++++++ llarp/ev/ev_libuv.hpp | 4 + llarp/ev/pipe.cpp | 4 +- llarp/ev/pipe.hpp | 2 +- llarp/mempipe/mempipe.cpp | 137 +++++++++++++++++++++++++++------- test/link/test_llarp_link.cpp | 94 +++++++++++++++++++++++ 7 files changed, 295 insertions(+), 32 deletions(-) diff --git a/llarp/ev/ev.hpp b/llarp/ev/ev.hpp index 0a4de55fa..1f610c100 100644 --- a/llarp/ev/ev.hpp +++ b/llarp/ev/ev.hpp @@ -40,6 +40,8 @@ typedef struct sockaddr_un #include #endif +struct llarp_ev_pkt_pipe; + #ifndef MAX_WRITE_QUEUE_SIZE #define MAX_WRITE_QUEUE_SIZE (1024UL) #endif @@ -772,6 +774,9 @@ struct llarp_ev_loop virtual llarp::ev_io* bind_tcp(llarp_tcp_acceptor* tcp, const sockaddr* addr) = 0; + virtual bool + add_pipe(llarp_ev_pkt_pipe* p) = 0; + /// register event listener virtual bool add_ev(llarp::ev_io* ev, bool write) = 0; diff --git a/llarp/ev/ev_libuv.cpp b/llarp/ev/ev_libuv.cpp index 3b9ac4307..93a815892 100644 --- a/llarp/ev/ev_libuv.cpp +++ b/llarp/ev/ev_libuv.cpp @@ -427,6 +427,77 @@ namespace libuv } }; + struct pipe_glue : public glue + { + byte_t m_Buffer[1024 * 8]; + llarp_ev_pkt_pipe* const m_Pipe; + pipe_glue(uv_loop_t* loop, llarp_ev_pkt_pipe* pipe) : m_Pipe(pipe) + { + m_Handle.data = this; + m_Ticker.data = this; + uv_poll_init(loop, &m_Handle, m_Pipe->fd); + uv_check_init(loop, &m_Ticker); + } + + void + Tick() + { + m_Pipe->tick(); + } + + static void + OnRead(uv_poll_t* handle, int status, int) + { + if(status) + { + return; + } + pipe_glue* glue = static_cast< pipe_glue* >(handle->data); + int r = glue->m_Pipe->read(glue->m_Buffer, sizeof(glue->m_Buffer)); + if(r <= 0) + return; + const llarp_buffer_t buf{glue->m_Buffer, size_t{r}}; + glue->m_Pipe->OnRead(buf); + } + + static void + OnClosed(uv_handle_t* h) + { + auto* self = static_cast< pipe_glue* >(h->data); + if(self) + { + h->data = nullptr; + delete self; + } + } + + void + Close() override + { + uv_check_stop(&m_Ticker); + uv_close((uv_handle_t*)&m_Handle, &OnClosed); + } + + static void + OnTick(uv_check_t* h) + { + static_cast< pipe_glue* >(h->data)->Tick(); + } + + bool + Start() + { + if(uv_poll_start(&m_Handle, UV_READABLE, &OnRead)) + return false; + if(uv_check_start(&m_Ticker, &OnTick)) + return false; + return true; + } + + uv_poll_t m_Handle; + uv_check_t m_Ticker; + }; + struct tun_glue : public glue { uv_poll_t m_Handle; @@ -703,4 +774,14 @@ namespace libuv return false; } + bool + Loop::add_pipe(llarp_ev_pkt_pipe* p) + { + auto* glue = new pipe_glue(m_Impl.get(), p); + if(glue->Start()) + return true; + delete glue; + return false; + } + } // namespace libuv diff --git a/llarp/ev/ev_libuv.hpp b/llarp/ev/ev_libuv.hpp index b9b85d3df..3ad9a6389 100644 --- a/llarp/ev/ev_libuv.hpp +++ b/llarp/ev/ev_libuv.hpp @@ -1,6 +1,7 @@ #ifndef LLARP_EV_LIBUV_HPP #define LLARP_EV_LIBUV_HPP #include +#include #include #include #include @@ -68,6 +69,9 @@ namespace libuv bool tcp_listen(llarp_tcp_acceptor* tcp, const sockaddr* addr) override; + bool + add_pipe(llarp_ev_pkt_pipe* p) override; + llarp::ev_io* bind_tcp(llarp_tcp_acceptor*, const sockaddr*) override { diff --git a/llarp/ev/pipe.cpp b/llarp/ev/pipe.cpp index 76d141a9e..049e702ee 100644 --- a/llarp/ev/pipe.cpp +++ b/llarp/ev/pipe.cpp @@ -12,7 +12,7 @@ llarp_ev_pkt_pipe::llarp_ev_pkt_pipe(llarp_ev_loop_ptr loop) } bool -llarp_ev_pkt_pipe::Start() +llarp_ev_pkt_pipe::StartPipe() { #if defined(_WIN32) llarp::LogError("llarp_ev_pkt_pipe not supported on win32"); @@ -26,7 +26,7 @@ llarp_ev_pkt_pipe::Start() } fd = _fds[0]; writefd = _fds[1]; - return true; + return m_Loop->add_pipe(this); #endif } diff --git a/llarp/ev/pipe.hpp b/llarp/ev/pipe.hpp index 0bf1953fc..2abff3c48 100644 --- a/llarp/ev/pipe.hpp +++ b/llarp/ev/pipe.hpp @@ -10,7 +10,7 @@ struct llarp_ev_pkt_pipe : public llarp::ev_io /// start the pipe, initialize fds bool - Start(); + StartPipe(); /// write to the pipe from outside the event loop /// returns true on success diff --git a/llarp/mempipe/mempipe.cpp b/llarp/mempipe/mempipe.cpp index 58a0a3696..3f0042de4 100644 --- a/llarp/mempipe/mempipe.cpp +++ b/llarp/mempipe/mempipe.cpp @@ -2,6 +2,7 @@ #include #include #include +#include namespace llarp { @@ -18,9 +19,8 @@ namespace llarp using SendEvent = std::tuple< RouterID, RouterID, std::vector< byte_t >, ILinkSession::CompletionHandler >; - std::deque< SendEvent > _sendQueue; - /// (src, dst, session, hook) + std::vector< SendEvent > _sendQueue; using NodeConnection_t = std::tuple< RouterID, RouterID >; struct NodeConnectionHash @@ -76,7 +76,10 @@ namespace llarp void CallLater(std::function< void(void) > f) { - m_Logic->call_later(10, f); + if(m_Logic && f) + m_Logic->queue_func(f); + else if(f) + LogError("dropping call"); } bool @@ -88,34 +91,38 @@ namespace llarp Pump() LOCKS_EXCLUDED(_access); void - Start() + Start(llarp_ev_loop_ptr loop) { + evloop = loop; m_Run.store(true); - m_Thread = new std::thread{[&]() { + std::promise< void > p; + m_Thread = std::make_unique< std::thread >([&]() { + LogDebug("mempipe started"); m_Logic = std::make_shared< Logic >(); + p.set_value(); while(m_Run.load()) { - Pump(); m_Logic->tick(time_now_ms()); std::this_thread::sleep_for(std::chrono::milliseconds(1)); + Pump(); } - m_Logic = nullptr; - }}; + m_Logic->stop(); + }); + p.get_future().wait(); + LogDebug("mempipe up"); } ~MempipeContext() { m_Run.store(false); if(m_Thread) - { m_Thread->join(); - delete m_Thread; - } } std::atomic< bool > m_Run; - std::shared_ptr< Logic > m_Logic = nullptr; - std::thread* m_Thread = nullptr; + std::shared_ptr< Logic > m_Logic; + std::unique_ptr< std::thread > m_Thread = nullptr; + llarp_ev_loop_ptr evloop = nullptr; }; using Globals_ptr = std::unique_ptr< MempipeContext >; @@ -123,15 +130,21 @@ namespace llarp Globals_ptr _globals; struct MemSession : public ILinkSession, + public llarp_ev_pkt_pipe, public std::enable_shared_from_this< MemSession > { - MemSession(LinkLayer_ptr _local, LinkLayer_ptr _remote) - : remote(std::move(_remote)), parent(std::move(_local)) + MemSession(llarp_ev_loop_ptr ev, LinkLayer_ptr _local, + LinkLayer_ptr _remote, bool inbound) + : llarp_ev_pkt_pipe(ev) + , remote{std::move(_remote)} + , parent{std::move(_local)} + , isInbound{inbound} { } LinkLayer_ptr remote; LinkLayer_ptr parent; + const bool isInbound; util::Mutex _access; @@ -160,6 +173,15 @@ namespace llarp return SendMessageBuffer(buf, nullptr); } + void + OnRead(const llarp_buffer_t& pkt) override + { + std::vector< byte_t > buf; + buf.resize(pkt.sz); + std::copy_n(pkt.base, pkt.sz, buf.begin()); + Recv(std::move(buf)); + } + void Recv(const std::vector< byte_t > msg) LOCKS_EXCLUDED(_access) { @@ -218,6 +240,7 @@ namespace llarp void Tick(llarp_time_t) override { + Pump(); } void @@ -265,9 +288,16 @@ namespace llarp void Start() override { + if(!StartPipe()) + return; + if(isInbound) + return; + LogDebug("outbound start"); auto self = shared_from_this(); - _globals->CallLater( - [=]() { _globals->InboundConnection(self->GetPubKey(), self); }); + _globals->CallLater([=]() { + LogDebug("Called inbound connection"); + _globals->InboundConnection(self->GetPubKey(), self); + }); } bool @@ -348,16 +378,49 @@ namespace llarp return 100; } + void + Pump() override + { + LogDebug("memlink pump"); + std::set< RouterID > sessions; + { + Lock l(&m_AuthedLinksMutex); + auto itr = m_AuthedLinks.begin(); + while(itr != m_AuthedLinks.end()) + { + sessions.insert(itr->first); + ++itr; + } + } + ILinkLayer::Pump(); + { + Lock l(&m_AuthedLinksMutex); + for(const auto& pk : sessions) + { + if(m_AuthedLinks.count(pk) == 0) + { + // all sessions were removed + SessionClosed(pk); + } + } + } + } + void RecvFrom(const llarp::Addr&, const void*, size_t) override { } bool - Configure(llarp_ev_loop_ptr, const std::string&, int, uint16_t) override + Configure(llarp_ev_loop_ptr ev, const std::string&, int, + uint16_t) override { + m_Loop = ev; if(_globals == nullptr) + { _globals = std::make_unique< MempipeContext >(); + _globals->Start(ev); + } return _globals != nullptr; } @@ -370,7 +433,8 @@ namespace llarp auto remote = _globals->FindNode(rc.pubkey); if(remote == nullptr) return nullptr; - return std::make_shared< MemSession >(shared_from_this(), remote); + return std::make_shared< MemSession >(m_Loop, shared_from_this(), + remote, false); } bool @@ -416,6 +480,7 @@ namespace llarp { util::Lock lock(&_access); _nodes.emplace(RouterID(ptr->GetOurRC().pubkey), ptr); + LogInfo("add mempipe node: ", RouterID(ptr->GetOurRC().pubkey)); } bool @@ -433,19 +498,30 @@ namespace llarp MempipeContext::InboundConnection(const RouterID to, const std::shared_ptr< MemSession >& ob) { + LogDebug("inbound connect to ", to, " from ", + RouterID(ob->parent->GetOurRC().pubkey)); std::shared_ptr< MemSession > other; { util::Lock lock(&_access); auto itr = _nodes.find(to); if(itr != _nodes.end()) { - other = std::make_shared< MemSession >(itr->second, ob->parent); + other = std::make_shared< MemSession >(evloop, itr->second, + ob->parent, true); } } if(other) { ConnectNode(other->GetPubKey(), ob->GetPubKey(), other); ConnectNode(ob->GetPubKey(), other->GetPubKey(), ob); + ob->parent->logic()->queue_func([ob]() { + ob->parent->MapAddr(RouterID{ob->GetPubKey()}, ob.get()); + ob->parent->SessionEstablished(ob.get()); + }); + other->parent->logic()->queue_func([other]() { + other->parent->MapAddr(RouterID{other->GetPubKey()}, other.get()); + other->parent->SessionEstablished(other.get()); + }); } else { @@ -457,6 +533,7 @@ namespace llarp MempipeContext::ConnectNode(const RouterID src, const RouterID dst, const std::shared_ptr< MemSession >& session) { + LogDebug("connect ", src, " to ", dst); util::Lock lock(&_access); _connections.emplace(std::make_pair(std::make_tuple(src, dst), session)); } @@ -464,6 +541,7 @@ namespace llarp void MempipeContext::DisconnectNode(const RouterID src, const RouterID dst) { + LogDebug("connect ", src, " from ", dst); util::Lock lock(&_access); _connections.erase({src, dst}); } @@ -507,27 +585,28 @@ namespace llarp void MempipeContext::Pump() { - std::deque< SendEvent > q; + std::vector< SendEvent > q; { util::Lock lock(&_access); q = std::move(_sendQueue); } - while(q.size()) + for(auto& f : q) { - const auto& f = q.front(); + ILinkSession::DeliveryStatus status = + ILinkSession::DeliveryStatus::eDeliveryDropped; { util::Lock lock(&_access); auto itr = _connections.find({std::get< 0 >(f), std::get< 1 >(f)}); - ILinkSession::DeliveryStatus status = - ILinkSession::DeliveryStatus::eDeliveryDropped; if(itr != _connections.end()) { - status = ILinkSession::DeliveryStatus::eDeliverySuccess; - itr->second->Recv(std::get< 2 >(f)); + const llarp_buffer_t pkt{std::get< 2 >(f)}; + if(itr->second->Write(pkt)) + status = ILinkSession::DeliveryStatus::eDeliverySuccess; } - CallLater(std::bind(std::get< 3 >(f), status)); } - q.pop_front(); + LogDebug(std::get< 0 >(f), "->", std::get< 1 >(f), + " status=", (int)status); + CallLater(std::bind(std::get< 3 >(f), status)); } } } // namespace mempipe diff --git a/test/link/test_llarp_link.cpp b/test/link/test_llarp_link.cpp index 63aec45f2..d214a9cc1 100644 --- a/test/link/test_llarp_link.cpp +++ b/test/link/test_llarp_link.cpp @@ -2,10 +2,12 @@ #include #include #include +#include #include #include #include + #include #include @@ -118,6 +120,7 @@ struct LinkLayerTest : public test::LlarpTest< NoOpCrypto > void SetUp() { + SetLogLevel(eLogDebug); oldRCLifetime = RouterContact::Lifetime; RouterContact::IgnoreBogons = true; RouterContact::Lifetime = 500; @@ -134,6 +137,7 @@ struct LinkLayerTest : public test::LlarpTest< NoOpCrypto > netLoop.reset(); RouterContact::IgnoreBogons = false; RouterContact::Lifetime = oldRCLifetime; + SetLogLevel(eLogInfo); } static void @@ -167,6 +171,96 @@ struct LinkLayerTest : public test::LlarpTest< NoOpCrypto > } }; +TEST_F(LinkLayerTest, TestMemPipe) +{ + Alice.link = mempipe::NewInboundLink( + Alice.encryptionKey, + [&]() -> const RouterContact& { return Alice.GetRC(); }, + [&](ILinkSession* s, const llarp_buffer_t& buf) -> bool { + if(Alice.gotLIM) + { + Alice.Regen(); + return s->RenegotiateSession(); + } + else + { + LinkIntroMessage msg; + ManagedBuffer copy{buf}; + if(!msg.BDecode(©.underlying)) + return false; + if(!s->GotLIM(&msg)) + return false; + Alice.gotLIM = true; + return true; + } + }, + [&](Signature& sig, const llarp_buffer_t& buf) -> bool { + return m_crypto.sign(sig, Alice.signingKey, buf); + }, + [&](ILinkSession* s) -> bool { + const auto rc = s->GetRemoteRC(); + return rc.pubkey == Bob.GetRC().pubkey; + }, + [&](RouterContact, RouterContact) -> bool { return true; }, + + [&](ILinkSession* session) { + ASSERT_FALSE(session->IsEstablished()); + Stop(); + }, + [&](RouterID router) { ASSERT_EQ(router, Bob.GetRouterID()); }); + + auto sendDiscardMessage = [](ILinkSession* s) -> bool { + // send discard message in reply to complete unit test + std::array< byte_t, 32 > tmp; + llarp_buffer_t otherBuf(tmp); + DiscardMessage discard; + if(!discard.BEncode(&otherBuf)) + return false; + otherBuf.sz = otherBuf.cur - otherBuf.base; + otherBuf.cur = otherBuf.base; + return s->SendMessageBuffer(otherBuf, nullptr); + }; + + Bob.link = mempipe::NewInboundLink( + Bob.encryptionKey, [&]() -> const RouterContact& { return Bob.GetRC(); }, + [&](ILinkSession* s, const llarp_buffer_t& buf) -> bool { + LinkIntroMessage msg; + ManagedBuffer copy{buf}; + if(!msg.BDecode(©.underlying)) + return false; + if(!s->GotLIM(&msg)) + return false; + Bob.gotLIM = true; + return sendDiscardMessage(s); + }, + + [&](Signature& sig, const llarp_buffer_t& buf) -> bool { + return m_crypto.sign(sig, Bob.signingKey, buf); + }, + [&](ILinkSession* s) -> bool { + if(s->GetRemoteRC().pubkey != Alice.GetRC().pubkey) + return false; + LogInfo("bob established with alice"); + return Bob.link->VisitSessionByPubkey(Alice.GetRC().pubkey.as_array(), + sendDiscardMessage); + }, + [&](RouterContact newrc, RouterContact oldrc) -> bool { + success = newrc.pubkey == oldrc.pubkey; + return true; + }, + [&](ILinkSession* session) { ASSERT_FALSE(session->IsEstablished()); }, + [&](RouterID router) { ASSERT_EQ(router, Alice.GetRouterID()); }); + + ASSERT_TRUE(Alice.Start(m_logic, netLoop, AlicePort)); + ASSERT_TRUE(Bob.Start(m_logic, netLoop, BobPort)); + + ASSERT_TRUE(Alice.link->TryEstablishTo(Bob.GetRC())); + + RunMainloop(); + ASSERT_TRUE(Bob.gotLIM); + ASSERT_TRUE(success); +}; + TEST_F(LinkLayerTest, TestUTPAliceRenegWithBob) { #ifdef WIN32 From 426ee41c46e809f345ec391b8950885381930cc9 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Thu, 22 Aug 2019 16:53:27 -0400 Subject: [PATCH 03/20] initial iwp --- llarp/CMakeLists.txt | 6 +- llarp/iwp/iwp.cpp | 34 +- llarp/iwp/iwp.hpp | 22 +- llarp/iwp/linklayer.cpp | 143 ++------ llarp/iwp/linklayer.hpp | 43 +-- llarp/iwp/message_buffer.cpp | 160 +++++++++ llarp/iwp/message_buffer.hpp | 97 ++++++ llarp/iwp/outermessage.cpp | 155 --------- llarp/iwp/outermessage.hpp | 86 ----- llarp/iwp/session.cpp | 536 +++++++++++++++++++++++++++++ llarp/iwp/session.hpp | 189 +++++++++++ llarp/link/factory.cpp | 8 +- llarp/link/session.hpp | 9 +- llarp/mempipe/mempipe.cpp | 613 ---------------------------------- llarp/mempipe/mempipe.hpp | 25 -- test/link/test_llarp_link.cpp | 13 +- 16 files changed, 1064 insertions(+), 1075 deletions(-) create mode 100644 llarp/iwp/message_buffer.cpp create mode 100644 llarp/iwp/message_buffer.hpp delete mode 100644 llarp/iwp/outermessage.cpp delete mode 100644 llarp/iwp/outermessage.hpp create mode 100644 llarp/iwp/session.cpp create mode 100644 llarp/iwp/session.hpp delete mode 100644 llarp/mempipe/mempipe.cpp delete mode 100644 llarp/mempipe/mempipe.hpp diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index db3854ce1..fd6a36fbc 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -176,15 +176,15 @@ set(LIB_SRC handlers/null.cpp handlers/tun.cpp hook/shell.cpp - iwp/linklayer.cpp - iwp/outermessage.cpp iwp/iwp.cpp + iwp/linklayer.cpp + iwp/message_buffer.cpp + iwp/session.cpp link/factory.cpp link/i_link_manager.cpp link/link_manager.cpp link/server.cpp link/session.cpp - mempipe/mempipe.cpp messages/dht_immediate.cpp messages/discard.cpp messages/link_intro.cpp diff --git a/llarp/iwp/iwp.cpp b/llarp/iwp/iwp.cpp index 457a51340..eae5384be 100644 --- a/llarp/iwp/iwp.cpp +++ b/llarp/iwp/iwp.cpp @@ -7,22 +7,26 @@ namespace llarp { namespace iwp { - std::unique_ptr< ILinkLayer > - NewServer(const SecretKey& enckey, GetRCFunc getrc, LinkMessageHandler h, - SessionEstablishedHandler est, SessionRenegotiateHandler reneg, - SignBufferFunc sign, TimeoutHandler t, - SessionClosedHandler closed) + LinkLayer_ptr + NewInboundLink(const SecretKey& routerEncSecret, GetRCFunc getrc, + LinkMessageHandler h, SignBufferFunc sign, + SessionEstablishedHandler est, + SessionRenegotiateHandler reneg, TimeoutHandler timeout, + SessionClosedHandler closed) { - (void)enckey; - (void)getrc; - (void)h; - (void)est; - (void)reneg; - (void)sign; - (void)t; - (void)closed; - // TODO: implement me - return nullptr; + return std::make_shared< LinkLayer >(routerEncSecret, getrc, h, sign, est, + reneg, timeout, closed, true); + } + + LinkLayer_ptr + NewOutboundLink(const SecretKey& routerEncSecret, GetRCFunc getrc, + LinkMessageHandler h, SignBufferFunc sign, + SessionEstablishedHandler est, + SessionRenegotiateHandler reneg, TimeoutHandler timeout, + SessionClosedHandler closed) + { + return std::make_shared< LinkLayer >(routerEncSecret, getrc, h, sign, est, + reneg, timeout, closed, false); } } // namespace iwp } // namespace llarp diff --git a/llarp/iwp/iwp.hpp b/llarp/iwp/iwp.hpp index e7a10413e..0e9eacaac 100644 --- a/llarp/iwp/iwp.hpp +++ b/llarp/iwp/iwp.hpp @@ -2,21 +2,25 @@ #define LLARP_IWP_HPP #include - +#include #include namespace llarp { - struct AbstractRouter; - namespace iwp { - std::unique_ptr< ILinkLayer > - NewServer(const SecretKey& routerEncSecret, llarp::GetRCFunc getrc, - llarp::LinkMessageHandler h, llarp::SessionEstablishedHandler est, - llarp::SessionRenegotiateHandler reneg, - llarp::SignBufferFunc sign, llarp::TimeoutHandler timeout, - llarp::SessionClosedHandler closed); + LinkLayer_ptr + NewInboundLink(const SecretKey& routerEncSecret, GetRCFunc getrc, + LinkMessageHandler h, SignBufferFunc sign, + SessionEstablishedHandler est, + SessionRenegotiateHandler reneg, TimeoutHandler timeout, + SessionClosedHandler closed); + LinkLayer_ptr + NewOutboundLink(const SecretKey& routerEncSecret, GetRCFunc getrc, + LinkMessageHandler h, SignBufferFunc sign, + SessionEstablishedHandler est, + SessionRenegotiateHandler reneg, TimeoutHandler timeout, + SessionClosedHandler closed); } // namespace iwp } // namespace llarp diff --git a/llarp/iwp/linklayer.cpp b/llarp/iwp/linklayer.cpp index 8a984d7c4..9de470693 100644 --- a/llarp/iwp/linklayer.cpp +++ b/llarp/iwp/linklayer.cpp @@ -1,16 +1,20 @@ #include +#include namespace llarp { namespace iwp { - LinkLayer::LinkLayer(const SecretKey& enckey, GetRCFunc getrc, - LinkMessageHandler h, SessionEstablishedHandler est, - SessionRenegotiateHandler reneg, SignBufferFunc sign, - TimeoutHandler t, SessionClosedHandler closed) - : ILinkLayer(enckey, getrc, h, sign, est, reneg, t, closed) + LinkLayer::LinkLayer(const SecretKey& routerEncSecret, GetRCFunc getrc, + LinkMessageHandler h, SignBufferFunc sign, + SessionEstablishedHandler est, + SessionRenegotiateHandler reneg, + TimeoutHandler timeout, SessionClosedHandler closed, + bool allowInbound) + : ILinkLayer(routerEncSecret, getrc, h, sign, est, reneg, timeout, + closed) + , permitInbound{allowInbound} { - m_FlowCookie.Randomize(); } LinkLayer::~LinkLayer() = default; @@ -44,135 +48,30 @@ namespace llarp bool LinkLayer::Start(std::shared_ptr< Logic > l) { - if(!ILinkLayer::Start(l)) - return false; - return false; + return ILinkLayer::Start(l); } void LinkLayer::RecvFrom(const Addr& from, const void* pkt, size_t sz) { - m_OuterMsg.Clear(); - llarp_buffer_t sigbuf(pkt, sz); - llarp_buffer_t decodebuf(pkt, sz); - if(!m_OuterMsg.Decode(&decodebuf)) + std::shared_ptr< ILinkSession > session; { - LogError("failed to decode outer message"); - return; - } - NetID ourNetID; - switch(m_OuterMsg.command) - { - case eOCMD_ObtainFlowID: - sigbuf.sz -= m_OuterMsg.Zsig.size(); - if(!CryptoManager::instance()->verify(m_OuterMsg.pubkey, sigbuf, - m_OuterMsg.Zsig)) - { - LogError("failed to verify signature on '", - (char)m_OuterMsg.command, "' message from ", from); - return; - } - if(!ShouldSendFlowID(from)) - { - SendReject(from, "no flo 4u :^)"); - return; - } - if(m_OuterMsg.netid == ourNetID) - { - if(GenFlowIDFor(m_OuterMsg.pubkey, from, m_OuterMsg.flow)) - SendFlowID(from, m_OuterMsg.flow); - else - SendReject(from, "genflow fail"); - } - else - SendReject(from, "bad netid"); + util::Lock lock(&m_PendingMutex); + if(m_Pending.count(from) == 0) + { + m_Pending.insert({from, std::make_shared< Session >(this, from)}); + } + session = m_Pending.find(from)->second; } + const llarp_buffer_t buf{pkt, sz}; + session->Recv_LL(buf); } std::shared_ptr< ILinkSession > LinkLayer::NewOutboundSession(const RouterContact& rc, const AddressInfo& ai) { - (void)rc; - (void)ai; - // TODO: implement me - return {}; - } - - void - LinkLayer::SendFlowID(const Addr& to, const FlowID_t& flow) - { - // TODO: implement me - (void)to; - (void)flow; - } - - bool - LinkLayer::VerifyFlowID(const PubKey& pk, const Addr& from, - const FlowID_t& flow) const - { - FlowID_t expected; - if(!GenFlowIDFor(pk, from, expected)) - return false; - return expected == flow; - } - - bool - LinkLayer::GenFlowIDFor(const PubKey& pk, const Addr& from, - FlowID_t& flow) const - { - std::array< byte_t, 128 > tmp = {{0}}; - if(inet_ntop(AF_INET6, from.addr6(), (char*)tmp.data(), tmp.size()) - == nullptr) - return false; - std::copy_n(pk.begin(), pk.size(), tmp.begin() + 64); - std::copy_n(m_FlowCookie.begin(), m_FlowCookie.size(), - tmp.begin() + 64 + pk.size()); - llarp_buffer_t buf(tmp); - ShortHash h; - if(!CryptoManager::instance()->shorthash(h, buf)) - return false; - std::copy_n(h.begin(), flow.size(), flow.begin()); - return true; - } - - bool - LinkLayer::ShouldSendFlowID(const Addr& to) const - { - (void)to; - // TODO: implement me - return false; - } - - void - LinkLayer::SendReject(const Addr& to, const char* msg) - { - if(strlen(msg) > 14) - { - throw std::logic_error("reject message too big"); - } - std::array< byte_t, 120 > pkt; - auto now = Now(); - PubKey pk = GetOurRC().pubkey; - OuterMessage m; - m.CreateReject(msg, now, pk); - llarp_buffer_t encodebuf(pkt); - if(!m.Encode(&encodebuf)) - { - LogError("failed to encode reject message to ", to); - return; - } - llarp_buffer_t signbuf(pkt.data(), pkt.size() - m.Zsig.size()); - if(!Sign(m.Zsig, signbuf)) - { - LogError("failed to sign reject messsage to ", to); - return; - } - std::copy_n(m.Zsig.begin(), m.Zsig.size(), - pkt.begin() + (pkt.size() - m.Zsig.size())); - llarp_buffer_t pktbuf(pkt); - SendTo_LL(to, pktbuf); + return std::make_shared< Session >(this, rc, ai); } } // namespace iwp - } // namespace llarp diff --git a/llarp/iwp/linklayer.hpp b/llarp/iwp/linklayer.hpp index e7265188e..364716de8 100644 --- a/llarp/iwp/linklayer.hpp +++ b/llarp/iwp/linklayer.hpp @@ -6,7 +6,6 @@ #include #include #include -#include namespace llarp { @@ -14,10 +13,11 @@ namespace llarp { struct LinkLayer final : public ILinkLayer { - LinkLayer(const SecretKey &encryptionSecretKey, GetRCFunc getrc, - LinkMessageHandler h, SessionEstablishedHandler established, - SessionRenegotiateHandler reneg, SignBufferFunc sign, - TimeoutHandler timeout, SessionClosedHandler closed); + LinkLayer(const SecretKey &routerEncSecret, GetRCFunc getrc, + LinkMessageHandler h, SignBufferFunc sign, + SessionEstablishedHandler est, SessionRenegotiateHandler reneg, + TimeoutHandler timeout, SessionClosedHandler closed, + bool permitInbound); ~LinkLayer() override; @@ -40,41 +40,14 @@ namespace llarp uint16_t Rank() const override; - /// verify that a new flow id matches addresses and pubkey - bool - VerifyFlowID(const PubKey &pk, const Addr &from, - const FlowID_t &flow) const; - void RecvFrom(const Addr &from, const void *buf, size_t sz) override; private: - bool - GenFlowIDFor(const PubKey &pk, const Addr &from, FlowID_t &flow) const; - - bool - ShouldSendFlowID(const Addr &from) const; - - void - SendReject(const Addr &to, const char *msg); - - void - SendFlowID(const Addr &to, const FlowID_t &flow); - - using ActiveFlows_t = - std::unordered_map< FlowID_t, RouterID, FlowID_t::Hash >; - - ActiveFlows_t m_ActiveFlows; - - using PendingFlows_t = std::unordered_map< Addr, FlowID_t, Addr::Hash >; - /// flows that are pending authentication - PendingFlows_t m_PendingFlows; - - /// cookie used in flow id computation - AlignedBuffer< 32 > m_FlowCookie; - - OuterMessage m_OuterMsg; + const bool permitInbound; }; + + using LinkLayer_ptr = std::shared_ptr< LinkLayer >; } // namespace iwp } // namespace llarp diff --git a/llarp/iwp/message_buffer.cpp b/llarp/iwp/message_buffer.cpp new file mode 100644 index 000000000..b2ed59a87 --- /dev/null +++ b/llarp/iwp/message_buffer.cpp @@ -0,0 +1,160 @@ +#include +#include + +namespace llarp +{ + namespace iwp + { + OutboundMessage::OutboundMessage() : + m_Size{0} {} + + OutboundMessage::OutboundMessage(uint64_t msgid, const llarp_buffer_t& pkt, + ILinkSession::CompletionHandler handler) : + m_Size{std::min(pkt.sz, MAX_LINK_MSG_SIZE)}, + m_MsgID{msgid}, + m_Completed{handler} + { + m_Data.Zero(); + std::copy_n(pkt.base, m_Size, m_Data.begin()); + } + + std::vector + OutboundMessage::XMIT() const + { + std::vector xmit{LLARP_PROTO_VERSION, Command::eXMIT, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + htobe16buf(xmit.data() + 2, m_Size); + htobe64buf(xmit.data() + 4, m_MsgID); + const llarp_buffer_t buf{m_Data.data(), m_Size}; + ShortHash H; + CryptoManager::instance()->shorthash(H, buf); + std::copy(H.begin(), H.end(), std::back_inserter(xmit)); + LogDebug("xmit H=", H.ToHex()); + return xmit; + } + + void + OutboundMessage::Completed() + { + if(m_Completed) + { + m_Completed(ILinkSession::DeliveryStatus::eDeliverySuccess); + } + m_Completed = nullptr; + } + + bool + OutboundMessage::ShouldFlush(llarp_time_t now) const + { + static constexpr llarp_time_t FlushInterval = 250; + return now - m_LastFlush >= FlushInterval; + } + + void + OutboundMessage::Ack(byte_t bitmask) + { + m_Acks = std::bitset<8>(bitmask); + } + + void + OutboundMessage::FlushUnAcked(std::function sendpkt, llarp_time_t now) + { + uint16_t idx = 0; + while(idx < m_Size) + { + if(not m_Acks[idx / FragmentSize]) + { + std::vector frag{LLARP_PROTO_VERSION, Command::eDATA, 0,0,0,0,0,0,0,0,0,0}; + htobe16buf(frag.data() + 2, idx); + htobe64buf(frag.data() + 4, m_MsgID); + std::copy(m_Data.begin() + idx, m_Data.begin() + idx + FragmentSize, std::back_inserter(frag)); + const llarp_buffer_t pkt{frag}; + sendpkt(pkt); + } + idx += FragmentSize; + } + m_LastFlush = now; + } + + bool + OutboundMessage::IsTransmitted() const + { + for(uint16_t idx = 0; idx < m_Size; idx += FragmentSize) + { + if(!m_Acks.test(idx / FragmentSize)) + return false; + } + return true; + } + + InboundMessage::InboundMessage() : m_Size{0} {} + + InboundMessage::InboundMessage(uint64_t msgid, uint16_t sz, ShortHash h) : + m_Digset{std::move(h)}, + m_Size{sz}, + m_MsgID{msgid} + {} + + void + InboundMessage::HandleData(uint16_t idx, const byte_t * ptr) + { + if(idx + FragmentSize > MAX_LINK_MSG_SIZE) + return; + auto * dst = m_Data.data() + idx; + std::copy_n(ptr, FragmentSize, dst); + m_Acks.set(idx / FragmentSize); + LogDebug("got fragment ", idx / FragmentSize , " of ", m_Size); + } + + + std::vector + InboundMessage::ACKS() const + { + std::vector acks{LLARP_PROTO_VERSION, Command::eACKS, 0, 0, 0, 0, 0, 0, 0, 0, uint8_t{m_Acks.to_ulong()}}; + + htobe64buf(acks.data() + 2, m_MsgID); + return acks; + } + + bool + InboundMessage::IsCompleted() const + { + for(uint16_t idx = 0; idx < m_Size; idx += FragmentSize) + { + if(!m_Acks.test(idx / FragmentSize)) + return false; + } + return true; + } + + bool + InboundMessage::ShouldSendACKS(llarp_time_t now) const + { + return now - m_LastACKSent > 1000 || IsCompleted(); + } + + void + InboundMessage::SendACKS(std::function sendpkt, llarp_time_t now) + { + auto acks = ACKS(); + const llarp_buffer_t pkt{acks}; + sendpkt(pkt); + m_LastACKSent = now; + } + + bool + InboundMessage::Verify() const + { + ShortHash gotten; + const llarp_buffer_t buf{m_Data.data(), m_Size}; + CryptoManager::instance()->shorthash(gotten, buf); + LogDebug("gotten=",gotten.ToHex()); + if(gotten != m_Digset) + { + DumpBuffer(buf); + return false; + } + return true; + } + + } +} \ No newline at end of file diff --git a/llarp/iwp/message_buffer.hpp b/llarp/iwp/message_buffer.hpp new file mode 100644 index 000000000..0d60e9a0a --- /dev/null +++ b/llarp/iwp/message_buffer.hpp @@ -0,0 +1,97 @@ +#ifndef LLARP_IWP_MESSAGE_BUFFER_HPP +#define LLARP_IWP_MESSAGE_BUFFER_HPP +#include +#include +#include +#include +#include +#include + +namespace llarp +{ + namespace iwp + { + enum Command + { + /// keep alive message + ePING = 0, + /// begin transission + eXMIT = 1, + /// fragment data + eDATA = 2, + /// acknolege fragments + eACKS = 3, + /// close session + eCLOS = 4 + }; + + static constexpr size_t FragmentSize = 1024; + + struct OutboundMessage + { + OutboundMessage(); + OutboundMessage(uint64_t msgid, const llarp_buffer_t& pkt, + ILinkSession::CompletionHandler handler); + + AlignedBuffer< MAX_LINK_MSG_SIZE > m_Data; + uint16_t m_Size = 0; + uint64_t m_MsgID = 0; + std::bitset< MAX_LINK_MSG_SIZE / FragmentSize > m_Acks; + ILinkSession::CompletionHandler m_Completed; + llarp_time_t m_LastFlush = 0; + + std::vector + XMIT() const; + + void + Ack(byte_t bitmask); + + void + FlushUnAcked(std::function sendpkt, llarp_time_t now); + + bool + ShouldFlush(llarp_time_t now) const; + + void + Completed(); + + bool + IsTransmitted() const; + }; + + struct InboundMessage + { + InboundMessage(); + InboundMessage(uint64_t msgid, uint16_t sz, ShortHash h); + + AlignedBuffer< MAX_LINK_MSG_SIZE > m_Data; + ShortHash m_Digset; + uint16_t m_Size = 0; + uint64_t m_MsgID = 0; + llarp_time_t m_LastACKSent = 0; + std::bitset< MAX_LINK_MSG_SIZE / FragmentSize > m_Acks; + + void + HandleData(uint16_t idx, const byte_t * ptr); + + bool + IsCompleted() const; + + bool + Verify() const; + + bool + ShouldSendACKS(llarp_time_t now) const; + + void + SendACKS(std::function sendpkt, llarp_time_t now); + + std::vector + ACKS() const; + + }; + + } // namespace iwp +} // namespace llarp + +#endif \ No newline at end of file diff --git a/llarp/iwp/outermessage.cpp b/llarp/iwp/outermessage.cpp deleted file mode 100644 index 3d7ad2af7..000000000 --- a/llarp/iwp/outermessage.cpp +++ /dev/null @@ -1,155 +0,0 @@ -#include -#include - -namespace llarp -{ - namespace iwp - { - std::array< byte_t, 6 > OuterMessage::obtain_flow_id_magic = - std::array< byte_t, 6 >{{'n', 'e', 't', 'i', 'd', '?'}}; - - std::array< byte_t, 6 > OuterMessage::give_flow_id_magic = - std::array< byte_t, 6 >{{'n', 'e', 't', 'i', 'd', '!'}}; - - OuterMessage::OuterMessage() - { - Clear(); - } - - OuterMessage::~OuterMessage() = default; - - void - OuterMessage::Clear() - { - command = 0; - flow.Zero(); - netid.Zero(); - reject.fill(0); - N.Zero(); - X.Zero(); - Xsize = 0; - Zsig.Zero(); - Zhash.Zero(); - pubkey.Zero(); - magic.fill(0); - uinteger = 0; - A.reset(); - } - - void - OuterMessage::CreateReject(const char* msg, llarp_time_t now, - const PubKey& pk) - { - Clear(); - std::copy_n(msg, std::min(strlen(msg), reject.size()), reject.begin()); - uinteger = now; - pubkey = pk; - } - - bool - OuterMessage::Encode(llarp_buffer_t* buf) const - { - if(buf->size_left() < 2) - return false; - *buf->cur = command; - buf->cur++; - *buf->cur = '='; - buf->cur++; - switch(command) - { - case eOCMD_ObtainFlowID: - - case eOCMD_GiveFlowID: - if(!buf->write(reject.begin(), reject.end())) - return false; - if(!buf->write(give_flow_id_magic.begin(), give_flow_id_magic.end())) - return false; - if(!buf->write(flow.begin(), flow.end())) - return false; - if(!buf->write(pubkey.begin(), pubkey.end())) - return false; - return buf->write(Zsig.begin(), Zsig.end()); - default: - return false; - } - } - - bool - OuterMessage::Decode(llarp_buffer_t* buf) - { - static constexpr size_t header_size = 2; - - if(buf->size_left() < header_size) - return false; - command = *buf->cur; - ++buf->cur; - if(*buf->cur != '=') - return false; - ++buf->cur; - switch(command) - { - case eOCMD_ObtainFlowID: - if(!buf->read_into(magic.begin(), magic.end())) - return false; - if(!buf->read_into(netid.begin(), netid.end())) - return false; - if(!buf->read_uint64(uinteger)) - return false; - if(!buf->read_into(pubkey.begin(), pubkey.end())) - return false; - if(buf->size_left() <= Zsig.size()) - return false; - Xsize = buf->size_left() - Zsig.size(); - if(!buf->read_into(X.begin(), X.begin() + Xsize)) - return false; - return buf->read_into(Zsig.begin(), Zsig.end()); - case eOCMD_GiveFlowID: - if(!buf->read_into(magic.begin(), magic.end())) - return false; - if(!buf->read_into(flow.begin(), flow.end())) - return false; - if(!buf->read_into(pubkey.begin(), pubkey.end())) - return false; - buf->cur += buf->size_left() - Zsig.size(); - return buf->read_into(Zsig.begin(), Zsig.end()); - case eOCMD_Reject: - if(!buf->read_into(reject.begin(), reject.end())) - return false; - if(!buf->read_uint64(uinteger)) - return false; - if(!buf->read_into(pubkey.begin(), pubkey.end())) - return false; - buf->cur += buf->size_left() - Zsig.size(); - return buf->read_into(Zsig.begin(), Zsig.end()); - case eOCMD_SessionNegotiate: - if(!buf->read_into(flow.begin(), flow.end())) - return false; - if(!buf->read_into(pubkey.begin(), pubkey.end())) - return false; - if(!buf->read_uint64(uinteger)) - return false; - if(buf->size_left() == Zsig.size() + 32) - { - A = std::make_unique< AlignedBuffer< 32 > >(); - if(!buf->read_into(A->begin(), A->end())) - return false; - } - return buf->read_into(Zsig.begin(), Zsig.end()); - case eOCMD_TransmitData: - if(!buf->read_into(flow.begin(), flow.end())) - return false; - if(!buf->read_into(N.begin(), N.end())) - return false; - if(buf->size_left() <= Zhash.size()) - return false; - Xsize = buf->size_left() - Zhash.size(); - if(!buf->read_into(X.begin(), X.begin() + Xsize)) - return false; - return buf->read_into(Zhash.begin(), Zhash.end()); - default: - return false; - } - } - } // namespace iwp - -} // namespace llarp diff --git a/llarp/iwp/outermessage.hpp b/llarp/iwp/outermessage.hpp deleted file mode 100644 index eefc05593..000000000 --- a/llarp/iwp/outermessage.hpp +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef LLARP_IWP_OUTERMESSAGE_HPP -#define LLARP_IWP_OUTERMESSAGE_HPP - -#include -#include -#include - -#include - -namespace llarp -{ - namespace iwp - { - using FlowID_t = AlignedBuffer< 32 >; - - using OuterCommand_t = byte_t; - - constexpr OuterCommand_t eOCMD_ObtainFlowID = 'O'; - constexpr OuterCommand_t eOCMD_GiveFlowID = 'G'; - constexpr OuterCommand_t eOCMD_Reject = 'R'; - constexpr OuterCommand_t eOCMD_SessionNegotiate = 'S'; - constexpr OuterCommand_t eOCMD_TransmitData = 'D'; - - using InnerCommand_t = byte_t; - - constexpr InnerCommand_t eICMD_KeepAlive = 'k'; - constexpr InnerCommand_t eICMD_KeepAliveAck = 'l'; - constexpr InnerCommand_t eICMD_Congestion = 'c'; - constexpr InnerCommand_t eICMD_AntiCongestion = 'd'; - constexpr InnerCommand_t eICMD_Transmit = 't'; - constexpr InnerCommand_t eICMD_Ack = 'a'; - constexpr InnerCommand_t eICMD_RotateKeys = 'r'; - constexpr InnerCommand_t eICMD_UpgradeProtocol = 'u'; - constexpr InnerCommand_t eICMD_VersionUpgrade = 'v'; - - struct OuterMessage - { - // required members - byte_t command; - FlowID_t flow; - - OuterMessage(); - ~OuterMessage(); - - // static members - static std::array< byte_t, 6 > obtain_flow_id_magic; - static std::array< byte_t, 6 > give_flow_id_magic; - - void - CreateReject(const char *msg, llarp_time_t now, const PubKey &pk); - - // optional members follow - std::array< byte_t, 6 > magic; - NetID netid; - // either timestamp or counter - uint64_t uinteger; - std::array< byte_t, 14 > reject; - AlignedBuffer< 24 > N; - PubKey pubkey; - - std::unique_ptr< AlignedBuffer< 32 > > A; - - static constexpr size_t ipv6_mtu = 1280; - static constexpr size_t overhead_size = 16 + 24 + 32; - static constexpr size_t payload_size = ipv6_mtu - overhead_size; - - AlignedBuffer< payload_size > X; - size_t Xsize; - ShortHash Zhash; - Signature Zsig; - - /// encode to buffer - bool - Encode(llarp_buffer_t *buf) const; - - /// decode from buffer - bool - Decode(llarp_buffer_t *buf); - - /// clear members - void - Clear(); - }; - } // namespace iwp -} // namespace llarp -#endif diff --git a/llarp/iwp/session.cpp b/llarp/iwp/session.cpp new file mode 100644 index 000000000..c81bb0b02 --- /dev/null +++ b/llarp/iwp/session.cpp @@ -0,0 +1,536 @@ +#include +#include +#include + +namespace llarp +{ + namespace iwp + { + static constexpr size_t PacketOverhead = HMACSIZE + TUNNONCESIZE; + + Session::Session(LinkLayer* p, RouterContact rc, AddressInfo ai) + : m_State{State::Initial} + , m_Inbound{false} + , m_Parent{p} + , m_CreatedAt{p->Now()} + , m_RemoteAddr{ai} + , m_ChosenAI{std::move(ai)} + , m_RemoteRC{std::move(rc)} + { + token.Zero(); + GotLIM = util::memFn(&Session::GotOutboundLIM, this); + } + + Session::Session(LinkLayer* p, Addr from) + : m_State{State::Initial} + , m_Inbound{true} + , m_Parent{p} + , m_CreatedAt{p->Now()} + , m_RemoteAddr{from} + { + token.Randomize(); + GotLIM = util::memFn(&Session::GotInboundLIM, this); + } + + Session::~Session() + { + } + + void + Session::Send_LL(const llarp_buffer_t& pkt) + { + LogDebug("send ", pkt.sz, " to ", m_RemoteAddr); + m_Parent->SendTo_LL(m_RemoteAddr, pkt); + m_LastTX = time_now_ms(); + } + + bool + Session::GotInboundLIM(const LinkIntroMessage * msg) + { + if(msg->rc.enckey != m_RemoteOnionKey) + return false; + m_State = State::Ready; + GotLIM = util::memFn(&Session::GotRenegLIM, this); + return true; + } + + bool + Session::GotOutboundLIM(const LinkIntroMessage * msg) + { + if(msg->rc.pubkey != m_RemoteRC.pubkey) + return false; + m_State = State::LinkIntro; + GotLIM = util::memFn(&Session::GotRenegLIM, this); + SendOurLIM(); + return true; + } + + void + Session::SendOurLIM() + { + LinkIntroMessage msg; + msg.rc = m_Parent->GetOurRC(); + msg.N.Randomize(); + msg.P = 60000; + if(not msg.Sign(m_Parent->Sign)) + { + LogError("failed to sign our RC for ", m_RemoteAddr); + return; + } + AlignedBuffer data; + llarp_buffer_t buf{data}; + if(not msg.BEncode(&buf)) + { + LogError("failed to encode LIM for ", m_RemoteAddr); + } + buf.sz = buf.cur - buf.base; + buf.cur = buf.base; + if(!SendMessageBuffer(buf, nullptr)) + { + LogError("failed to send LIM to ", m_RemoteAddr); + } + LogDebug("sent LIM to ", m_RemoteAddr); + } + + void + Session::EncryptAndSend(const llarp_buffer_t& data) + { + + std::vector< byte_t > pkt; + pkt.resize(data.sz + PacketOverhead); + CryptoManager::instance()->randbytes(pkt.data(), pkt.size()); + llarp_buffer_t pktbuf{pkt}; + pktbuf.base += PacketOverhead; + pktbuf.sz -= PacketOverhead; + byte_t* nonce_ptr = pkt.data() + HMACSIZE; + + + CryptoManager::instance()->xchacha20_alt(pktbuf, data, m_SessionKey, + nonce_ptr); + + pktbuf.base = nonce_ptr; + pktbuf.sz = data.sz + 32; + CryptoManager::instance()->hmac(pkt.data(), pktbuf, m_SessionKey); + + pktbuf.base = pkt.data(); + pktbuf.sz = pkt.size(); + Send_LL(pktbuf); + } + + void + Session::Close() + { + if(m_State == State::Closed) + return; + const std::vector close_msg = {LLARP_PROTO_VERSION, Command::eCLOS}; + const llarp_buffer_t buf{close_msg}; + EncryptAndSend(buf); + m_State = State::Closed; + } + + bool + Session::SendMessageBuffer(const llarp_buffer_t& buf, + ILinkSession::CompletionHandler completed) + { + const auto msgid = m_TXID++; + auto& msg = m_TXMsgs.emplace(msgid, OutboundMessage{msgid, buf, completed}) + .first->second; + auto xmit = msg.XMIT(); + const llarp_buffer_t pkt{xmit}; + EncryptAndSend(pkt); + msg.FlushUnAcked(util::memFn(&Session::EncryptAndSend, this), m_Parent->Now()); + LogDebug("send message ", msgid); + return true; + } + + void + Session::Pump() + { + static constexpr llarp_time_t IntroInterval = 500; + const auto now = m_Parent->Now(); + if(m_State == State::Introduction) + { + if(not m_Inbound) + { + // resend intro + if(now - m_LastTX >= IntroInterval) + { + GenerateAndSendIntro(); + } + } + } + else if(m_State == State::Ready || m_State == State::LinkIntro) + { + for(auto itr = m_RXMsgs.begin(); itr != m_RXMsgs.end(); ) + { + if(itr->second.ShouldSendACKS(now)) + { + itr->second.SendACKS(util::memFn(&Session::EncryptAndSend, this), now); + } + if(itr->second.IsCompleted()) + { + if(itr->second.Verify()) + { + const llarp_buffer_t buf{itr->second.m_Data.data(), itr->second.m_Size}; + LogDebug("got message ", itr->first); + m_Parent->HandleMessage(this, buf); + } + else + { + LogError("hash missmatch for message ", itr->first); + } + itr = m_RXMsgs.erase(itr); + continue; + } + ++itr; + } + for(auto itr = m_TXMsgs.begin(); itr != m_TXMsgs.end(); ) + { + if(itr->second.ShouldFlush(now)) + itr->second.FlushUnAcked(util::memFn(&Session::EncryptAndSend, this), now); + if(itr->second.IsTransmitted()) + { + LogDebug("sent message ", itr->first); + itr->second.Completed(); + itr = m_TXMsgs.erase(itr); + continue; + } + ++itr; + } + } + } + + bool + Session::GotRenegLIM(const LinkIntroMessage * lim) + { + return m_Parent->SessionRenegotiate(lim->rc, m_RemoteRC); + } + + bool + Session::RenegotiateSession() + { + SendOurLIM(); + return true; + } + + bool + Session::ShouldPing() const + { + static constexpr llarp_time_t PingInterval = 1000; + const auto now = m_Parent->Now(); + return now - m_LastTX > PingInterval; + } + + util::StatusObject + Session::ExtractStatus() const + { + return { + {"remoteAddr", m_RemoteAddr.ToString()}, + {"remoteRC", m_RemoteRC.ExtractStatus()} + }; + } + + bool + Session::TimedOut(llarp_time_t now) const + { + static constexpr llarp_time_t SessionAliveTimeout = 5000; + if(m_State != State::Ready) + return now - m_CreatedAt > SessionAliveTimeout; + return now - m_LastRX > SessionAliveTimeout; + } + + void + Session::Tick(llarp_time_t) + { + } + + using Introduction = AlignedBuffer<64>; + + void + Session::GenerateAndSendIntro() + { + Introduction intro; + + TunnelNonce N; + N.Randomize(); + if(not CryptoManager::instance()->transport_dh_client(m_SessionKey, m_ChosenAI.pubkey, m_Parent->RouterEncryptionSecret(), N)) + { + LogError("failed to transport_dh_client on outbound session to ", m_RemoteAddr); + return; + } + const auto pk = m_Parent->RouterEncryptionSecret().toPublic(); + std::copy_n(pk.begin(), pk.size(), intro.begin()); + std::copy(N.begin(), N.end(), intro.begin() + 32); + LogDebug("pk=", pk.ToHex(), " N=", N.ToHex(), " remote-pk=", m_ChosenAI.pubkey.ToHex()); + std::vector req; + req.resize(intro.size() + (randint() % 64)); + CryptoManager::instance()->randbytes(req.data(), req.size()); + std::copy_n(intro.begin(), intro.size(), req.begin()); + const llarp_buffer_t buf{req}; + Send_LL(buf); + m_State = State::Introduction; + } + + void + Session::HandleCreateSessionRequest(const llarp_buffer_t & buf) + { + std::vector result; + if(not DecryptMessage(buf, result)) + { + LogError("failed to decrypt session request from ", m_RemoteAddr); + return; + } + if(result.size() < token.size()) + { + LogError("bad session request size, ", result.size(), " < ", token.size(), " from ", m_RemoteAddr); + return; + } + if(not std::equal(result.begin(), result.begin() + token.size(), token.begin())) + { + LogError("token missmatch from ", m_RemoteAddr); + return; + } + SendOurLIM(); + m_State = State::LinkIntro; + } + + void + Session::HandleGotIntro(const llarp_buffer_t & buf) + { + if(buf.sz < Introduction::SIZE) + return; + TunnelNonce N; + std::copy_n(buf.base, PubKey::SIZE, m_RemoteOnionKey.begin()); + std::copy_n(buf.base + PubKey::SIZE, TunnelNonce::SIZE, N.begin()); + const PubKey pk = m_Parent->TransportSecretKey().toPublic(); + LogDebug("remote-pk=", m_RemoteOnionKey.ToHex(), " N=", N.ToHex(), " local-pk=", pk.ToHex()); + if(not CryptoManager::instance()->transport_dh_server(m_SessionKey, m_RemoteOnionKey, m_Parent->TransportSecretKey(), N)) + { + LogError("failed to transport_dh_server on inbound intro from ", m_RemoteAddr); + return; + } + std::vector reply; + reply.resize(token.size() + (randint() % 32)); + CryptoManager::instance()->randbytes(reply.data(), reply.size()); + std::copy_n(token.begin(), token.size(), reply.begin()); + const llarp_buffer_t pkt{reply}; + m_LastRX = m_Parent->Now(); + EncryptAndSend(pkt); + m_State = State::Introduction; + } + + void + Session::HandleGotIntroAck(const llarp_buffer_t & buf) + { + std::vector reply; + if(not DecryptMessage(buf, reply)) + { + LogError("intro ack decrypt failed from ", m_RemoteAddr); + return; + } + if(reply.size() < token.size()) + { + LogError("bad intro ack size ", reply.size(), " < ", token.size(), " from ", m_RemoteAddr); + return; + } + m_LastRX = m_Parent->Now(); + std::copy_n(reply.begin(), token.size(), token.begin()); + const llarp_buffer_t pkt{token}; + EncryptAndSend(pkt); + m_State = State::LinkIntro; + } + + bool + Session::DecryptMessage(const llarp_buffer_t & buf, std::vector & result) + { + if(buf.sz <= PacketOverhead) + return false; + ShortHash H; + llarp_buffer_t curbuf{buf.base, buf.sz}; + curbuf.base += ShortHash::SIZE; + curbuf.sz -= ShortHash::SIZE; + if(not CryptoManager::instance()->hmac(H.data(), curbuf, m_SessionKey)) + { + LogError("failed to caclulate keyed hash for ", m_RemoteAddr); + return false; + } + const ShortHash expected{buf.base}; + if(H != expected) + { + LogError("keyed hash missmatch ", H, " != ", expected, " from ", m_RemoteAddr); + return false; + } + const byte_t * nonce_ptr = curbuf.base; + curbuf.base += 32; + curbuf.sz -= 32; + result.resize(buf.sz - PacketOverhead); + const llarp_buffer_t outbuf{result}; + LogDebug("decrypt: ", result.size(), " bytes from ", m_RemoteAddr); + return CryptoManager::instance()->xchacha20_alt(outbuf, curbuf, m_SessionKey, nonce_ptr); + } + + void + Session::Start() + { + if(m_Inbound) + return; + GenerateAndSendIntro(); + } + + void + Session::HandleSessionData(const llarp_buffer_t & buf) + { + std::vector result; + if(not DecryptMessage(buf, result)) + { + LogError("failed to decrypt session data from ", m_RemoteAddr); + return; + } + if(result[0] != LLARP_PROTO_VERSION) + { + LogError("protocol version missmatch ", int(result[0]), " != ", LLARP_PROTO_VERSION); + return; + } + LogDebug("command ", int(result[1]), " from ", m_RemoteAddr); + switch(result[1]) + { + case Command::eXMIT: + HandleXMIT(std::move(result)); + break; + case Command::eDATA: + HandleDATA(std::move(result)); + break; + case Command::eACKS: + HandleACKS(std::move(result)); + break; + case Command::ePING: + HandlePING(std::move(result)); + break; + case Command::eCLOS: + HandleCLOS(std::move(result)); + break; + default: + LogError("invalid command ", int(result[1])); + } + } + + void + Session::HandleXMIT(std::vector data) + { + if(data.size() < 44) + { + LogError("short XMIT from ", m_RemoteAddr, " ", data.size(), " < 44"); + return; + } + uint16_t sz = bufbe16toh(data.data() + 2); + uint64_t rxid = bufbe64toh(data.data() + 4); + ShortHash h{data.data() + 12}; + LogDebug("rxid=", rxid, " sz=", sz, " h=", h.ToHex()); + m_RXMsgs.emplace(rxid, InboundMessage{rxid, sz, std::move(h)}); + m_LastRX = m_Parent->Now(); + } + + void + Session::HandleDATA(std::vector data) + { + if(data.size() < FragmentSize + 12) + { + LogError("short DATA from ", m_RemoteAddr, " ", data.size(), " < ", FragmentSize + 8); + return; + } + uint16_t sz = bufbe16toh(data.data() + 2); + uint64_t rxid = bufbe64toh(data.data() + 4); + auto itr = m_RXMsgs.find(rxid); + if(itr == m_RXMsgs.end()) + { + LogWarn("no rxid=", rxid, " for ", m_RemoteAddr); + return; + } + itr->second.HandleData(sz, data.data() + 12); + m_LastRX = m_Parent->Now(); + LogDebug(itr->first, " completed=", itr->second.IsCompleted()); + } + + void + Session::HandleACKS(std::vector data) + { + if(data.size() < 11) + { + LogError("short ACKS from ", m_RemoteAddr, " ", data.size(), " < 11"); + return; + } + uint64_t txid = bufbe64toh(data.data() + 2); + auto itr = m_TXMsgs.find(txid); + if(itr == m_TXMsgs.end()) + { + LogWarn("no txid=", txid, " for ", m_RemoteAddr); + return; + } + itr->second.Ack(data[10]); + m_LastRX = m_Parent->Now(); + } + + void + Session::HandleCLOS(std::vector) + { + Close(); + } + + void + Session::HandlePING(std::vector) + { + m_LastRX = m_Parent->Now(); + } + + bool + Session::SendKeepAlive() + { + // TODO: Implement me + return false; + } + + bool + Session::IsEstablished() const + { + return m_State == State::Ready; + } + + void + Session::Recv_LL(const llarp_buffer_t& buf) + { + switch(m_State) + { + case State::Initial: + if(m_Inbound) + { + // initial data + // enter introduction phase + HandleGotIntro(buf); + } + else + { + // this case should never happen + ::abort(); + } + break; + case State::Introduction: + if(m_Inbound) + { + // we are replying to an intro ack + HandleCreateSessionRequest(buf); + } + else + { + // we got an intro ack + // send a session request + HandleGotIntroAck(buf); + } + break; + case State::LinkIntro: + default: + HandleSessionData(buf); + break; + } + } + } // namespace iwp +} // namespace llarp \ No newline at end of file diff --git a/llarp/iwp/session.hpp b/llarp/iwp/session.hpp new file mode 100644 index 000000000..423348bc0 --- /dev/null +++ b/llarp/iwp/session.hpp @@ -0,0 +1,189 @@ +#ifndef LLARP_IWP_SESSION_HPP +#define LLARP_IWP_SESSION_HPP + +#include +#include +#include + +namespace llarp +{ + namespace iwp + { + struct Session : public ILinkSession, + public std::enable_shared_from_this< Session > + { + /// outbound session + Session(LinkLayer* parent, RouterContact rc, AddressInfo ai); + /// inbound session + Session(LinkLayer* parent, Addr from); + + ~Session(); + + void + Pump() override; + + void + Tick(llarp_time_t now) override; + + bool + SendMessageBuffer(const llarp_buffer_t& buf, + CompletionHandler resultHandler) override; + + void + Send_LL(const llarp_buffer_t& pkt); + + void + EncryptAndSend(const llarp_buffer_t& data); + + void + Start() override; + + void + Close() override; + + void + Recv_LL(const llarp_buffer_t& pkt) override; + + bool + SendKeepAlive() override; + + bool + IsEstablished() const override; + + bool + TimedOut(llarp_time_t now) const override; + + PubKey + GetPubKey() const override + { + return m_RemoteRC.pubkey; + } + + Addr + GetRemoteEndpoint() const override + { + return m_RemoteAddr; + } + + RouterContact + GetRemoteRC() const override + { + return m_RemoteRC; + } + + size_t + SendQueueBacklog() const override + { + return m_TXMsgs.size(); + } + + ILinkLayer* + GetLinkLayer() const override + { + return m_Parent; + } + + bool + RenegotiateSession() override; + + bool + ShouldPing() const override; + + util::StatusObject + ExtractStatus() const override; + + private: + enum class State + { + /// we have no data recv'd + Initial, + /// we are in introduction/intro ack phase + Introduction, + /// we sent our LIM + LinkIntro, + /// handshake done and LIM has been obtained + Ready, + /// we are closed now + Closed + }; + State m_State; + /// are we inbound session ? + const bool m_Inbound; + /// parent link layer + LinkLayer* const m_Parent; + const llarp_time_t m_CreatedAt; + const Addr m_RemoteAddr; + + AddressInfo m_ChosenAI; + /// remote rc + RouterContact m_RemoteRC; + /// session key + SharedSecret m_SessionKey; + /// session token + AlignedBuffer<16> token; + + PubKey m_RemoteOnionKey; + + llarp_time_t m_LastTX = 0; + llarp_time_t m_LastRX = 0; + + uint64_t m_TXID = 0; + + std::unordered_map< uint64_t, InboundMessage > m_RXMsgs; + std::unordered_map< uint64_t, OutboundMessage > m_TXMsgs; + + void + HandleGotIntro(const llarp_buffer_t& buf); + + void + HandleGotIntroAck(const llarp_buffer_t& buf); + + void + HandleCreateSessionRequest(const llarp_buffer_t& buf); + + void + ProcessSessionRequest(const llarp_buffer_t& buf); + + void + ProcessCreateSessionReply(const llarp_buffer_t& buf); + + void + HandleSessionData(const llarp_buffer_t& buf); + + bool + DecryptMessage(const llarp_buffer_t & buf, std::vector & result); + + void + GenerateAndSendIntro(); + + bool + GotInboundLIM(const LinkIntroMessage * msg); + + bool + GotOutboundLIM(const LinkIntroMessage * msg); + + bool + GotRenegLIM(const LinkIntroMessage * msg); + + void + SendOurLIM(); + + void + HandleXMIT(std::vector msg); + + void + HandleDATA(std::vector msg); + + void + HandleACKS(std::vector msg); + + void + HandlePING(std::vector msg); + + void + HandleCLOS(std::vector msg); + }; + } // namespace iwp +} // namespace llarp + +#endif \ No newline at end of file diff --git a/llarp/link/factory.cpp b/llarp/link/factory.cpp index ba71f9a1d..734e7b1ef 100644 --- a/llarp/link/factory.cpp +++ b/llarp/link/factory.cpp @@ -1,6 +1,6 @@ #include +#include #include -#include namespace llarp { @@ -41,10 +41,10 @@ namespace llarp if(permitInbound) return llarp::utp::NewInboundLink; return llarp::utp::NewOutboundLink; - case LinkType::eLinkMempipe: + case LinkType::eLinkIWP: if(permitInbound) - return llarp::mempipe::NewInboundLink; - return llarp::mempipe::NewOutboundLink; + return llarp::iwp::NewInboundLink; + return llarp::iwp::NewOutboundLink; default: return nullptr; } diff --git a/llarp/link/session.hpp b/llarp/link/session.hpp index 39dc1ae96..73a6efe3e 100644 --- a/llarp/link/session.hpp +++ b/llarp/link/session.hpp @@ -27,7 +27,7 @@ namespace llarp /// hook for utp for when we have established a connection virtual void - OnLinkEstablished(ILinkLayer *p) = 0; + OnLinkEstablished(ILinkLayer *){}; /// called every event loop tick virtual void @@ -50,6 +50,13 @@ namespace llarp virtual void Close() = 0; + /// recv packet on low layer + /// not used by utp + virtual void + Recv_LL(const llarp_buffer_t &) + { + } + /// send a keepalive to the remote endpoint virtual bool SendKeepAlive() = 0; diff --git a/llarp/mempipe/mempipe.cpp b/llarp/mempipe/mempipe.cpp deleted file mode 100644 index 3f0042de4..000000000 --- a/llarp/mempipe/mempipe.cpp +++ /dev/null @@ -1,613 +0,0 @@ -#include -#include -#include -#include -#include - -namespace llarp -{ - namespace mempipe - { - struct MemLink; - struct MemSession; - - struct MempipeContext - { - using Nodes_t = - std::unordered_map< RouterID, LinkLayer_ptr, RouterID::Hash >; - Nodes_t _nodes; - using SendEvent = std::tuple< RouterID, RouterID, std::vector< byte_t >, - ILinkSession::CompletionHandler >; - - /// (src, dst, session, hook) - std::vector< SendEvent > _sendQueue; - using NodeConnection_t = std::tuple< RouterID, RouterID >; - - struct NodeConnectionHash - { - size_t - operator()(const NodeConnection_t con) const - { - const auto& a = std::get< 0 >(con); - const auto& b = std::get< 1 >(con); - auto op = std::bit_xor< size_t >(); - return std::accumulate(a.begin(), a.end(), - std::accumulate(b.begin(), b.end(), 0, op), - op); - } - }; - - using NodeConnections_t = - std::unordered_map< NodeConnection_t, std::shared_ptr< MemSession >, - NodeConnectionHash >; - - NodeConnections_t _connections; - - mutable util::Mutex _access; - - void - AddNode(LinkLayer_ptr ptr) LOCKS_EXCLUDED(_access); - - void - RemoveNode(LinkLayer_ptr ptr) LOCKS_EXCLUDED(_access); - - LinkLayer_ptr - FindNode(const RouterID pk) LOCKS_EXCLUDED(_access); - - /// connect src to dst - void - ConnectNode(const RouterID src, const RouterID dst, - const std::shared_ptr< MemSession >& ptr) - LOCKS_EXCLUDED(_access); - - /// remote both src and dst as connected - void - DisconnectNode(const RouterID src, const RouterID dst) - LOCKS_EXCLUDED(_access); - - bool - HasConnection(const RouterID src, const RouterID dst) const - LOCKS_EXCLUDED(_access); - - void - InboundConnection(const RouterID to, - const std::shared_ptr< MemSession >& obsession); - - void - CallLater(std::function< void(void) > f) - { - if(m_Logic && f) - m_Logic->queue_func(f); - else if(f) - LogError("dropping call"); - } - - bool - SendTo(const RouterID src, const RouterID dst, - const std::vector< byte_t > msg, - ILinkSession::CompletionHandler delivery) LOCKS_EXCLUDED(_access); - - void - Pump() LOCKS_EXCLUDED(_access); - - void - Start(llarp_ev_loop_ptr loop) - { - evloop = loop; - m_Run.store(true); - std::promise< void > p; - m_Thread = std::make_unique< std::thread >([&]() { - LogDebug("mempipe started"); - m_Logic = std::make_shared< Logic >(); - p.set_value(); - while(m_Run.load()) - { - m_Logic->tick(time_now_ms()); - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - Pump(); - } - m_Logic->stop(); - }); - p.get_future().wait(); - LogDebug("mempipe up"); - } - - ~MempipeContext() - { - m_Run.store(false); - if(m_Thread) - m_Thread->join(); - } - - std::atomic< bool > m_Run; - std::shared_ptr< Logic > m_Logic; - std::unique_ptr< std::thread > m_Thread = nullptr; - llarp_ev_loop_ptr evloop = nullptr; - }; - - using Globals_ptr = std::unique_ptr< MempipeContext >; - - Globals_ptr _globals; - - struct MemSession : public ILinkSession, - public llarp_ev_pkt_pipe, - public std::enable_shared_from_this< MemSession > - { - MemSession(llarp_ev_loop_ptr ev, LinkLayer_ptr _local, - LinkLayer_ptr _remote, bool inbound) - : llarp_ev_pkt_pipe(ev) - , remote{std::move(_remote)} - , parent{std::move(_local)} - , isInbound{inbound} - { - } - - LinkLayer_ptr remote; - LinkLayer_ptr parent; - const bool isInbound; - - util::Mutex _access; - - std::deque< std::vector< byte_t > > m_recvQueue; - std::deque< std::tuple< std::vector< byte_t >, CompletionHandler > > - m_sendQueue; - - llarp_time_t lastRecv = 0; - - PubKey - GetPubKey() const override - { - return remote->GetOurRC().pubkey; - } - - bool - SendKeepAlive() override - { - std::array< byte_t, 128 > pkt; - DiscardMessage msg; - llarp_buffer_t buf{pkt}; - if(!msg.BEncode(&buf)) - return false; - buf.sz = buf.cur - buf.base; - buf.cur = buf.base; - return SendMessageBuffer(buf, nullptr); - } - - void - OnRead(const llarp_buffer_t& pkt) override - { - std::vector< byte_t > buf; - buf.resize(pkt.sz); - std::copy_n(pkt.base, pkt.sz, buf.begin()); - Recv(std::move(buf)); - } - - void - Recv(const std::vector< byte_t > msg) LOCKS_EXCLUDED(_access) - { - util::Lock lock(&_access); - m_recvQueue.emplace_back(std::move(msg)); - lastRecv = parent->Now(); - } - - void - OnLinkEstablished(ILinkLayer*) override - { - return; - } - - bool - TimedOut(llarp_time_t now) const override - { - return now >= lastRecv && now - lastRecv > 5000; - } - - void - PumpWrite() LOCKS_EXCLUDED(_access) - { - std::deque< std::tuple< std::vector< byte_t >, CompletionHandler > > q; - { - util::Lock lock(&_access); - if(m_sendQueue.size()) - q = std::move(m_sendQueue); - } - const RouterID src = parent->GetOurRC().pubkey; - const RouterID dst = GetPubKey(); - while(q.size()) - { - const auto& f = q.front(); - _globals->SendTo(src, dst, std::get< 0 >(f), std::get< 1 >(f)); - q.pop_front(); - } - } - - void - PumpRead() LOCKS_EXCLUDED(_access) - { - std::deque< std::vector< byte_t > > q; - { - util::Lock lock(&_access); - if(m_recvQueue.size()) - q = std::move(m_recvQueue); - } - while(q.size()) - { - const llarp_buffer_t buf{q.front()}; - parent->HandleMessage(this, buf); - q.pop_front(); - } - } - - void Tick(llarp_time_t) override - { - Pump(); - } - - void - Pump() override - { - PumpRead(); - PumpWrite(); - } - - void - Close() override - { - auto self = shared_from_this(); - _globals->CallLater([=]() { self->Disconnected(); }); - } - - RouterContact - GetRemoteRC() const override - { - return remote->GetOurRC(); - } - - bool - ShouldPing() const override - { - return true; - } - - bool - SendMessageBuffer(const llarp_buffer_t& pkt, - ILinkSession::CompletionHandler completed) override - { - if(completed == nullptr) - completed = [](ILinkSession::DeliveryStatus) {}; - auto self = shared_from_this(); - std::vector< byte_t > buf(pkt.sz); - std::copy_n(pkt.base, pkt.sz, buf.begin()); - return _globals->SendTo(parent->GetOurRC().pubkey, GetRemoteRC().pubkey, - buf, [=](ILinkSession::DeliveryStatus status) { - self->parent->logic()->call_later( - 10, std::bind(completed, status)); - }); - } - - void - Start() override - { - if(!StartPipe()) - return; - if(isInbound) - return; - LogDebug("outbound start"); - auto self = shared_from_this(); - _globals->CallLater([=]() { - LogDebug("Called inbound connection"); - _globals->InboundConnection(self->GetPubKey(), self); - }); - } - - bool - IsEstablished() const override - { - return _globals->HasConnection(parent->GetOurRC().pubkey, GetPubKey()); - } - - void - Disconnected() - { - _globals->DisconnectNode(parent->GetOurRC().pubkey, GetPubKey()); - } - - bool - RenegotiateSession() override - { - return true; - } - - ILinkLayer* - GetLinkLayer() const override - { - return parent.get(); - } - - util::StatusObject - ExtractStatus() const override - { - return {}; - } - - llarp::Addr - GetRemoteEndpoint() const override - { - return {}; - } - - size_t - SendQueueBacklog() const override - { - return m_sendQueue.size(); - } - }; - - struct MemLink : public ILinkLayer, - public std::enable_shared_from_this< MemLink > - { - MemLink(const SecretKey& routerEncSecret, GetRCFunc getrc, - LinkMessageHandler h, SignBufferFunc sign, - SessionEstablishedHandler est, SessionRenegotiateHandler reneg, - TimeoutHandler timeout, SessionClosedHandler closed, - bool permitInbound) - : ILinkLayer(routerEncSecret, getrc, h, sign, est, reneg, timeout, - closed) - , allowInbound(permitInbound) - { - } - - const bool allowInbound; - - bool - KeyGen(SecretKey& k) override - { - k.Zero(); - return true; - } - - const char* - Name() const override - { - return "mempipe"; - } - - uint16_t - Rank() const override - { - return 100; - } - - void - Pump() override - { - LogDebug("memlink pump"); - std::set< RouterID > sessions; - { - Lock l(&m_AuthedLinksMutex); - auto itr = m_AuthedLinks.begin(); - while(itr != m_AuthedLinks.end()) - { - sessions.insert(itr->first); - ++itr; - } - } - ILinkLayer::Pump(); - { - Lock l(&m_AuthedLinksMutex); - for(const auto& pk : sessions) - { - if(m_AuthedLinks.count(pk) == 0) - { - // all sessions were removed - SessionClosed(pk); - } - } - } - } - - void - RecvFrom(const llarp::Addr&, const void*, size_t) override - { - } - - bool - Configure(llarp_ev_loop_ptr ev, const std::string&, int, - uint16_t) override - { - m_Loop = ev; - if(_globals == nullptr) - { - _globals = std::make_unique< MempipeContext >(); - _globals->Start(ev); - } - return _globals != nullptr; - } - - std::shared_ptr< ILinkSession > - NewOutboundSession(const RouterContact& rc, - const AddressInfo& ai) override - { - if(ai.dialect != Name()) - return nullptr; - auto remote = _globals->FindNode(rc.pubkey); - if(remote == nullptr) - return nullptr; - return std::make_shared< MemSession >(m_Loop, shared_from_this(), - remote, false); - } - - bool - Start(std::shared_ptr< Logic > l) override - { - if(!ILinkLayer::Start(l)) - return false; - _globals->AddNode(shared_from_this()); - return true; - } - - void - Stop() override - { - _globals->RemoveNode(shared_from_this()); - } - }; - - LinkLayer_ptr - NewOutboundLink(const SecretKey& routerEncSecret, GetRCFunc getrc, - LinkMessageHandler h, SignBufferFunc sign, - SessionEstablishedHandler est, - SessionRenegotiateHandler reneg, TimeoutHandler timeout, - SessionClosedHandler closed) - { - return std::make_shared< MemLink >(routerEncSecret, getrc, h, sign, est, - reneg, timeout, closed, false); - } - - LinkLayer_ptr - NewInboundLink(const SecretKey& routerEncSecret, GetRCFunc getrc, - LinkMessageHandler h, SignBufferFunc sign, - SessionEstablishedHandler est, - SessionRenegotiateHandler reneg, TimeoutHandler timeout, - SessionClosedHandler closed) - { - return std::make_shared< MemLink >(routerEncSecret, getrc, h, sign, est, - reneg, timeout, closed, true); - } - - void - MempipeContext::AddNode(LinkLayer_ptr ptr) - { - util::Lock lock(&_access); - _nodes.emplace(RouterID(ptr->GetOurRC().pubkey), ptr); - LogInfo("add mempipe node: ", RouterID(ptr->GetOurRC().pubkey)); - } - - bool - MempipeContext::SendTo(const RouterID src, const RouterID dst, - const std::vector< byte_t > msg, - ILinkSession::CompletionHandler delivery) - { - util::Lock lock(&_access); - _sendQueue.emplace_back(std::move(src), std::move(dst), std::move(msg), - std::move(delivery)); - return true; - } - - void - MempipeContext::InboundConnection(const RouterID to, - const std::shared_ptr< MemSession >& ob) - { - LogDebug("inbound connect to ", to, " from ", - RouterID(ob->parent->GetOurRC().pubkey)); - std::shared_ptr< MemSession > other; - { - util::Lock lock(&_access); - auto itr = _nodes.find(to); - if(itr != _nodes.end()) - { - other = std::make_shared< MemSession >(evloop, itr->second, - ob->parent, true); - } - } - if(other) - { - ConnectNode(other->GetPubKey(), ob->GetPubKey(), other); - ConnectNode(ob->GetPubKey(), other->GetPubKey(), ob); - ob->parent->logic()->queue_func([ob]() { - ob->parent->MapAddr(RouterID{ob->GetPubKey()}, ob.get()); - ob->parent->SessionEstablished(ob.get()); - }); - other->parent->logic()->queue_func([other]() { - other->parent->MapAddr(RouterID{other->GetPubKey()}, other.get()); - other->parent->SessionEstablished(other.get()); - }); - } - else - { - ob->Disconnected(); - } - } - - void - MempipeContext::ConnectNode(const RouterID src, const RouterID dst, - const std::shared_ptr< MemSession >& session) - { - LogDebug("connect ", src, " to ", dst); - util::Lock lock(&_access); - _connections.emplace(std::make_pair(std::make_tuple(src, dst), session)); - } - - void - MempipeContext::DisconnectNode(const RouterID src, const RouterID dst) - { - LogDebug("connect ", src, " from ", dst); - util::Lock lock(&_access); - _connections.erase({src, dst}); - } - - LinkLayer_ptr - MempipeContext::FindNode(const RouterID rid) - { - util::Lock lock(&_access); - auto itr = _nodes.find(rid); - if(itr == _nodes.end()) - return nullptr; - return itr->second; - } - - bool - MempipeContext::HasConnection(const RouterID src, const RouterID dst) const - { - util::Lock lock(&_access); - return _connections.find({src, dst}) != _connections.end(); - } - - void - MempipeContext::RemoveNode(LinkLayer_ptr node) - { - util::Lock lock(&_access); - const RouterID pk = node->GetOurRC().pubkey; - _nodes.erase(pk); - auto itr = _connections.begin(); - while(itr != _connections.end()) - { - if(std::get< 0 >(itr->first) == pk || std::get< 1 >(itr->first) == pk) - { - auto s = itr->second->shared_from_this(); - itr->second->GetLinkLayer()->logic()->call_later( - 1, [s]() { s->Disconnected(); }); - } - ++itr; - } - } - - void - MempipeContext::Pump() - { - std::vector< SendEvent > q; - { - util::Lock lock(&_access); - q = std::move(_sendQueue); - } - for(auto& f : q) - { - ILinkSession::DeliveryStatus status = - ILinkSession::DeliveryStatus::eDeliveryDropped; - { - util::Lock lock(&_access); - auto itr = _connections.find({std::get< 0 >(f), std::get< 1 >(f)}); - if(itr != _connections.end()) - { - const llarp_buffer_t pkt{std::get< 2 >(f)}; - if(itr->second->Write(pkt)) - status = ILinkSession::DeliveryStatus::eDeliverySuccess; - } - } - LogDebug(std::get< 0 >(f), "->", std::get< 1 >(f), - " status=", (int)status); - CallLater(std::bind(std::get< 3 >(f), status)); - } - } - } // namespace mempipe -} // namespace llarp \ No newline at end of file diff --git a/llarp/mempipe/mempipe.hpp b/llarp/mempipe/mempipe.hpp deleted file mode 100644 index 91094602a..000000000 --- a/llarp/mempipe/mempipe.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef LLARP_MEMPIPE_MEMPIPE_HPP -#define LLARP_MEMPIPE_MEMPIPE_HPP -#include -#include - -namespace llarp -{ - namespace mempipe - { - LinkLayer_ptr - NewInboundLink(const SecretKey& routerEncSecret, GetRCFunc getrc, - LinkMessageHandler h, SignBufferFunc sign, - SessionEstablishedHandler est, - SessionRenegotiateHandler reneg, TimeoutHandler timeout, - SessionClosedHandler closed); - LinkLayer_ptr - NewOutboundLink(const SecretKey& routerEncSecret, GetRCFunc getrc, - LinkMessageHandler h, SignBufferFunc sign, - SessionEstablishedHandler est, - SessionRenegotiateHandler reneg, TimeoutHandler timeout, - SessionClosedHandler closed); - } // namespace mempipe -} // namespace llarp - -#endif \ No newline at end of file diff --git a/test/link/test_llarp_link.cpp b/test/link/test_llarp_link.cpp index d214a9cc1..5f03069fb 100644 --- a/test/link/test_llarp_link.cpp +++ b/test/link/test_llarp_link.cpp @@ -1,8 +1,8 @@ -#include +#include #include #include #include -#include +#include #include #include #include @@ -15,7 +15,7 @@ using namespace ::llarp; using namespace ::testing; -struct LinkLayerTest : public test::LlarpTest< NoOpCrypto > +struct LinkLayerTest : public test::LlarpTest< llarp::sodium::CryptoLibSodium > { static constexpr uint16_t AlicePort = 5000; static constexpr uint16_t BobPort = 6000; @@ -171,9 +171,9 @@ struct LinkLayerTest : public test::LlarpTest< NoOpCrypto > } }; -TEST_F(LinkLayerTest, TestMemPipe) +TEST_F(LinkLayerTest, TestIWP) { - Alice.link = mempipe::NewInboundLink( + Alice.link = iwp::NewInboundLink( Alice.encryptionKey, [&]() -> const RouterContact& { return Alice.GetRC(); }, [&](ILinkSession* s, const llarp_buffer_t& buf) -> bool { @@ -221,7 +221,7 @@ TEST_F(LinkLayerTest, TestMemPipe) return s->SendMessageBuffer(otherBuf, nullptr); }; - Bob.link = mempipe::NewInboundLink( + Bob.link = iwp::NewInboundLink( Bob.encryptionKey, [&]() -> const RouterContact& { return Bob.GetRC(); }, [&](ILinkSession* s, const llarp_buffer_t& buf) -> bool { LinkIntroMessage msg; @@ -258,7 +258,6 @@ TEST_F(LinkLayerTest, TestMemPipe) RunMainloop(); ASSERT_TRUE(Bob.gotLIM); - ASSERT_TRUE(success); }; TEST_F(LinkLayerTest, TestUTPAliceRenegWithBob) From ba316f85ba7d584d19ba64dec4fac5cc28a9dd3f Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Thu, 22 Aug 2019 16:56:27 -0400 Subject: [PATCH 04/20] default to iwp --- llarp/config/config.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llarp/config/config.hpp b/llarp/config/config.hpp index 2a618154e..56f199d45 100644 --- a/llarp/config/config.hpp +++ b/llarp/config/config.hpp @@ -118,7 +118,7 @@ namespace llarp int m_workerThreads = 1; int m_numNetThreads = 1; - std::string m_DefaultLinkProto = "utp"; + std::string m_DefaultLinkProto = "iwp"; public: // clang-format off From acf5f789499056728c83bd8fe678376511e1615a Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Fri, 23 Aug 2019 07:32:52 -0400 Subject: [PATCH 05/20] update iwp , add NACK --- llarp/iwp/linklayer.cpp | 52 +++- llarp/iwp/linklayer.hpp | 7 + llarp/iwp/message_buffer.cpp | 128 +++++---- llarp/iwp/message_buffer.hpp | 37 +-- llarp/iwp/session.cpp | 329 +++++++++++++++--------- llarp/iwp/session.hpp | 52 ++-- llarp/link/link_manager.cpp | 5 +- llarp/link/server.hpp | 2 +- llarp/router/outbound_session_maker.cpp | 2 + llarp/router/outbound_session_maker.hpp | 7 + llarp/router/router.cpp | 2 +- 11 files changed, 392 insertions(+), 231 deletions(-) diff --git a/llarp/iwp/linklayer.cpp b/llarp/iwp/linklayer.cpp index 9de470693..57d0c499a 100644 --- a/llarp/iwp/linklayer.cpp +++ b/llarp/iwp/linklayer.cpp @@ -22,7 +22,28 @@ namespace llarp void LinkLayer::Pump() { + std::set< RouterID > sessions; + { + Lock l(&m_AuthedLinksMutex); + auto itr = m_AuthedLinks.begin(); + while(itr != m_AuthedLinks.end()) + { + sessions.insert(itr->first); + ++itr; + } + } ILinkLayer::Pump(); + { + Lock l(&m_AuthedLinksMutex); + for(const auto& pk : sessions) + { + if(m_AuthedLinks.count(pk) == 0) + { + // all sessions were removed + SessionClosed(pk); + } + } + } } const char* @@ -55,16 +76,43 @@ namespace llarp LinkLayer::RecvFrom(const Addr& from, const void* pkt, size_t sz) { std::shared_ptr< ILinkSession > session; + auto itr = m_AuthedAddrs.find(from); + if(itr == m_AuthedAddrs.end()) { util::Lock lock(&m_PendingMutex); if(m_Pending.count(from) == 0) { + if(not permitInbound) + return; m_Pending.insert({from, std::make_shared< Session >(this, from)}); } session = m_Pending.find(from)->second; } - const llarp_buffer_t buf{pkt, sz}; - session->Recv_LL(buf); + else + { + auto range = m_AuthedLinks.equal_range(itr->second); + session = range.first->second; + } + if(session) + { + const llarp_buffer_t buf{pkt, sz}; + session->Recv_LL(buf); + } + } + + bool + LinkLayer::MapAddr(const RouterID& r, ILinkSession* s) + { + if(!ILinkLayer::MapAddr(r, s)) + return false; + m_AuthedAddrs.emplace(s->GetRemoteEndpoint(), r); + return true; + } + + void + LinkLayer::UnmapAddr(const Addr& a) + { + m_AuthedAddrs.erase(a); } std::shared_ptr< ILinkSession > diff --git a/llarp/iwp/linklayer.hpp b/llarp/iwp/linklayer.hpp index 364716de8..13ecf3ecf 100644 --- a/llarp/iwp/linklayer.hpp +++ b/llarp/iwp/linklayer.hpp @@ -43,7 +43,14 @@ namespace llarp void RecvFrom(const Addr &from, const void *buf, size_t sz) override; + bool + MapAddr(const RouterID &pk, ILinkSession *s) override; + + void + UnmapAddr(const Addr &addr); + private: + std::unordered_map< Addr, RouterID, Addr::Hash > m_AuthedAddrs; const bool permitInbound; }; diff --git a/llarp/iwp/message_buffer.cpp b/llarp/iwp/message_buffer.cpp index b2ed59a87..283bb3b91 100644 --- a/llarp/iwp/message_buffer.cpp +++ b/llarp/iwp/message_buffer.cpp @@ -5,23 +5,25 @@ namespace llarp { namespace iwp { - OutboundMessage::OutboundMessage() : - m_Size{0} {} - - OutboundMessage::OutboundMessage(uint64_t msgid, const llarp_buffer_t& pkt, - ILinkSession::CompletionHandler handler) : - m_Size{std::min(pkt.sz, MAX_LINK_MSG_SIZE)}, - m_MsgID{msgid}, - m_Completed{handler} - { - m_Data.Zero(); - std::copy_n(pkt.base, m_Size, m_Data.begin()); - } - - std::vector - OutboundMessage::XMIT() const - { - std::vector xmit{LLARP_PROTO_VERSION, Command::eXMIT, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + OutboundMessage::OutboundMessage() : m_Size{0} + { + } + + OutboundMessage::OutboundMessage(uint64_t msgid, const llarp_buffer_t &pkt, + ILinkSession::CompletionHandler handler) + : m_Size{std::min(pkt.sz, MAX_LINK_MSG_SIZE)} + , m_MsgID{msgid} + , m_Completed{handler} + { + m_Data.Zero(); + std::copy_n(pkt.base, m_Size, m_Data.begin()); + } + + std::vector< byte_t > + OutboundMessage::XMIT() const + { + std::vector< byte_t > xmit{ + LLARP_PROTO_VERSION, Command::eXMIT, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; htobe16buf(xmit.data() + 2, m_Size); htobe64buf(xmit.data() + 4, m_MsgID); const llarp_buffer_t buf{m_Data.data(), m_Size}; @@ -33,7 +35,7 @@ namespace llarp } void - OutboundMessage::Completed() + OutboundMessage::Completed() { if(m_Completed) { @@ -45,28 +47,41 @@ namespace llarp bool OutboundMessage::ShouldFlush(llarp_time_t now) const { - static constexpr llarp_time_t FlushInterval = 250; + static constexpr llarp_time_t FlushInterval = 500; return now - m_LastFlush >= FlushInterval; } - void + void OutboundMessage::Ack(byte_t bitmask) { - m_Acks = std::bitset<8>(bitmask); + m_Acks = std::bitset< 8 >(bitmask); } - void - OutboundMessage::FlushUnAcked(std::function sendpkt, llarp_time_t now) + void + OutboundMessage::FlushUnAcked( + std::function< void(const llarp_buffer_t &) > sendpkt, llarp_time_t now) { uint16_t idx = 0; while(idx < m_Size) { if(not m_Acks[idx / FragmentSize]) { - std::vector frag{LLARP_PROTO_VERSION, Command::eDATA, 0,0,0,0,0,0,0,0,0,0}; + std::vector< byte_t > frag{LLARP_PROTO_VERSION, + Command::eDATA, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0}; htobe16buf(frag.data() + 2, idx); htobe64buf(frag.data() + 4, m_MsgID); - std::copy(m_Data.begin() + idx, m_Data.begin() + idx + FragmentSize, std::back_inserter(frag)); + std::copy(m_Data.begin() + idx, m_Data.begin() + idx + FragmentSize, + std::back_inserter(frag)); const llarp_buffer_t pkt{frag}; sendpkt(pkt); } @@ -75,47 +90,49 @@ namespace llarp m_LastFlush = now; } - bool - OutboundMessage::IsTransmitted() const - { - for(uint16_t idx = 0; idx < m_Size; idx += FragmentSize) - { - if(!m_Acks.test(idx / FragmentSize)) - return false; + bool + OutboundMessage::IsTransmitted() const + { + for(uint16_t idx = 0; idx < m_Size; idx += FragmentSize) + { + if(!m_Acks.test(idx / FragmentSize)) + return false; + } + return true; } - return true; - } - InboundMessage::InboundMessage() : m_Size{0} {} + InboundMessage::InboundMessage() : m_Size{0} + { + } - InboundMessage::InboundMessage(uint64_t msgid, uint16_t sz, ShortHash h) : - m_Digset{std::move(h)}, - m_Size{sz}, - m_MsgID{msgid} - {} + InboundMessage::InboundMessage(uint64_t msgid, uint16_t sz, ShortHash h) + : m_Digset{std::move(h)}, m_Size{sz}, m_MsgID{msgid} + { + } - void - InboundMessage::HandleData(uint16_t idx, const byte_t * ptr) + void + InboundMessage::HandleData(uint16_t idx, const byte_t *ptr) { if(idx + FragmentSize > MAX_LINK_MSG_SIZE) return; - auto * dst = m_Data.data() + idx; + auto *dst = m_Data.data() + idx; std::copy_n(ptr, FragmentSize, dst); m_Acks.set(idx / FragmentSize); - LogDebug("got fragment ", idx / FragmentSize , " of ", m_Size); + LogDebug("got fragment ", idx / FragmentSize, " of ", m_Size); } - - std::vector - InboundMessage::ACKS() const + std::vector< byte_t > + InboundMessage::ACKS() const { - std::vector acks{LLARP_PROTO_VERSION, Command::eACKS, 0, 0, 0, 0, 0, 0, 0, 0, uint8_t{m_Acks.to_ulong()}}; - + std::vector< byte_t > acks{ + LLARP_PROTO_VERSION, Command::eACKS, 0, 0, 0, 0, 0, 0, 0, 0, + uint8_t{m_Acks.to_ulong()}}; + htobe64buf(acks.data() + 2, m_MsgID); return acks; } - bool + bool InboundMessage::IsCompleted() const { for(uint16_t idx = 0; idx < m_Size; idx += FragmentSize) @@ -133,7 +150,8 @@ namespace llarp } void - InboundMessage::SendACKS(std::function sendpkt, llarp_time_t now) + InboundMessage::SendACKS( + std::function< void(const llarp_buffer_t &) > sendpkt, llarp_time_t now) { auto acks = ACKS(); const llarp_buffer_t pkt{acks}; @@ -141,13 +159,13 @@ namespace llarp m_LastACKSent = now; } - bool + bool InboundMessage::Verify() const { ShortHash gotten; const llarp_buffer_t buf{m_Data.data(), m_Size}; CryptoManager::instance()->shorthash(gotten, buf); - LogDebug("gotten=",gotten.ToHex()); + LogDebug("gotten=", gotten.ToHex()); if(gotten != m_Digset) { DumpBuffer(buf); @@ -156,5 +174,5 @@ namespace llarp return true; } - } -} \ No newline at end of file + } // namespace iwp +} // namespace llarp \ No newline at end of file diff --git a/llarp/iwp/message_buffer.hpp b/llarp/iwp/message_buffer.hpp index 0d60e9a0a..8082fb706 100644 --- a/llarp/iwp/message_buffer.hpp +++ b/llarp/iwp/message_buffer.hpp @@ -21,8 +21,10 @@ namespace llarp eDATA = 2, /// acknolege fragments eACKS = 3, + /// negative ack + eNACK = 4, /// close session - eCLOS = 4 + eCLOS = 5 }; static constexpr size_t FragmentSize = 1024; @@ -30,26 +32,27 @@ namespace llarp struct OutboundMessage { OutboundMessage(); - OutboundMessage(uint64_t msgid, const llarp_buffer_t& pkt, + OutboundMessage(uint64_t msgid, const llarp_buffer_t &pkt, ILinkSession::CompletionHandler handler); AlignedBuffer< MAX_LINK_MSG_SIZE > m_Data; - uint16_t m_Size = 0; + uint16_t m_Size = 0; uint64_t m_MsgID = 0; std::bitset< MAX_LINK_MSG_SIZE / FragmentSize > m_Acks; ILinkSession::CompletionHandler m_Completed; llarp_time_t m_LastFlush = 0; - std::vector + std::vector< byte_t > XMIT() const; void Ack(byte_t bitmask); - void - FlushUnAcked(std::function sendpkt, llarp_time_t now); + void + FlushUnAcked(std::function< void(const llarp_buffer_t &) > sendpkt, + llarp_time_t now); - bool + bool ShouldFlush(llarp_time_t now) const; void @@ -66,29 +69,29 @@ namespace llarp AlignedBuffer< MAX_LINK_MSG_SIZE > m_Data; ShortHash m_Digset; - uint16_t m_Size = 0; - uint64_t m_MsgID = 0; + uint16_t m_Size = 0; + uint64_t m_MsgID = 0; llarp_time_t m_LastACKSent = 0; std::bitset< MAX_LINK_MSG_SIZE / FragmentSize > m_Acks; void - HandleData(uint16_t idx, const byte_t * ptr); + HandleData(uint16_t idx, const byte_t *ptr); - bool + bool IsCompleted() const; - bool + bool Verify() const; - bool + bool ShouldSendACKS(llarp_time_t now) const; - void - SendACKS(std::function sendpkt, llarp_time_t now); + void + SendACKS(std::function< void(const llarp_buffer_t &) > sendpkt, + llarp_time_t now); - std::vector + std::vector< byte_t > ACKS() const; - }; } // namespace iwp diff --git a/llarp/iwp/session.cpp b/llarp/iwp/session.cpp index c81bb0b02..3321c8a7b 100644 --- a/llarp/iwp/session.cpp +++ b/llarp/iwp/session.cpp @@ -1,6 +1,7 @@ #include #include #include +#include namespace llarp { @@ -45,28 +46,44 @@ namespace llarp } bool - Session::GotInboundLIM(const LinkIntroMessage * msg) + Session::GotInboundLIM(const LinkIntroMessage* msg) { if(msg->rc.enckey != m_RemoteOnionKey) + { + LogError("key missmatch"); return false; - m_State = State::Ready; - GotLIM = util::memFn(&Session::GotRenegLIM, this); - return true; + } + m_State = State::Ready; + GotLIM = util::memFn(&Session::GotRenegLIM, this); + m_RemoteRC = msg->rc; + m_Parent->MapAddr(m_RemoteRC.pubkey, this); + return m_Parent->SessionEstablished(this); } bool - Session::GotOutboundLIM(const LinkIntroMessage * msg) + Session::GotOutboundLIM(const LinkIntroMessage* msg) { if(msg->rc.pubkey != m_RemoteRC.pubkey) + { + LogError("ident key missmatch"); return false; - m_State = State::LinkIntro; - GotLIM = util::memFn(&Session::GotRenegLIM, this); - SendOurLIM(); + } + m_RemoteRC = msg->rc; + GotLIM = util::memFn(&Session::GotRenegLIM, this); + auto self = shared_from_this(); + SendOurLIM([self](ILinkSession::DeliveryStatus st) { + if(st == ILinkSession::DeliveryStatus::eDeliverySuccess) + { + self->m_State = State::Ready; + self->m_Parent->MapAddr(self->m_RemoteRC.pubkey, self.get()); + self->m_Parent->SessionEstablished(self.get()); + } + }); return true; } void - Session::SendOurLIM() + Session::SendOurLIM(ILinkSession::CompletionHandler h) { LinkIntroMessage msg; msg.rc = m_Parent->GetOurRC(); @@ -77,15 +94,15 @@ namespace llarp LogError("failed to sign our RC for ", m_RemoteAddr); return; } - AlignedBuffer data; + AlignedBuffer< LinkIntroMessage::MaxSize > data; llarp_buffer_t buf{data}; if(not msg.BEncode(&buf)) { LogError("failed to encode LIM for ", m_RemoteAddr); } - buf.sz = buf.cur - buf.base; + buf.sz = buf.cur - buf.base; buf.cur = buf.base; - if(!SendMessageBuffer(buf, nullptr)) + if(!SendMessageBuffer(buf, h)) { LogError("failed to send LIM to ", m_RemoteAddr); } @@ -95,7 +112,6 @@ namespace llarp void Session::EncryptAndSend(const llarp_buffer_t& data) { - std::vector< byte_t > pkt; pkt.resize(data.sz + PacketOverhead); CryptoManager::instance()->randbytes(pkt.data(), pkt.size()); @@ -104,16 +120,15 @@ namespace llarp pktbuf.sz -= PacketOverhead; byte_t* nonce_ptr = pkt.data() + HMACSIZE; - CryptoManager::instance()->xchacha20_alt(pktbuf, data, m_SessionKey, nonce_ptr); pktbuf.base = nonce_ptr; - pktbuf.sz = data.sz + 32; + pktbuf.sz = data.sz + 32; CryptoManager::instance()->hmac(pkt.data(), pktbuf, m_SessionKey); pktbuf.base = pkt.data(); - pktbuf.sz = pkt.size(); + pktbuf.sz = pkt.size(); Send_LL(pktbuf); } @@ -122,10 +137,14 @@ namespace llarp { if(m_State == State::Closed) return; - const std::vector close_msg = {LLARP_PROTO_VERSION, Command::eCLOS}; + const std::vector< byte_t > close_msg = {LLARP_PROTO_VERSION, + Command::eCLOS}; const llarp_buffer_t buf{close_msg}; EncryptAndSend(buf); + if(m_State == State::Ready) + m_Parent->UnmapAddr(m_RemoteAddr); m_State = State::Closed; + LogInfo("closing connection to ", m_RemoteAddr); } bool @@ -133,12 +152,14 @@ namespace llarp ILinkSession::CompletionHandler completed) { const auto msgid = m_TXID++; - auto& msg = m_TXMsgs.emplace(msgid, OutboundMessage{msgid, buf, completed}) - .first->second; - auto xmit = msg.XMIT(); + auto& msg = + m_TXMsgs.emplace(msgid, OutboundMessage{msgid, buf, completed}) + .first->second; + const auto xmit = msg.XMIT(); const llarp_buffer_t pkt{xmit}; EncryptAndSend(pkt); - msg.FlushUnAcked(util::memFn(&Session::EncryptAndSend, this), m_Parent->Now()); + msg.FlushUnAcked(util::memFn(&Session::EncryptAndSend, this), + m_Parent->Now()); LogDebug("send message ", msgid); return true; } @@ -146,67 +167,34 @@ namespace llarp void Session::Pump() { - static constexpr llarp_time_t IntroInterval = 500; const auto now = m_Parent->Now(); - if(m_State == State::Introduction) + if(m_State == State::Ready || m_State == State::LinkIntro) { - if(not m_Inbound) - { - // resend intro - if(now - m_LastTX >= IntroInterval) - { - GenerateAndSendIntro(); - } - } - } - else if(m_State == State::Ready || m_State == State::LinkIntro) - { - for(auto itr = m_RXMsgs.begin(); itr != m_RXMsgs.end(); ) + for(auto itr = m_RXMsgs.begin(); itr != m_RXMsgs.end(); ++itr) { if(itr->second.ShouldSendACKS(now)) { - itr->second.SendACKS(util::memFn(&Session::EncryptAndSend, this), now); - } - if(itr->second.IsCompleted()) - { - if(itr->second.Verify()) - { - const llarp_buffer_t buf{itr->second.m_Data.data(), itr->second.m_Size}; - LogDebug("got message ", itr->first); - m_Parent->HandleMessage(this, buf); - } - else - { - LogError("hash missmatch for message ", itr->first); - } - itr = m_RXMsgs.erase(itr); - continue; + itr->second.SendACKS(util::memFn(&Session::EncryptAndSend, this), + now); } - ++itr; } - for(auto itr = m_TXMsgs.begin(); itr != m_TXMsgs.end(); ) + for(auto itr = m_TXMsgs.begin(); itr != m_TXMsgs.end(); ++itr) { if(itr->second.ShouldFlush(now)) - itr->second.FlushUnAcked(util::memFn(&Session::EncryptAndSend, this), now); - if(itr->second.IsTransmitted()) - { - LogDebug("sent message ", itr->first); - itr->second.Completed(); - itr = m_TXMsgs.erase(itr); - continue; - } - ++itr; + itr->second.FlushUnAcked( + util::memFn(&Session::EncryptAndSend, this), now); } } } - bool - Session::GotRenegLIM(const LinkIntroMessage * lim) + bool + Session::GotRenegLIM(const LinkIntroMessage* lim) { + LogInfo("renegotiate session on ", m_RemoteAddr); return m_Parent->SessionRenegotiate(lim->rc, m_RemoteRC); } - bool + bool Session::RenegotiateSession() { SendOurLIM(); @@ -216,65 +204,73 @@ namespace llarp bool Session::ShouldPing() const { - static constexpr llarp_time_t PingInterval = 1000; - const auto now = m_Parent->Now(); - return now - m_LastTX > PingInterval; + if(m_State == State::Ready || m_State == State::LinkIntro) + { + static constexpr llarp_time_t PingInterval = 500; + const auto now = m_Parent->Now(); + return now - m_LastTX > PingInterval; + } + return false; } util::StatusObject Session::ExtractStatus() const { - return { - {"remoteAddr", m_RemoteAddr.ToString()}, - {"remoteRC", m_RemoteRC.ExtractStatus()} - }; + return {{"remoteAddr", m_RemoteAddr.ToString()}, + {"remoteRC", m_RemoteRC.ExtractStatus()}}; } bool Session::TimedOut(llarp_time_t now) const { - static constexpr llarp_time_t SessionAliveTimeout = 5000; - if(m_State != State::Ready) - return now - m_CreatedAt > SessionAliveTimeout; - return now - m_LastRX > SessionAliveTimeout; + static constexpr llarp_time_t SessionAliveTimeout = 10000; + if(m_State == State::Ready || m_State == State::LinkIntro) + { + return now > m_LastRX && now - m_LastRX > SessionAliveTimeout; + } + return now - m_CreatedAt > SessionAliveTimeout; } - void - Session::Tick(llarp_time_t) + void Session::Tick(llarp_time_t) { } - using Introduction = AlignedBuffer<64>; + using Introduction = AlignedBuffer< 64 >; - void + void Session::GenerateAndSendIntro() { Introduction intro; - + TunnelNonce N; N.Randomize(); - if(not CryptoManager::instance()->transport_dh_client(m_SessionKey, m_ChosenAI.pubkey, m_Parent->RouterEncryptionSecret(), N)) + if(not CryptoManager::instance()->transport_dh_client( + m_SessionKey, m_ChosenAI.pubkey, + m_Parent->RouterEncryptionSecret(), N)) { - LogError("failed to transport_dh_client on outbound session to ", m_RemoteAddr); + LogError("failed to transport_dh_client on outbound session to ", + m_RemoteAddr); return; } const auto pk = m_Parent->RouterEncryptionSecret().toPublic(); std::copy_n(pk.begin(), pk.size(), intro.begin()); std::copy(N.begin(), N.end(), intro.begin() + 32); - LogDebug("pk=", pk.ToHex(), " N=", N.ToHex(), " remote-pk=", m_ChosenAI.pubkey.ToHex()); - std::vector req; + LogDebug("pk=", pk.ToHex(), " N=", N.ToHex(), + " remote-pk=", m_ChosenAI.pubkey.ToHex()); + std::vector< byte_t > req; req.resize(intro.size() + (randint() % 64)); CryptoManager::instance()->randbytes(req.data(), req.size()); std::copy_n(intro.begin(), intro.size(), req.begin()); const llarp_buffer_t buf{req}; Send_LL(buf); m_State = State::Introduction; + LogDebug("sent intro to ", m_RemoteAddr); } - + void - Session::HandleCreateSessionRequest(const llarp_buffer_t & buf) + Session::HandleCreateSessionRequest(const llarp_buffer_t& buf) { - std::vector result; + std::vector< byte_t > result; if(not DecryptMessage(buf, result)) { LogError("failed to decrypt session request from ", m_RemoteAddr); @@ -282,47 +278,57 @@ namespace llarp } if(result.size() < token.size()) { - LogError("bad session request size, ", result.size(), " < ", token.size(), " from ", m_RemoteAddr); + LogError("bad session request size, ", result.size(), " < ", + token.size(), " from ", m_RemoteAddr); return; } - if(not std::equal(result.begin(), result.begin() + token.size(), token.begin())) + if(not std::equal(result.begin(), result.begin() + token.size(), + token.begin())) { LogError("token missmatch from ", m_RemoteAddr); return; } + m_LastRX = m_Parent->Now(); + m_State = State::LinkIntro; SendOurLIM(); - m_State = State::LinkIntro; } - void - Session::HandleGotIntro(const llarp_buffer_t & buf) + void + Session::HandleGotIntro(const llarp_buffer_t& buf) { if(buf.sz < Introduction::SIZE) + { + LogWarn("intro too small from ", m_RemoteAddr); return; + } TunnelNonce N; std::copy_n(buf.base, PubKey::SIZE, m_RemoteOnionKey.begin()); std::copy_n(buf.base + PubKey::SIZE, TunnelNonce::SIZE, N.begin()); const PubKey pk = m_Parent->TransportSecretKey().toPublic(); - LogDebug("remote-pk=", m_RemoteOnionKey.ToHex(), " N=", N.ToHex(), " local-pk=", pk.ToHex()); - if(not CryptoManager::instance()->transport_dh_server(m_SessionKey, m_RemoteOnionKey, m_Parent->TransportSecretKey(), N)) + LogDebug("got intro: remote-pk=", m_RemoteOnionKey.ToHex(), + " N=", N.ToHex(), " local-pk=", pk.ToHex(), " sz=", buf.sz); + if(not CryptoManager::instance()->transport_dh_server( + m_SessionKey, m_RemoteOnionKey, m_Parent->TransportSecretKey(), N)) { - LogError("failed to transport_dh_server on inbound intro from ", m_RemoteAddr); + LogError("failed to transport_dh_server on inbound intro from ", + m_RemoteAddr); return; } - std::vector reply; + std::vector< byte_t > reply; reply.resize(token.size() + (randint() % 32)); CryptoManager::instance()->randbytes(reply.data(), reply.size()); std::copy_n(token.begin(), token.size(), reply.begin()); const llarp_buffer_t pkt{reply}; m_LastRX = m_Parent->Now(); EncryptAndSend(pkt); + LogDebug("sent intro ack to ", m_RemoteAddr); m_State = State::Introduction; } void - Session::HandleGotIntroAck(const llarp_buffer_t & buf) + Session::HandleGotIntroAck(const llarp_buffer_t& buf) { - std::vector reply; + std::vector< byte_t > reply; if(not DecryptMessage(buf, reply)) { LogError("intro ack decrypt failed from ", m_RemoteAddr); @@ -330,21 +336,27 @@ namespace llarp } if(reply.size() < token.size()) { - LogError("bad intro ack size ", reply.size(), " < ", token.size(), " from ", m_RemoteAddr); + LogError("bad intro ack size ", reply.size(), " < ", token.size(), + " from ", m_RemoteAddr); return; } m_LastRX = m_Parent->Now(); std::copy_n(reply.begin(), token.size(), token.begin()); const llarp_buffer_t pkt{token}; EncryptAndSend(pkt); + LogDebug("sent session request to ", m_RemoteAddr); m_State = State::LinkIntro; } bool - Session::DecryptMessage(const llarp_buffer_t & buf, std::vector & result) + Session::DecryptMessage(const llarp_buffer_t& buf, + std::vector< byte_t >& result) { if(buf.sz <= PacketOverhead) + { + LogError("packet too small ", buf.sz); return false; + } ShortHash H; llarp_buffer_t curbuf{buf.base, buf.sz}; curbuf.base += ShortHash::SIZE; @@ -357,16 +369,18 @@ namespace llarp const ShortHash expected{buf.base}; if(H != expected) { - LogError("keyed hash missmatch ", H, " != ", expected, " from ", m_RemoteAddr); + LogError("keyed hash missmatch ", H, " != ", expected, " from ", + m_RemoteAddr, " state=", int(m_State), " size=", buf.sz); return false; } - const byte_t * nonce_ptr = curbuf.base; + const byte_t* nonce_ptr = curbuf.base; curbuf.base += 32; curbuf.sz -= 32; result.resize(buf.sz - PacketOverhead); const llarp_buffer_t outbuf{result}; LogDebug("decrypt: ", result.size(), " bytes from ", m_RemoteAddr); - return CryptoManager::instance()->xchacha20_alt(outbuf, curbuf, m_SessionKey, nonce_ptr); + return CryptoManager::instance()->xchacha20_alt(outbuf, curbuf, + m_SessionKey, nonce_ptr); } void @@ -378,17 +392,25 @@ namespace llarp } void - Session::HandleSessionData(const llarp_buffer_t & buf) + Session::HandleSessionData(const llarp_buffer_t& buf) { - std::vector result; + std::vector< byte_t > result; if(not DecryptMessage(buf, result)) { LogError("failed to decrypt session data from ", m_RemoteAddr); return; } + if(result.size() == token.size()) + { + /// we got a token so we return it + const llarp_buffer_t pktbuf{token}; + EncryptAndSend(pktbuf); + return; + } if(result[0] != LLARP_PROTO_VERSION) { - LogError("protocol version missmatch ", int(result[0]), " != ", LLARP_PROTO_VERSION); + LogError("protocol version missmatch ", int(result[0]), + " != ", LLARP_PROTO_VERSION); return; } LogDebug("command ", int(result[1]), " from ", m_RemoteAddr); @@ -406,78 +428,127 @@ namespace llarp case Command::ePING: HandlePING(std::move(result)); break; + case Command::eNACK: + HandleNACK(std::move(result)); + break; case Command::eCLOS: HandleCLOS(std::move(result)); break; - default: + default: LogError("invalid command ", int(result[1])); } } void - Session::HandleXMIT(std::vector data) + Session::HandleNACK(std::vector< byte_t > data) + { + uint64_t txid = bufbe64toh(data.data() + 2); + LogDebug("got nack on ", txid, " from ", m_RemoteAddr); + auto itr = m_TXMsgs.find(txid); + if(itr != m_TXMsgs.end()) + { + auto xmit = itr->second.XMIT(); + const llarp_buffer_t pkt{xmit}; + EncryptAndSend(pkt); + } + } + + void + Session::HandleXMIT(std::vector< byte_t > data) { if(data.size() < 44) { LogError("short XMIT from ", m_RemoteAddr, " ", data.size(), " < 44"); return; } - uint16_t sz = bufbe16toh(data.data() + 2); + uint16_t sz = bufbe16toh(data.data() + 2); uint64_t rxid = bufbe64toh(data.data() + 4); ShortHash h{data.data() + 12}; LogDebug("rxid=", rxid, " sz=", sz, " h=", h.ToHex()); - m_RXMsgs.emplace(rxid, InboundMessage{rxid, sz, std::move(h)}); + auto itr = m_RXMsgs.find(rxid); + if(itr == m_RXMsgs.end()) + m_RXMsgs.emplace(rxid, InboundMessage{rxid, sz, std::move(h)}); + else + LogWarn("got duplicate xmit on ", rxid, " from ", m_RemoteAddr); m_LastRX = m_Parent->Now(); } void - Session::HandleDATA(std::vector data) + Session::HandleDATA(std::vector< byte_t > data) { if(data.size() < FragmentSize + 12) { - LogError("short DATA from ", m_RemoteAddr, " ", data.size(), " < ", FragmentSize + 8); + LogError("short DATA from ", m_RemoteAddr, " ", data.size()); return; } - uint16_t sz = bufbe16toh(data.data() + 2); + m_LastRX = m_Parent->Now(); + uint16_t sz = bufbe16toh(data.data() + 2); uint64_t rxid = bufbe64toh(data.data() + 4); - auto itr = m_RXMsgs.find(rxid); + auto itr = m_RXMsgs.find(rxid); if(itr == m_RXMsgs.end()) { LogWarn("no rxid=", rxid, " for ", m_RemoteAddr); + std::vector< byte_t > nack = { + LLARP_PROTO_VERSION, Command::eNACK, 0, 0, 0, 0, 0, 0, 0, 0}; + htobe64buf(nack.data() + 2, rxid); + const llarp_buffer_t nackbuf{nack}; + EncryptAndSend(nackbuf); return; } itr->second.HandleData(sz, data.data() + 12); - m_LastRX = m_Parent->Now(); - LogDebug(itr->first, " completed=", itr->second.IsCompleted()); + + if(itr->second.IsCompleted()) + { + itr->second.SendACKS(util::memFn(&Session::EncryptAndSend, this), + m_Parent->Now()); + if(itr->second.Verify()) + { + const llarp_buffer_t buf{itr->second.m_Data.data(), + itr->second.m_Size}; + LogDebug("got message ", itr->first); + m_Parent->HandleMessage(this, buf); + } + else + { + LogError("hash missmatch for message ", itr->first); + } + m_RXMsgs.erase(itr); + } } - void - Session::HandleACKS(std::vector data) + void + Session::HandleACKS(std::vector< byte_t > data) { if(data.size() < 11) { LogError("short ACKS from ", m_RemoteAddr, " ", data.size(), " < 11"); return; } + m_LastRX = m_Parent->Now(); uint64_t txid = bufbe64toh(data.data() + 2); - auto itr = m_TXMsgs.find(txid); + auto itr = m_TXMsgs.find(txid); if(itr == m_TXMsgs.end()) { LogWarn("no txid=", txid, " for ", m_RemoteAddr); return; } itr->second.Ack(data[10]); - m_LastRX = m_Parent->Now(); + + if(itr->second.IsTransmitted()) + { + LogDebug("sent message ", itr->first); + itr->second.Completed(); + itr = m_TXMsgs.erase(itr); + } } - void - Session::HandleCLOS(std::vector) + void Session::HandleCLOS(std::vector< byte_t >) { + LogInfo("remote closed by ", m_RemoteAddr); Close(); } - void - Session::HandlePING(std::vector) + void Session::HandlePING(std::vector< byte_t >) { m_LastRX = m_Parent->Now(); } @@ -485,7 +556,13 @@ namespace llarp bool Session::SendKeepAlive() { - // TODO: Implement me + if(m_State == State::Ready) + { + std::vector< byte_t > ping{LLARP_PROTO_VERSION, Command::ePING}; + const llarp_buffer_t buf{ping}; + EncryptAndSend(buf); + return true; + } return false; } diff --git a/llarp/iwp/session.hpp b/llarp/iwp/session.hpp index 423348bc0..cb83494de 100644 --- a/llarp/iwp/session.hpp +++ b/llarp/iwp/session.hpp @@ -97,7 +97,7 @@ namespace llarp { /// we have no data recv'd Initial, - /// we are in introduction/intro ack phase + /// we are in introduction phase Introduction, /// we sent our LIM LinkIntro, @@ -120,7 +120,7 @@ namespace llarp /// session key SharedSecret m_SessionKey; /// session token - AlignedBuffer<16> token; + AlignedBuffer< 24 > token; PubKey m_RemoteOnionKey; @@ -142,46 +142,46 @@ namespace llarp HandleCreateSessionRequest(const llarp_buffer_t& buf); void - ProcessSessionRequest(const llarp_buffer_t& buf); - - void - ProcessCreateSessionReply(const llarp_buffer_t& buf); + HandleAckSession(const llarp_buffer_t& buf); void HandleSessionData(const llarp_buffer_t& buf); - bool - DecryptMessage(const llarp_buffer_t & buf, std::vector & result); + bool + DecryptMessage(const llarp_buffer_t& buf, std::vector< byte_t >& result); - void + void GenerateAndSendIntro(); bool - GotInboundLIM(const LinkIntroMessage * msg); - + GotInboundLIM(const LinkIntroMessage* msg); + bool - GotOutboundLIM(const LinkIntroMessage * msg); + GotOutboundLIM(const LinkIntroMessage* msg); bool - GotRenegLIM(const LinkIntroMessage * msg); - + GotRenegLIM(const LinkIntroMessage* msg); + + void + SendOurLIM(ILinkSession::CompletionHandler h = nullptr); + void - SendOurLIM(); + HandleXMIT(std::vector< byte_t > msg); - void - HandleXMIT(std::vector msg); - - void - HandleDATA(std::vector msg); + void + HandleDATA(std::vector< byte_t > msg); - void - HandleACKS(std::vector msg); + void + HandleACKS(std::vector< byte_t > msg); - void - HandlePING(std::vector msg); + void + HandleNACK(std::vector< byte_t > msg); - void - HandleCLOS(std::vector msg); + void + HandlePING(std::vector< byte_t > msg); + + void + HandleCLOS(std::vector< byte_t > msg); }; } // namespace iwp } // namespace llarp diff --git a/llarp/link/link_manager.cpp b/llarp/link/link_manager.cpp index 8c6c5a42f..69b58dc0a 100644 --- a/llarp/link/link_manager.cpp +++ b/llarp/link/link_manager.cpp @@ -346,21 +346,20 @@ namespace llarp if(stopping) return nullptr; - for(const auto &link : inboundLinks) + for(const auto &link : outboundLinks) { if(link->HasSessionTo(remote)) { return link; } } - for(const auto &link : outboundLinks) + for(const auto &link : inboundLinks) { if(link->HasSessionTo(remote)) { return link; } } - return nullptr; } diff --git a/llarp/link/server.hpp b/llarp/link/server.hpp index 3f12f455d..be25c4fdc 100644 --- a/llarp/link/server.hpp +++ b/llarp/link/server.hpp @@ -186,7 +186,7 @@ namespace llarp bool GenEphemeralKeys(); - bool + virtual bool MapAddr(const RouterID& pk, ILinkSession* s); void diff --git a/llarp/router/outbound_session_maker.cpp b/llarp/router/outbound_session_maker.cpp index efdc73b1d..fd64990ce 100644 --- a/llarp/router/outbound_session_maker.cpp +++ b/llarp/router/outbound_session_maker.cpp @@ -226,6 +226,8 @@ namespace llarp bool OutboundSessionMaker::ShouldConnectTo(const RouterID &router) const { + if(router == us) + return false; size_t numPending = 0; { util::Lock lock(&_mutex); diff --git a/llarp/router/outbound_session_maker.hpp b/llarp/router/outbound_session_maker.hpp index f14352651..9be7f47c5 100644 --- a/llarp/router/outbound_session_maker.hpp +++ b/llarp/router/outbound_session_maker.hpp @@ -61,6 +61,12 @@ namespace llarp std::shared_ptr< Logic > logic, llarp_nodedb *nodedb, std::shared_ptr< llarp::thread::ThreadPool > threadpool); + void + SetOurRouter(RouterID r) + { + us = std::move(r); + } + /// always maintain this many connections to other routers size_t minConnectedRouters = 4; /// hard upperbound limit on the number of router to router connections @@ -108,6 +114,7 @@ namespace llarp std::shared_ptr< Logic > _logic; llarp_nodedb *_nodedb; std::shared_ptr< llarp::thread::ThreadPool > _threadpool; + RouterID us; }; } // namespace llarp diff --git a/llarp/router/router.cpp b/llarp/router/router.cpp index 67760fd4e..917172a63 100644 --- a/llarp/router/router.cpp +++ b/llarp/router/router.cpp @@ -906,7 +906,7 @@ namespace llarp LogError("failed to save RC"); return false; } - + _outboundSessionMaker.SetOurRouter(pubkey()); if(!_linkManager.StartLinks(_logic)) { LogWarn("One or more links failed to start."); From 461f41a4c65cbe04f0ccf56ae135fcdfa6e2cbfb Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Fri, 23 Aug 2019 07:36:11 -0400 Subject: [PATCH 06/20] mark alive on nack --- llarp/iwp/session.cpp | 3 ++- llarp/link/server.cpp | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/llarp/iwp/session.cpp b/llarp/iwp/session.cpp index 3321c8a7b..a5c729b2c 100644 --- a/llarp/iwp/session.cpp +++ b/llarp/iwp/session.cpp @@ -204,7 +204,7 @@ namespace llarp bool Session::ShouldPing() const { - if(m_State == State::Ready || m_State == State::LinkIntro) + if(m_State == State::Ready) { static constexpr llarp_time_t PingInterval = 500; const auto now = m_Parent->Now(); @@ -451,6 +451,7 @@ namespace llarp const llarp_buffer_t pkt{xmit}; EncryptAndSend(pkt); } + m_LastRX = m_Parent->Now(); } void diff --git a/llarp/link/server.cpp b/llarp/link/server.cpp index 73da6dcb3..28da29194 100644 --- a/llarp/link/server.cpp +++ b/llarp/link/server.cpp @@ -175,6 +175,7 @@ namespace llarp { if(m_AuthedLinks.count(pk) > MaxSessionsPerKey) { + LogWarn("too many session for ", pk); s->Close(); return false; } From d6ec5e7ed7df621aeb94ef0af66a43b6dd6950c0 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Fri, 23 Aug 2019 07:50:22 -0400 Subject: [PATCH 07/20] don't crash --- llarp/iwp/session.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/llarp/iwp/session.cpp b/llarp/iwp/session.cpp index a5c729b2c..af28443a0 100644 --- a/llarp/iwp/session.cpp +++ b/llarp/iwp/session.cpp @@ -504,16 +504,15 @@ namespace llarp m_Parent->Now()); if(itr->second.Verify()) { - const llarp_buffer_t buf{itr->second.m_Data.data(), - itr->second.m_Size}; - LogDebug("got message ", itr->first); + auto msg = std::move(itr->second); + const llarp_buffer_t buf{msg.m_Data.data(), msg.m_Size}; m_Parent->HandleMessage(this, buf); } else { LogError("hash missmatch for message ", itr->first); } - m_RXMsgs.erase(itr); + m_RXMsgs.erase(rxid); } } From 7e38a133d81dcaf88e6a151c8f7df7041ad54b10 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Fri, 23 Aug 2019 07:57:57 -0400 Subject: [PATCH 08/20] send keep alive on pump when needed --- llarp/iwp/session.cpp | 2 ++ llarp/link/server.cpp | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/llarp/iwp/session.cpp b/llarp/iwp/session.cpp index af28443a0..09c3c7694 100644 --- a/llarp/iwp/session.cpp +++ b/llarp/iwp/session.cpp @@ -170,6 +170,8 @@ namespace llarp const auto now = m_Parent->Now(); if(m_State == State::Ready || m_State == State::LinkIntro) { + if(ShouldPing()) + SendKeepAlive(); for(auto itr = m_RXMsgs.begin(); itr != m_RXMsgs.end(); ++itr) { if(itr->second.ShouldSendACKS(now)) diff --git a/llarp/link/server.cpp b/llarp/link/server.cpp index 28da29194..e1478fc9b 100644 --- a/llarp/link/server.cpp +++ b/llarp/link/server.cpp @@ -129,7 +129,7 @@ namespace llarp auto itr = m_AuthedLinks.begin(); while(itr != m_AuthedLinks.end()) { - if(itr->second.get() && !itr->second->TimedOut(_now)) + if(not itr->second->TimedOut(_now)) { itr->second->Pump(); ++itr; @@ -149,7 +149,7 @@ namespace llarp auto itr = m_Pending.begin(); while(itr != m_Pending.end()) { - if(itr->second.get() && !itr->second->TimedOut(_now)) + if(not itr->second->TimedOut(_now)) { itr->second->Pump(); ++itr; From f8bf907f2405c924b323c72799c8402223310263 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Fri, 23 Aug 2019 08:27:57 -0400 Subject: [PATCH 09/20] disable log spew --- test/link/test_llarp_link.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/link/test_llarp_link.cpp b/test/link/test_llarp_link.cpp index 5f03069fb..23316cc05 100644 --- a/test/link/test_llarp_link.cpp +++ b/test/link/test_llarp_link.cpp @@ -120,7 +120,6 @@ struct LinkLayerTest : public test::LlarpTest< llarp::sodium::CryptoLibSodium > void SetUp() { - SetLogLevel(eLogDebug); oldRCLifetime = RouterContact::Lifetime; RouterContact::IgnoreBogons = true; RouterContact::Lifetime = 500; @@ -137,7 +136,6 @@ struct LinkLayerTest : public test::LlarpTest< llarp::sodium::CryptoLibSodium > netLoop.reset(); RouterContact::IgnoreBogons = false; RouterContact::Lifetime = oldRCLifetime; - SetLogLevel(eLogInfo); } static void From 5f8388b1c08fdf818aff55d364ed924503eab1f2 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Fri, 23 Aug 2019 08:30:07 -0400 Subject: [PATCH 10/20] lower log level for renegotiate --- llarp/iwp/session.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llarp/iwp/session.cpp b/llarp/iwp/session.cpp index 09c3c7694..480c3da7e 100644 --- a/llarp/iwp/session.cpp +++ b/llarp/iwp/session.cpp @@ -192,7 +192,7 @@ namespace llarp bool Session::GotRenegLIM(const LinkIntroMessage* lim) { - LogInfo("renegotiate session on ", m_RemoteAddr); + LogDebug("renegotiate session on ", m_RemoteAddr); return m_Parent->SessionRenegotiate(lim->rc, m_RemoteRC); } From 4ac07ea9fbf6ba7d5c7cf0f8733a26d3d23f4c6e Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Fri, 23 Aug 2019 08:40:56 -0400 Subject: [PATCH 11/20] use std::make_tuple --- llarp/config/config.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp index 489701197..a8b67849e 100644 --- a/llarp/config/config.cpp +++ b/llarp/config/config.cpp @@ -242,8 +242,8 @@ namespace llarp if(key == "*") { - m_OutboundLink = {"*", AF_INET, fromEnv(proto, "OUTBOUND_PORT"), - std::move(opts)}; + m_OutboundLink = std::make_tuple( + "*", AF_INET, fromEnv(proto, "OUTBOUND_PORT"), std::move(opts)); } else { From 82ea973137103aa8b8eac5b2788da6f86db79b6b Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Fri, 23 Aug 2019 08:48:40 -0400 Subject: [PATCH 12/20] silence clang errors --- llarp/iwp/message_buffer.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/llarp/iwp/message_buffer.cpp b/llarp/iwp/message_buffer.cpp index 283bb3b91..76d7240d7 100644 --- a/llarp/iwp/message_buffer.cpp +++ b/llarp/iwp/message_buffer.cpp @@ -11,7 +11,7 @@ namespace llarp OutboundMessage::OutboundMessage(uint64_t msgid, const llarp_buffer_t &pkt, ILinkSession::CompletionHandler handler) - : m_Size{std::min(pkt.sz, MAX_LINK_MSG_SIZE)} + : m_Size{(uint16_t)std::min(pkt.sz, MAX_LINK_MSG_SIZE)} , m_MsgID{msgid} , m_Completed{handler} { @@ -124,9 +124,17 @@ namespace llarp std::vector< byte_t > InboundMessage::ACKS() const { - std::vector< byte_t > acks{ - LLARP_PROTO_VERSION, Command::eACKS, 0, 0, 0, 0, 0, 0, 0, 0, - uint8_t{m_Acks.to_ulong()}}; + std::vector< byte_t > acks{LLARP_PROTO_VERSION, + Command::eACKS, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + uint8_t{(uint8_t)m_Acks.to_ulong()}}; htobe64buf(acks.data() + 2, m_MsgID); return acks; From 1d32e6a28f9757e36b98e0f8754cfc2f54501703 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Fri, 23 Aug 2019 08:55:28 -0400 Subject: [PATCH 13/20] silence clang errors again --- llarp/ev/ev_libuv.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llarp/ev/ev_libuv.cpp b/llarp/ev/ev_libuv.cpp index 93a815892..732770dda 100644 --- a/llarp/ev/ev_libuv.cpp +++ b/llarp/ev/ev_libuv.cpp @@ -456,7 +456,7 @@ namespace libuv int r = glue->m_Pipe->read(glue->m_Buffer, sizeof(glue->m_Buffer)); if(r <= 0) return; - const llarp_buffer_t buf{glue->m_Buffer, size_t{r}}; + const llarp_buffer_t buf{glue->m_Buffer, static_cast< size_t >(r)}; glue->m_Pipe->OnRead(buf); } From 35c78348f211f6e0a322075cf98705eb42576f33 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Fri, 23 Aug 2019 09:29:57 -0400 Subject: [PATCH 14/20] default to no implementation on pipe for pleasing win32 --- llarp/ev/ev.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/llarp/ev/ev.hpp b/llarp/ev/ev.hpp index 1f610c100..4d351292e 100644 --- a/llarp/ev/ev.hpp +++ b/llarp/ev/ev.hpp @@ -775,7 +775,10 @@ struct llarp_ev_loop bind_tcp(llarp_tcp_acceptor* tcp, const sockaddr* addr) = 0; virtual bool - add_pipe(llarp_ev_pkt_pipe* p) = 0; + add_pipe(llarp_ev_pkt_pipe*) + { + return false; + } /// register event listener virtual bool From 647f874d0f44751cac6a990633e46314eae42fbf Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Fri, 23 Aug 2019 16:49:12 -0400 Subject: [PATCH 15/20] ignore test on win32 --- test/link/test_llarp_link.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/link/test_llarp_link.cpp b/test/link/test_llarp_link.cpp index 23316cc05..21f197118 100644 --- a/test/link/test_llarp_link.cpp +++ b/test/link/test_llarp_link.cpp @@ -171,6 +171,9 @@ struct LinkLayerTest : public test::LlarpTest< llarp::sodium::CryptoLibSodium > TEST_F(LinkLayerTest, TestIWP) { +#ifdef WIN32 + GTEST_SKIP(); +#else Alice.link = iwp::NewInboundLink( Alice.encryptionKey, [&]() -> const RouterContact& { return Alice.GetRC(); }, @@ -256,6 +259,7 @@ TEST_F(LinkLayerTest, TestIWP) RunMainloop(); ASSERT_TRUE(Bob.gotLIM); +#endif }; TEST_F(LinkLayerTest, TestUTPAliceRenegWithBob) From 6a48a3b402547612ef0e2097c402229d8e1f6f36 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 26 Aug 2019 07:16:46 -0400 Subject: [PATCH 16/20] code review fixes: * use std::unordered_set * use default for ctor/dtor * don't crash on short packet with nack --- llarp/config/config.cpp | 4 ++-- llarp/config/config.hpp | 3 ++- llarp/iwp/message_buffer.cpp | 16 +++------------- llarp/iwp/message_buffer.hpp | 5 +++-- llarp/iwp/session.cpp | 9 +++++---- llarp/iwp/session.hpp | 2 +- 6 files changed, 16 insertions(+), 23 deletions(-) diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp index a8b67849e..75a193ac3 100644 --- a/llarp/config/config.cpp +++ b/llarp/config/config.cpp @@ -204,7 +204,7 @@ namespace llarp { uint16_t proto = 0; - std::set< std::string > parsed_opts; + std::unordered_set< std::string > parsed_opts; std::string v = tostr(val); std::string::size_type idx; do @@ -220,7 +220,7 @@ namespace llarp parsed_opts.insert(v); } } while(idx != std::string::npos); - std::set< std::string > opts; + std::unordered_set< std::string > opts; /// for each option for(const auto &item : parsed_opts) { diff --git a/llarp/config/config.hpp b/llarp/config/config.hpp index 56f199d45..950c8a75f 100644 --- a/llarp/config/config.hpp +++ b/llarp/config/config.hpp @@ -12,6 +12,7 @@ #include #include #include +#include namespace llarp { @@ -195,7 +196,7 @@ namespace llarp static constexpr int Port = 2; static constexpr int Options = 3; - using ServerOptions = std::set< std::string >; + using ServerOptions = std::unordered_set< std::string >; using LinkInfo = std::tuple< std::string, int, uint16_t, ServerOptions >; using Links = std::vector< LinkInfo >; diff --git a/llarp/iwp/message_buffer.cpp b/llarp/iwp/message_buffer.cpp index 76d7240d7..af73c23ce 100644 --- a/llarp/iwp/message_buffer.cpp +++ b/llarp/iwp/message_buffer.cpp @@ -5,10 +5,6 @@ namespace llarp { namespace iwp { - OutboundMessage::OutboundMessage() : m_Size{0} - { - } - OutboundMessage::OutboundMessage(uint64_t msgid, const llarp_buffer_t &pkt, ILinkSession::CompletionHandler handler) : m_Size{(uint16_t)std::min(pkt.sz, MAX_LINK_MSG_SIZE)} @@ -17,6 +13,8 @@ namespace llarp { m_Data.Zero(); std::copy_n(pkt.base, m_Size, m_Data.begin()); + const llarp_buffer_t buf{m_Data.data(), m_Size}; + CryptoManager::instance()->shorthash(digest, buf); } std::vector< byte_t > @@ -26,11 +24,7 @@ namespace llarp LLARP_PROTO_VERSION, Command::eXMIT, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; htobe16buf(xmit.data() + 2, m_Size); htobe64buf(xmit.data() + 4, m_MsgID); - const llarp_buffer_t buf{m_Data.data(), m_Size}; - ShortHash H; - CryptoManager::instance()->shorthash(H, buf); - std::copy(H.begin(), H.end(), std::back_inserter(xmit)); - LogDebug("xmit H=", H.ToHex()); + std::copy(digest.begin(), digest.end(), std::back_inserter(xmit)); return xmit; } @@ -101,10 +95,6 @@ namespace llarp return true; } - InboundMessage::InboundMessage() : m_Size{0} - { - } - InboundMessage::InboundMessage(uint64_t msgid, uint16_t sz, ShortHash h) : m_Digset{std::move(h)}, m_Size{sz}, m_MsgID{msgid} { diff --git a/llarp/iwp/message_buffer.hpp b/llarp/iwp/message_buffer.hpp index 8082fb706..ded62a3a4 100644 --- a/llarp/iwp/message_buffer.hpp +++ b/llarp/iwp/message_buffer.hpp @@ -31,7 +31,7 @@ namespace llarp struct OutboundMessage { - OutboundMessage(); + OutboundMessage() = default; OutboundMessage(uint64_t msgid, const llarp_buffer_t &pkt, ILinkSession::CompletionHandler handler); @@ -41,6 +41,7 @@ namespace llarp std::bitset< MAX_LINK_MSG_SIZE / FragmentSize > m_Acks; ILinkSession::CompletionHandler m_Completed; llarp_time_t m_LastFlush = 0; + ShortHash digest; std::vector< byte_t > XMIT() const; @@ -64,7 +65,7 @@ namespace llarp struct InboundMessage { - InboundMessage(); + InboundMessage() = default; InboundMessage(uint64_t msgid, uint16_t sz, ShortHash h); AlignedBuffer< MAX_LINK_MSG_SIZE > m_Data; diff --git a/llarp/iwp/session.cpp b/llarp/iwp/session.cpp index 480c3da7e..235761b8d 100644 --- a/llarp/iwp/session.cpp +++ b/llarp/iwp/session.cpp @@ -33,10 +33,6 @@ namespace llarp GotLIM = util::memFn(&Session::GotInboundLIM, this); } - Session::~Session() - { - } - void Session::Send_LL(const llarp_buffer_t& pkt) { @@ -444,6 +440,11 @@ namespace llarp void Session::HandleNACK(std::vector< byte_t > data) { + if(data.size() < 10) + { + LogError("short nack from ", m_RemoteAddr); + return; + } uint64_t txid = bufbe64toh(data.data() + 2); LogDebug("got nack on ", txid, " from ", m_RemoteAddr); auto itr = m_TXMsgs.find(txid); diff --git a/llarp/iwp/session.hpp b/llarp/iwp/session.hpp index cb83494de..b9f598bf1 100644 --- a/llarp/iwp/session.hpp +++ b/llarp/iwp/session.hpp @@ -17,7 +17,7 @@ namespace llarp /// inbound session Session(LinkLayer* parent, Addr from); - ~Session(); + ~Session() = default; void Pump() override; From 94f853177603046717ba227b1f406c45e1b2b05a Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 26 Aug 2019 10:29:29 -0400 Subject: [PATCH 17/20] more fixups --- llarp/config/config.cpp | 19 ++++++++++++++++--- llarp/iwp/session.cpp | 15 +++++++-------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp index 75a193ac3..ca5f69b62 100644 --- a/llarp/config/config.cpp +++ b/llarp/config/config.cpp @@ -207,17 +207,30 @@ namespace llarp std::unordered_set< std::string > parsed_opts; std::string v = tostr(val); std::string::size_type idx; + static constexpr char delimiter = ','; + static const auto strip_spaces = [](const auto &begin, + const auto &end) -> std::string { + std::string val; + std::for_each(begin, end, [&val](const char &ch) { + // strip spaces + if(::isspace(ch) || ch == delimiter) + return; + val += ch; + }); + return val; + }; + do { - idx = v.find_first_of(','); + idx = v.find_first_of(delimiter); if(idx != std::string::npos) { - parsed_opts.insert(v.substr(0, idx)); + parsed_opts.emplace(strip_spaces(v.begin(), v.begin() + idx)); v = v.substr(idx + 1); } else { - parsed_opts.insert(v); + parsed_opts.insert(strip_spaces(v.begin(), v.end())); } } while(idx != std::string::npos); std::unordered_set< std::string > opts; diff --git a/llarp/iwp/session.cpp b/llarp/iwp/session.cpp index 235761b8d..26499b6d6 100644 --- a/llarp/iwp/session.cpp +++ b/llarp/iwp/session.cpp @@ -416,25 +416,24 @@ namespace llarp { case Command::eXMIT: HandleXMIT(std::move(result)); - break; + return; case Command::eDATA: HandleDATA(std::move(result)); - break; + return; case Command::eACKS: HandleACKS(std::move(result)); - break; + return; case Command::ePING: HandlePING(std::move(result)); - break; + return; case Command::eNACK: HandleNACK(std::move(result)); - break; + return; case Command::eCLOS: HandleCLOS(std::move(result)); - break; - default: - LogError("invalid command ", int(result[1])); + return; } + LogError("invalid command ", int(result[1])); } void From 0241851b72eb5ace7ad5675a543a115aa601af41 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 27 Aug 2019 08:07:48 -0400 Subject: [PATCH 18/20] add likn layer delivery timeout notification for iwp --- llarp/config/config.cpp | 21 ++++-------- llarp/iwp/message_buffer.cpp | 31 +++++++++++++++-- llarp/iwp/message_buffer.hpp | 23 ++++++++++--- llarp/iwp/session.cpp | 41 +++++++++++++++++------ llarp/router/outbound_message_handler.cpp | 19 ++++------- 5 files changed, 91 insertions(+), 44 deletions(-) diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp index ca5f69b62..e6726dc63 100644 --- a/llarp/config/config.cpp +++ b/llarp/config/config.cpp @@ -11,6 +11,8 @@ #include #include +#include + #include #include #include @@ -208,29 +210,20 @@ namespace llarp std::string v = tostr(val); std::string::size_type idx; static constexpr char delimiter = ','; - static const auto strip_spaces = [](const auto &begin, - const auto &end) -> std::string { - std::string val; - std::for_each(begin, end, [&val](const char &ch) { - // strip spaces - if(::isspace(ch) || ch == delimiter) - return; - val += ch; - }); - return val; - }; - do { idx = v.find_first_of(delimiter); if(idx != std::string::npos) { - parsed_opts.emplace(strip_spaces(v.begin(), v.begin() + idx)); + std::string val = v.substr(0, idx); + absl::StripAsciiWhitespace(&val); + parsed_opts.emplace(std::move(val)); v = v.substr(idx + 1); } else { - parsed_opts.insert(strip_spaces(v.begin(), v.end())); + absl::StripAsciiWhitespace(&v); + parsed_opts.insert(std::move(v)); } } while(idx != std::string::npos); std::unordered_set< std::string > opts; diff --git a/llarp/iwp/message_buffer.cpp b/llarp/iwp/message_buffer.cpp index af73c23ce..4ec5e663e 100644 --- a/llarp/iwp/message_buffer.cpp +++ b/llarp/iwp/message_buffer.cpp @@ -6,10 +6,12 @@ namespace llarp namespace iwp { OutboundMessage::OutboundMessage(uint64_t msgid, const llarp_buffer_t &pkt, + llarp_time_t now, ILinkSession::CompletionHandler handler) : m_Size{(uint16_t)std::min(pkt.sz, MAX_LINK_MSG_SIZE)} , m_MsgID{msgid} , m_Completed{handler} + , m_StartedAt{now} { m_Data.Zero(); std::copy_n(pkt.base, m_Size, m_Data.begin()); @@ -95,13 +97,35 @@ namespace llarp return true; } - InboundMessage::InboundMessage(uint64_t msgid, uint16_t sz, ShortHash h) - : m_Digset{std::move(h)}, m_Size{sz}, m_MsgID{msgid} + bool + OutboundMessage::IsTimedOut(const llarp_time_t now) const + { + // TODO: make configurable by outbound message deliverer + return now > m_StartedAt && now - m_StartedAt > 5000; + } + + void + OutboundMessage::InformTimeout() + { + if(m_Completed) + { + m_Completed(ILinkSession::DeliveryStatus::eDeliveryDropped); + } + m_Completed = nullptr; + } + + InboundMessage::InboundMessage(uint64_t msgid, uint16_t sz, ShortHash h, + llarp_time_t now) + : m_Digset{std::move(h)} + , m_Size{sz} + , m_MsgID{msgid} + , m_LastActiveAt{now} { } void - InboundMessage::HandleData(uint16_t idx, const byte_t *ptr) + InboundMessage::HandleData(uint16_t idx, const byte_t *ptr, + llarp_time_t now) { if(idx + FragmentSize > MAX_LINK_MSG_SIZE) return; @@ -109,6 +133,7 @@ namespace llarp std::copy_n(ptr, FragmentSize, dst); m_Acks.set(idx / FragmentSize); LogDebug("got fragment ", idx / FragmentSize, " of ", m_Size); + m_LastActiveAt = now; } std::vector< byte_t > diff --git a/llarp/iwp/message_buffer.hpp b/llarp/iwp/message_buffer.hpp index ded62a3a4..8a714f045 100644 --- a/llarp/iwp/message_buffer.hpp +++ b/llarp/iwp/message_buffer.hpp @@ -33,6 +33,7 @@ namespace llarp { OutboundMessage() = default; OutboundMessage(uint64_t msgid, const llarp_buffer_t &pkt, + llarp_time_t now, ILinkSession::CompletionHandler handler); AlignedBuffer< MAX_LINK_MSG_SIZE > m_Data; @@ -42,6 +43,7 @@ namespace llarp ILinkSession::CompletionHandler m_Completed; llarp_time_t m_LastFlush = 0; ShortHash digest; + llarp_time_t m_StartedAt = 0; std::vector< byte_t > XMIT() const; @@ -61,26 +63,37 @@ namespace llarp bool IsTransmitted() const; + + bool + IsTimedOut(llarp_time_t now) const; + + void + InformTimeout(); }; struct InboundMessage { InboundMessage() = default; - InboundMessage(uint64_t msgid, uint16_t sz, ShortHash h); + InboundMessage(uint64_t msgid, uint16_t sz, ShortHash h, + llarp_time_t now); AlignedBuffer< MAX_LINK_MSG_SIZE > m_Data; ShortHash m_Digset; - uint16_t m_Size = 0; - uint64_t m_MsgID = 0; - llarp_time_t m_LastACKSent = 0; + uint16_t m_Size = 0; + uint64_t m_MsgID = 0; + llarp_time_t m_LastACKSent = 0; + llarp_time_t m_LastActiveAt = 0; std::bitset< MAX_LINK_MSG_SIZE / FragmentSize > m_Acks; void - HandleData(uint16_t idx, const byte_t *ptr); + HandleData(uint16_t idx, const byte_t *ptr, llarp_time_t now); bool IsCompleted() const; + bool + IsTimedOut(llarp_time_t now) const; + bool Verify() const; diff --git a/llarp/iwp/session.cpp b/llarp/iwp/session.cpp index 26499b6d6..6adf14ea6 100644 --- a/llarp/iwp/session.cpp +++ b/llarp/iwp/session.cpp @@ -147,15 +147,15 @@ namespace llarp Session::SendMessageBuffer(const llarp_buffer_t& buf, ILinkSession::CompletionHandler completed) { + const auto now = m_Parent->Now(); const auto msgid = m_TXID++; auto& msg = - m_TXMsgs.emplace(msgid, OutboundMessage{msgid, buf, completed}) + m_TXMsgs.emplace(msgid, OutboundMessage{msgid, buf, now, completed}) .first->second; const auto xmit = msg.XMIT(); const llarp_buffer_t pkt{xmit}; EncryptAndSend(pkt); - msg.FlushUnAcked(util::memFn(&Session::EncryptAndSend, this), - m_Parent->Now()); + msg.FlushUnAcked(util::memFn(&Session::EncryptAndSend, this), now); LogDebug("send message ", msgid); return true; } @@ -168,19 +168,21 @@ namespace llarp { if(ShouldPing()) SendKeepAlive(); - for(auto itr = m_RXMsgs.begin(); itr != m_RXMsgs.end(); ++itr) + for(auto& item : m_RXMsgs) { - if(itr->second.ShouldSendACKS(now)) + if(item.second.ShouldSendACKS(now)) { - itr->second.SendACKS(util::memFn(&Session::EncryptAndSend, this), + item.second.SendACKS(util::memFn(&Session::EncryptAndSend, this), now); } } - for(auto itr = m_TXMsgs.begin(); itr != m_TXMsgs.end(); ++itr) + for(auto& item : m_TXMsgs) { - if(itr->second.ShouldFlush(now)) - itr->second.FlushUnAcked( + if(item.second.ShouldFlush(now)) + { + item.second.FlushUnAcked( util::memFn(&Session::EncryptAndSend, this), now); + } } } } @@ -229,8 +231,27 @@ namespace llarp return now - m_CreatedAt > SessionAliveTimeout; } - void Session::Tick(llarp_time_t) + void + Session::Tick(llarp_time_t now) { + // remove pending outbound messsages that timed out + // inform waiters + auto itr = m_TXMsgs.begin(); + while(itr != m_TXMsgs.end()) + { + if(itr->second.IsTimedOut(now)) + { + itr->second.InformTimeout(); + itr = m_TXMsgs.erase(itr); + } + else + ++itr; + } + // remove pending inbound messages that timed out + std::remove_if(m_RXMsgs.begin(), m_RXMsgs.end(), + [now](const auto& item) -> bool { + return item.second.IsTimedOut(now); + }); } using Introduction = AlignedBuffer< 64 >; diff --git a/llarp/router/outbound_message_handler.cpp b/llarp/router/outbound_message_handler.cpp index d5102a2ed..99782de55 100644 --- a/llarp/router/outbound_message_handler.cpp +++ b/llarp/router/outbound_message_handler.cpp @@ -170,18 +170,13 @@ namespace llarp { const llarp_buffer_t buf(msg.first); auto callback = msg.second; - if(!_linkManager->SendTo( - remote, buf, [=](ILinkSession::DeliveryStatus status) { - if(status == ILinkSession::DeliveryStatus::eDeliverySuccess) - DoCallback(callback, SendStatus::Success); - else - DoCallback(callback, SendStatus::Congestion); - })) - { - DoCallback(callback, SendStatus::Congestion); - return false; - } - return true; + return _linkManager->SendTo( + remote, buf, [=](ILinkSession::DeliveryStatus status) { + if(status == ILinkSession::DeliveryStatus::eDeliverySuccess) + DoCallback(callback, SendStatus::Success); + else + DoCallback(callback, SendStatus::Congestion); + }); } bool From 88f685b74ad80f4d6d1f56e1768a504ea9be97d4 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 27 Aug 2019 08:13:55 -0400 Subject: [PATCH 19/20] add forgotten bits --- llarp/iwp/message_buffer.cpp | 6 ++++++ llarp/iwp/session.cpp | 39 +++++++++++++++++++++++------------- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/llarp/iwp/message_buffer.cpp b/llarp/iwp/message_buffer.cpp index 4ec5e663e..dc3319700 100644 --- a/llarp/iwp/message_buffer.cpp +++ b/llarp/iwp/message_buffer.cpp @@ -172,6 +172,12 @@ namespace llarp return now - m_LastACKSent > 1000 || IsCompleted(); } + bool + InboundMessage::IsTimedOut(const llarp_time_t now) const + { + return now > m_LastActiveAt && now - m_LastActiveAt > 5000; + } + void InboundMessage::SendACKS( std::function< void(const llarp_buffer_t &) > sendpkt, llarp_time_t now) diff --git a/llarp/iwp/session.cpp b/llarp/iwp/session.cpp index 6adf14ea6..81e859d8e 100644 --- a/llarp/iwp/session.cpp +++ b/llarp/iwp/session.cpp @@ -236,22 +236,32 @@ namespace llarp { // remove pending outbound messsages that timed out // inform waiters - auto itr = m_TXMsgs.begin(); - while(itr != m_TXMsgs.end()) { - if(itr->second.IsTimedOut(now)) + auto itr = m_TXMsgs.begin(); + while(itr != m_TXMsgs.end()) { - itr->second.InformTimeout(); - itr = m_TXMsgs.erase(itr); + if(itr->second.IsTimedOut(now)) + { + itr->second.InformTimeout(); + itr = m_TXMsgs.erase(itr); + } + else + ++itr; + } + } + { + // remove pending inbound messages that timed out + auto itr = m_RXMsgs.begin(); + while(itr != m_RXMsgs.end()) + { + if(itr->second.IsTimedOut(now)) + { + itr = m_RXMsgs.erase(itr); + } + else + ++itr; } - else - ++itr; } - // remove pending inbound messages that timed out - std::remove_if(m_RXMsgs.begin(), m_RXMsgs.end(), - [now](const auto& item) -> bool { - return item.second.IsTimedOut(now); - }); } using Introduction = AlignedBuffer< 64 >; @@ -491,7 +501,8 @@ namespace llarp LogDebug("rxid=", rxid, " sz=", sz, " h=", h.ToHex()); auto itr = m_RXMsgs.find(rxid); if(itr == m_RXMsgs.end()) - m_RXMsgs.emplace(rxid, InboundMessage{rxid, sz, std::move(h)}); + m_RXMsgs.emplace( + rxid, InboundMessage{rxid, sz, std::move(h), m_Parent->Now()}); else LogWarn("got duplicate xmit on ", rxid, " from ", m_RemoteAddr); m_LastRX = m_Parent->Now(); @@ -519,7 +530,7 @@ namespace llarp EncryptAndSend(nackbuf); return; } - itr->second.HandleData(sz, data.data() + 12); + itr->second.HandleData(sz, data.data() + 12, m_Parent->Now()); if(itr->second.IsCompleted()) { From 4c8da9bb6d060afa565f85f42590406f571d3d25 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 27 Aug 2019 09:14:44 -0400 Subject: [PATCH 20/20] use correct constructor for llarp_buffer_t --- llarp/iwp/session.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/llarp/iwp/session.cpp b/llarp/iwp/session.cpp index 81e859d8e..00b2c868a 100644 --- a/llarp/iwp/session.cpp +++ b/llarp/iwp/session.cpp @@ -91,7 +91,7 @@ namespace llarp return; } AlignedBuffer< LinkIntroMessage::MaxSize > data; - llarp_buffer_t buf{data}; + llarp_buffer_t buf(data); if(not msg.BEncode(&buf)) { LogError("failed to encode LIM for ", m_RemoteAddr); @@ -111,7 +111,7 @@ namespace llarp std::vector< byte_t > pkt; pkt.resize(data.sz + PacketOverhead); CryptoManager::instance()->randbytes(pkt.data(), pkt.size()); - llarp_buffer_t pktbuf{pkt}; + llarp_buffer_t pktbuf(pkt); pktbuf.base += PacketOverhead; pktbuf.sz -= PacketOverhead; byte_t* nonce_ptr = pkt.data() + HMACSIZE; @@ -135,7 +135,7 @@ namespace llarp return; const std::vector< byte_t > close_msg = {LLARP_PROTO_VERSION, Command::eCLOS}; - const llarp_buffer_t buf{close_msg}; + const llarp_buffer_t buf(close_msg); EncryptAndSend(buf); if(m_State == State::Ready) m_Parent->UnmapAddr(m_RemoteAddr); @@ -290,7 +290,7 @@ namespace llarp req.resize(intro.size() + (randint() % 64)); CryptoManager::instance()->randbytes(req.data(), req.size()); std::copy_n(intro.begin(), intro.size(), req.begin()); - const llarp_buffer_t buf{req}; + const llarp_buffer_t buf(req); Send_LL(buf); m_State = State::Introduction; LogDebug("sent intro to ", m_RemoteAddr); @@ -387,7 +387,7 @@ namespace llarp return false; } ShortHash H; - llarp_buffer_t curbuf{buf.base, buf.sz}; + llarp_buffer_t curbuf(buf.base, buf.sz); curbuf.base += ShortHash::SIZE; curbuf.sz -= ShortHash::SIZE; if(not CryptoManager::instance()->hmac(H.data(), curbuf, m_SessionKey)) @@ -406,7 +406,7 @@ namespace llarp curbuf.base += 32; curbuf.sz -= 32; result.resize(buf.sz - PacketOverhead); - const llarp_buffer_t outbuf{result}; + const llarp_buffer_t outbuf(result); LogDebug("decrypt: ", result.size(), " bytes from ", m_RemoteAddr); return CryptoManager::instance()->xchacha20_alt(outbuf, curbuf, m_SessionKey, nonce_ptr); @@ -432,7 +432,7 @@ namespace llarp if(result.size() == token.size()) { /// we got a token so we return it - const llarp_buffer_t pktbuf{token}; + const llarp_buffer_t pktbuf(token); EncryptAndSend(pktbuf); return; } @@ -481,7 +481,7 @@ namespace llarp if(itr != m_TXMsgs.end()) { auto xmit = itr->second.XMIT(); - const llarp_buffer_t pkt{xmit}; + const llarp_buffer_t pkt(xmit); EncryptAndSend(pkt); } m_LastRX = m_Parent->Now(); @@ -526,7 +526,7 @@ namespace llarp std::vector< byte_t > nack = { LLARP_PROTO_VERSION, Command::eNACK, 0, 0, 0, 0, 0, 0, 0, 0}; htobe64buf(nack.data() + 2, rxid); - const llarp_buffer_t nackbuf{nack}; + const llarp_buffer_t nackbuf(nack); EncryptAndSend(nackbuf); return; } @@ -539,7 +539,7 @@ namespace llarp if(itr->second.Verify()) { auto msg = std::move(itr->second); - const llarp_buffer_t buf{msg.m_Data.data(), msg.m_Size}; + const llarp_buffer_t buf(msg.m_Data.data(), msg.m_Size); m_Parent->HandleMessage(this, buf); } else @@ -593,7 +593,7 @@ namespace llarp if(m_State == State::Ready) { std::vector< byte_t > ping{LLARP_PROTO_VERSION, Command::ePING}; - const llarp_buffer_t buf{ping}; + const llarp_buffer_t buf(ping); EncryptAndSend(buf); return true; }