@@ -10,9 +10,6 @@
10-- Applications that use the TCP transport should use
10-- Applications that use the TCP transport should use
11-- 'Network.Socket.withSocketsDo' in their main function for Windows
11-- 'Network.Socket.withSocketsDo' in their main function for Windows
12-- compatibility (see "Network.Socket").
12-- compatibility (see "Network.Socket").
15−-- * Output exception on channel after endpoint is closed
16module Network.Transport.TCP ( -- * Main API
13module Network.Transport.TCP ( -- * Main API
17 createTransport
14 createTransport
18 -- * Internals (exposed for unit tests)
15 -- * Internals (exposed for unit tests)
@@ -80,6 +77,7 @@ import Control.Monad.Error (ErrorT(..), runErrorT)
80import Control.Exception ( IOException
77import Control.Exception ( IOException
81 , SomeException
78 , SomeException
85 , bracketOnError
83 , bracketOnError
@@ -293,7 +291,7 @@ data ValidLocalEndPointState = ValidLocalEndPointState
294-- INV-CLOSE: Whenever we put an endpoint in closed state we remove that
292-- INV-CLOSE: Whenever we put an endpoint in closed state we remove that
295-- endpoint from localConnections first, so that if a concurrent thread reads
293-- endpoint from localConnections first, so that if a concurrent thread reads
296−-- the mvar, finds EndPointClosed, and then looks up the endpoint in
294+-- the mvar, finds RemoteEndPointClosed, and then looks up the endpoint in
297-- localConnections it is guaranteed to either find a different remote
295-- localConnections it is guaranteed to either find a different remote
298-- endpoint, or else none at all.
296-- endpoint, or else none at all.
299-- INV-RESOLVE: Whenever we move a endpoint from Closing to Closed state, we
297-- INV-RESOLVE: Whenever we move a endpoint from Closing to Closed state, we
@@ -399,7 +397,9 @@ createTransportExposeInternals host port = do
400 ( Transport
398 ( Transport
401 { newEndPoint = apiNewEndPoint transport
399 { newEndPoint = apiNewEndPoint transport
402− , closeTransport = let evs = [EndPointClosed] in
400+ , closeTransport = let evs = [ EndPointClosed
401+ , throw $ userError "Transport closed"
403 apiCloseTransport transport (Just tid) evs
403 apiCloseTransport transport (Just tid) evs
405 , TransportInternals
405 , TransportInternals
@@ -410,8 +410,10 @@ createTransportExposeInternals host port = do
411 terminationHandler :: TCPTransport -> SomeException -> IO ()
411 terminationHandler :: TCPTransport -> SomeException -> IO ()
412 terminationHandler transport ex = do
412 terminationHandler transport ex = do
413− let ev = ErrorEvent (TransportError EventTransportFailed (show ex))
413+ let evs = [ ErrorEvent (TransportError EventTransportFailed (show ex))
414+ , throw $ userError "Transport closed"
414− apiCloseTransport transport Nothing [ev]
416+ apiCloseTransport transport Nothing evs
416--------------------------------------------------------------------------------
418--------------------------------------------------------------------------------
417-- API functions --
419-- API functions --
@@ -438,7 +440,10 @@ apiNewEndPoint transport = try $ do
438 { receive = readChan (localChannel ourEndPoint)
440 { receive = readChan (localChannel ourEndPoint)
439 , address = localAddress ourEndPoint
441 , address = localAddress ourEndPoint
440 , connect = apiConnect ourEndPoint
442 , connect = apiConnect ourEndPoint
441− , closeEndPoint = apiCloseEndPoint transport [EndPointClosed] ourEndPoint
443+ , closeEndPoint = let evs = [ EndPointClosed
444+ , throw $ userError "Endpoint closed"
446+ apiCloseEndPoint transport evs ourEndPoint
442 , newMulticastGroup = return . Left $ newMulticastGroupError
447 , newMulticastGroup = return . Left $ newMulticastGroupError
443 , resolveMulticastGroup = return . Left . const resolveMulticastGroupError
448 , resolveMulticastGroup = return . Left . const resolveMulticastGroupError
@@ -501,7 +506,7 @@ apiSend :: EndPointPair -- ^ Local and remote endpoint
501 -> [ByteString] -- ^ Payload
506 -> [ByteString] -- ^ Payload
502 -> IO (Either (TransportError SendErrorCode) ())
507 -> IO (Either (TransportError SendErrorCode) ())
503apiSend (ourEndPoint, theirEndPoint) connId connAlive payload =
508apiSend (ourEndPoint, theirEndPoint) connId connAlive payload =
504− -- The 'join' joins the inner exception that we explicitly return) for
509+ -- The 'join' joins the inner exception (which we explicitly return, for
505 -- instance if the connection is closed) with the outer exception (which is
510 -- instance if the connection is closed) with the outer exception (which is
506 -- returned by 'try' when an exception is thrown by 'sendOn', and handled
511 -- returned by 'try' when an exception is thrown by 'sendOn', and handled
507 -- by 'withRemoteState')
512 -- by 'withRemoteState')
@@ -733,7 +738,7 @@ requestConnectionTo ourEndPoint theirAddress = go
733 readMVar resolved >> go
738 readMVar resolved >> go
735 RemoteEndPointClosed ->
740 RemoteEndPointClosed ->
736− -- EndPointClosed indicates that a concurrent thread was in the
741+ -- RemoteEndPointClosed indicates that a concurrent thread was in the
737 -- process of closing the TCP connection to the remote endpoint when
742 -- process of closing the TCP connection to the remote endpoint when
738 -- we obtained a reference to it. By INV-CLOSE we can assume that the
743 -- we obtained a reference to it. By INV-CLOSE we can assume that the
739 -- remote endpoint will now have been removed from ourState, so we
744 -- remote endpoint will now have been removed from ourState, so we