quic 0.3.2 → 0.3.3
raw patch · 10 files changed
+75/−19 lines, 10 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
+ Network.QUIC.Internal: [onResetStreamReceived2] :: Hooks -> Maybe Stream -> ApplicationProtocolError -> Int -> IO ()
+ Network.QUIC.Internal: getTxStreamFinalSize :: Stream -> IO Offset
- Network.QUIC.Internal: Hooks :: IO () -> (EncryptionLevel -> Plain -> Plain) -> (Parameters -> Parameters) -> ([ExtensionRaw] -> [ExtensionRaw]) -> ([(EncryptionLevel, CryptoData)] -> ([(EncryptionLevel, CryptoData)], Bool)) -> (Stream -> ApplicationProtocolError -> IO ()) -> IO () -> (ConnectionInfo -> IO ()) -> Hooks
+ Network.QUIC.Internal: Hooks :: IO () -> (EncryptionLevel -> Plain -> Plain) -> (Parameters -> Parameters) -> ([ExtensionRaw] -> [ExtensionRaw]) -> ([(EncryptionLevel, CryptoData)] -> ([(EncryptionLevel, CryptoData)], Bool)) -> (Stream -> ApplicationProtocolError -> IO ()) -> (Maybe Stream -> ApplicationProtocolError -> Int -> IO ()) -> IO () -> (ConnectionInfo -> IO ()) -> Hooks
Files
- ChangeLog.md +5/−0
- Network/QUIC/Config.hs +2/−0
- Network/QUIC/IO.hs +2/−1
- Network/QUIC/Receiver.hs +6/−3
- Network/QUIC/Stream.hs +1/−0
- Network/QUIC/Stream/Misc.hs +4/−0
- Network/QUIC/Utils.hs +9/−9
- Network/QUIC/Windows.hs +4/−4
- quic.cabal +2/−2
- test/IOSpec.hs +40/−0
ChangeLog.md view
@@ -1,5 +1,10 @@ # ChangeLog +## 0.3.3++* RST_STREAM now contains a proper final size.+ [#93](https://github.com/kazu-yamamoto/quic/pull/93)+ ## 0.3.2 * Support Unreliable Datagrams extension (RFC9221)
Network/QUIC/Config.hs view
@@ -36,6 +36,7 @@ :: [(EncryptionLevel, CryptoData)] -> ([(EncryptionLevel, CryptoData)], Bool) , onResetStreamReceived :: Stream -> ApplicationProtocolError -> IO ()+ , onResetStreamReceived2 :: Maybe Stream -> ApplicationProtocolError -> Int -> IO () , onServerReady :: IO () , onConnectionEstablished :: ConnectionInfo -> IO () }@@ -50,6 +51,7 @@ , onTLSExtensionCreated = id , onTLSHandshakeCreated = (,False) , onResetStreamReceived = \_ _ -> return ()+ , onResetStreamReceived2 = \_ _ _ -> return () , onServerReady = return () , onConnectionEstablished = \_ -> return () }
Network/QUIC/IO.hs view
@@ -217,10 +217,11 @@ let sid = streamId s sclosed <- isTxStreamClosed s unless sclosed $ do+ finalSize <- getTxStreamFinalSize s setTxStreamClosed s setRxStreamClosed s lvl <- getEncryptionLevel conn- let frame = ResetStream sid aerr 0+ let frame = ResetStream sid aerr finalSize putOutput conn $ OutControl lvl [frame] delStream conn s
Network/QUIC/Receiver.hs view
@@ -11,6 +11,7 @@ import Network.TLS (AlertDescription (..)) import System.Log.FastLogger +import Control.Concurrent.STM import Network.QUIC.Config import Network.QUIC.Connection import Network.QUIC.Connector@@ -23,7 +24,6 @@ import Network.QUIC.Parameters import Network.QUIC.Qlog import Network.QUIC.Recovery-import Control.Concurrent.STM import Network.QUIC.Stream import Network.QUIC.Types as QUIC @@ -242,12 +242,13 @@ processFrame conn lvl (Ack ackInfo ackDelay) = do when (lvl == RTT0Level) $ closeConnection conn ProtocolViolation "ACK" onAckReceived (connLDCC conn) lvl ackInfo $ milliToMicro ackDelay-processFrame conn lvl (ResetStream sid aerr _finlen) = do+processFrame conn lvl (ResetStream sid aerr finlen) = do when (lvl == InitialLevel || lvl == HandshakeLevel) $ closeConnection conn ProtocolViolation "RESET_STREAM" when (isSendOnly conn sid) $ closeConnection conn StreamStateError "Received in a send-only stream" mstrm <- findStream conn sid+ onResetStreamReceived2 (connHooks conn) mstrm aerr finlen case mstrm of Nothing -> return () Just strm -> do@@ -265,7 +266,9 @@ mstrm <- findStream conn sid case mstrm of Nothing -> streamNotCreatedYet conn sid "No such stream for STOP_SENDING"- Just _strm -> sendFrames conn lvl [ResetStream sid err 0]+ Just strm -> do+ finalSize <- getTxStreamFinalSize strm+ sendFrames conn lvl [ResetStream sid err finalSize] processFrame _ _ (CryptoF _ "") = return () processFrame conn lvl (CryptoF off cdat) = do when (lvl == RTT0Level) $
Network/QUIC/Stream.hs view
@@ -13,6 +13,7 @@ waitFinTx, -- * Misc+ getTxStreamFinalSize, getTxStreamOffset, isTxStreamClosed, setTxStreamClosed,
Network/QUIC/Stream/Misc.hs view
@@ -2,6 +2,7 @@ {-# LANGUAGE RecordWildCards #-} module Network.QUIC.Stream.Misc (+ getTxStreamFinalSize, getTxStreamOffset, isTxStreamClosed, setTxStreamClosed,@@ -26,6 +27,9 @@ import Network.QUIC.Stream.Types ----------------------------------------------------------------++getTxStreamFinalSize :: Stream -> IO Offset+getTxStreamFinalSize Stream{..} = streamOffset <$> readIORef streamStateTx getTxStreamOffset :: Stream -> Int -> IO Offset getTxStreamOffset Stream{..} len = atomicModifyIORef' streamStateTx get
Network/QUIC/Utils.hs view
@@ -3,7 +3,7 @@ module Network.QUIC.Utils where -import Control.Exception+import qualified Control.Exception as E import Control.Monad (replicateM) import qualified Data.ByteString as BS import Data.ByteString.Base16@@ -60,18 +60,18 @@ shortpack :: String -> ShortByteString shortpack = Short.toShort . C8.pack -ignore :: SomeException -> IO ()+ignore :: E.SomeException -> IO () ignore se- | isAsyncException se = throwIO se+ | isAsyncException se = E.throwIO se | otherwise = return () -isAsyncException :: Exception e => e -> Bool+isAsyncException :: E.Exception e => e -> Bool isAsyncException e =- case fromException (toException e) of- Just (SomeAsyncException _) -> True+ case E.fromException (E.toException e) of+ Just (E.SomeAsyncException _) -> True Nothing -> False -throughAsync :: IO a -> SomeException -> IO a-throughAsync action (SomeException e)- | isAsyncException e = throwIO e+throughAsync :: IO a -> E.SomeException -> IO a+throughAsync action (E.SomeException e)+ | isAsyncException e = E.throwIO e | otherwise = action
Network/QUIC/Windows.hs view
@@ -6,16 +6,16 @@ #if defined(mingw32_HOST_OS) import Control.Concurrent-import qualified Control.Exception as CE+import qualified Control.Exception as E import Control.Monad windowsThreadBlockHack :: IO a -> IO a windowsThreadBlockHack act = do- var <- newEmptyMVar :: IO (MVar (Either CE.SomeException a))- void . forkIO $ CE.try act >>= putMVar var+ var <- newEmptyMVar :: IO (MVar (Either E.SomeException a))+ void . forkIO $ E.try act >>= putMVar var res <- takeMVar var case res of- Left e -> print e >> CE.throwIO e+ Left e -> print e >> E.throwIO e Right r -> return r #else windowsThreadBlockHack :: IO a -> IO a
quic.cabal view
@@ -1,6 +1,6 @@ cabal-version: >=1.10 name: quic-version: 0.3.2+version: 0.3.3 license: BSD3 license-file: LICENSE maintainer: kazu@iij.ad.jp@@ -151,7 +151,7 @@ serialise, stm >=2.5 && <2.6, tls >=2.4.0 && <2.5,- unix-time >=0.4.12 && <0.5+ unix-time >=0.4.12 && <0.6 if os(linux) cc-options: -DOS_Linux
test/IOSpec.hs view
@@ -7,6 +7,7 @@ import qualified Control.Exception as E import Control.Monad import qualified Data.ByteString as BS+import qualified System.Timeout as Timeout import Test.Hspec import Network.QUIC@@ -86,6 +87,12 @@ withPipe (Randomly 20) $ testRecvStreamClientStopFirst cc sc waitS it "don't block if server stop sending first" $ do withPipe (Randomly 20) $ testRecvStreamServerStopFirst cc sc waitS+ -- RFC 9000: https://www.rfc-editor.org/rfc/rfc9000.html+ -- Section 3.5 says STOP_SENDING asks the peer to send RESET_STREAM.+ -- Sections 4.5 and 19.4 define RESET_STREAM Final Size as the+ -- number of bytes sent by the RESET_STREAM sender.+ it "sends RESET_STREAM with the bytes sent as final size" $ do+ withPipe (DropClientPacket []) $ testResetStreamFinalSize cc sc waitS describe "concurrency" $ do it "can handle multiple clients" $ do withPipe (Randomly 20) $ testMultiSendRecv cc sc waitS 500@@ -104,6 +111,39 @@ assertEndOfStream :: Stream -> IO () assertEndOfStream strm = recvStream strm 1024 `shouldReturn` ""++testResetStreamFinalSize+ :: C.ClientConfig -> ServerConfig -> IO () -> IO ()+testResetStreamFinalSize cc0 sc waitS = do+ finalSizeVar <- newEmptyMVar+ doneVar <- newEmptyMVar+ let request = "open"+ payload = BS.replicate 1234 0+ hooks = (ccHooks cc0){onResetStreamReceived2 = record finalSizeVar}+ cc = cc0{ccHooks = hooks}+ E.bracket (forkIO $ server request payload doneVar) killThread $ \_ ->+ client cc request payload finalSizeVar doneVar+ where+ aerr = ApplicationProtocolError 0++ record finalSizeVar _strm _aerr finalSize = void $ tryPutMVar finalSizeVar finalSize++ client cc request payload finalSizeVar doneVar = do+ waitS+ C.run cc $ \conn -> do+ strm <- stream conn+ sendStream strm request+ consumeBytes strm (BS.length payload)+ stopStream strm aerr+ mres <- Timeout.timeout 5000000 $ takeMVar finalSizeVar+ mres `shouldBe` Just (BS.length payload)+ putMVar doneVar ()++ server request payload doneVar = run sc $ \conn -> do+ strm <- acceptStream conn+ consumeBytes strm (BS.length request)+ sendStream strm payload+ takeMVar doneVar testRecvStreamClientStopFirst :: C.ClientConfig -> ServerConfig -> IO () -> IO ()