llarp/iwp/session.hpp

Namespaces

Name
llarp
[crypto.hpp]
llarp::iwp

Classes

Name
struct llarp::iwp::Session

Source code

#pragma once

#include <cstdint>
#include <llarp/link/session.hpp>
#include "linklayer.hpp"
#include "message_buffer.hpp"

#include <map>
#include <unordered_set>
#include <deque>

#include <llarp/util/priority_queue.hpp>
#include <llarp/util/thread/queue.hpp>

namespace llarp
{
  namespace iwp
  {
    static constexpr size_t PacketOverhead = HMACSIZE + TUNNONCESIZE;
    ILinkSession::Packet_t
    CreatePacket(Command cmd, size_t plainsize, size_t min_pad = 16, size_t pad_variance = 16);
    static constexpr std::chrono::milliseconds DeliveryTimeout = 500ms;
    static constexpr auto ReceivalTimeout = (DeliveryTimeout * 8) / 5;
    static constexpr auto ReplayWindow = (ReceivalTimeout * 3) / 2;
    static constexpr auto ACKResendInterval = DeliveryTimeout / 2;
    static constexpr auto TXFlushInterval = (DeliveryTimeout / 5) * 4;
    static constexpr std::chrono::milliseconds PingInterval = 5s;
    static constexpr auto SessionAliveTimeout = PingInterval * 5;

    struct Session : public ILinkSession, public std::enable_shared_from_this<Session>
    {
      using Time_t = std::chrono::milliseconds;

      static constexpr std::size_t MaxACKSInMACK = 1024 / sizeof(uint64_t);

      Session(LinkLayer* parent, const RouterContact& rc, const AddressInfo& ai);
      Session(LinkLayer* parent, const SockAddr& from);

      // Signal the event loop that a pump is needed (idempotent)
      void
      TriggerPump();

      // Does the actual pump
      void
      Pump() override;

      void
      Tick(llarp_time_t now) override;

      bool
      SendMessageBuffer(
          ILinkSession::Message_t msg,
          CompletionHandler resultHandler,
          uint16_t priority = 0) override;

      void
      Send_LL(const byte_t* buf, size_t sz);

      void EncryptAndSend(ILinkSession::Packet_t);

      void
      Start() override;

      void
      Close() override;

      bool Recv_LL(ILinkSession::Packet_t) override;

      bool
      SendKeepAlive() override;

      bool
      IsEstablished() const override;

      bool
      TimedOut(llarp_time_t now) const override;

      PubKey
      GetPubKey() const override
      {
        return m_RemoteRC.pubkey;
      }

      const SockAddr&
      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;

      SessionStats
      GetSessionStats() const override;

      bool
      IsInbound() const override
      {
        return m_Inbound;
      }
      void
      HandlePlaintext() override;

      void
      VerifiedMessage(uint64_t msgid);

      void
      DropMessage(uint64_t msgid);

      void
      TriggerHashGen();

      void
      SendMACK();

      void
      RecvHashed(std::vector<OutboundMessage> msgs);

     private:
      enum class State
      {
        Initial,
        Introduction,
        LinkIntro,
        Ready,
        Closed
      };
      static std::string
      StateToString(State state);
      State m_State;
      SessionStats m_Stats;

      const bool m_Inbound;
      LinkLayer* const m_Parent;
      const llarp_time_t m_CreatedAt;
      const SockAddr m_RemoteAddr;

      AddressInfo m_ChosenAI;
      RouterContact m_RemoteRC;
      SharedSecret m_SessionKey;
      AlignedBuffer<24> token;

      PubKey m_ExpectedIdent;
      PubKey m_RemoteOnionKey;

      llarp_time_t m_LastTX = 0s;
      llarp_time_t m_LastRX = 0s;

      // accumulate for periodic rate calculation
      uint64_t m_TXRate = 0;
      uint64_t m_RXRate = 0;

      llarp_time_t m_ResetRatesAt = 0s;

      uint64_t m_TXID = 0;

      bool
      ShouldResetRates(llarp_time_t now) const;

      void
      ResetRates();

      std::map<uint64_t, InboundMessage> m_RXMsgs;
      std::map<uint64_t, OutboundMessage> m_TXMsgs;

      std::unordered_map<uint64_t, llarp_time_t> m_ReplayFilter;
      std::priority_queue<uint64_t> m_SendMACKs;

      using CryptoQueue_t = std::vector<Packet_t>;

      CryptoQueue_t m_EncryptNext;
      CryptoQueue_t m_DecryptNext;

      std::atomic_flag m_PlaintextEmpty;
      llarp::thread::Queue<CryptoQueue_t> m_PlaintextRecv;
      std::unordered_set<uint64_t> m_ToHash;
      std::unordered_set<uint64_t> m_PendingHash;
      std::atomic_flag m_SentClosed;

      template <typename Iter_t>
      void
      maybe_queue_verify(Iter_t itr);

      void
      HandleGeneratedHash(const OutboundMessage&);

      void
      EncryptWorker(CryptoQueue_t msgs);

      void
      DecryptWorker(CryptoQueue_t msgs);

      void
      HandleGotIntro(Packet_t pkt);

      void
      HandleGotIntroAck(Packet_t pkt);

      void
      HandleCreateSessionRequest(Packet_t pkt);

      void
      HandleAckSession(Packet_t pkt);

      void
      HandleSessionData(Packet_t pkt);

      bool
      DecryptMessageInPlace(Packet_t& pkt);

      void
      HandleRecvMsgCompleted(const InboundMessage& msg);

      void
      GenerateAndSendIntro();

      bool
      GotInboundLIM(const LinkIntroMessage* msg);

      bool
      GotOutboundLIM(const LinkIntroMessage* msg);

      bool
      GotRenegLIM(const LinkIntroMessage* msg);

      void
      SendOurLIM(ILinkSession::CompletionHandler h = nullptr);

      void
      HandleXMIT(Packet_t msg);

      void
      HandleDATA(Packet_t msg);

      void
      HandleACKS(Packet_t msg);

      void
      HandleNACK(Packet_t msg);

      void
      HandlePING(Packet_t msg);

      void
      HandleCLOS(Packet_t msg);

      void
      HandleMACK(Packet_t msg);
    };
  }  // namespace iwp
}  // namespace llarp

Updated on 2026-01-10 at 22:49:45 +0000