@@ -1,4 +1,9 @@
1-- | TCP transport
1-- | TCP transport
4+-- * Various errors are still left as "undefined"
5+-- * Many possible errors are not yet dealt with
6+-- * Connections are not yet lightweight
2module Network.Transport.TCP ( -- * Main API
7module Network.Transport.TCP ( -- * Main API
3 createTransport
8 createTransport
4 , -- TCP specific functionality
9 , -- TCP specific functionality
@@ -8,7 +13,9 @@ module Network.Transport.TCP ( -- * Main API
9import Network.Transport
14import Network.Transport
10import Network.Transport.Internal.TCP ( forkServer
15import Network.Transport.Internal.TCP ( forkServer
11 , recvExact
17 , recvExact
12 , recvWithLength
19 , recvWithLength
13 , sendWithLength
20 , sendWithLength
@@ -20,19 +27,9 @@ import Network.Transport.Internal ( encodeInt16
20import qualified Network.Socket as N ( HostName
27import qualified Network.Socket as N ( HostName
21 , ServiceName
28 , ServiceName
24− , SocketOption(ReuseAddr)
35−import qualified Network.Socket.ByteString as NBS (sendMany)
36import Control.Concurrent (forkIO)
33import Control.Concurrent (forkIO)
37import Control.Concurrent.Chan (Chan, newChan, readChan, writeChan)
34import Control.Concurrent.Chan (Chan, newChan, readChan, writeChan)
38import Control.Concurrent.MVar (MVar, newMVar, modifyMVar, readMVar)
35import Control.Concurrent.MVar (MVar, newMVar, modifyMVar, readMVar)
@@ -109,16 +106,18 @@ endpointServer sock theirAddress chan state = forever $ do
109 connBS <- recvExact sock 2
106 connBS <- recvExact sock 2
110 connIx <- fromIntegral <$> decodeInt16 (BS.concat connBS)
107 connIx <- fromIntegral <$> decodeInt16 (BS.concat connBS)
111 if connIx == 0
108 if connIx == 0
112− then liftIO $ createNewConnection
109+ then createNewConnection
113 else readMessage connIx
110 else readMessage connIx
115 -- Create a new connection
112 -- Create a new connection
116− createNewConnection :: IO ()
113+ createNewConnection :: MaybeT IO ()
117 createNewConnection = do
114 createNewConnection = do
115+ (newIx, newBs) <- liftIO $ do
118− newIx <- modifyMVar state $ \st -> return (nextConnectionIx ^+= 1 $ st, st ^. nextConnectionIx)
116+ newIx <- modifyMVar state $ \st -> return (nextConnectionIx ^+= 1 $ st, st ^. nextConnectionIx)
119− newBs <- encodeInt16 (fromIntegral newIx)
117+ newBs <- encodeInt16 (fromIntegral newIx)
118+ return (newIx, newBs)
120− NBS.sendMany sock [newBs]
119+ sendMany sock [newBs]
121− writeChan chan (ConnectionOpened newIx ReliableOrdered theirAddress)
120+ liftIO $ writeChan chan (ConnectionOpened newIx ReliableOrdered theirAddress)
123 -- Read a message and output it on the endPoint's channel
122 -- Read a message and output it on the endPoint's channel
124 readMessage :: ConnectionIx -> MaybeT IO ()
123 readMessage :: ConnectionIx -> MaybeT IO ()
@@ -149,16 +148,16 @@ tcpNewEndPoint transportState host port = do
149tcpConnect :: EndPointAddress -> EndPointAddress -> Reliability -> IO (Either (FailedWith ConnectErrorCode) Connection)
148tcpConnect :: EndPointAddress -> EndPointAddress -> Reliability -> IO (Either (FailedWith ConnectErrorCode) Connection)
150tcpConnect myAddress theirAddress _ = runErrorT $ do
149tcpConnect myAddress theirAddress _ = runErrorT $ do
151 sock <- socketForEndPoint myAddress theirAddress
150 sock <- socketForEndPoint myAddress theirAddress
152− -- TODO: test this failure
153− connIx <- maybeTToErrorT (FailedWith undefined undefined) $ requestNewConnection sock
151+ connIx <- maybeTToErrorT undefined $ requestNewConnection sock
152+ return $ Connection { send = \msg -> runErrorT $ maybeTToErrorT (FailedWith SendFailed "Send failed") $
154− return $ Connection { send = sendWithLength sock (Just connIx)
153+ sendWithLength sock (Just connIx) msg
155 , close = N.sClose sock
154 , close = N.sClose sock
158-- | Request a new connection
157-- | Request a new connection
159requestNewConnection :: N.Socket -> MaybeT IO ByteString
158requestNewConnection :: N.Socket -> MaybeT IO ByteString
160requestNewConnection sock = do
159requestNewConnection sock = do
161− liftIO $ pure <$> encodeInt16 0 >>= NBS.sendMany sock
160+ (liftIO $ pure <$> encodeInt16 0) >>= sendMany sock
162 BS.concat <$> recvExact sock 2
161 BS.concat <$> recvExact sock 2
164-- | Find a socket to the specified endpoint
163-- | Find a socket to the specified endpoint
@@ -171,17 +170,10 @@ socketForEndPoint :: EndPointAddress -- ^ Our address
171 -> ErrorT (FailedWith ConnectErrorCode) IO N.Socket
170 -> ErrorT (FailedWith ConnectErrorCode) IO N.Socket
172socketForEndPoint (EndPointAddress myAddress) theirAddress = do
171socketForEndPoint (EndPointAddress myAddress) theirAddress = do
173 (host, port, endPointIx) <- maybeToErrorT invalidAddress (decodeEndPointAddress theirAddress)
172 (host, port, endPointIx) <- maybeToErrorT invalidAddress (decodeEndPointAddress theirAddress)
174− liftIO $ do
173+ sock <- maybeTToErrorT undefined (connectTo host port)
175− -- Connect to the destination transport
176− addr:_ <- N.getAddrInfo Nothing (Just host) (Just port)
177− sock <- N.socket (N.addrFamily addr) N.Stream N.defaultProtocol
178− N.setSocketOption sock N.ReuseAddr 1
179− N.connect sock (N.addrAddress addr)
180− -- Tell it what endpoint we're interested in and our own address
181− endPointBS <- encodeInt16 (fromIntegral endPointIx)
174+ endPointBS <- liftIO $ encodeInt16 (fromIntegral endPointIx)
182− sendWithLength sock (Just endPointBS) [myAddress]
175+ maybeTToErrorT undefined $ sendWithLength sock (Just endPointBS) [myAddress]
183− -- Connection is now established
184− return sock
176+ return sock
186 invalidAddress = FailedWith ConnectInvalidAddress "Invalid address"
178 invalidAddress = FailedWith ConnectInvalidAddress "Invalid address"
@@ -192,4 +184,3 @@ decodeEndPointAddress (EndPointAddress bs) = match endPointAddressRE (BSC.unpack
193 endPointAddressRE :: RE Char (N.HostName, N.ServiceName, EndPointIx)
185 endPointAddressRE :: RE Char (N.HostName, N.ServiceName, EndPointIx)
194 endPointAddressRE = (,,) <$> few anySym <*> (sym ':' *> few anySym) <*> (sym ':' *> (read <$> many anySym))
186 endPointAddressRE = (,,) <$> few anySym <*> (sym ':' *> few anySym) <*> (sym ':' *> (read <$> many anySym))