@@ -58,7 +58,7 @@ import Control.Concurrent.MVar ( MVar
58import Control.Category ((>>>))
58import Control.Category ((>>>))
59import Control.Applicative ((<*>), (*>), (<$>))
59import Control.Applicative ((<*>), (*>), (<$>))
60import Control.Monad (forM_, void, unless)
60import Control.Monad (forM_, void, unless)
61−import Control.Monad.Error (MonadError, ErrorT(ErrorT), runErrorT, throwError)
61+import Control.Monad.Error (ErrorT(ErrorT), runErrorT)
62import Control.Monad.IO.Class (liftIO)
62import Control.Monad.IO.Class (liftIO)
63import Control.Exception (IOException, bracket_)
63import Control.Exception (IOException, bracket_)
64import Data.ByteString (ByteString)
64import Data.ByteString (ByteString)
@@ -256,15 +256,16 @@ apiConnect :: LocalEndPoint -- ^ Local end point
256apiConnect ourEndPoint theirAddress _ = runErrorT $ do
256apiConnect ourEndPoint theirAddress _ = runErrorT $ do
257 theirEndPoint <- findRemoteEndPoint ourEndPoint theirAddress
257 theirEndPoint <- findRemoteEndPoint ourEndPoint theirAddress
258 connId <- requestNewConnection (ourEndPoint, theirEndPoint)
258 connId <- requestNewConnection (ourEndPoint, theirEndPoint)
259+ connAlive <- liftIO $ newMVar True
259− return $ Connection { send = apiSend theirEndPoint connId
260+ return $ Connection { send = apiSend theirEndPoint connId connAlive
260− , close = apiClose (ourEndPoint, theirEndPoint) connId
261+ , close = apiClose (ourEndPoint, theirEndPoint) connId connAlive
263-- | Close a connection
264-- | Close a connection
265-- TODO: We ignore errors during a close. Is that right?
266-- TODO: We ignore errors during a close. Is that right?
266−apiClose :: Conn -> ConnectionId -> IO ()
267+apiClose :: Conn -> ConnectionId -> MVar Bool -> IO ()
267−apiClose (ourEndPoint, theirEndPoint) connId = void . tryIO $ do
268+apiClose (ourEndPoint, theirEndPoint) connId connAlive = void . tryIO $ do
268 sendTo theirEndPoint [encodeInt32 CloseConnection, encodeInt32 connId]
269 sendTo theirEndPoint [encodeInt32 CloseConnection, encodeInt32 connId]
269 decreaseRemoteRefCount (ourEndPoint, theirEndPoint)
270 decreaseRemoteRefCount (ourEndPoint, theirEndPoint)
@@ -272,8 +273,8 @@ apiClose (ourEndPoint, theirEndPoint) connId = void . tryIO $ do
273-- TODO: we should have some per-connection state so that the user cannot send
274-- TODO: we should have some per-connection state so that the user cannot send
274-- to the connection after they closed it, or close it more than once
275-- to the connection after they closed it, or close it more than once
275−apiSend :: RemoteEndPoint -> ConnectionId -> [ByteString] -> IO (Either (FailedWith SendErrorCode) ())
276+apiSend :: RemoteEndPoint -> ConnectionId -> MVar Bool -> [ByteString] -> IO (Either (FailedWith SendErrorCode) ())
276−apiSend theirEndPoint connId payload = runErrorT $
277+apiSend theirEndPoint connId connAlive payload = runErrorT $
277 failWithIO (FailedWith SendFailed . show) $
278 failWithIO (FailedWith SendFailed . show) $
278 sendTo theirEndPoint (encodeInt32 connId : prependLength payload)
279 sendTo theirEndPoint (encodeInt32 connId : prependLength payload)
@@ -372,16 +373,19 @@ connectToRemoteEndPoint ourEndPoint theirMVar theirAddress = do
373-- | Request a new connection
374-- | Request a new connection
374requestNewConnection :: Conn -> ErrorT (FailedWith ConnectErrorCode) IO ConnectionId
375requestNewConnection :: Conn -> ErrorT (FailedWith ConnectErrorCode) IO ConnectionId
375−requestNewConnection (ourEndPoint, theirEndPoint) = do
376+requestNewConnection (ourEndPoint, theirEndPoint) = ErrorT $ do
376− mcid <- failWithIO (failed . show) $ do
377+ -- We increment the refcount before sending the request, because if a
378+ -- CloseSocket request comes this way first we want to ignore it
379+ increaseRemoteRefCount (ourEndPoint, theirEndPoint)
377 reply <- sendRemoteRequest (ourEndPoint, theirEndPoint) RequestConnectionId
381 reply <- sendRemoteRequest (ourEndPoint, theirEndPoint) RequestConnectionId
378 decodeInt32 . BS.concat <$> takeMVar reply
382 decodeInt32 . BS.concat <$> takeMVar reply
379− case mcid of
383+ case mcid of
380− Nothing ->
384+ Left err -> do decreaseRemoteRefCount (ourEndPoint, theirEndPoint)
385+ return . Left $ failed (show err)
386+ Right Nothing -> do decreaseRemoteRefCount (ourEndPoint, theirEndPoint)
381− throwError (failed "Invalid integer")
387+ return . Left $ failed "Invalid integer"
382− Just cid -> do
388+ Right (Just cid) -> do return . Right $ cid
383− liftIO $ increaseRemoteRefCount (ourEndPoint, theirEndPoint)
386 failed = FailedWith ConnectFailed
390 failed = FailedWith ConnectFailed