git.iko.soy/distributed-process
on master help sign in
Add ConnectHints, reintroduce SendClosed
commit393c37c8ca6a2d912f1f6b51bf00db0afa124f6e authorEdsko de Vries <edsko@edsko.net> dateThu 17 May 2012, 16:33 (14 years ago) parent3ddacf5
6 files changed+68−46
network-transport/network-transport.cabal+4−4 network-transport/src/Network/Transport.hs+28−15 network-transport/src/Network/Transport/Chan.hs+10−5 network-transport/src/Network/Transport/TCP.hs+7−8 network-transport/tests/TestTCP.hs+9−9 network-transport/tests/TestTransport.hs+10−5
network-transport/network-transport.cabal+4−4
@@ -23,7 +23,7 @@ Library
2323 Network.Transport.Chan,
2424 Network.Transport.TCP,
2525 Network.Transport.Util
26− extensions: OverloadedStrings, ForeignFunctionInterface, DeriveDataTypeable
26+ extensions: OverloadedStrings, ForeignFunctionInterface, DeriveDataTypeable, EmptyDataDecls
2727 ghc-options: -Wall -fno-warn-unused-do-bind
2828 HS-Source-Dirs: src
2929
@@ -38,7 +38,7 @@ Test-Suite TestTCP
3838 mtl,
3939 transformers,
4040 ansi-terminal
41− extensions: OverloadedStrings, ForeignFunctionInterface, DeriveDataTypeable, ExistentialQuantification, FlexibleInstances, RankNTypes, OverlappingInstances
41+ extensions: OverloadedStrings, ForeignFunctionInterface, DeriveDataTypeable, EmptyDataDecls, ExistentialQuantification, FlexibleInstances, RankNTypes, OverlappingInstances
4242 ghc-options: -Wall -fno-warn-unused-do-bind
4343 HS-Source-Dirs: tests src
4444
@@ -52,7 +52,7 @@ Test-Suite TestMulticastInMemory
5252 mtl,
5353 transformers,
5454 ansi-terminal
55− extensions: OverloadedStrings, ForeignFunctionInterface, DeriveDataTypeable, ExistentialQuantification, FlexibleInstances, RankNTypes, OverlappingInstances
55+ extensions: OverloadedStrings, ForeignFunctionInterface, DeriveDataTypeable, EmptyDataDecls, ExistentialQuantification, FlexibleInstances, RankNTypes, OverlappingInstances
5656 ghc-options: -Wall -fno-warn-unused-do-bind
5757 HS-Source-Dirs: tests src
5858
@@ -66,6 +66,6 @@ Test-Suite TestInMemory
6666 mtl,
6767 transformers,
6868 ansi-terminal
69− extensions: OverloadedStrings, ForeignFunctionInterface, DeriveDataTypeable, ExistentialQuantification, FlexibleInstances, RankNTypes, OverlappingInstances
69+ extensions: OverloadedStrings, ForeignFunctionInterface, DeriveDataTypeable, EmptyDataDecls, ExistentialQuantification, FlexibleInstances, RankNTypes, OverlappingInstances
7070 ghc-options: -Wall -fno-warn-unused-do-bind
7171 HS-Source-Dirs: tests src
network-transport/src/Network/Transport.hs+28−15
@@ -9,6 +9,9 @@ module Network.Transport ( -- * Types
99 , MulticastGroup(..)
1010 , EndPointAddress(..)
1111 , MulticastAddress(..)
12+ -- * Hints
13+ , ConnectHints
14+ , defaultConnectHints
1215 -- * Error codes
1316 , TransportError(..)
1417 , NewEndPointErrorCode(..)
@@ -43,7 +46,7 @@ data EndPoint = EndPoint {
4346 -- | EndPointAddress of the endpoint.
4447 , address :: EndPointAddress
4548 -- | Create a new lightweight connection.
46− , connect :: EndPointAddress -> Reliability -> IO (Either (TransportError ConnectErrorCode) Connection)
49+ , connect :: EndPointAddress -> Reliability -> ConnectHints -> IO (Either (TransportError ConnectErrorCode) Connection)
4750 -- | Create a new multicast group.
4851 , newMulticastGroup :: IO (Either (TransportError NewMulticastGroupErrorCode) MulticastGroup)
4952 -- | Resolve an address to a multicast group.
@@ -76,7 +79,7 @@ data Event =
7679 | ErrorEvent (TransportError EventErrorCode)
7780 deriving Show
7881
79−-- | Connection IDs enable receivers to distinguish one connection from another.
82+-- | Connection data ConnectHintsIDs enable receivers to distinguish one connection from another.
8083type ConnectionId = Int
8184
8285-- | Reliability guarantees of a connection.
@@ -118,10 +121,31 @@ newtype MulticastAddress = MulticastAddress { multicastAddressToByteString :: By
118121instance Show MulticastAddress where
119122 show = show . multicastAddressToByteString
120123
124+--------------------------------------------------------------------------------
125+-- Hints --
126+-- --
127+-- Hints provide transport-generic "suggestions". For now, these are --
128+-- placeholders only. --
129+--------------------------------------------------------------------------------
130+
131+-- Hints used by 'connect'
132+data ConnectHints
133+
134+-- Default hints for connecting
135+defaultConnectHints :: ConnectHints
136+defaultConnectHints = undefined
137+
121138--------------------------------------------------------------------------------
122139-- Error codes --
140+-- --
141+-- Errors should be transport-implementation independent. The deciding factor --
142+-- for distinguishing one kind of error from another should be: might --
143+-- application code have to take a different action depending on the kind of --
144+-- error? --
123145--------------------------------------------------------------------------------
124146
147+-- | Errors returned by Network.Transport API functions consist of an error
148+-- code and a human readable description of the problem
125149data TransportError error = TransportError error String
126150 deriving (Show, Typeable)
127151
@@ -133,33 +157,26 @@ instance (Typeable err, Show err) => Exception (TransportError err)
133157-- | Errors during the creation of an endpoint
134158data NewEndPointErrorCode =
135159 -- | Not enough resources
136− -- (i.e., this could be a temporary local problem)
137160 NewEndPointInsufficientResources
138161 -- | Failed for some other reason
139− -- (i.e., there is probably no point trying again)
140162 | NewEndPointFailed
141163 deriving (Show, Typeable)
142164
143165-- | Connection failure
144166data ConnectErrorCode =
145167 -- | Could not resolve the address
146− -- (i.e., this could be a temporary remote problem)
147168 ConnectNotFound
148169 -- | Insufficient resources (for instance, no more sockets available)
149− -- (i.e., this could be a temporary local problem)
150170 | ConnectInsufficientResources
151171 -- | Failed for other reasons (including syntax error)
152− -- (i.e., there is probably no point trying again).
153172 | ConnectFailed
154173 deriving (Show, Typeable)
155174
156175-- | Failure during the creation of a new multicast group
157176data NewMulticastGroupErrorCode =
158177 -- | Insufficient resources
159− -- (i.e., this could be a temporary problem)
160178 NewMulticastGroupInsufficientResources
161179 -- | Failed for some other reason
162− -- (i.e., there is probably no point trying again)
163180 | NewMulticastGroupFailed
164181 -- | Not all transport implementations support multicast
165182 | NewMulticastGroupUnsupported
@@ -168,10 +185,8 @@ data NewMulticastGroupErrorCode =
168185-- | Failure during the resolution of a multicast group
169186data ResolveMulticastGroupErrorCode =
170187 -- | Multicast group not found
171− -- (i.e., this could be a temporary problem)
172188 ResolveMulticastGroupNotFound
173189 -- | Failed for some other reason (including syntax error)
174− -- (i.e., there is probably no point trying again)
175190 | ResolveMulticastGroupFailed
176191 -- | Not all transport implementations support multicast
177192 | ResolveMulticastGroupUnsupported
@@ -179,11 +194,9 @@ data ResolveMulticastGroupErrorCode =
179194
180195-- | Failure during sending a message
181196data SendErrorCode =
182− -- | Could not send this message
183− -- (but another attempt might succeed)
184− SendUnreachable
197+ -- | Connection was closed
198+ SendClosed
185199 -- | Send failed for some other reason
186− -- (and retrying probably won't help)
187200 | SendFailed
188201 deriving (Show, Typeable)
189202
network-transport/src/Network/Transport/Chan.hs+10−5
@@ -53,8 +53,13 @@ apiNewEndPoint state = do
5353 }
5454
5555-- | Create a new connection
56−apiConnect :: EndPointAddress -> MVar TransportState -> EndPointAddress -> Reliability -> IO (Either (TransportError ConnectErrorCode) Connection)
57−apiConnect myAddress state theirAddress _ = do
56+apiConnect :: EndPointAddress
57+ -> MVar TransportState
58+ -> EndPointAddress
59+ -> Reliability
60+ -> ConnectHints
61+ -> IO (Either (TransportError ConnectErrorCode) Connection)
62+apiConnect myAddress state theirAddress _reliability _hints = do
5863 (chan, conn) <- modifyMVar state $ \st -> do
5964 let chan = st ^. channelAt theirAddress
6065 let conn = st ^. nextConnectionIdAt theirAddress
@@ -105,10 +110,10 @@ createMulticastGroup state ourAddress groupAddress group =
105110 cs <- (^. channels) <$> readMVar state
106111 es <- readMVar group
107112 forM_ (Set.elems es) $ \ep -> do
108− let ch = (cs ^. at ep "Invalid endpoint")
113+ let ch = cs ^. at ep "Invalid endpoint"
109114 writeChan ch (ReceivedMulticast groupAddress payload)
110− , multicastSubscribe = modifyMVar_ group $ return . (Set.insert ourAddress)
111− , multicastUnsubscribe = modifyMVar_ group $ return . (Set.delete ourAddress)
115+ , multicastSubscribe = modifyMVar_ group $ return . Set.insert ourAddress
116+ , multicastUnsubscribe = modifyMVar_ group $ return . Set.delete ourAddress
112117 , multicastClose = return ()
113118 }
114119
network-transport/src/Network/Transport/TCP.hs+7−8
@@ -370,10 +370,11 @@ apiNewEndPoint transport = try $ do
370370apiConnect :: LocalEndPoint -- ^ Local end point
371371 -> EndPointAddress -- ^ Remote address
372372 -> Reliability -- ^ Reliability (ignored)
373+ -> ConnectHints -- ^ Hints (ignored for now)
373374 -> IO (Either (TransportError ConnectErrorCode) Connection)
374−apiConnect ourEndPoint theirAddress _ | localAddress ourEndPoint == theirAddress =
375+apiConnect ourEndPoint theirAddress _reliability _hints | localAddress ourEndPoint == theirAddress =
375376 connectToSelf ourEndPoint
376−apiConnect ourEndPoint theirAddress _ = try $ do
377+apiConnect ourEndPoint theirAddress _reliability _hints = try $ do
377378 (theirEndPoint, connId) <- requestConnectionTo ourEndPoint theirAddress
378379 -- connAlive can be an IORef rather than an MVar because it is protected by
379380 -- the remoteState MVar. We don't need the overhead of locking twice.
@@ -422,9 +423,9 @@ apiSend theirEndPoint connId connAlive payload = do
422423 alive <- readIORef connAlive
423424 try $ if alive
424425 then mapExceptionIO sendFailed $ sendOn vst (encodeInt32 connId : prependLength payload)
425− else throw $ TransportError SendFailed "Connection closed"
426+ else throw $ TransportError SendClosed "Connection closed"
426427 RemoteEndPointClosed -> do
427− return (Left $ TransportError SendFailed "Connection closed")
428+ return (Left $ TransportError SendClosed "Connection lost")
428429 RemoteEndPointClosing _ _ ->
429430 -- The only way for the endpoint to be in closing state, while a
430431 -- connection is still active, is for the application to call 'close'
@@ -433,7 +434,7 @@ apiSend theirEndPoint connId connAlive payload = do
433434 -- yet. Even if the remote endpoint comes back with "please don't
434435 -- close", this still means that our *outgoing* connection has been
435436 -- closed
436− return (Left $ TransportError SendFailed "Connection closed")
437+ return (Left $ TransportError SendClosed "Connection lost")
437438 RemoteEndPointInvalid _ ->
438439 error "apiSend RELY violation"
439440 where
@@ -706,9 +707,7 @@ socketToEndPoint (EndPointAddress ourAddress) theirAddress = try $ do
706707 where
707708 createSocket :: N.AddrInfo -> IO N.Socket
708709 createSocket addr = mapExceptionIO insufficientResources $ do
709− sock <- N.socket (N.addrFamily addr) N.Stream N.defaultProtocol
710− -- putStrLn $ "Created client socket " ++ show sock
711− return sock
710+ N.socket (N.addrFamily addr) N.Stream N.defaultProtocol
712711
713712 invalidAddress, insufficientResources, failed :: IOException -> TransportError ConnectErrorCode
714713 invalidAddress = TransportError ConnectNotFound . show
network-transport/tests/TestTCP.hs+9−9
@@ -77,7 +77,7 @@ testEarlyDisconnect nextPort = do
7777 -- establish a connection to them. This should re-establish the broken
7878 -- TCP connection.
7979 tlog "Trying to connect to client"
80− Right conn <- connect endpoint theirAddr ReliableOrdered
80+ Right conn <- connect endpoint theirAddr ReliableOrdered defaultConnectHints
8181
8282 -- TEST 3: To test the connection, we do a simple ping test; as before,
8383 -- however, the remote client won't close the connection nicely but just
@@ -97,7 +97,7 @@ testEarlyDisconnect nextPort = do
9797 return ()
9898
9999 -- TEST 4: A subsequent send on an already-open connection will now break
100− Left (TransportError SendFailed _) <- send conn ["ping2"]
100+ Left (TransportError SendClosed _) <- send conn ["ping2"]
101101
102102 -- *Pfew*
103103 putMVar serverDone ()
@@ -183,7 +183,7 @@ testEarlyCloseSocket nextPort = do
183183 -- establish a connection to them. This should re-establish the broken
184184 -- TCP connection.
185185 tlog "Trying to connect to client"
186− Right conn <- connect endpoint theirAddr ReliableOrdered
186+ Right conn <- connect endpoint theirAddr ReliableOrdered defaultConnectHints
187187
188188 -- TEST 3: To test the connection, we do a simple ping test; as before,
189189 -- however, the remote client won't close the connection nicely but just
@@ -208,7 +208,7 @@ testEarlyCloseSocket nextPort = do
208208 return ()
209209
210210 -- TEST 4: A subsequent send on an already-open connection will now break
211− Left (TransportError SendFailed _) <- send conn ["ping2"]
211+ Left (TransportError SendClosed _) <- send conn ["ping2"]
212212
213213 -- *Pfew*
214214 putMVar serverDone ()
@@ -275,19 +275,19 @@ testInvalidConnect nextPort = do
275275
276276 -- Syntax error in the endpoint address
277277 Left (TransportError ConnectFailed _) <-
278− connect endpoint (EndPointAddress "InvalidAddress") ReliableOrdered
278+ connect endpoint (EndPointAddress "InvalidAddress") ReliableOrdered defaultConnectHints
279279
280280 -- Syntax connect, but invalid hostname (TCP address lookup failure)
281281 Left (TransportError ConnectNotFound _) <-
282− connect endpoint (encodeEndPointAddress "invalidHost" "port" 0) ReliableOrdered
282+ connect endpoint (encodeEndPointAddress "invalidHost" "port" 0) ReliableOrdered defaultConnectHints
283283
284284 -- TCP address correct, but nobody home at that address
285285 Left (TransportError ConnectNotFound _) <-
286− connect endpoint (encodeEndPointAddress "127.0.0.1" "9000" 0) ReliableOrdered
286+ connect endpoint (encodeEndPointAddress "127.0.0.1" "9000" 0) ReliableOrdered defaultConnectHints
287287
288288 -- Valid TCP address but invalid endpoint number
289289 Left (TransportError ConnectNotFound _) <-
290− connect endpoint (encodeEndPointAddress "127.0.0.1" port 1) ReliableOrdered
290+ connect endpoint (encodeEndPointAddress "127.0.0.1" port 1) ReliableOrdered defaultConnectHints
291291
292292 return ()
293293
@@ -404,7 +404,7 @@ testBlockAfterCloseSocket nextPort = do
404404 -- At this point the server will have sent a CloseSocket request to the
405405 -- client, and must block until the client responds
406406 tlog "Server waiting to connect to the client.."
407− Right _ <- readMVar clientAddr >>= \addr -> connect endpoint addr ReliableOrdered
407+ Right _ <- readMVar clientAddr >>= \addr -> connect endpoint addr ReliableOrdered defaultConnectHints
408408
409409 tlog "Server waiting.."
410410
network-transport/tests/TestTransport.hs+10−5
@@ -6,7 +6,8 @@ import TestAuxiliary (forkTry, runTests)
66import Control.Concurrent.MVar (newEmptyMVar, takeMVar, putMVar, readMVar)
77import Control.Monad (replicateM, replicateM_, when, guard, forM_)
88import Control.Monad.Error ()
9−import Network.Transport
9+import Network.Transport hiding (connect)
10+import qualified Network.Transport as NT
1011import Network.Transport.Internal (tlog)
1112import Network.Transport.Util (spawn)
1213import Data.ByteString (ByteString)
@@ -16,6 +17,10 @@ import qualified Data.Map as Map (empty, insert, delete, findWithDefault, adjust
1617import Data.String (fromString)
1718import Traced
1819
20+-- | We overload connect to always pass the default hints
21+connect :: EndPoint -> EndPointAddress -> Reliability -> IO (Either (TransportError ConnectErrorCode) Connection)
22+connect ep addr rel = NT.connect ep addr rel defaultConnectHints
23+
1924-- | Server that echoes messages straight back to the origin endpoint.
2025echoServer :: EndPoint -> IO ()
2126echoServer endpoint = do
@@ -390,12 +395,12 @@ testSendAfterClose transport numRepeats = do
390395 -- connection (i.e., on a closed connection while there is still another
391396 -- connection open)
392397 close conn2
393− Left (TransportError SendFailed _) <- send conn2 ["ping2"]
398+ Left (TransportError SendClosed _) <- send conn2 ["ping2"]
394399
395400 -- Now close the first connection, and output on it (i.e., output while
396401 -- there are no lightweight connection at all anymore)
397402 close conn1
398− Left (TransportError SendFailed _) <- send conn2 ["ping2"]
403+ Left (TransportError SendClosed _) <- send conn2 ["ping2"]
399404
400405 return ()
401406
@@ -558,7 +563,7 @@ testCloseEndPoint transport _ = do
558563 ConnectionClosed cid'' <- receive endpoint ; True <- return $ cid == cid''
559564 ErrorEvent (TransportError (EventConnectionLost addr' []) _) <- receive endpoint ; True <- return $ addr' == theirAddr
560565
561− Left (TransportError SendFailed _) <- send conn ["pong2"]
566+ Left (TransportError SendClosed _) <- send conn ["pong2"]
562567
563568 return ()
564569
@@ -596,7 +601,7 @@ testCloseEndPoint transport _ = do
596601 EndPointClosed <- receive endpoint
597602
598603 -- Attempt to send should fail with connection closed
599− Left (TransportError SendFailed _) <- send conn ["ping2"]
604+ Left (TransportError SendClosed _) <- send conn ["ping2"]
600605
601606 -- An attempt to close the already closed connection should just return
602607 () <- close conn