@@ -29,6 +29,7 @@ import Network.Transport.Internal ( encodeInt32
2929 , failWith
3030 , failWithIO
3131 , tryIO
32+ , tryToEnum
3233 )
3334import qualified Network.Socket as N ( HostName
3435 , ServiceName
@@ -61,7 +62,7 @@ import Data.IORef (IORef, newIORef, writeIORef, readIORef, modifyIORef)
6162import Control.Category ((>>>))
6263import Control.Applicative ((<*>), (*>), (<$>))
6364import Control.Monad (forM_, void, when)
64−import Control.Monad.Error (ErrorT(ErrorT), runErrorT)
65+import Control.Monad.Error (ErrorT(ErrorT), runErrorT, throwError)
6566import Control.Monad.IO.Class (liftIO)
6667import Control.Exception (IOException)
6768import Data.ByteString (ByteString)
@@ -250,14 +251,14 @@ data ControlHeader =
250251 | CloseConnection -- ^ Tell the remote endpoint we will no longer be using a connection
251252 | ControlResponse -- ^ Respond to a control request _from_ the remote endpoint
252253 | CloseSocket -- ^ Request to close the connection (see module description)
253− deriving Enum
254+ deriving (Enum, Bounded)
254255
255256-- Response sent by /B/ to /A/ when /A/ tries to connect
256257data ConnectionRequestResponse =
257258 ConnectionRequestAccepted -- ^ /B/ accepts the connection
258259 | ConnectionRequestEndPointInvalid -- ^ /A/ requested an invalid endpoint
259260 | ConnectionRequestCrossed -- ^ /A/s request crossed with a request from /B/ (see protocols)
260− deriving Enum
261+ deriving (Enum, Bounded)
261262
262263--------------------------------------------------------------------------------
263264-- Top-level functionality --
@@ -527,13 +528,14 @@ connectToRemoteEndPoint (ourEndPoint, theirEndPoint) = do
527528 N.getAddrInfo Nothing (Just host) (Just port)
528529 sock <- failWithIO (insufficientResources . show) $
529530 N.socket (N.addrFamily addr) N.Stream N.defaultProtocol
530− failWithIO (failed . show) $ do
531+ response <- failWithIO (failed . show) $ do
531532 N.setSocketOption sock N.ReuseAddr 1
532533 N.connect sock (N.addrAddress addr)
533534 sendMany sock (encodeInt32 theirEndPointId : prependLength [ourAddress])
534− -- TODO: what happens when the server sends an int outside the range of ConnectionRequestResponse?
535− response <- recvInt32 sock
536− return (response, sock)
535+ recvInt32 sock
536+ case tryToEnum response of
537+ Nothing -> throwError (failed "Unexpected response")
538+ Just r -> return (r, sock)
537539
538540 invalidAddress, insufficientResources, failed :: String -> FailedWith ConnectErrorCode
539541 invalidAddress = FailedWith ConnectInvalidAddress
@@ -667,19 +669,22 @@ handleIncomingMessages (ourEndPoint, theirEndPoint) = do
667669 readMessage sock connId
668670 go sock openConnections
669671 else do
670− case toEnum (fromIntegral connId) of
671− RequestConnectionId -> do
672+ case tryToEnum (fromIntegral connId) of
673+ Just RequestConnectionId -> do
672674 recvInt32 sock >>= createNewConnection openConnections
673675 go sock openConnections
674− ControlResponse -> do
676+ Just ControlResponse -> do
675677 recvInt32 sock >>= readControlResponse sock
676678 go sock openConnections
677− CloseConnection -> do
679+ Just CloseConnection -> do
678680 recvInt32 sock >>= closeConnection openConnections
679681 go sock openConnections
680− CloseSocket -> do
682+ Just CloseSocket -> do
681683 closeSocket sock
682684 go sock openConnections
685+ Nothing ->
686+ -- Invalid control request, exit
687+ putStrLn "Warning: invalid control request"
683688
684689 -- Create a new connection
685690 createNewConnection :: IORef IntSet -> ControlRequestId -> IO ()