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 "message_buffer.hpp"

#include <map>
#include <unordered_set>

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

namespace llarp::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;

  class EncryptWorker;
  class DecryptWorker;
  struct LinkLayer;

  struct Session : ILinkSession, std::enable_shared_from_this<Session>
  {
    friend EncryptWorker;
    friend DecryptWorker;
    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;

    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);
    using PlaintextEvent_t = std::pair<uint64_t, Packet_t>;

   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;
    util::descending_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<PlaintextEvent_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
    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(const Packet_t& msg);

    void
    HandleDATA(const Packet_t& msg);

    void
    HandleACKS(const Packet_t& msg);

    void
    HandleNACK(const Packet_t& msg);

    void
    HandlePING(const Packet_t& msg);

    void
    HandleCLOS(const Packet_t& msg);

    void
    HandleMACK(const Packet_t& msg);
  };

  bool
  operator<(const Session::PlaintextEvent_t& lhs, const Session::PlaintextEvent_t& rhs);

}  // namespace llarp::iwp

Updated on 2026-04-01 at 23:35:40 +0000