@@ -1,4 +1,9 @@
11-- | TCP transport
2+--
3+-- TODOs:
4+-- * Various errors are still left as "undefined"
5+-- * Many possible errors are not yet dealt with
6+-- * Connections are not yet lightweight
27module Network.Transport.TCP ( -- * Main API
38 createTransport
49 , -- TCP specific functionality
@@ -8,7 +13,9 @@ module Network.Transport.TCP ( -- * Main API
813
914import Network.Transport
1015import Network.Transport.Internal.TCP ( forkServer
16+ , connectTo
1117 , recvExact
18+ , sendMany
1219 , recvWithLength
1320 , sendWithLength
1421 )
@@ -20,19 +27,9 @@ import Network.Transport.Internal ( encodeInt16
2027import qualified Network.Socket as N ( HostName
2128 , ServiceName
2229 , Socket
23− , SocketType(Stream)
24− , SocketOption(ReuseAddr)
25− , getAddrInfo
26− , socket
27− , addrFamily
28− , addrAddress
29− , defaultProtocol
30− , setSocketOption
31− , connect
3230 , sClose
3331 , accept
3432 )
35−import qualified Network.Socket.ByteString as NBS (sendMany)
3633import Control.Concurrent (forkIO)
3734import Control.Concurrent.Chan (Chan, newChan, readChan, writeChan)
3835import Control.Concurrent.MVar (MVar, newMVar, modifyMVar, readMVar)
@@ -109,16 +106,18 @@ endpointServer sock theirAddress chan state = forever $ do
109106 connBS <- recvExact sock 2
110107 connIx <- fromIntegral <$> decodeInt16 (BS.concat connBS)
111108 if connIx == 0
112− then liftIO $ createNewConnection
109+ then createNewConnection
113110 else readMessage connIx
114111 where
115112 -- Create a new connection
116− createNewConnection :: IO ()
113+ createNewConnection :: MaybeT IO ()
117114 createNewConnection = do
118− newIx <- modifyMVar state $ \st -> return (nextConnectionIx ^+= 1 $ st, st ^. nextConnectionIx)
119− newBs <- encodeInt16 (fromIntegral newIx)
120− NBS.sendMany sock [newBs]
121− writeChan chan (ConnectionOpened newIx ReliableOrdered theirAddress)
115+ (newIx, newBs) <- liftIO $ do
116+ newIx <- modifyMVar state $ \st -> return (nextConnectionIx ^+= 1 $ st, st ^. nextConnectionIx)
117+ newBs <- encodeInt16 (fromIntegral newIx)
118+ return (newIx, newBs)
119+ sendMany sock [newBs]
120+ liftIO $ writeChan chan (ConnectionOpened newIx ReliableOrdered theirAddress)
122121
123122 -- Read a message and output it on the endPoint's channel
124123 readMessage :: ConnectionIx -> MaybeT IO ()
@@ -149,16 +148,16 @@ tcpNewEndPoint transportState host port = do
149148tcpConnect :: EndPointAddress -> EndPointAddress -> Reliability -> IO (Either (FailedWith ConnectErrorCode) Connection)
150149tcpConnect myAddress theirAddress _ = runErrorT $ do
151150 sock <- socketForEndPoint myAddress theirAddress
152− -- TODO: test this failure
153− connIx <- maybeTToErrorT (FailedWith undefined undefined) $ requestNewConnection sock
154− return $ Connection { send = sendWithLength sock (Just connIx)
151+ connIx <- maybeTToErrorT undefined $ requestNewConnection sock
152+ return $ Connection { send = \msg -> runErrorT $ maybeTToErrorT (FailedWith SendFailed "Send failed") $
153+ sendWithLength sock (Just connIx) msg
155154 , close = N.sClose sock
156155 }
157156
158157-- | Request a new connection
159158requestNewConnection :: N.Socket -> MaybeT IO ByteString
160159requestNewConnection sock = do
161− liftIO $ pure <$> encodeInt16 0 >>= NBS.sendMany sock
160+ (liftIO $ pure <$> encodeInt16 0) >>= sendMany sock
162161 BS.concat <$> recvExact sock 2
163162
164163-- | Find a socket to the specified endpoint
@@ -171,17 +170,10 @@ socketForEndPoint :: EndPointAddress -- ^ Our address
171170 -> ErrorT (FailedWith ConnectErrorCode) IO N.Socket
172171socketForEndPoint (EndPointAddress myAddress) theirAddress = do
173172 (host, port, endPointIx) <- maybeToErrorT invalidAddress (decodeEndPointAddress theirAddress)
174− liftIO $ do
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)
182− sendWithLength sock (Just endPointBS) [myAddress]
183− -- Connection is now established
184− return sock
173+ sock <- maybeTToErrorT undefined (connectTo host port)
174+ endPointBS <- liftIO $ encodeInt16 (fromIntegral endPointIx)
175+ maybeTToErrorT undefined $ sendWithLength sock (Just endPointBS) [myAddress]
176+ return sock
185177 where
186178 invalidAddress = FailedWith ConnectInvalidAddress "Invalid address"
187179
@@ -192,4 +184,3 @@ decodeEndPointAddress (EndPointAddress bs) = match endPointAddressRE (BSC.unpack
192184 where
193185 endPointAddressRE :: RE Char (N.HostName, N.ServiceName, EndPointIx)
194186 endPointAddressRE = (,,) <$> few anySym <*> (sym ':' *> few anySym) <*> (sym ':' *> (read <$> many anySym))
195−