#ifndef LLARP_LINK_SERVER_HPP #define LLARP_LINK_SERVER_HPP #include #include #include #include #include #include #include #include #include #include #include #include namespace llarp { /// handle a link layer message. this allows for the message to be handled by "upper layers" /// /// currently called from iwp::Session when messages are sent or received. using LinkMessageHandler = std::function; /// sign a buffer with identity key. this function should take the given `llarp_buffer_t` and /// sign it, prividing the signature in the out variable `Signature&`. /// /// currently called from iwp::Session for signing LIMs (link introduction messages) using SignBufferFunc = std::function; /// handle connection timeout /// /// currently called from ILinkLayer::Pump() when an unestablished session times out using TimeoutHandler = std::function; /// get our RC /// /// currently called by iwp::Session to include as part of a LIM (link introduction message) using GetRCFunc = std::function; /// handler of session established /// return false to reject /// return true to accept /// /// currently called in iwp::Session when a valid LIM is received. using SessionEstablishedHandler = std::function; /// f(new, old) /// handler of session renegotiation /// returns true if the new rc is valid /// returns false otherwise and the session is terminated /// /// currently called from iwp::Session when we receive a renegotiation LIM using SessionRenegotiateHandler = std::function; /// handles close of all sessions with pubkey /// /// Note that this handler is called while m_AuthedLinksMutex is held /// /// currently called from iwp::ILinkSession when a previously established session times out using SessionClosedHandler = std::function; /// notifies router that a link session has ended its pump and we should flush /// messages to upper layers /// /// currently called at the end of every iwp::Session::Pump() call using PumpDoneHandler = std::function; using Work_t = std::function; /// queue work to worker thread using WorkerFunc_t = std::function; /// before connection hook, called before we try connecting via outbound link using BeforeConnectFunc_t = std::function; struct ILinkLayer { ILinkLayer( std::shared_ptr keyManager, GetRCFunc getrc, LinkMessageHandler handler, SignBufferFunc signFunc, BeforeConnectFunc_t before, SessionEstablishedHandler sessionEstablish, SessionRenegotiateHandler renegotiate, TimeoutHandler timeout, SessionClosedHandler closed, PumpDoneHandler pumpDone, WorkerFunc_t doWork); virtual ~ILinkLayer(); /// get current time via event loop llarp_time_t Now() const { return llarp_ev_loop_time_now_ms(m_Loop); } bool HasSessionTo(const RouterID& pk); void ForEachSession(std::function visit, bool randomize = false) const EXCLUDES(m_AuthedLinksMutex); void ForEachSession(std::function visit) EXCLUDES(m_AuthedLinksMutex); static void udp_tick(llarp_udp_io* udp); void SendTo_LL(const SockAddr& to, const llarp_buffer_t& pkt) { llarp_ev_udp_sendto(&m_udp, to, pkt); } virtual bool Configure(llarp_ev_loop_ptr loop, const std::string& ifname, int af, uint16_t port); virtual std::shared_ptr NewOutboundSession(const RouterContact& rc, const AddressInfo& ai) = 0; /// fetch a session by the identity pubkey it claims std::shared_ptr FindSessionByPubkey(RouterID pk); virtual void Pump(); virtual void RecvFrom(const SockAddr& from, ILinkSession::Packet_t pkt) = 0; bool PickAddress(const RouterContact& rc, AddressInfo& picked) const; bool TryEstablishTo(RouterContact rc); bool Start(std::shared_ptr l); virtual void Stop(); virtual const char* Name() const = 0; util::StatusObject ExtractStatus() const EXCLUDES(m_AuthedLinksMutex); void CloseSessionTo(const RouterID& remote); void KeepAliveSessionTo(const RouterID& remote); virtual bool SendTo( const RouterID& remote, const llarp_buffer_t& buf, ILinkSession::CompletionHandler completed); virtual bool GetOurAddressInfo(AddressInfo& addr) const; bool VisitSessionByPubkey(const RouterID& pk, std::function visit) EXCLUDES(m_AuthedLinksMutex); virtual uint16_t Rank() const = 0; const byte_t* TransportPubKey() const; const SecretKey& RouterEncryptionSecret() const { return m_RouterEncSecret; } const SecretKey& TransportSecretKey() const; bool IsCompatable(const llarp::RouterContact& other) const { const std::string us = Name(); for (const auto& ai : other.addrs) if (ai.dialect == us) return true; return false; } virtual bool MapAddr(const RouterID& pk, ILinkSession* s); void Tick(llarp_time_t now); LinkMessageHandler HandleMessage; TimeoutHandler HandleTimeout; SignBufferFunc Sign; GetRCFunc GetOurRC; BeforeConnectFunc_t BeforeConnect; SessionEstablishedHandler SessionEstablished; SessionClosedHandler SessionClosed; SessionRenegotiateHandler SessionRenegotiate; PumpDoneHandler PumpDone; std::shared_ptr keyManager; WorkerFunc_t QueueWork; std::shared_ptr logic() { return m_Logic; } bool operator<(const ILinkLayer& other) const { return Rank() < other.Rank() || Name() < other.Name() || m_ourAddr < other.m_ourAddr; } /// called by link session to remove a pending session who is timed out // void // RemovePending(ILinkSession* s) EXCLUDES(m_PendingMutex); /// count the number of sessions that are yet to be fully connected size_t NumberOfPendingSessions() const { Lock_t lock(m_PendingMutex); return m_Pending.size(); } int GetUDPSocket() const { return m_udp.fd; } private: void OnTick(); void ScheduleTick(llarp_time_t interval); uint32_t tick_id; const SecretKey& m_RouterEncSecret; protected: #ifdef TRACY_ENABLE using Lock_t = std::lock_guard; using Mutex_t = std::mutex; #else using Lock_t = util::NullLock; using Mutex_t = util::NullMutex; #endif bool PutSession(const std::shared_ptr& s); std::shared_ptr m_Logic = nullptr; llarp_ev_loop_ptr m_Loop; SockAddr m_ourAddr; llarp_udp_io m_udp; SecretKey m_SecretKey; using AuthedLinks = std::unordered_multimap, RouterID::Hash>; using Pending = std::unordered_multimap, SockAddr::Hash>; mutable DECLARE_LOCK(Mutex_t, m_AuthedLinksMutex, ACQUIRED_BEFORE(m_PendingMutex)); AuthedLinks m_AuthedLinks GUARDED_BY(m_AuthedLinksMutex); mutable DECLARE_LOCK(Mutex_t, m_PendingMutex, ACQUIRED_AFTER(m_AuthedLinksMutex)); Pending m_Pending GUARDED_BY(m_PendingMutex); std::unordered_map m_RecentlyClosed; }; using LinkLayer_ptr = std::shared_ptr; } // namespace llarp #endif