@@ -9,6 +9,7 @@ module Network.Transport.TCP ( -- * Main API
9 , -- TCP specific functionality
9 , -- TCP specific functionality
10 EndPointId
10 EndPointId
11 , decodeEndPointAddress
11 , decodeEndPointAddress
14import Network.Transport
15import Network.Transport
@@ -22,6 +23,7 @@ import Network.Transport.Internal ( encodeInt32
22 , prependLength
23 , prependLength
23 , failWith
24 , failWith
24 , failWithIO
25 , failWithIO
26import qualified Network.Socket as N ( HostName
28import qualified Network.Socket as N ( HostName
27 , ServiceName
29 , ServiceName
@@ -104,12 +106,12 @@ createTransport host port = do
104 state <- newMVar TransportState { _localEndPoints = IntMap.empty
106 state <- newMVar TransportState { _localEndPoints = IntMap.empty
105 , _remoteEndPoints = Map.empty
107 , _remoteEndPoints = Map.empty
107− let transport = TCPTransport { _transportState = state
109+ let transport = TCPTransport { _transportState = state
108− , _transportHost = host
110+ , _transportHost = host
109− , _transportPort = port
111+ , _transportPort = port
111 runErrorT $ do
113 runErrorT $ do
112− forkServer host port (transportServer transport)
114+ failWithIO id $ forkServer host port (transportServer transport)
113 return Transport { newEndPoint = tcpNewEndPoint transport }
115 return Transport { newEndPoint = tcpNewEndPoint transport }
115-- | The transport server handles incoming connections for all endpoints
117-- | The transport server handles incoming connections for all endpoints
@@ -129,13 +131,16 @@ handleConnectionRequest transport sock = do
129 ourEndPoint <- MaybeT $ (^. localEndPointAt ourEndPointId) <$> readMVar (transport ^. transportState)
131 ourEndPoint <- MaybeT $ (^. localEndPointAt ourEndPointId) <$> readMVar (transport ^. transportState)
130 return (ourEndPoint, theirAddress)
132 return (ourEndPoint, theirAddress)
131 case request of
133 case request of
132− Just (ourEndPoint, theirAddress) ->
134+ Just (ourEndPoint, theirAddress) -> do
135+ -- Send acknowledgement
136+ sendMany sock [encodeInt32 ValidEndPoint]
133 -- We ignore the return value of 'forkRemoteEndPoint' here because _they_ are
137 -- We ignore the return value of 'forkRemoteEndPoint' here because _they_ are
134 -- connecting to _us_. 'forkRemoteEndPoint' will have stored the remote endpoint
138 -- connecting to _us_. 'forkRemoteEndPoint' will have stored the remote endpoint
135 -- in the transport state, however, in case _we_ later connect to _them_.
139 -- in the transport state, however, in case _we_ later connect to _them_.
136 void $ forkRemoteEndPoint transport ourEndPoint theirAddress sock
140 void $ forkRemoteEndPoint transport ourEndPoint theirAddress sock
137 Nothing ->
141 Nothing ->
138− return ()
142+ -- Invalid request
140-- | Set up a new remote endpoint (either because we connected to a
145-- | Set up a new remote endpoint (either because we connected to a
141-- new remote endpoint, or because a remote endpoint connected to us)
146-- new remote endpoint, or because a remote endpoint connected to us)
@@ -159,8 +164,9 @@ forkRemoteEndPoint transport ourEndPoint theirAddress sock = do
159 return theirEndPoint
164 return theirEndPoint
161-- Control headers
166-- Control headers
162−data ControlHeaders =
167+data ControlHeader =
168+ ValidEndPoint -- ^ Acknowledgement sent when setting up a new TCP connection
163− RequestConnectionId -- ^ Request a new connection ID from the remote endpoint
169+ | RequestConnectionId -- ^ Request a new connection ID from the remote endpoint
164 | ControlResponse -- ^ Respond to a control request _from_ the remote endpoint
170 | ControlResponse -- ^ Respond to a control request _from_ the remote endpoint
165 deriving Enum
171 deriving Enum
@@ -188,7 +194,7 @@ handleIncomingMessages ourEndPoint theirEndPoint = execWriterT . runMaybeT . for
188 createNewConnection :: ControlRequestId -> MaybeT (WriterT [ConnectionId] IO) ()
194 createNewConnection :: ControlRequestId -> MaybeT (WriterT [ConnectionId] IO) ()
189 createNewConnection reqId = do
195 createNewConnection reqId = do
190 newId <- liftIO $ getNextConnectionId ourEndPoint
196 newId <- liftIO $ getNextConnectionId ourEndPoint
191− withRemoteLock theirEndPoint $ do
197+ withRemoteLock theirEndPoint $
192 sendMany sock (encodeInt32 ControlResponse : encodeInt32 reqId : prependLength [encodeInt32 newId])
198 sendMany sock (encodeInt32 ControlResponse : encodeInt32 reqId : prependLength [encodeInt32 newId])
193 liftIO $ writeChan ourChannel (ConnectionOpened newId ReliableOrdered (theirEndPoint ^. remoteAddress))
199 liftIO $ writeChan ourChannel (ConnectionOpened newId ReliableOrdered (theirEndPoint ^. remoteAddress))
194 -- We add the new connection ID to the list of open connections only once the
200 -- We add the new connection ID to the list of open connections only once the
@@ -258,18 +264,18 @@ tcpConnect :: TCPTransport -- ^ Transport
258 -> Reliability -- ^ Reliability (ignored)
264 -> Reliability -- ^ Reliability (ignored)
259 -> IO (Either (FailedWith ConnectErrorCode) Connection)
265 -> IO (Either (FailedWith ConnectErrorCode) Connection)
260tcpConnect transport ourEndPoint theirAddress _ = runErrorT $ do
266tcpConnect transport ourEndPoint theirAddress _ = runErrorT $ do
261− theirEndPoint <- remoteEndPoint transport ourEndPoint theirAddress
267+ theirEndPoint <- remoteEndPoint transport ourEndPoint theirAddress
262− connId <- requestNewConnection ourEndPoint theirEndPoint
268+ connId <- requestNewConnection ourEndPoint theirEndPoint
263− let sock = theirEndPoint ^. remoteSocket
269+ let sock = theirEndPoint ^. remoteSocket
264− return Connection { send = runErrorT .
270+ return Connection { send = runErrorT .
265− failWithIO (FailedWith SendFailed . show) .
271+ failWithIO (FailedWith SendFailed . show) .
266− withRemoteLock theirEndPoint .
272+ withRemoteLock theirEndPoint .
267− sendMany sock .
273+ sendMany sock .
268− (\payload -> encodeInt32 connId : prependLength payload)
274+ (\payload -> encodeInt32 connId : prependLength payload)
269− , close = -- TODO: we should not close the TCP connection until all
275+ , close = -- TODO: we should not close the TCP connection until all
270− -- lightweight connections have been closed
276+ -- lightweight connections have been closed
271− N.sClose sock
277+ N.sClose sock
274-- | Request a new connection
280-- | Request a new connection
275requestNewConnection :: (MonadIO m, MonadError (FailedWith ConnectErrorCode) m)
281requestNewConnection :: (MonadIO m, MonadError (FailedWith ConnectErrorCode) m)
@@ -310,7 +316,7 @@ remoteEndPoint transport ourEndPoint theirAddress = do
310 -- Create a new connection
316 -- Create a new connection
311 -- liftIO $ putStrLn $ "Creating socket from " ++ show ourAddress ++ " to " ++ show theirAddress
317 -- liftIO $ putStrLn $ "Creating socket from " ++ show ourAddress ++ " to " ++ show theirAddress
312 (host, port, endPointId) <- failWith (invalidAddress "Could not parse") $
318 (host, port, endPointId) <- failWith (invalidAddress "Could not parse") $
313− (decodeEndPointAddress theirAddress)
319+ decodeEndPointAddress theirAddress
314 addr:_ <- failWithIO (invalidAddress . show) $
320 addr:_ <- failWithIO (invalidAddress . show) $
315 N.getAddrInfo Nothing (Just host) (Just port)
321 N.getAddrInfo Nothing (Just host) (Just port)
316 sock <- failWithIO (insufficientResources . show) $
322 sock <- failWithIO (insufficientResources . show) $
@@ -319,7 +325,11 @@ remoteEndPoint transport ourEndPoint theirAddress = do
319 failWithIO (failed . show) $ N.connect sock (N.addrAddress addr)
325 failWithIO (failed . show) $ N.connect sock (N.addrAddress addr)
320 -- Send the endpoint ID we're interested in and our own address
326 -- Send the endpoint ID we're interested in and our own address
321 failWithIO (failed . show) $ sendMany sock (encodeInt32 endPointId : prependLength [ourAddress])
327 failWithIO (failed . show) $ sendMany sock (encodeInt32 endPointId : prependLength [ourAddress])
328+ -- For the remote endpoint to acknowledge
329+ ack <- failWithMaybeIO (invalidAddress . show) $ recvInt32 sock
322− liftIO $ forkRemoteEndPoint transport ourEndPoint theirAddress sock
331+ ValidEndPoint -> liftIO $ forkRemoteEndPoint transport ourEndPoint theirAddress sock
332+ _ -> throwError (invalidAddress "Unexpected response")
324 invalidAddress = FailedWith ConnectInvalidAddress
334 invalidAddress = FailedWith ConnectInvalidAddress
325 insufficientResources = FailedWith ConnectInsufficientResources
335 insufficientResources = FailedWith ConnectInsufficientResources
@@ -399,3 +409,5 @@ remoteEndPointAt addr = remoteEndPoints >>> mapLens addr
400pendingCtrlRequestsAt :: ControlRequestId -> Lens EndPointState (Maybe (MVar [ByteString]))
410pendingCtrlRequestsAt :: ControlRequestId -> Lens EndPointState (Maybe (MVar [ByteString]))
401pendingCtrlRequestsAt ix = pendingCtrlRequests >>> intMapLens (fromIntegral ix)
411pendingCtrlRequestsAt ix = pendingCtrlRequests >>> intMapLens (fromIntegral ix)