1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
|
{-# LANGUAGE RecordWildCards #-}
module Network.Control.Flow (
-- * Constants for flow control.
defaultMaxStreams,
defaultMaxStreamData,
defaultMaxData,
-- * Flow control for sending
TxFlow (..),
newTxFlow,
txWindowSize,
WindowSize,
-- * Flow control for receiving
RxFlow (..),
newRxFlow,
FlowControlType (..),
maybeOpenRxWindow,
checkRxLimit,
) where
import Data.Bits
-- | Default max streams. (64)
defaultMaxStreams :: Int
defaultMaxStreams = 64
-- | Default max data of a stream. (256K bytes)
defaultMaxStreamData :: Int
defaultMaxStreamData = 262144
-- | Default max data of a connection. (1M bytes)
defaultMaxData :: Int
defaultMaxData = 1048576
-- | Window size.
type WindowSize = Int
-- | Flow for sending
data TxFlow = TxFlow
{ txfSent :: Int
, txfLimit :: Int
}
deriving (Show)
-- | Creating TX flow with an initial window size.
newTxFlow :: WindowSize -> TxFlow
newTxFlow win = TxFlow 0 win
-- | 'txfLimit' - 'txfSent'.
txWindowSize :: TxFlow -> WindowSize
txWindowSize TxFlow{..} = txfLimit - txfSent
-- | Flow for receiving
data RxFlow = RxFlow
{ rxfWindow :: WindowSize
, rxfConsumed :: Int
, rxfReceived :: Int
, rxfLimit :: Int
}
deriving (Show)
-- | Creating RX flow with an initial window size.
newRxFlow :: WindowSize -> RxFlow
newRxFlow win = RxFlow win 0 0 win
-- | The representation of window size update.
data FlowControlType
= -- | HTTP\/2 style
FCTWindowUpdate
| -- | QUIC style
FCTMaxData
-- | When an application consumed received data,
-- this function should be called to update 'rxfConsumed'.
-- If the window size is less than the half of the initial window.
-- the representation of window size update is returned.
maybeOpenRxWindow
:: Int
-- ^ The consumed size.
-> FlowControlType
-> RxFlow
-> (RxFlow, Maybe Int)
-- ^ 'Just' if the size should be informed to the peer.
maybeOpenRxWindow consumed fct flow@RxFlow{..}
| available < threshold =
let limit = consumed' + rxfWindow
flow' =
flow
{ rxfConsumed = consumed'
, rxfLimit = limit
}
update = case fct of
FCTWindowUpdate -> limit - rxfLimit
FCTMaxData -> limit
in (flow', Just update)
| otherwise =
let flow' = flow{rxfConsumed = consumed'}
in (flow', Nothing)
where
available = rxfLimit - rxfReceived
threshold = rxfWindow `unsafeShiftR` 1
consumed' = rxfConsumed + consumed
-- | Checking if received data is acceptable against the
-- current window.
checkRxLimit
:: Int
-- ^ The size of received data.
-> RxFlow
-> (RxFlow, Bool)
-- ^ Acceptable if 'True'.
checkRxLimit received flow@RxFlow{..}
| received' <= rxfLimit =
let flow' = flow{rxfReceived = received'}
in (flow', True)
| otherwise = (flow, False)
where
received' = rxfReceived + received
|