{-# LANGUAGE MagicHash #-}
module Hmssql.Tds.Smp
( SmpHeader (..)
, SmpFlag (..)
, smpFlagWord
, smpHeaderLength
, smpIdentifier
, readSmpHeader
, pokeSmpHeader
, smpControlPacket
, smpDataPacket
, smpInitialWindow
) where
import qualified Data.ByteString as B
import qualified Data.ByteString.Internal as BI
import Data.Word (Word16, Word32, Word8)
import Foreign.Ptr (Ptr)
import Foreign.Storable (pokeByteOff)
import Hmssql.Internal.Derived
import Hmssql.Tds.Bytes (word16LeAt, word32LeAt, word8At)
import Hmssql.Tds.Bytes.Unsafe (pokeWord16LE, pokeWord32LE)
data SmpFlag
= SmpSyn
| SmpAck
| SmpFin
| SmpData
deriving stock (SmpFlag -> SmpFlag -> Bool
(SmpFlag -> SmpFlag -> Bool)
-> (SmpFlag -> SmpFlag -> Bool) -> Eq SmpFlag
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: SmpFlag -> SmpFlag -> Bool
== :: SmpFlag -> SmpFlag -> Bool
$c/= :: SmpFlag -> SmpFlag -> Bool
/= :: SmpFlag -> SmpFlag -> Bool
Eq, Int -> SmpFlag -> ShowS
[SmpFlag] -> ShowS
SmpFlag -> String
(Int -> SmpFlag -> ShowS)
-> (SmpFlag -> String) -> ([SmpFlag] -> ShowS) -> Show SmpFlag
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> SmpFlag -> ShowS
showsPrec :: Int -> SmpFlag -> ShowS
$cshow :: SmpFlag -> String
show :: SmpFlag -> String
$cshowList :: [SmpFlag] -> ShowS
showList :: [SmpFlag] -> ShowS
Show)
smpFlagWord :: SmpFlag -> Word8
smpFlagWord :: SmpFlag -> Word8
smpFlagWord = \case
SmpFlag
SmpSyn -> Word8
0x01
SmpFlag
SmpAck -> Word8
0x02
SmpFlag
SmpFin -> Word8
0x04
SmpFlag
SmpData -> Word8
0x08
data =
{ SmpHeader -> Word8
smpFlags :: !Word8
, SmpHeader -> Word16
smpSession :: !Word16
, SmpHeader -> Word32
smpLength :: !Word32
, SmpHeader -> Word32
smpSeqNum :: !Word32
, SmpHeader -> Word32
smpWindow :: !Word32
}
instance Show SmpHeader where
showsPrec :: Int -> SmpHeader -> ShowS
showsPrec Int
p (SmpHeader Word8
a Word16
b Word32
c Word32
e Word32
f) = Int -> Addr# -> [Field] -> ShowS
showRecord Int
p Addr#
"SmpHeader"#
[ Addr#
"smpFlags"# Addr# -> Word8 -> Field
forall a. Show a => Addr# -> a -> Field
:= Word8
a, Addr#
"smpSession"# Addr# -> Word16 -> Field
forall a. Show a => Addr# -> a -> Field
:= Word16
b, Addr#
"smpLength"# Addr# -> Word32 -> Field
forall a. Show a => Addr# -> a -> Field
:= Word32
c, Addr#
"smpSeqNum"# Addr# -> Word32 -> Field
forall a. Show a => Addr# -> a -> Field
:= Word32
e
, Addr#
"smpWindow"# Addr# -> Word32 -> Field
forall a. Show a => Addr# -> a -> Field
:= Word32
f
]
{-# OPAQUE showsPrec #-}
instance Eq SmpHeader where
SmpHeader Word8
a Word16
b Word32
c Word32
e Word32
f == :: SmpHeader -> SmpHeader -> Bool
== SmpHeader Word8
a' Word16
b' Word32
c' Word32
e' Word32
f' =
Word8
a Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
a' Bool -> Bool -> Bool
&& Word16
b Word16 -> Word16 -> Bool
forall a. Eq a => a -> a -> Bool
== Word16
b' Bool -> Bool -> Bool
&& Word32
c Word32 -> Word32 -> Bool
forall a. Eq a => a -> a -> Bool
== Word32
c' Bool -> Bool -> Bool
&& Word32
e Word32 -> Word32 -> Bool
forall a. Eq a => a -> a -> Bool
== Word32
e' Bool -> Bool -> Bool
&& Word32
f Word32 -> Word32 -> Bool
forall a. Eq a => a -> a -> Bool
== Word32
f'
{-# OPAQUE (==) #-}
smpHeaderLength :: Int
= Int
16
smpIdentifier :: Word8
smpIdentifier :: Word8
smpIdentifier = Word8
0x53
smpInitialWindow :: Word32
smpInitialWindow :: Word32
smpInitialWindow = Word32
4
readSmpHeader :: B.ByteString -> SmpHeader
ByteString
bs = SmpHeader
{ smpFlags :: Word8
smpFlags = ByteString -> Int -> Word8
word8At ByteString
bs Int
1
, smpSession :: Word16
smpSession = ByteString -> Int -> Word16
word16LeAt ByteString
bs Int
2
, smpLength :: Word32
smpLength = ByteString -> Int -> Word32
word32LeAt ByteString
bs Int
4
, smpSeqNum :: Word32
smpSeqNum = ByteString -> Int -> Word32
word32LeAt ByteString
bs Int
8
, smpWindow :: Word32
smpWindow = ByteString -> Int -> Word32
word32LeAt ByteString
bs Int
12
}
pokeSmpHeader :: Ptr Word8 -> SmpFlag -> Word16 -> Int -> Word32 -> Word32 -> IO ()
Ptr Word8
p SmpFlag
flag Word16
sid Int
len Word32
seqNum Word32
window = do
Ptr Word8 -> Int -> Word8 -> IO ()
forall b. Ptr b -> Int -> Word8 -> IO ()
forall a b. Storable a => Ptr b -> Int -> a -> IO ()
pokeByteOff Ptr Word8
p Int
0 Word8
smpIdentifier
Ptr Word8 -> Int -> Word8 -> IO ()
forall b. Ptr b -> Int -> Word8 -> IO ()
forall a b. Storable a => Ptr b -> Int -> a -> IO ()
pokeByteOff Ptr Word8
p Int
1 (SmpFlag -> Word8
smpFlagWord SmpFlag
flag)
Ptr Word8 -> Int -> Word16 -> IO ()
pokeWord16LE Ptr Word8
p Int
2 Word16
sid
Ptr Word8 -> Int -> Word32 -> IO ()
pokeWord32LE Ptr Word8
p Int
4 (Int -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len)
Ptr Word8 -> Int -> Word32 -> IO ()
pokeWord32LE Ptr Word8
p Int
8 Word32
seqNum
Ptr Word8 -> Int -> Word32 -> IO ()
pokeWord32LE Ptr Word8
p Int
12 Word32
window
smpControlPacket :: SmpFlag -> Word16 -> Word32 -> Word32 -> B.ByteString
smpControlPacket :: SmpFlag -> Word16 -> Word32 -> Word32 -> ByteString
smpControlPacket SmpFlag
flag Word16
sid Word32
seqNum Word32
window =
Int -> (Ptr Word8 -> IO ()) -> ByteString
BI.unsafeCreate Int
smpHeaderLength ((Ptr Word8 -> IO ()) -> ByteString)
-> (Ptr Word8 -> IO ()) -> ByteString
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p -> Ptr Word8 -> SmpFlag -> Word16 -> Int -> Word32 -> Word32 -> IO ()
pokeSmpHeader Ptr Word8
p SmpFlag
flag Word16
sid Int
smpHeaderLength Word32
seqNum Word32
window
smpDataPacket :: Word16 -> Word32 -> Word32 -> B.ByteString -> [B.ByteString]
smpDataPacket :: Word16 -> Word32 -> Word32 -> ByteString -> [ByteString]
smpDataPacket Word16
sid Word32
window Word32
seqNum ByteString
packet =
[ Int -> (Ptr Word8 -> IO ()) -> ByteString
BI.unsafeCreate Int
smpHeaderLength ((Ptr Word8 -> IO ()) -> ByteString)
-> (Ptr Word8 -> IO ()) -> ByteString
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p ->
Ptr Word8 -> SmpFlag -> Word16 -> Int -> Word32 -> Word32 -> IO ()
pokeSmpHeader Ptr Word8
p SmpFlag
SmpData Word16
sid (Int
smpHeaderLength Int -> Int -> Int
forall a. Num a => a -> a -> a
+ ByteString -> Int
B.length ByteString
packet) Word32
seqNum Word32
window
, ByteString
packet
]