{-# LANGUAGE
MagicHash
, RecordWildCards
, UndecidableInstances
#-}
{-# OPTIONS_GHC -Wno-duplicate-exports #-}
module Net.DNSBase.RData.SVCB
(
X_svcb(.., T_SVCB, T_HTTPS)
, type XsvcbConName
, T_svcb
, T_https
, svcPriority
, svcTarget
, svcParamValues
, httpsPriority
, httpsTarget
, httpsParamValues
, KnownSVCParamValue(..)
, SPVSet(..)
, spvLookup
, module Net.DNSBase.RData.SVCB.SPV
, module Net.DNSBase.RData.SVCB.SVCParamValue
, module Net.DNSBase.RData.SVCB.SVCParamKey
) where
import qualified Data.IntMap as IM
import Data.IntMap (IntMap)
import GHC.Exts (proxy#)
import GHC.IsList(IsList(..))
import GHC.TypeLits as TL (TypeError, ErrorMessage(..))
import GHC.TypeLits (KnownSymbol, Symbol, symbolVal')
import Net.DNSBase.Internal.Util
import Net.DNSBase.Decode.Domain
import Net.DNSBase.Decode.State
import Net.DNSBase.Domain
import Net.DNSBase.Encode.Metric
import Net.DNSBase.Encode.State
import Net.DNSBase.Nat16
import Net.DNSBase.Present
import Net.DNSBase.RData
import Net.DNSBase.RData.SVCB.SPV
import Net.DNSBase.RData.SVCB.SVCParamKey
import Net.DNSBase.RData.SVCB.SVCParamValue
import Net.DNSBase.RData.SVCB.SPVSet (SPVSet(..), spvSetFromMonoList, spvLookup)
import Net.DNSBase.RRTYPE
type XsvcbConName :: Nat -> Symbol
type family XsvcbConName n where
XsvcbConName N_svcb = "T_SVCB"
XsvcbConName N_https = "T_HTTPS"
XsvcbConName n = TypeError
( ShowType n
:<>: TL.Text " is not a SVCB-based RRTYPE" )
type SPVDecoderMap = IntMap (Int -> SGet SVCParamValue)
type T_svcb = X_svcb N_svcb
type T_https = X_svcb N_https
pattern T_SVCB :: Word16
-> Domain
-> SPVSet
-> T_svcb
pattern $mT_SVCB :: forall {r}.
T_svcb -> (Word16 -> Domain -> SPVSet -> r) -> ((# #) -> r) -> r
$bT_SVCB :: Word16 -> Domain -> SPVSet -> T_svcb
T_SVCB { T_svcb -> Word16
svcPriority, T_svcb -> Domain
svcTarget, T_svcb -> SPVSet
svcParamValues }
= (X_SVCB svcPriority svcTarget svcParamValues :: T_svcb)
{-# COMPLETE T_SVCB #-}
pattern T_HTTPS :: Word16
-> Domain
-> SPVSet
-> T_https
pattern $mT_HTTPS :: forall {r}.
T_https -> (Word16 -> Domain -> SPVSet -> r) -> ((# #) -> r) -> r
$bT_HTTPS :: Word16 -> Domain -> SPVSet -> T_https
T_HTTPS { T_https -> Word16
httpsPriority, T_https -> Domain
httpsTarget, T_https -> SPVSet
httpsParamValues }
= (X_SVCB httpsPriority httpsTarget httpsParamValues :: T_https)
{-# COMPLETE T_HTTPS #-}
type X_svcb :: Nat -> Type
type role X_svcb nominal
data X_svcb n = X_SVCB
{ forall (n :: Nat). X_svcb n -> Word16
_svcPriority :: Word16
, forall (n :: Nat). X_svcb n -> Domain
_svcTarget :: Domain
, forall (n :: Nat). X_svcb n -> SPVSet
_svcParamValues :: SPVSet
}
deriving instance Eq (X_svcb n)
instance (KnownSymbol (XsvcbConName n)) => Show (X_svcb n) where
showsPrec :: Int -> X_svcb n -> ShowS
showsPrec Int
p X_SVCB{Word16
Domain
SPVSet
_svcPriority :: forall (n :: Nat). X_svcb n -> Word16
_svcTarget :: forall (n :: Nat). X_svcb n -> Domain
_svcParamValues :: forall (n :: Nat). X_svcb n -> SPVSet
_svcPriority :: Word16
_svcTarget :: Domain
_svcParamValues :: SPVSet
..} = Int -> ShowS -> ShowS
showsP Int
p (ShowS -> ShowS) -> ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$
String -> ShowS
showString (Proxy# (XsvcbConName n) -> String
forall (n :: Symbol). KnownSymbol n => Proxy# n -> String
symbolVal' (forall {k} (a :: k). Proxy# a
forall (a :: Symbol). Proxy# a
proxy# @(XsvcbConName n))) ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> ShowS
showChar Char
' '
ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word16 -> ShowS
forall a. Show a => a -> ShowS
shows' Word16
_svcPriority ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> ShowS
showChar Char
' '
ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Domain -> ShowS
forall a. Show a => a -> ShowS
shows' Domain
_svcTarget ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> ShowS
showChar Char
' '
ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SPVSet -> ShowS
forall a. Show a => a -> ShowS
shows' SPVSet
_svcParamValues
instance Ord (X_svcb n) where
X_svcb n
a compare :: X_svcb n -> X_svcb n -> Ordering
`compare` X_svcb n
b = (X_svcb n -> Word16
forall (n :: Nat). X_svcb n -> Word16
_svcPriority X_svcb n
a) Word16 -> Word16 -> Ordering
forall a. Ord a => a -> a -> Ordering
`compare` (X_svcb n -> Word16
forall (n :: Nat). X_svcb n -> Word16
_svcPriority X_svcb n
b)
Ordering -> Ordering -> Ordering
forall a. Semigroup a => a -> a -> a
<> (X_svcb n -> Domain
forall (n :: Nat). X_svcb n -> Domain
_svcTarget X_svcb n
a) Domain -> Domain -> Ordering
forall a. Ord a => a -> a -> Ordering
`compare` (X_svcb n -> Domain
forall (n :: Nat). X_svcb n -> Domain
_svcTarget X_svcb n
b)
Ordering -> Ordering -> Ordering
forall a. Semigroup a => a -> a -> a
<> (X_svcb n -> [SVCParamValue]
forall {n :: Nat}. X_svcb n -> [SVCParamValue]
spvs X_svcb n
a) [SVCParamValue] -> [SVCParamValue] -> Ordering
forall a. Ord a => a -> a -> Ordering
`compare` (X_svcb n -> [SVCParamValue]
forall {n :: Nat}. X_svcb n -> [SVCParamValue]
spvs X_svcb n
b)
where
spvs :: X_svcb n -> [SVCParamValue]
spvs = SPVSet -> [Item SPVSet]
SPVSet -> [SVCParamValue]
forall l. IsList l => l -> [Item l]
toList (SPVSet -> [SVCParamValue])
-> (X_svcb n -> SPVSet) -> X_svcb n -> [SVCParamValue]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. X_svcb n -> SPVSet
forall (n :: Nat). X_svcb n -> SPVSet
_svcParamValues
instance Presentable (X_svcb n) where
present :: X_svcb n -> Builder -> Builder
present (X_SVCB Word16
p Domain
d SPVSet
vs) =
Word16 -> Builder -> Builder
forall a. Presentable a => a -> Builder -> Builder
present Word16
p (Builder -> Builder) -> (Builder -> Builder) -> Builder -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Domain -> Builder -> Builder
forall a. Presentable a => a -> Builder -> Builder
presentSp Domain
d (Builder -> Builder) -> (Builder -> Builder) -> Builder -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Builder -> [SVCParamValue] -> Builder)
-> [SVCParamValue] -> Builder -> Builder
forall a b c. (a -> b -> c) -> b -> a -> c
flip ((SVCParamValue -> Builder -> Builder)
-> Builder -> [SVCParamValue] -> Builder
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr SVCParamValue -> Builder -> Builder
forall a. Presentable a => a -> Builder -> Builder
presentSp) (SPVSet -> [Item SPVSet]
forall l. IsList l => l -> [Item l]
toList SPVSet
vs)
instance (Nat16 n, KnownSymbol (XsvcbConName n)) => KnownRData (X_svcb n) where
type RDataExtensionVal (X_svcb n) = SPVDecoderMap
rdataExtensionVal :: forall b -> (b ~ X_svcb n) => RDataExtensionVal (X_svcb n)
rdataExtensionVal _ = SPVDecoderMap
RDataExtensionVal (X_svcb n)
baseSVCParams
rdType :: forall b -> (b ~ X_svcb n) => RRTYPE
rdType _ = Word16 -> RRTYPE
RRTYPE (Word16 -> RRTYPE) -> Word16 -> RRTYPE
forall a b. (a -> b) -> a -> b
$ natToWord16 n
rdEncode :: forall s. X_svcb n -> SPut s RData
rdEncode (X_SVCB Word16
p Domain
d SPVSet
vs) = do
SizedBuilder -> SPut s RData
forall r s. ErrorContext r => SizedBuilder -> SPut s r
putSizedBuilder (SizedBuilder -> SPut s RData) -> SizedBuilder -> SPut s RData
forall a b. (a -> b) -> a -> b
$ Word16 -> SizedBuilder
mbWord16 Word16
p SizedBuilder -> SizedBuilder -> SizedBuilder
forall a. Semigroup a => a -> a -> a
<> Domain -> SizedBuilder
mbWireForm Domain
d
(SVCParamValue -> SPut s RData) -> [SVCParamValue] -> SPut s RData
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ SVCParamValue -> SPut s RData
forall {r} {s}.
(Typeable r, Show r, Eq r) =>
SVCParamValue -> SPutM s r ()
enc ([SVCParamValue] -> SPut s RData)
-> [SVCParamValue] -> SPut s RData
forall a b. (a -> b) -> a -> b
$ SPVSet -> [Item SPVSet]
forall l. IsList l => l -> [Item l]
toList SPVSet
vs
where
enc :: SVCParamValue -> SPutM s r ()
enc (SVCParamValue (a
x :: t)) = do
Word16 -> SPutM s r ()
forall r s. ErrorContext r => Word16 -> SPut s r
put16 (Word16 -> SPutM s r ()) -> Word16 -> SPutM s r ()
forall a b. (a -> b) -> a -> b
$ SVCParamKey -> Word16
forall a b. Coercible a b => a -> b
coerce (SVCParamKey -> Word16) -> SVCParamKey -> Word16
forall a b. (a -> b) -> a -> b
$ spvKey t
SPutM s r () -> SPutM s r ()
forall r s a. ErrorContext r => SPutM s r a -> SPutM s r a
passLen (SPutM s r () -> SPutM s r ()) -> SPutM s r () -> SPutM s r ()
forall a b. (a -> b) -> a -> b
$ a -> SPutM s r ()
forall a r s.
(KnownSVCParamValue a, ErrorContext r) =>
a -> SPut s r
forall r s. ErrorContext r => a -> SPut s r
encodeSPV a
x
rdDecode :: forall b ->
(b ~ X_svcb n) => RDataExtensionVal (X_svcb n) -> Int -> SGet RData
rdDecode _ RDataExtensionVal (X_svcb n)
sdm Int
len = do
pos0 <- SGet Int
getPosition
_svcPriority <- get16
_svcTarget <- getDomainNC
pos1 <- getPosition
vals <- decodeSVCFieldValues (len - (pos1 - pos0))
let _svcParamValues = [SVCParamValue] -> SPVSet
spvSetFromMonoList ([SVCParamValue] -> SPVSet) -> [SVCParamValue] -> SPVSet
forall a b. (a -> b) -> a -> b
$ [SVCParamValue] -> [SVCParamValue]
forall a. [a] -> [a]
reverse [SVCParamValue]
vals
pure $ RData $ (X_SVCB{..} :: X_svcb n)
where
decodeSVCFieldValues :: Int -> SGet [SVCParamValue]
decodeSVCFieldValues :: Int -> SGet [SVCParamValue]
decodeSVCFieldValues = Int -> SGet [SVCParamValue] -> SGet [SVCParamValue]
forall a. Int -> SGet a -> SGet a
fitSGet (Int -> SGet [SVCParamValue] -> SGet [SVCParamValue])
-> (Int -> Int)
-> Int
-> SGet [SVCParamValue]
-> SGet [SVCParamValue]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> Int
forall a. a -> a
id (Int -> SGet [SVCParamValue] -> SGet [SVCParamValue])
-> (Int -> SGet [SVCParamValue]) -> Int -> SGet [SVCParamValue]
forall a b. (Int -> a -> b) -> (Int -> a) -> Int -> b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> [SVCParamValue] -> Word16 -> Int -> SGet [SVCParamValue]
loop [] Word16
0
where
loop :: [SVCParamValue] -> Word16 -> Int -> SGet [SVCParamValue]
loop :: [SVCParamValue] -> Word16 -> Int -> SGet [SVCParamValue]
loop [SVCParamValue]
acc !Word16
kmin !Int
n | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0 = do
pos0 <- SGet Int
getPosition
key <- get16
vlen <- getInt16
when (key == 0xffff) reserved
when (kmin > key) $ nonmono (kmin-1) key
spv <- case IM.lookup (fromIntegral key) sdm of
Just Int -> SGet SVCParamValue
dc -> Int -> SGet SVCParamValue -> SGet SVCParamValue
forall a. Int -> SGet a -> SGet a
fitSGet Int
vlen (SGet SVCParamValue -> SGet SVCParamValue)
-> SGet SVCParamValue -> SGet SVCParamValue
forall a b. (a -> b) -> a -> b
$ Int -> SGet SVCParamValue
dc Int
vlen
Maybe (Int -> SGet SVCParamValue)
Nothing -> Word16 -> ShortByteString -> SVCParamValue
opaqueSPV Word16
key (ShortByteString -> SVCParamValue)
-> SGet ShortByteString -> SGet SVCParamValue
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> SGet ShortByteString
getShortNByteString Int
vlen
used <- (subtract pos0) <$> getPosition
loop (spv : acc) (key + 1) (n - used)
loop [SVCParamValue]
acc Word16
_ Int
0 = [SVCParamValue] -> SGet [SVCParamValue]
forall a. a -> SGet a
forall (f :: * -> *) a. Applicative f => a -> f a
pure [SVCParamValue]
acc
loop [SVCParamValue]
_ Word16
_ Int
_ = String -> SGet [SVCParamValue]
forall a. String -> SGet a
failSGet String
"internal error"
reserved :: SGet a
reserved = String -> SGet a
forall a. String -> SGet a
failSGet String
"Reserved invalid key: 65535"
nonmono :: a -> a -> SGet a
nonmono a
k1 a
k2 =
String -> SGet a
forall a. String -> SGet a
failSGet (String -> SGet a) -> String -> SGet a
forall a b. (a -> b) -> a -> b
$ String
"Non-increasing keys: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ a -> String
forall a. Show a => a -> String
show a
k1 String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
", " String -> ShowS
forall a. [a] -> [a] -> [a]
++ a -> String
forall a. Show a => a -> String
show a
k2
instance (Nat16 n, KnownSymbol (XsvcbConName n))
=> TypeExtensible (X_svcb n) SPVDecoderMap where
type TypeExtensionArg (X_svcb n) b = KnownSVCParamValue b
extendByType :: forall t b ->
(t ~ X_svcb n, TypeExtensionArg t b) =>
SPVDecoderMap -> SPVDecoderMap
extendByType _ b SPVDecoderMap
m
| Int
key Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
mandatoryKey = SPVDecoderMap
m
| Bool
otherwise = Int
-> (Int -> SGet SVCParamValue) -> SPVDecoderMap -> SPVDecoderMap
forall a. Int -> a -> IntMap a -> IntMap a
IM.insert Int
key (decodeSPV b) SPVDecoderMap
m
where
key :: Int
key = forall a b. (Integral a, Num b) => a -> b
fromIntegral @Word16 (Word16 -> Int) -> (SVCParamKey -> Word16) -> SVCParamKey -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SVCParamKey -> Word16
forall a b. Coercible a b => a -> b
coerce (SVCParamKey -> Int) -> SVCParamKey -> Int
forall a b. (a -> b) -> a -> b
$ spvKey b
baseSVCParams :: SPVDecoderMap
baseSVCParams :: SPVDecoderMap
baseSVCParams = [(Int, Int -> SGet SVCParamValue)] -> SPVDecoderMap
forall a. [(Int, a)] -> IntMap a
IM.fromList
[ spvMapEntry SPV_mandatory
, spvMapEntry SPV_alpn
, spvMapEntry SPV_ndalpn
, spvMapEntry SPV_port
, spvMapEntry SPV_ipv4hint
, spvMapEntry SPV_ech
, spvMapEntry SPV_ipv6hint
, spvMapEntry SPV_dohpath
, spvMapEntry SPV_tlsgroups
, spvMapEntry SPV_docpath
, spvMapEntry SPV_pvd
]
where
spvMapEntry :: forall a -> KnownSVCParamValue a
=> (Int, Int -> SGet SVCParamValue)
spvMapEntry :: forall a ->
KnownSVCParamValue a => (Int, Int -> SGet SVCParamValue)
spvMapEntry a =
( forall a b. (Integral a, Num b) => a -> b
fromIntegral @Word16 (Word16 -> Int) -> (SVCParamKey -> Word16) -> SVCParamKey -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SVCParamKey -> Word16
forall a b. Coercible a b => a -> b
coerce (SVCParamKey -> Int) -> SVCParamKey -> Int
forall a b. (a -> b) -> a -> b
$ spvKey a
, decodeSPV a)
mandatoryKey :: Int
mandatoryKey :: Int
mandatoryKey = forall a b. (Integral a, Num b) => a -> b
fromIntegral @Word16 (Word16 -> Int) -> (SVCParamKey -> Word16) -> SVCParamKey -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SVCParamKey -> Word16
forall a b. Coercible a b => a -> b
coerce (SVCParamKey -> Int) -> SVCParamKey -> Int
forall a b. (a -> b) -> a -> b
$ spvKey SPV_mandatory