@@ -58,13 +58,11 @@ import Control.Concurrent.MVar ( MVar
5858 , putMVar
5959 , newEmptyMVar
6060 , withMVar
61− , tryTakeMVar
6261 )
6362import Control.Category ((>>>))
6463import Control.Applicative ((<*>), (*>), (<$>))
65−import Control.Monad (forM_, void, when, mzero, unless)
64+import Control.Monad (forM, forM_, void, when, unless)
6665import Control.Monad.Error (ErrorT(ErrorT), runErrorT, throwError)
67−import Control.Monad.Trans.Maybe (MaybeT, runMaybeT)
6866import Control.Monad.IO.Class (liftIO)
6967import Control.Exception (IOException, SomeException)
7068import Data.IORef (IORef, newIORef, writeIORef, readIORef)
@@ -75,7 +73,7 @@ import Data.Int (Int32)
7573import Data.IntMap (IntMap)
7674import qualified Data.IntMap as IntMap (empty)
7775import Data.IntSet (IntSet)
78−import qualified Data.IntSet as IntSet (empty, insert, elems, singleton, null, delete)
76+import qualified Data.IntSet as IntSet (empty, insert, elems, singleton, null, delete, unions)
7977import Data.Map (Map)
8078import qualified Data.Map as Map (empty, elems, size)
8179import Data.Lens.Lazy (Lens, lens, intMapLens, mapLens, (^.), (^=), (^+=), (^%=))
@@ -396,28 +394,30 @@ apiCloseEndPoint transport ourEndPoint = do
396394 -- We take the endpoint state and don't put it back
397395 -- (this may block some threads, but we don't care: we are killing them anyway)
398396 ourState <- takeMVar (localState ourEndPoint)
399− --incoming <- IntSet.elems <$> takeMVar (localIncoming ourEndPoint)
400− let incoming = undefined
401− -- Kill all threads associated with this endpoint and close all sockets
397+ -- Close all endpoints and kill all threads
398+ incoming <- IntSet.elems . IntSet.unions <$> (forM (Map.elems $ ourState ^. localConnections) $ tryCloseRemoteSocket)
402399 forM_ (ourState ^. internalThreads) killThread
403− forM_ (Map.elems $ ourState ^. localConnections) $ \theirEndPoint ->
404− runMaybeT $ remoteSocketOf theirEndPoint >>= liftIO . N.sClose
405400 -- We send a single message to the endpoint that it is closed. Subsequent
406401 -- calls will block. We could change this so that all subsequent calls to
407402 -- receive return an error, but this would mean checking for some state on
408403 -- every call to receive, which is an unnecessary overhead.
409404 writeChan (localChannel ourEndPoint) (ErrorEvent $ ErrorEventEndPointClosed incoming)
410405 where
411− remoteSocketOf :: RemoteEndPoint -> MaybeT IO N.Socket
412− remoteSocketOf theirEndPoint = do
406+ -- Close the remote socket and return the set of all incoming connections
407+ tryCloseRemoteSocket :: RemoteEndPoint -> IO IntSet
408+ tryCloseRemoteSocket theirEndPoint = do
413409 -- Like above, we take but don't put back
414− mRemoteState <- liftIO $ tryTakeMVar (remoteState theirEndPoint)
415− case mRemoteState of
416− Nothing -> mzero
417− Just (RemoteEndPointInvalid _) -> mzero
418− Just (RemoteEndPointValid conn) -> return $ remoteSocket conn
419− Just (RemoteEndPointClosing _ conn) -> return $ remoteSocket conn
420− Just RemoteEndPointClosed -> mzero
410+ st <- takeMVar (remoteState theirEndPoint)
411+ -- We make an attempt to close the connection nicely (by sending a CloseSocket first)
412+ case st of
413+ RemoteEndPointInvalid _ -> do return IntSet.empty
414+ RemoteEndPointValid conn -> do tryIO $ do
415+ sendOn conn [encodeInt32 CloseSocket]
416+ N.sClose (remoteSocket conn)
417+ return (conn ^. remoteIncoming)
418+ RemoteEndPointClosing _ conn -> do tryIO $ N.sClose (remoteSocket conn)
419+ return IntSet.empty
420+ RemoteEndPointClosed -> do return IntSet.empty
421421
422422-- | Special case of 'apiConnect': connect an endpoint to itself
423423connectToSelf :: LocalEndPoint -> IO (Either (FailedWith ConnectErrorCode) Connection)
@@ -906,7 +906,6 @@ handleIncomingMessages (ourEndPoint, theirEndPoint) = do
906906 Just unclosedConnections -> writeChan ourChannel . ErrorEvent $
907907 ErrorEventConnectionLost (remoteAddress theirEndPoint) (IntSet.elems unclosedConnections)
908908
909−
910909-- | Get the next connection ID
911910getNextConnectionId :: LocalEndPoint -> IO ConnectionId
912911getNextConnectionId ourEndpoint =