packages feed

quic-0.3.24: Network/QUIC/Connection/PacketNumber.hs

{-# LANGUAGE RecordWildCards #-}

module Network.QUIC.Connection.PacketNumber (
    nextPacketNumber,
    setPeerPacketNumber,
    getPeerPacketNumber,
    recordPeerPacketNumber,
    receivedWindow,
) where

import qualified Data.IntSet as IntSet

import Network.QUIC.Connection.Types
import Network.QUIC.Connector
import Network.QUIC.Imports hiding (range)
import Network.QUIC.Types

----------------------------------------------------------------
-- My packet numbers

nextPacketNumber :: Connection -> IO PacketNumber
nextPacketNumber Connection{..} = atomicModifyIORef' (packetNumber connState) inc
  where
    inc pn = (pn + 1, pn)

----------------------------------------------------------------
-- Peer's largest packet number, which a truncated one is decoded against

getPeerPacketNumber :: Connection -> EncryptionLevel -> IO PacketNumber
getPeerPacketNumber Connection{..} lvl = readIORef (peerPacketNumber ! lvl)

setPeerPacketNumber :: Connection -> EncryptionLevel -> PacketNumber -> IO ()
setPeerPacketNumber Connection{..} lvl n =
    atomicModifyIORef'' (peerPacketNumber ! lvl) $ max n

----------------------------------------------------------------
-- Peer's packet numbers processed, against duplicates

-- | How far below the largest a packet number is remembered.  Older ones
--   are taken as duplicates (RFC 9000 Sec 12.3).
receivedWindow :: PacketNumber
receivedWindow = 4096

-- | Recording a packet number of the peer, 'False' if it may be a duplicate.
recordPeerPacketNumber
    :: Connection -> EncryptionLevel -> PacketNumber -> IO Bool
recordPeerPacketNumber Connection{..} lvl pn =
    atomicModifyIORef' (peerReceived ! lvl) record
  where
    record pns
        | pn `IntSet.member` pns = (pns, False)
        | otherwise = case fst <$> IntSet.maxView pns of
            Just mx
                | pn < mx - receivedWindow -> (pns, False)
                | pn < mx -> (IntSet.insert pn pns, True)
            _ -> (snd $ IntSet.split (pn - receivedWindow - 1) $ IntSet.insert pn pns, True)