diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,17 @@
 # ChangeLog for http2
 
+## 5.3.11
+
+* Implementing `auxSendPing` for client.
+* Server and client terminates their threads in the right order.
+* Using `copy` in frame decoders to avoid potential fragmentation of
+  `ByteString`.
+* Defining `confReadNTimeout` (default to `False`). If `confReadN`
+  implements timeout by itself, set it to `True`.
+* TCP closing is now treaated as `ConnectionIsClosed` instead of
+  `ConnectionIsTimeout`.
+* GOAWAY now contains a right last streamd ID.
+
 ## 5.3.10
 
 * Introducing closure.
@@ -69,7 +81,7 @@
   workers collaborate with the sender after queuing a response and
   finish after all response data are sent.
 * All threads are labeled with `labelThread`. You can see them by
-  `listThreas` if necessary.
+  `listThreads` if necessary.
 
 ## 5.2.6
 
@@ -183,7 +195,7 @@
   [#80](https://github.com/kazu-yamamoto/http2/pull/80)
 * Introducing `KilledByHttp2ThreadManager` instead of `ThreadKilled`.
   [#79](https://github.com/kazu-yamamoto/http2/pull/79)
-  [#81](https://github.com/kazu-yamamoto/http2/pull/82)
+  [#81](https://github.com/kazu-yamamoto/http2/pull/81)
   [#82](https://github.com/kazu-yamamoto/http2/pull/82)
 * Handle RST_STREAM with NO_ERROR.
   [#78](https://github.com/kazu-yamamoto/http2/pull/78)
diff --git a/Network/HPACK/Types.hs b/Network/HPACK/Types.hs
--- a/Network/HPACK/Types.hs
+++ b/Network/HPACK/Types.hs
@@ -1,5 +1,3 @@
-{-# LANGUAGE DeriveDataTypeable #-}
-
 module Network.HPACK.Types (
     -- * Header
     FieldValue,
diff --git a/Network/HTTP2/Client.hs b/Network/HTTP2/Client.hs
--- a/Network/HTTP2/Client.hs
+++ b/Network/HTTP2/Client.hs
@@ -1,4 +1,3 @@
-{-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE RankNTypes #-}
 
 -- | HTTP\/2 client library.
diff --git a/Network/HTTP2/Client/Run.hs b/Network/HTTP2/Client/Run.hs
--- a/Network/HTTP2/Client/Run.hs
+++ b/Network/HTTP2/Client/Run.hs
@@ -80,8 +80,13 @@
         n <- oddConc <$> readTVarIO (oddStreamTable ctx)
         return (x - n)
     aux ctx =
-        Aux
+        defaultAux
             { auxPossibleClientStreams = possibleClientStream ctx
+            , auxSendPing =
+                sendPing
+                    ctx
+                    False
+                    "Haskell!" -- 8 bytes
             }
     clientCore ctx req processResponse = do
         (strm, moutobj) <- makeStream ctx scheme authority req
@@ -129,25 +134,26 @@
             connectionWindowSize
             settings
             confTimeoutManager
+            Nothing
     exchangeSettings ctx
     return ctx
 
 runH2 :: Config -> Context -> IO a -> IO a
 runH2 conf ctx runClient = do
-    T.stopAfter mgr (try runAll >>= closureClient conf) $ \res ->
+    T.stopAfter mgr (try runAll >>= closureClient conf ctx) $ \res ->
         closeAllStreams (oddStreamTable ctx) (evenStreamTable ctx) res
   where
     mgr = threadManager ctx
     runReceiver = frameReceiver ctx conf
     runSender = frameSender ctx conf
-    runBackgroundThreads = do
-        labelMe "H2 runBackgroundThreads"
-        concurrently_ runReceiver runSender
-    runAll = do
-        er <- race runBackgroundThreads runClient
+    runClientReceiver = do
+        labelMe "H2 ClientReceiver"
+        er <- race runReceiver runClient
         case er of
-            Left () -> undefined
             Right r -> return r
+            -- never reached because runReceiver throws an exception to exit.
+            Left () -> throwIO ConnectionIsClosed
+    runAll = snd <$> concurrently runSender runClientReceiver
 
 makeStream
     :: Context
diff --git a/Network/HTTP2/Frame/Decode.hs b/Network/HTTP2/Frame/Decode.hs
--- a/Network/HTTP2/Frame/Decode.hs
+++ b/Network/HTTP2/Frame/Decode.hs
@@ -214,11 +214,11 @@
 
 -- | Frame payload decoder for DATA frame.
 decodeDataFrame :: FramePayloadDecoder
-decodeDataFrame header bs = decodeWithPadding header bs DataFrame
+decodeDataFrame header _bs = decodeWithPadding header _bs DataFrame
 
 -- | Frame payload decoder for HEADERS frame.
 decodeHeadersFrame :: FramePayloadDecoder
-decodeHeadersFrame header bs = decodeWithPadding header bs $ \bs' ->
+decodeHeadersFrame header _bs = decodeWithPadding header _bs $ \bs' ->
     if hasPriority
         then
             let (bs0, bs1) = BS.splitAt 5 bs'
@@ -234,7 +234,7 @@
 
 -- | Frame payload decoder for RST_STREAM frame.
 decodeRSTStreamFrame :: FramePayloadDecoder
-decodeRSTStreamFrame _ bs = Right $ RSTStreamFrame $ toErrorCode (N.word32 bs)
+decodeRSTStreamFrame _ bs = Right $ RSTStreamFrame $ toErrorCode $ N.word32 bs
 
 -- | Frame payload decoder for SETTINGS frame.
 decodeSettingsFrame :: FramePayloadDecoder
@@ -258,19 +258,22 @@
 
 -- | Frame payload decoder for PUSH_PROMISE frame.
 decodePushPromiseFrame :: FramePayloadDecoder
-decodePushPromiseFrame header bs = decodeWithPadding header bs $ \bs' ->
+decodePushPromiseFrame header _bs = decodeWithPadding header _bs $ \bs' ->
     let (bs0, bs1) = BS.splitAt 4 bs'
         sid = streamIdentifier (N.word32 bs0)
      in PushPromiseFrame sid bs1
 
 -- | Frame payload decoder for PING frame.
 decodePingFrame :: FramePayloadDecoder
-decodePingFrame _ bs = Right $ PingFrame bs
+decodePingFrame _ _bs = Right $ PingFrame bs
+  where
+    bs = BS.copy _bs
 
 -- | Frame payload decoder for GOAWAY frame.
 decodeGoAwayFrame :: FramePayloadDecoder
-decodeGoAwayFrame _ bs = Right $ GoAwayFrame sid ecid bs2
+decodeGoAwayFrame _ _bs = Right $ GoAwayFrame sid ecid bs2
   where
+    bs = BS.copy _bs
     (bs0, bs1') = BS.splitAt 4 bs
     (bs1, bs2) = BS.splitAt 4 bs1'
     sid = streamIdentifier (N.word32 bs0)
@@ -287,10 +290,14 @@
 
 -- | Frame payload decoder for CONTINUATION frame.
 decodeContinuationFrame :: FramePayloadDecoder
-decodeContinuationFrame _ bs = Right $ ContinuationFrame bs
+decodeContinuationFrame _ _bs = Right $ ContinuationFrame bs
+  where
+    bs = BS.copy _bs
 
 decodeUnknownFrame :: FrameType -> FramePayloadDecoder
-decodeUnknownFrame typ _ bs = Right $ UnknownFrame typ bs
+decodeUnknownFrame typ _ _bs = Right $ UnknownFrame typ bs
+  where
+    bs = BS.copy _bs
 
 ----------------------------------------------------------------
 
@@ -311,14 +318,15 @@
     -> Either FrameDecodeError FramePayload
 decodeWithPadding FrameHeader{..} bs body
     | padded =
-        let (w8, rest) = fromMaybe (error "decodeWithPadding") $ BS.uncons bs
+        let (w8, rest) = fromMaybe (error "decodeWithPadding") $ BS.uncons bs'
             padlen = intFromWord8 w8
             bodylen = payloadLength - padlen - 1
          in if bodylen < 0
                 then Left $ FrameDecodeError ProtocolError streamId "padding is not enough"
                 else Right . body $ BS.take bodylen rest
-    | otherwise = Right $ body bs
+    | otherwise = Right $ body bs'
   where
+    bs' = BS.copy bs
     padded = testPadded flags
 
 streamIdentifier :: Word32 -> StreamId
diff --git a/Network/HTTP2/H2/Config.hs b/Network/HTTP2/H2/Config.hs
--- a/Network/HTTP2/H2/Config.hs
+++ b/Network/HTTP2/H2/Config.hs
@@ -32,6 +32,7 @@
     confTimeoutManager <- T.initialize usec
     confMySockAddr <- getSocketName s
     confPeerSockAddr <- getPeerName s
+    let confReadNTimeout = False
     return Config{..}
 
 -- | Deallocating the resource of the simple configuration.
diff --git a/Network/HTTP2/H2/Context.hs b/Network/HTTP2/H2/Context.hs
--- a/Network/HTTP2/H2/Context.hs
+++ b/Network/HTTP2/H2/Context.hs
@@ -71,6 +71,7 @@
     --   this requirement.
     , myStreamId         :: TVar StreamId
     , peerStreamId       :: IORef StreamId
+    , peerLastStreamId   :: IORef StreamId
     , outputBufferLimit  :: IORef Int
     , outputQ            :: TQueue Output
     -- ^ Invariant: Each stream will only ever have at most one 'Output'
@@ -89,6 +90,8 @@
     , mySockAddr         :: SockAddr
     , peerSockAddr       :: SockAddr
     , threadManager      :: T.ThreadManager
+    , receiverDone       :: TVar Bool
+    , workersDone        :: STM Bool
     }
 {- FOURMOLU_ENABLE -}
 
@@ -102,8 +105,9 @@
     -> Int
     -> Settings
     -> T.Manager
+    -> Maybe (STM Bool)
     -> IO Context
-newContext roleInfo Config{..} cacheSiz connRxWS mySettings timmgr = do
+newContext roleInfo Config{..} cacheSiz connRxWS mySettings timmgr mdone = do
     -- My: Use this even if ack has not been received yet.
     myFirstSettings <- newIORef False
     -- Peer: The spec defines max concurrency is infinite unless
@@ -116,6 +120,7 @@
     continued         <- newIORef Nothing
     myStreamId        <- newTVarIO sid0
     peerStreamId      <- newIORef 0
+    peerLastStreamId  <- newIORef 0
     outputBufferLimit <- newIORef buflim
     outputQ           <- newTQueueIO
     outputQStreamID   <- newTVarIO sid0
@@ -133,6 +138,8 @@
     let mySockAddr   = confMySockAddr
     let peerSockAddr = confPeerSockAddr
     threadManager   <- T.newThreadManager timmgr
+    receiverDone    <- newTVarIO False
+    let workersDone = fromMaybe (T.isAllGone threadManager) mdone
     return Context{..}
   where
     role = case roleInfo of
@@ -169,6 +176,14 @@
 
 setPeerStreamID :: Context -> StreamId -> IO ()
 setPeerStreamID ctx sid = writeIORef (peerStreamId ctx) sid
+
+----------------------------------------------------------------
+
+getPeerLastStreamId :: Context -> IO StreamId
+getPeerLastStreamId ctx = readIORef $ peerLastStreamId ctx
+
+modifyPeerLastStreamId :: Context -> StreamId -> IO ()
+modifyPeerLastStreamId ctx sid = atomicModifyIORef' (peerLastStreamId ctx) $ \n -> if sid > n then (sid, ()) else (n, ())
 
 ----------------------------------------------------------------
 
diff --git a/Network/HTTP2/H2/EncodeFrame.hs b/Network/HTTP2/H2/EncodeFrame.hs
--- a/Network/HTTP2/H2/EncodeFrame.hs
+++ b/Network/HTTP2/H2/EncodeFrame.hs
@@ -23,10 +23,10 @@
   where
     einfo = encodeInfo func 0
 
-pingFrame :: ByteString -> ByteString
-pingFrame bs = encodeFrame einfo $ PingFrame bs
+pingFrame :: Bool -> ByteString -> ByteString
+pingFrame ack bs = encodeFrame einfo $ PingFrame bs
   where
-    einfo = encodeInfo setAck 0
+    einfo = encodeInfo (if ack then setAck else id) 0
 
 windowUpdateFrame :: StreamId -> WindowSize -> ByteString
 windowUpdateFrame sid winsiz = encodeFrame einfo $ WindowUpdateFrame winsiz
diff --git a/Network/HTTP2/H2/Receiver.hs b/Network/HTTP2/H2/Receiver.hs
--- a/Network/HTTP2/H2/Receiver.hs
+++ b/Network/HTTP2/H2/Receiver.hs
@@ -8,6 +8,7 @@
     frameReceiver,
     closureClient,
     closureServer,
+    sendPing,
 ) where
 
 import Control.Concurrent
@@ -20,6 +21,7 @@
 import Data.IORef
 import Network.Control
 import Network.HTTP.Semantics
+import qualified System.ThreadManager as T
 
 import Imports hiding (delete, insert)
 import Network.HTTP2.Frame
@@ -44,17 +46,35 @@
 ----------------------------------------------------------------
 
 frameReceiver :: Context -> Config -> IO ()
-frameReceiver ctx conf@Config{..} = do
-    labelMe "H2 receiver"
-    loop
+frameReceiver ctx conf@Config{..} =
+    (switch `E.catch` handler)
+        `E.finally` atomically
+            (writeTVar (receiverDone ctx) True)
   where
-    loop = do
-        -- If 'confReadN' is timeouted, an exception is thrown
+    handler ConnectionIsClosed = return ()
+    handler e = E.throwIO e
+    switch = do
+        labelMe "H2 receiver"
+        tid <- myThreadId
+        if confReadNTimeout
+            then
+                loop1
+            else
+                void $
+                    T.withHandle (threadManager ctx) (E.throwTo tid ConnectionIsTimeout) loop2
+    loop1 = do
+        hd <- confReadN frameHeaderLength -- throwing an exception on timeout
+        when (BS.null hd) $ E.throwIO ConnectionIsClosed
+        processFrame ctx conf $ decodeFrameHeader hd
+        loop1
+    loop2 th = do
+        -- If 'confReadN' is timeouted, 'ConnectionIsTimeout' is thrown
         -- to destroy the thread trees.
         hd <- confReadN frameHeaderLength
-        when (BS.null hd) $ E.throwIO ConnectionIsTimeout
+        T.tickle th
+        when (BS.null hd) $ E.throwIO ConnectionIsClosed
         processFrame ctx conf $ decodeFrameHeader hd
-        loop
+        loop2 th
 
 ----------------------------------------------------------------
 
@@ -291,14 +311,12 @@
                         setframe = CFrames (Just peerAlist) (frames ++ [ack])
                     writeIORef myFirstSettings True
                     enqueueControl controlQ setframe
-control FramePing FrameHeader{flags, streamId} bs Context{mySettings, controlQ, pingRate} =
+control FramePing FrameHeader{flags, streamId} bs ctx@Context{mySettings, pingRate} =
     unless (testAck flags) $ do
         rate <- getRate pingRate
         if rate > pingRateLimit mySettings
             then E.throwIO $ ConnectionErrorIsSent EnhanceYourCalm streamId "too many ping"
-            else do
-                let frame = pingFrame bs
-                enqueueControl controlQ $ CFrames Nothing [frame]
+            else sendPing ctx True bs
 control FrameGoAway header bs _ = do
     GoAwayFrame sid err msg <- guardIt $ decodeGoAwayFrame header bs
     if err == NoError
@@ -622,36 +640,63 @@
 
 ----------------------------------------------------------------
 
-closureClient :: Config -> Either E.SomeException a -> IO a
-closureClient Config{..} (Right x) = do
-    let frame = goawayFrame 0 NoError ""
-    confSendAll frame `E.catch` ignore
+closureClient :: Config -> Context -> Either E.SomeException a -> IO a
+closureClient conf ctx (Right x) = do
+    frame <- goaway ctx NoError "no error"
+    sendGoaway conf frame
     return x
-  where
-    ignore (E.SomeException e)
-        | isAsyncException e = E.throwIO e
-        | otherwise = return ()
-closureClient conf (Left se) = closureServer conf se
+closureClient conf ctx (Left se) = closureServer conf ctx se
 
-closureServer :: Config -> E.SomeException -> IO a
-closureServer Config{..} se
-    | isAsyncException se = E.throwIO se
+closureServer :: Config -> Context -> E.SomeException -> IO a
+closureServer conf ctx se
+    | isAsyncException se = do
+        frame <- goaway ctx NoError "maybe timeout by manager"
+        sendGoaway conf frame
+        E.throwIO se
     | Just ConnectionIsClosed <- E.fromException se = do
+        frame <- goaway ctx NoError "no error"
+        sendGoaway conf frame
         E.throwIO ConnectionIsClosed
-    | Just e@(ConnectionErrorIsReceived{}) <- E.fromException se =
+    | Just ConnectionIsTimeout <- E.fromException se = do
+        frame <- goaway ctx NoError "timeout"
+        sendGoaway conf frame
+        E.throwIO ConnectionIsTimeout
+    | Just e@(ConnectionErrorIsReceived _err _sid msg) <- E.fromException se = do
+        frame <- goaway ctx NoError $ Short.fromShort msg
+        sendGoaway conf frame
         E.throwIO e
-    | Just e@(ConnectionErrorIsSent err sid msg) <- E.fromException se = do
-        let frame = goawayFrame sid err $ Short.fromShort msg
-        confSendAll frame
+    | Just e@(ConnectionErrorIsSent err _sid msg) <- E.fromException se = do
+        frame <- goaway ctx err $ Short.fromShort msg
+        sendGoaway conf frame
         E.throwIO e
-    | Just e@(StreamErrorIsSent err sid msg) <- E.fromException se = do
-        let frame = resetFrame err sid
-        let frame' = goawayFrame sid err $ Short.fromShort msg
-        confSendAll $ frame <> frame'
+    | Just e@(StreamErrorIsSent err _sid msg) <- E.fromException se = do
+        let frame = resetFrame err _sid
+        frame' <- goaway ctx err $ Short.fromShort msg
+        sendGoaway conf (frame <> frame')
         E.throwIO e
-    | Just e@(StreamErrorIsReceived err sid) <- E.fromException se = do
-        let frame = goawayFrame sid err "treat a stream error as a connection error"
-        confSendAll frame
+    | Just e@(StreamErrorIsReceived err _sid) <- E.fromException se = do
+        frame <- goaway ctx err "treat a stream error as a connection error"
+        sendGoaway conf frame
         E.throwIO e
     | Just (_ :: HTTP2Error) <- E.fromException se = E.throwIO se
     | otherwise = E.throwIO $ BadThingHappen se
+
+goaway :: Context -> ErrorCode -> ByteString -> IO ByteString
+goaway ctx err msg = do
+    sid <- getPeerLastStreamId ctx
+    return $ goawayFrame sid err msg
+
+sendGoaway :: Config -> ByteString -> IO ()
+sendGoaway Config{..} frame = confSendAll frame `E.catch` ignore
+
+ignore :: E.SomeException -> IO ()
+ignore (E.SomeException e)
+    | isAsyncException e = E.throwIO e
+    | otherwise = return ()
+
+----------------------------------------------------------------
+
+sendPing :: Context -> Bool -> ByteString -> IO ()
+sendPing Context{..} ack bs = enqueueControl controlQ $ CFrames Nothing [frame]
+  where
+    frame = pingFrame ack bs
diff --git a/Network/HTTP2/H2/Sender.hs b/Network/HTTP2/H2/Sender.hs
--- a/Network/HTTP2/H2/Sender.hs
+++ b/Network/HTTP2/H2/Sender.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE LambdaCase #-}
 {-# LANGUAGE NamedFieldPuns #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE RecordWildCards #-}
@@ -15,6 +16,7 @@
 import Network.ByteOrder
 import Network.HTTP.Semantics.Client
 import Network.HTTP.Semantics.IO
+import System.ThreadManager
 
 import Imports
 import Network.HPACK (setLimitForEncoding, toTokenHeaderTable)
@@ -57,6 +59,21 @@
     updateAllStreamTxFlow siz strms =
         forM_ strms $ \strm -> increaseStreamWindowSize strm siz
 
+checkDone :: Context -> Int -> IO Bool
+checkDone Context{..} 0 = atomically $ do
+    isEmptyC <- isEmptyTQueue controlQ
+    isEmptyO <- isEmptyTQueue outputQ
+    if not isEmptyC || not isEmptyO
+        then
+            return False
+        else do
+            gone <- isAllGone threadManager
+            unless gone retry
+            done <- readTVar receiverDone
+            unless done retry
+            return True
+checkDone _ _ = return False
+
 frameSender :: Context -> Config -> IO ()
 frameSender
     ctx@Context{outputQ, controlQ, encodeDynamicTable, outputBufferLimit}
@@ -67,11 +84,13 @@
         ----------------------------------------------------------------
         loop :: Offset -> IO ()
         loop off = do
-            x <- atomically $ dequeue off
-            case x of
-                C ctl -> flushN off >> control ctl >> loop 0
-                O out -> outputAndSync out off >>= flushIfNecessary >>= loop
-                Flush -> flushN off >> loop 0
+            done <- checkDone ctx off
+            unless done $ do
+                x <- atomically $ dequeue off
+                case x of
+                    C ctl -> flushN off >> control ctl >> loop 0
+                    O out -> outputAndSync out off >>= flushIfNecessary >>= loop
+                    Flush -> flushN off >> loop 0
 
         -- Flush the connection buffer to the socket, where the first 'n' bytes of
         -- the buffer are filled.
@@ -196,35 +215,34 @@
             let payloadOff = off0 + frameHeaderLength
                 datBuf = confWriteBuffer `plusPtr` payloadOff
                 datBufSiz = buflim - payloadOff
-            curr datBuf (min datBufSiz lim) >>= \next ->
-                case next of
-                    Next datPayloadLen reqflush mnext -> do
-                        NextTrailersMaker tlrmkr' <- runTrailersMaker tlrmkr datBuf datPayloadLen
-                        fillDataHeader
-                            strm
-                            off0
-                            datPayloadLen
-                            mnext
-                            tlrmkr'
-                            out
-                            reqflush
-                    CancelNext mErr -> do
-                        -- Stream cancelled
-                        --
-                        -- At this point, the headers have already been sent.
-                        -- Therefore, the stream cannot be in the 'Idle' state, so we
-                        -- are justified in sending @RST_STREAM@.
-                        --
-                        -- By the invariant on the 'outputQ', there are no other
-                        -- outputs for this stream already enqueued. Therefore, we can
-                        -- safely cancel it knowing that we won't try and send any
-                        -- more data frames on this stream.
-                        case mErr of
-                            Just err ->
-                                resetStream strm InternalError err
-                            Nothing ->
-                                resetStream strm Cancel (E.toException CancelledStream)
-                        return (off0, Nothing)
+            curr datBuf (min datBufSiz lim) >>= \case
+                Next datPayloadLen reqflush mnext -> do
+                    NextTrailersMaker tlrmkr' <- runTrailersMaker tlrmkr datBuf datPayloadLen
+                    fillDataHeader
+                        strm
+                        off0
+                        datPayloadLen
+                        mnext
+                        tlrmkr'
+                        out
+                        reqflush
+                CancelNext mErr -> do
+                    -- Stream cancelled
+                    --
+                    -- At this point, the headers have already been sent.
+                    -- Therefore, the stream cannot be in the 'Idle' state, so we
+                    -- are justified in sending @RST_STREAM@.
+                    --
+                    -- By the invariant on the 'outputQ', there are no other
+                    -- outputs for this stream already enqueued. Therefore, we can
+                    -- safely cancel it knowing that we won't try and send any
+                    -- more data frames on this stream.
+                    case mErr of
+                        Just err ->
+                            resetStream strm InternalError err
+                        Nothing ->
+                            resetStream strm Cancel (E.toException CancelledStream)
+                    return (off0, Nothing)
         output (Output strm (OPush ths pid) _) off0 _lim = do
             -- Creating a push promise header
             -- Frame id should be associated stream id from the client.
diff --git a/Network/HTTP2/H2/Stream.hs b/Network/HTTP2/H2/Stream.hs
--- a/Network/HTTP2/H2/Stream.hs
+++ b/Network/HTTP2/H2/Stream.hs
@@ -121,11 +121,7 @@
     terminated <- newTVarIO Nothing
     let whenNotTerminated act = do
             mTerminated <- readTVar terminated
-            case mTerminated of
-                Just reason ->
-                    throwSTM reason
-                Nothing ->
-                    act
+            maybe act throwSTM mTerminated
 
         terminateWith reason act = do
             mTerminated <- readTVar terminated
@@ -154,10 +150,11 @@
                     atomically $
                         whenNotTerminated $
                             writeTBQueue tbq StreamingFlush
-                , outBodyCancel = \mErr ->
-                    atomically $
-                        terminateWith StreamCancelled $
-                            writeTBQueue tbq (StreamingCancelled mErr)
+                , outBodyCancel =
+                    atomically
+                        . terminateWith StreamCancelled
+                        . writeTBQueue tbq
+                        . StreamingCancelled
                 }
         finished = atomically $ do
             terminateWith StreamOutOfScope $
diff --git a/Network/HTTP2/H2/Types.hs b/Network/HTTP2/H2/Types.hs
--- a/Network/HTTP2/H2/Types.hs
+++ b/Network/HTTP2/H2/Types.hs
@@ -269,6 +269,7 @@
     -- ^ This is copied into 'Aux', if exist, on server.
     , confPeerSockAddr :: SockAddr
     -- ^ This is copied into 'Aux', if exist, on server.
+    , confReadNTimeout :: Bool
     }
 
 isAsyncException :: Exception e => e -> Bool
diff --git a/Network/HTTP2/Server/Run.hs b/Network/HTTP2/Server/Run.hs
--- a/Network/HTTP2/Server/Run.hs
+++ b/Network/HTTP2/Server/Run.hs
@@ -51,7 +51,7 @@
     ok <- checkPreface conf
     when ok $ do
         let lnch = runServer conf server
-        ctx <- setup sconf conf lnch
+        ctx <- setup sconf conf lnch Nothing
         runH2 conf ctx
 
 ----------------------------------------------------------------
@@ -63,6 +63,7 @@
     , sioWriteResponse :: a -> Response -> IO ()
     -- ^ 'Response' MUST be created with 'responseBuilder'.
     -- Others are not supported.
+    , sioDone :: IO ()
     }
 
 -- | Launching a receiver and a sender without workers.
@@ -77,7 +78,8 @@
     when ok $ do
         inpQ <- newTQueueIO
         let lnch _ strm inpObj = atomically $ writeTQueue inpQ (strm, inpObj)
-        ctx <- setup sconf conf lnch
+        done <- newTVarIO False
+        ctx <- setup sconf conf lnch $ Just $ readTVar done
         let get = do
                 (strm, inpObj) <- atomically $ readTQueue inpQ
                 return (strm, Request inpObj)
@@ -94,6 +96,7 @@
                     , sioPeerSockAddr = confPeerSockAddr
                     , sioReadRequest = get
                     , sioWriteResponse = putR
+                    , sioDone = atomically $ writeTVar done True
                     }
         io <- action serverIO
         concurrently_ io $ runH2 conf ctx
@@ -107,8 +110,8 @@
             return False
         else return True
 
-setup :: ServerConfig -> Config -> Launch -> IO Context
-setup ServerConfig{..} conf@Config{..} lnch = do
+setup :: ServerConfig -> Config -> Launch -> Maybe (STM Bool) -> IO Context
+setup ServerConfig{..} conf@Config{..} lnch mIsDone = do
     let serverInfo = newServerInfo lnch
     newContext
         serverInfo
@@ -117,6 +120,7 @@
         connectionWindowSize
         settings
         confTimeoutManager
+        mIsDone
 
 runH2 :: Config -> Context -> IO ()
 runH2 conf ctx = do
@@ -127,8 +131,8 @@
             er <- E.try $ concurrently_ runReceiver runSender
             case er of
                 Right () -> return ()
-                Left e -> closureServer conf e
-    T.stopAfter mgr (runBackgroundThreads) $ \res ->
+                Left e -> closureServer conf ctx e
+    T.stopAfter mgr runBackgroundThreads $ \res ->
         closeAllStreams (oddStreamTable ctx) (evenStreamTable ctx) res
 
 -- connClose must not be called here since Run:fork calls it
diff --git a/Network/HTTP2/Server/Worker.hs b/Network/HTTP2/Server/Worker.hs
--- a/Network/HTTP2/Server/Worker.hs
+++ b/Network/HTTP2/Server/Worker.hs
@@ -24,11 +24,17 @@
 runServer conf server ctx@Context{..} strm req =
     T.forkManagedTimeout threadManager label $ \th -> do
         let req' = pauseRequestBody th
-            aux = Aux th mySockAddr peerSockAddr
+            aux =
+                defaultAux
+                    { auxTimeHandle = th
+                    , auxMySockAddr = mySockAddr
+                    , auxPeerSockAddr = peerSockAddr
+                    }
             request = Request req'
         lc <- newLoopCheck strm Nothing
         server request aux $ sendResponse conf ctx lc strm request
         adjustRxWindow ctx strm
+        modifyPeerLastStreamId ctx $ streamNumber strm
   where
     label = "H2 response sender for stream " ++ show (streamNumber strm)
     pauseRequestBody th = req{inpObjBody = readBody'}
@@ -37,7 +43,7 @@
         readBody' = do
             T.pause th
             bs <- readBody
-            T.resume th
+            T.resume th -- this is the same as 'tickle'
             return bs
 
 ----------------------------------------------------------------
@@ -173,11 +179,11 @@
                         { outBodyPush = \b -> do
                             T.pause th
                             outBodyPush iface b
-                            T.resume th
+                            T.resume th -- this is the same as 'tickle'
                         , outBodyPushFinal = \b -> do
                             T.pause th
                             outBodyPushFinal iface b
-                            T.resume th
+                            T.resume th -- this is the same as 'tickle'
                         }
             strmbdy iface'
     return tbq
diff --git a/http2.cabal b/http2.cabal
--- a/http2.cabal
+++ b/http2.cabal
@@ -1,6 +1,6 @@
 cabal-version:      >=1.10
 name:               http2
-version:            5.3.10
+version:            5.3.11
 license:            BSD3
 license-file:       LICENSE
 maintainer:         Kazu Yamamoto <kazu@iij.ad.jp>
@@ -114,14 +114,14 @@
         bytestring >=0.10,
         case-insensitive >=1.2 && <1.3,
         containers >=0.6,
-        http-semantics >= 0.3 && <0.4,
+        http-semantics >= 0.3.1 && <0.4,
         http-types >=0.12 && <0.13,
         iproute >= 1.7 && < 1.8,
         network >=3.1,
         network-byte-order >=0.1.7 && <0.2,
         network-control >=0.1 && <0.2,
         stm >=2.5 && <2.6,
-        time-manager >=0.2 && <0.3,
+        time-manager >=0.2 && <0.4,
         unix-time >=0.4.11 && <0.5,
         utf8-string >=1.0 && <1.1
 
@@ -138,7 +138,8 @@
         bytestring,
         http-types,
         http2,
-        network-run >= 0.3 && <0.5,
+        network,
+        network-run >= 0.5 && <0.6,
         unix-time
 
     if flag(devel)
@@ -307,7 +308,7 @@
         http-types,
         http2,
         network,
-        network-run >=0.3.0,
+        network-run >= 0.5 && <0.6,
         random,
         typed-process
 
@@ -326,7 +327,7 @@
         hspec >=1.3,
         http-types,
         http2,
-        network-run >=0.3.0,
+        network-run >= 0.5 && <0.6,
         typed-process
 
     if flag(h2spec)
diff --git a/util/Client.hs b/util/Client.hs
--- a/util/Client.hs
+++ b/util/Client.hs
@@ -4,13 +4,16 @@
 
 module Client where
 
+import Control.Concurrent
 import Control.Concurrent.Async
 import qualified Control.Exception as E
 import Control.Monad
+import Data.ByteString (ByteString)
 import qualified Data.ByteString.Char8 as C8
 import Data.UnixTime
 import Foreign.C.Types
 import Network.HTTP.Types
+import System.IO
 import Text.Printf
 
 import Network.HTTP2.Client
@@ -21,6 +24,7 @@
     { optPerformance :: Int
     , optNumOfReqs :: Int
     , optMonitor :: Bool
+    , optInteractive :: Bool
     }
     deriving (Show)
 
@@ -82,3 +86,32 @@
             / fromIntegral millisecs
             / 1024
             / 1024
+
+console
+    :: Options -> [ByteString] -> IO () -> Aux -> IO ()
+console _opt paths cli aux = do
+    putStrLn "q -- quit"
+    putStrLn "g -- get"
+    putStrLn "p -- ping"
+    mvar <- newEmptyMVar
+    loop mvar `E.catch` \(E.SomeException _) -> return ()
+  where
+    loop mvar = do
+        hSetBuffering stdout NoBuffering
+        putStr "> "
+        hSetBuffering stdout LineBuffering
+        l <- getLine
+        case l of
+            "q" -> putStrLn "bye"
+            "g" -> do
+                mapM_ (\p -> putStrLn $ "GET " ++ C8.unpack p) paths
+                _ <- forkIO $ cli >> putMVar mvar ()
+                takeMVar mvar
+                loop mvar
+            "p" -> do
+                putStrLn "Ping"
+                auxSendPing aux
+                loop mvar
+            _ -> do
+                putStrLn "No such command"
+                loop mvar
diff --git a/util/Monitor.hs b/util/Monitor.hs
--- a/util/Monitor.hs
+++ b/util/Monitor.hs
@@ -16,7 +16,7 @@
     showT (i, l, s) = i ++ " " ++ l ++ ": " ++ show s
 
 threadSummary :: IO [(String, String, ThreadStatus)]
-threadSummary = (sort <$> listThreads) >>= mapM summary
+threadSummary = listThreads >>= mapM summary . sort
   where
     summary t = do
         let idstr = drop 9 $ show t
diff --git a/util/Server.hs b/util/Server.hs
--- a/util/Server.hs
+++ b/util/Server.hs
@@ -3,7 +3,7 @@
 module Server where
 
 import Control.Monad
-import Crypto.Hash (Context, SHA1) -- cryptonite
+import Crypto.Hash (Context, SHA1) -- crypton
 import qualified Crypto.Hash as CH
 import Data.ByteString (ByteString)
 import qualified Data.ByteString as B
diff --git a/util/h2c-client.hs b/util/h2c-client.hs
--- a/util/h2c-client.hs
+++ b/util/h2c-client.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RankNTypes #-}
 
 module Main where
 
@@ -8,6 +9,7 @@
 import qualified Data.ByteString.Char8 as C8
 import Network.HTTP2.Client
 import Network.Run.TCP (runTCPClient)
+import Network.Socket
 import System.Console.GetOpt
 import System.Environment
 import System.Exit
@@ -21,6 +23,7 @@
         { optPerformance = 0
         , optNumOfReqs = 1
         , optMonitor = False
+        , optInteractive = False
         }
 
 usage :: String
@@ -43,6 +46,11 @@
         ["monitor"]
         (NoArg (\opts -> opts{optMonitor = True}))
         "run thread monitor"
+    , Option
+        ['i']
+        ["interactive"]
+        (NoArg (\o -> o{optInteractive = True}))
+        "enter interactive mode"
     ]
 
 showUsageAndExit :: String -> IO a
@@ -69,8 +77,19 @@
         h : p : ps -> return (h, p, C8.pack <$> ps)
     when (optMonitor opts) $ void $ forkIO $ monitor $ threadDelay 1000000
     let cliconf = defaultClientConfig{authority = host}
-    runTCPClient host port $ \s ->
-        E.bracket
-            (allocSimpleConfig' s 4096 5000000)
-            freeSimpleConfig
-            (\conf -> run cliconf conf $ client opts paths)
+    run' cliconf host port $ client' opts paths
+
+run' :: ClientConfig -> HostName -> ServiceName -> Client a -> IO a
+run' cliconf host port f = runTCPClient host port $ \s ->
+    E.bracket
+        (allocSimpleConfig' s 4096 10000000)
+        freeSimpleConfig
+        (\conf -> run cliconf conf f)
+
+client' :: Options -> [Path] -> Client ()
+client' opts paths sendRequest _aux
+    | optInteractive opts = do
+        let action = client opts paths sendRequest _aux
+        console opts paths action _aux
+        return ()
+    | otherwise = client opts paths sendRequest _aux
