@@ -8,11 +8,15 @@ import Network.Transport
88import Control.Concurrent (forkIO)
99import Control.Concurrent.Chan
1010import Control.Concurrent.MVar
11−import Control.Monad (forever, unless)
11+import Control.Monad (forever)
1212import Data.ByteString.Lazy.Char8 (ByteString)
1313import Data.IntMap (IntMap)
1414import Data.Int
1515import Network.Socket
16+ ( AddrInfoFlag (AI_PASSIVE), HostName, ServiceName, Socket
17+ , SocketType (Stream), SocketOption (ReuseAddr)
18+ , accept, addrAddress, addrFlags, addrFamily, bindSocket, defaultProtocol
19+ , getAddrInfo, listen, setSocketOption, socket, sClose, withSocketsDo )
1620import Safe
1721
1822import qualified Data.Binary as B
@@ -21,8 +25,8 @@ import qualified Data.IntMap as IntMap
2125import qualified Network.Socket as N
2226import qualified Network.Socket.ByteString.Lazy as NBS
2327
24−type ChanId = Int
25−type Chans = MVar (ChanId, IntMap (Chan ByteString))
28+type ChanId = Int
29+type Chans = MVar (ChanId, IntMap (Chan ByteString, MVar [Socket]))
2630
2731-- | This deals with several different configuration properties:
2832-- * Buffer size, specified in Hints
@@ -49,14 +53,15 @@ mkTransport (TCPConfig _hints host service) = withSocketsDo $ do
4953 sock <- socket (addrFamily serverAddr) Stream defaultProtocol
5054 bindSocket sock (addrAddress serverAddr)
5155 listen sock 5
52− forkIO $ procConnections channels sock
56+ _ <- forkIO $ procConnections channels sock
5357
5458 return Transport
5559 { newConnectionWith = \_ -> do
5660 (chanId, chanMap) <- takeMVar channels
5761 chan <- newChan
58− putMVar channels (chanId + 1, IntMap.insert chanId chan chanMap)
59− return (mkSourceAddr host service chanId, mkTargetEnd chan)
62+ socks <- newMVar [sock]
63+ putMVar channels (chanId + 1, IntMap.insert chanId (chan, socks) chanMap)
64+ return (mkSourceAddr host service chanId, mkTargetEnd chan socks)
6065 , newMulticastWith = error "newMulticastWith: not defined"
6166 , deserialize = \bs ->
6267 let (host, service, chanId) = B.decode bs in
@@ -81,18 +86,20 @@ mkTransport (TCPConfig _hints host service) = withSocketsDo $ do
8186 N.connect sock (addrAddress serverAddr)
8287 NBS.sendAll sock $ B.encode (fromIntegral chanId :: Int64)
8388 return SourceEnd
84− { Network.Transport.send = \bs -> do
85− let size = fromIntegral (sum . map BS.length $ bs) :: Int64
89+ { send = \bss -> do
90+ let size = fromIntegral (sum . map BS.length $ bss) :: Int64
8691 NBS.sendAll sock (B.encode size)
87− mapM_ (NBS.sendAll sock) bs
92+ mapM_ (NBS.sendAll sock) bss
93+ , closeSourceEnd = sClose sock
8894 }
8995
90− mkTargetEnd :: Chan ByteString -> TargetEnd
91− mkTargetEnd chan = TargetEnd
96+ mkTargetEnd :: Chan ByteString -> MVar [Socket] -> TargetEnd
97+ mkTargetEnd chan socks = TargetEnd
9298 { -- for now we will implement this as a Chan
9399 receive = do
94100 bs <- readChan chan
95101 return [bs]
102+ , closeTargetEnd = takeMVar socks >>= mapM_ sClose
96103 }
97104
98105 procConnections :: Chans -> Socket -> IO ()
@@ -104,7 +111,9 @@ mkTransport (TCPConfig _hints host service) = withSocketsDo $ do
104111 (_, chanMap) <- readMVar chans
105112 case IntMap.lookup chanId chanMap of
106113 Nothing -> error "procConnections: cannot find chanId"
107− Just chan -> forkIO $ procMessages chan clientSock
114+ Just (chan, socks) -> do
115+ modifyMVar_ socks (return . (clientSock :))
116+ forkIO $ procMessages chan clientSock
108117
109118 -- This function first extracts a header of type Int64, which determines
110119 -- the size of the ByteString that follows. The ByteString is then