@@ -46,7 +46,7 @@ import qualified Network.Socket as N ( HostName
4646 , connect
4747 )
4848import Network.Socket.ByteString (sendMany)
49−import Control.Concurrent (forkIO, ThreadId)
49+import Control.Concurrent (forkIO, ThreadId, killThread)
5050import Control.Concurrent.Chan (Chan, newChan, readChan, writeChan)
5151import Control.Concurrent.MVar ( MVar
5252 , newMVar
@@ -58,13 +58,13 @@ import Control.Concurrent.MVar ( MVar
5858 , newEmptyMVar
5959 , withMVar
6060 )
61−import Data.IORef (IORef, newIORef, writeIORef, readIORef, modifyIORef)
6261import Control.Category ((>>>))
6362import Control.Applicative ((<*>), (*>), (<$>))
6463import Control.Monad (forM_, void, when)
6564import Control.Monad.Error (ErrorT(ErrorT), runErrorT, throwError)
6665import Control.Monad.IO.Class (liftIO)
67−import Control.Exception (IOException)
66+import Control.Exception (IOException, SomeException)
67+import Data.IORef (IORef, newIORef, writeIORef, readIORef, modifyIORef)
6868import Data.ByteString (ByteString)
6969import qualified Data.ByteString as BS (concat)
7070import qualified Data.ByteString.Char8 as BSC (pack, unpack)
@@ -183,15 +183,18 @@ data LocalEndPoint = LocalEndPoint { localAddress :: EndPointAddress
183183 }
184184data RemoteEndPoint = RemoteEndPoint { remoteAddress :: EndPointAddress
185185 , remoteState :: MVar RemoteState
186+ , remoteThread :: ThreadId
186187 }
187188
188189-- We use underscores for fields that we might update (using lenses).
189190
190−data TransportState = TransportState { _localEndPoints :: IntMap LocalEndPoint }
191−data LocalState = LocalState { _nextConnectionId :: ConnectionId
192− , _pendingCtrlRequests :: IntMap (MVar [ByteString])
193− , _nextCtrlRequestId :: ControlRequestId
194− , _localConnections :: Map EndPointAddress RemoteEndPoint
191+data TransportState = TransportState { _localEndPoints :: IntMap LocalEndPoint
192+ , _acceptNewConnections :: Bool
193+ }
194+data LocalState = LocalState { _nextConnectionId :: ConnectionId
195+ , _pendingCtrlRequests :: IntMap (MVar [ByteString])
196+ , _nextCtrlRequestId :: ControlRequestId
197+ , _localConnections :: Map EndPointAddress RemoteEndPoint
195198 }
196199
197200-- A remote endpoint has incoming and outgoing connections, and when the total
@@ -220,15 +223,15 @@ data LocalState = LocalState { _nextConnectionId :: ConnectionId
220223-- the writes for control messages).
221224--
222225-- Of course, "serialize" does not mean that we want for the remote endpoint to
223−-- reply. "Send" takes the mvar, sends to the endpoint, and then puts the mvar
224−-- back, without waiting for the endpoint to receive the message. Similarly,
225−-- when requesting a new connection, we take the mvar, tentatively increment the
226−-- reference count, send the control request, and then put the mvar back. When
227−-- the remote host responds to the new connection request we might have to do
228−-- another state change (reduce the refcount) if the connection request was
229−-- refused but we don't want to increment the ref count only after the remote
230−-- host acknowledges the request because then a concurrent 'close' might
231−-- actually attempt to close the socket.
226+-- reply. "Send" takes the mvar, sends to the endpoint (asynchronously), and
227+-- then puts the mvar back, without waiting for the endpoint to receive the
228+-- message. Similarly, when requesting a new connection, we take the mvar,
229+-- tentatively increment the reference count, send the control request, and
230+-- then put the mvar back. When the remote host responds to the new connection
231+-- request we might have to do another state change (reduce the refcount) if
232+-- the connection request was refused but we don't want to increment the ref
233+-- count only after the remote host acknowledges the request because then a
234+-- concurrent 'close' might actually attempt to close the socket.
232235--
233236-- Since we don't do concurrent reads from the same socket we don't need to
234237-- take the lock when reading from the socket.
@@ -270,14 +273,32 @@ data ConnectionRequestResponse =
270273-- TODOs: deal with hints
271274createTransport :: N.HostName -> N.ServiceName -> IO (Either IOException Transport)
272275createTransport host port = do
273− state <- newMVar TransportState { _localEndPoints = IntMap.empty }
274− let transport = TCPTransport { transportState = state
275− , transportHost = host
276− , transportPort = port
277− }
278− tryIO $ do
279− forkServer host port $ void . handleConnectionRequest transport
280− return Transport { newEndPoint = apiNewEndPoint transport }
276+ state <- newMVar TransportState { _localEndPoints = IntMap.empty
277+ , _acceptNewConnections = True
278+ }
279+ let transport = TCPTransport { transportState = state
280+ , transportHost = host
281+ , transportPort = port
282+ }
283+ tryIO $ do
284+ -- TODO: "5" is listed as "system dependent maximum backlog"?
285+ transportThread <- forkServer host port 5 (handleConnectionRequest transport)
286+ (terminationHandler transport)
287+ return Transport { newEndPoint = apiNewEndPoint transport
288+ , closeTransport = apiCloseTransport transportThread
289+ }
290+ where
291+ terminationHandler :: TCPTransport -> SomeException -> IO ()
292+ terminationHandler transport _ =
293+ modifyMVar_ (transportState transport) $ return . (acceptNewConnections ^= False)
294+
295+-- | Shut down the transport
296+apiCloseTransport :: ThreadId -> IO ()
297+apiCloseTransport transportThread = do
298+ -- Kill the thread that is listening for new incoming connections
299+ killThread transportThread
300+ -- Not yet implemented
301+ undefined
281302
282303--------------------------------------------------------------------------------
283304-- API functions --
@@ -593,20 +614,18 @@ decreaseRemoteRefCount theirEndPoint = do
593614
594615-- | Handle a connection request (that is, a remote endpoint that is trying to
595616-- establish a TCP connection with us)
596−--
597−-- Returns the thread ID of the thread that is handling incoming messages.
598−handleConnectionRequest :: TCPTransport -> N.Socket -> IO (Maybe ThreadId)
617+handleConnectionRequest :: TCPTransport -> N.Socket -> IO ()
599618handleConnectionRequest transport sock = do
619+ let tState = transportState transport
600620 request <- tryIO $ do
601621 ourEndPointId <- recvInt32 sock
602622 theirAddress <- EndPointAddress . BS.concat <$> recvWithLength sock
603− ourEndPoint <- (^. localEndPointAt ourEndPointId) <$> readMVar (transportState transport)
623+ ourEndPoint <- (^. localEndPointAt ourEndPointId) <$> readMVar tState
604624 return (theirAddress, ourEndPoint)
605625 case request of
606626 Right (_, Nothing) -> do
607627 sendMany sock [encodeInt32 ConnectionRequestEndPointInvalid]
608628 N.sClose sock
609− return Nothing
610629 Right (theirAddress, Just ourEndPoint) -> do
611630 (crossed, theirEndPoint) <- modifyMVar (localState ourEndPoint) $ \st ->
612631 case st ^. connectionTo theirAddress of
@@ -622,7 +641,6 @@ handleConnectionRequest transport sock = do
622641 then do
623642 sendMany sock [encodeInt32 ConnectionRequestCrossed]
624643 N.sClose sock
625− return Nothing
626644 else do
627645 let remoteConn = RemoteConnection { remoteSocket = sock
628646 , _remoteRefCount = 0
@@ -630,12 +648,12 @@ handleConnectionRequest transport sock = do
630648 }
631649 putMVar (remoteState theirEndPoint) (RemoteEndPointValid remoteConn)
632650 sendMany sock [encodeInt32 ConnectionRequestAccepted]
651+ -- TODO: we should store the tid as part of the endpoint state
633652 tid <- forkIO $ handleIncomingMessages (ourEndPoint, theirEndPoint)
634− return (Just tid)
653+ return ()
635654 Left _ -> do
636655 -- Invalid request
637656 N.sClose sock
638− return Nothing
639657
640658-- | Handle requests from a remote endpoint.
641659--
@@ -794,6 +812,9 @@ firstNonReservedConnectionId = 1024
794812localEndPoints :: Lens TransportState (IntMap LocalEndPoint)
795813localEndPoints = lens _localEndPoints (\es st -> st { _localEndPoints = es })
796814
815+acceptNewConnections :: Lens TransportState Bool
816+acceptNewConnections = lens _acceptNewConnections (\acc st -> st { _acceptNewConnections = acc })
817+
797818pendingCtrlRequests :: Lens LocalState (IntMap (MVar [ByteString]))
798819pendingCtrlRequests = lens _pendingCtrlRequests (\rep st -> st { _pendingCtrlRequests = rep })
799820