@@ -49,7 +49,7 @@ import Control.Concurrent.MVar ( MVar
50import Control.Category ((>>>))
50import Control.Category ((>>>))
51import Control.Applicative ((<*>), (*>), (<$>))
51import Control.Applicative ((<*>), (*>), (<$>))
52−import Control.Monad (forever, forM_, void)
52+import Control.Monad (forever, forM_, void, when)
53import Control.Monad.Error (MonadError, ErrorT, liftIO, runErrorT, throwError)
53import Control.Monad.Error (MonadError, ErrorT, liftIO, runErrorT, throwError)
54import Control.Monad.Trans.Maybe (MaybeT(MaybeT), runMaybeT)
54import Control.Monad.Trans.Maybe (MaybeT(MaybeT), runMaybeT)
55import Control.Monad.Trans.Writer (WriterT, execWriterT)
55import Control.Monad.Trans.Writer (WriterT, execWriterT)
@@ -81,6 +81,7 @@ data LocalEndPoint = LocalEndPoint { _localAddress :: EndPointAddress
81data RemoteEndPoint = RemoteEndPoint { _remoteAddress :: EndPointAddress
81data RemoteEndPoint = RemoteEndPoint { _remoteAddress :: EndPointAddress
82 , _remoteSocket :: N.Socket
82 , _remoteSocket :: N.Socket
83 , _remoteLock :: MVar ()
83 , _remoteLock :: MVar ()
84+ , _remoteRefCount :: MVar Int
85data EndPointState = EndPointState { _nextConnectionId :: ConnectionId
86data EndPointState = EndPointState { _nextConnectionId :: ConnectionId
86 , _pendingCtrlRequests :: IntMap (MVar [ByteString])
87 , _pendingCtrlRequests :: IntMap (MVar [ByteString])
@@ -146,10 +147,13 @@ forkRemoteEndPoint :: TCPTransport
146 -> N.Socket
147 -> N.Socket
147 -> IO RemoteEndPoint
148 -> IO RemoteEndPoint
148forkRemoteEndPoint transport ourEndPoint theirAddress sock = do
149forkRemoteEndPoint transport ourEndPoint theirAddress sock = do
150+ -- putStrLn "Creating new refcount.."
149− lock <- newMVar ()
151+ lock <- newMVar ()
152+ refCount <- newMVar 0
150− let theirEndPoint = RemoteEndPoint { _remoteAddress = theirAddress
153+ let theirEndPoint = RemoteEndPoint { _remoteAddress = theirAddress
151− , _remoteSocket = sock
154+ , _remoteSocket = sock
152− , _remoteLock = lock
155+ , _remoteLock = lock
156+ , _remoteRefCount = refCount
154 modifyMVar_ (transport ^. transportState) $ return . (remoteEndPointAt theirAddress ^= Just theirEndPoint)
158 modifyMVar_ (transport ^. transportState) $ return . (remoteEndPointAt theirAddress ^= Just theirEndPoint)
155 forkIO $ do
159 forkIO $ do
@@ -262,17 +266,38 @@ tcpConnect :: TCPTransport -- ^ Transport
262tcpConnect transport ourEndPoint theirAddress _ = runErrorT $ do
266tcpConnect transport ourEndPoint theirAddress _ = runErrorT $ do
263 theirEndPoint <- remoteEndPoint transport ourEndPoint theirAddress
267 theirEndPoint <- remoteEndPoint transport ourEndPoint theirAddress
264 connId <- requestNewConnection ourEndPoint theirEndPoint
268 connId <- requestNewConnection ourEndPoint theirEndPoint
269+ increaseRemoteRefCount theirEndPoint
265 let sock = theirEndPoint ^. remoteSocket
270 let sock = theirEndPoint ^. remoteSocket
271+ -- TODO: should we modify send so that it returns an error when the user closes the connection?
266 return Connection { send = runErrorT .
272 return Connection { send = runErrorT .
267 failWithIO (FailedWith SendFailed . show) .
273 failWithIO (FailedWith SendFailed . show) .
268 withRemoteLock theirEndPoint .
274 withRemoteLock theirEndPoint .
269 sendMany sock .
275 sendMany sock .
270 (\payload -> encodeInt32 connId : prependLength payload)
276 (\payload -> encodeInt32 connId : prependLength payload)
271− , close = -- TODO: we should not close the TCP connection until all
277+ , close = decreaseRemoteRefCount theirEndPoint
272− -- lightweight connections have been closed
280+-- | Increase the refcount on a remote endpoint
281+increaseRemoteRefCount :: MonadIO m => RemoteEndPoint -> m ()
282+increaseRemoteRefCount endPoint = liftIO $ do
285+ rc <- modifyMVar (endPoint ^. remoteRefCount) $ \rc -> return (rc + 1, rc)
286+ putStrLn $ "Increased refcount from " ++ show rc
289+-- | Decrease the refcount on a remote endpoint and close the socket
290+-- when it reaches zero.
291+decreaseRemoteRefCount :: MonadIO m => RemoteEndPoint -> m ()
292+decreaseRemoteRefCount endPoint = liftIO $ do
295+ rc <- modifyMVar (endPoint ^. remoteRefCount) $ \rc -> return (rc - 1, rc)
296+ putStrLn $ "Reduced refcount from " ++ show rc
298+ N.sClose (endPoint ^. remoteSocket)
276-- | Request a new connection
301-- | Request a new connection
277requestNewConnection :: (MonadIO m, MonadError (FailedWith ConnectErrorCode) m)
302requestNewConnection :: (MonadIO m, MonadError (FailedWith ConnectErrorCode) m)
278 => LocalEndPoint
303 => LocalEndPoint
@@ -388,6 +413,9 @@ remoteSocket = lens _remoteSocket (\sock ep -> ep { _remoteSocket = sock })
388remoteLock :: Lens RemoteEndPoint (MVar ())
413remoteLock :: Lens RemoteEndPoint (MVar ())
389remoteLock = lens _remoteLock (\lock ep -> ep { _remoteLock = lock })
414remoteLock = lens _remoteLock (\lock ep -> ep { _remoteLock = lock })
416+remoteRefCount :: Lens RemoteEndPoint (MVar Int)
417+remoteRefCount = lens _remoteRefCount (\rc ep -> ep { _remoteRefCount = rc })
391nextConnectionId :: Lens EndPointState ConnectionId
419nextConnectionId :: Lens EndPointState ConnectionId
392nextConnectionId = lens _nextConnectionId (\cix st -> st { _nextConnectionId = cix })
420nextConnectionId = lens _nextConnectionId (\cix st -> st { _nextConnectionId = cix })