git.iko.soy/distributed-process
on master help sign in
Deal with invalid close requests
commitecd82fce32cea6125d9bfcd7b6f610a7157716ec authorEdsko de Vries <edsko@edsko.net> dateWed 23 May 2012, 13:19 (14 years ago) parent978ca36
2 files changed+48−4
network-transport/src/Network/Transport/TCP.hs+10−4 network-transport/tests/TestTCP.hs+38
network-transport/src/Network/Transport/TCP.hs+10−4
@@ -101,6 +101,7 @@ import qualified Data.IntSet as IntSet ( empty
101101 , singleton
102102 , null
103103 , delete
104+ , member
104105 )
105106import Data.Map (Map)
106107import qualified Data.Map as Map (empty)
@@ -1333,15 +1334,18 @@ handleIncomingMessages (ourEndPoint, theirEndPoint) = do
13331334 putMVar mvar response
13341335
13351336 -- Close a connection
1337+ -- It is important that we verify that the connection is in fact open,
1338+ -- because otherwise we should not decrement the reference count
13361339 closeConnection :: ConnectionId -> IO ()
13371340 closeConnection cid = do
1338− -- TODO: we should check that this connection is in fact open
1339− writeChan ourChannel (ConnectionClosed cid)
1340− modifyMVar_ theirState $ \(RemoteEndPointValid vst) ->
1341+ modifyMVar_ theirState $ \(RemoteEndPointValid vst) -> do
1342+ unless (IntSet.member cid (vst ^. remoteIncoming)) $
1343+ throwIO $ userError "Invalid CloseConnection"
13411344 return ( RemoteEndPointValid
13421345 . (remoteIncoming ^: IntSet.delete cid)
13431346 $ vst
13441347 )
1348+ writeChan ourChannel (ConnectionClosed cid)
13451349 closeIfUnused (ourEndPoint, theirEndPoint)
13461350
13471351 -- Close the socket (if we don't have any outgoing connections)
@@ -1382,7 +1386,9 @@ handleIncomingMessages (ourEndPoint, theirEndPoint) = do
13821386 putMVar resolved ()
13831387 return True
13841388
1385− -- Read a message and output it on the endPoint's channel
1389+ -- Read a message and output it on the endPoint's channel By rights we
1390+ -- should verify that the connection ID is valid, but this is unnecessary
1391+ -- overhead
13861392 readMessage :: N.Socket -> ConnectionId -> IO ()
13871393 readMessage sock connId =
13881394 recvWithLength sock >>= writeChan ourChannel . Received connId
network-transport/tests/TestTCP.hs+38
@@ -691,6 +691,43 @@ testUnidirectionalError nextPort = do
691691
692692 takeMVar clientDone
693693
694+testInvalidCloseConnection :: IO N.ServiceName -> IO ()
695+testInvalidCloseConnection nextPort = do
696+ Right (transport, internals) <- nextPort >>= createTransportExposeInternals "127.0.0.1"
697+ serverAddr <- newEmptyMVar
698+ clientDone <- newEmptyMVar
699+ serverDone <- newEmptyMVar
700+
701+ -- Server
702+ forkTry $ do
703+ Right endpoint <- newEndPoint transport
704+ putMVar serverAddr (address endpoint)
705+
706+ ConnectionOpened _ _ _ <- receive endpoint
707+
708+ -- At this point the client sends an invalid request, so we terminate the
709+ -- connection
710+ ErrorEvent (TransportError (EventConnectionLost _ [_]) _) <- receive endpoint
711+
712+ putMVar serverDone ()
713+
714+ -- Client
715+ forkTry $ do
716+ Right endpoint <- newEndPoint transport
717+ let ourAddr = address endpoint
718+
719+ -- Connect so that we have a TCP connection
720+ theirAddr <- readMVar serverAddr
721+ Right _ <- connect endpoint theirAddr ReliableOrdered defaultConnectHints
722+
723+ -- Get a handle on the TCP connection and manually send an invalid CloseConnection request
724+ Right sock <- socketBetween internals ourAddr theirAddr
725+ sendMany sock [encodeInt32 CloseConnection, encodeInt32 (12345 :: Int)]
726+
727+ putMVar clientDone ()
728+
729+ mapM_ takeMVar [clientDone, serverDone]
730+
694731main :: IO ()
695732main = do
696733 portMVar <- newEmptyMVar
@@ -708,5 +745,6 @@ main = do
708745 , ("BreakTransport", testBreakTransport nextPort)
709746 , ("Reconnect", testReconnect nextPort)
710747 , ("UnidirectionalError", testUnidirectionalError nextPort)
748+ , ("InvalidCloseConnection", testInvalidCloseConnection nextPort)
711749 ]
712750 testTransport (either (Left . show) (Right) <$> nextPort >>= createTransport "127.0.0.1")