@@ -254,6 +254,37 @@ apiConnect :: LocalEndPoint -- ^ Local end point
254254 -> EndPointAddress -- ^ Remote address
255255 -> Reliability -- ^ Reliability (ignored)
256256 -> IO (Either (FailedWith ConnectErrorCode) Connection)
257+-- Special case for self-connection
258+apiConnect ourEndPoint theirAddress _ | ourEndPoint ^. localAddress == theirAddress = do
259+ connAlive <- newMVar True
260+ connId <- modifyMVar (ourEndPoint ^. localState) $ \st -> do
261+ let connId = st ^. nextConnectionId
262+ return (nextConnectionId ^= connId + 1 $ st, connId)
263+
264+ let ourChan :: Chan Event
265+ ourChan = ourEndPoint ^. localChannel
266+
267+ selfSend :: [ByteString] -> IO (Either (FailedWith SendErrorCode) ())
268+ selfSend msg = do
269+ modifyMVar connAlive $ \alive ->
270+ if alive
271+ then do
272+ writeChan ourChan (Received connId msg)
273+ return (alive, Right ())
274+ else
275+ return (alive, Left (FailedWith SendConnectionClosed "Connection closed"))
276+
277+ selfClose :: IO ()
278+ selfClose = do
279+ modifyMVar_ connAlive $ \alive -> do
280+ when alive $ writeChan ourChan (ConnectionClosed connId)
281+ return False
282+
283+ writeChan ourChan (ConnectionOpened connId ReliableOrdered theirAddress)
284+ return . Right $ Connection { send = selfSend
285+ , close = selfClose
286+ }
287+-- Regular case
257288apiConnect ourEndPoint theirAddress _ = runErrorT $ do
258289 theirEndPoint <- findRemoteEndPoint ourEndPoint theirAddress
259290 connId <- requestNewConnection (ourEndPoint, theirEndPoint)
@@ -325,14 +356,14 @@ findRemoteEndPoint ourEndPoint theirAddress = ErrorT $ go
325356 return (connectionTo theirAddress ^= Just (Nothing, theirMVar) $ st, theirMVar)
326357 theirState <- readMVar endPoint
327358 case theirState of
328− EndPointInvalid err ->
359+ EndPointInvalid err -> do
329360 -- We remove the endpoint from the state again because the next call
330361 -- to 'connect' might give a different result
331362 modifyMVar state $ \st ->
332363 return (connectionTo theirAddress ^= Nothing $ st, Left err)
333− EndPointValid _ ep ->
364+ EndPointValid _ ep -> do
334365 return $ Right ep
335− EndPointClosed ->
366+ EndPointClosed -> do
336367 go
337368
338369 state :: MVar LocalState
@@ -348,9 +379,9 @@ connectToRemoteEndPoint ourEndPoint theirMVar theirAddress = do
348379 Right (ConnectionRequestEndPointInvalid, sock) -> do
349380 putMVar theirMVar (EndPointInvalid (invalidAddress "Invalid endpoint"))
350381 N.sClose sock
351− Right (ConnectionRequestCrossed, sock) ->
382+ Right (ConnectionRequestCrossed, sock) -> do
352383 N.sClose sock
353− Left err ->
384+ Left err -> do
354385 -- TODO: this isn't quite right; socket *might* have been opened here,
355386 -- in which case we should close it
356387 putMVar theirMVar (EndPointInvalid err)
@@ -421,12 +452,12 @@ sendRemoteRequest (ourEndPoint, theirEndPoint) header = do
421452increaseRemoteRefCount :: Conn -> IO ()
422453increaseRemoteRefCount (ourEndPoint, theirEndPoint) = do
423454 let theirAddr = theirEndPoint ^. remoteAddress
424− state = ourEndPoint ^. localState
455+ ourState = ourEndPoint ^. localState
425456 -- If this endpoint was closing, cancel that
426− theirMVar <- modifyMVar state $ \st -> do
457+ theirMVar <- modifyMVar ourState $ \st -> do
427458 let Just (isClosing, theirMVar) = st ^. connectionTo theirAddr
428459 case isClosing of
429− Nothing ->
460+ Nothing -> do
430461 return (st, theirMVar)
431462 Just ep -> do
432463 putMVar theirMVar (EndPointValid 0 ep)
@@ -475,7 +506,7 @@ handleConnectionRequest transport sock = do
475506 mvar <- newEmptyMVar
476507 return (connectionTo theirAddress ^= Just (Nothing, mvar) $ st, (False, mvar))
477508 Just (_, mvar) ->
478− return (st, (ourEndPoint ^. localAddress <= theirAddress, mvar))
509+ return (st, (ourEndPoint ^. localAddress < theirAddress, mvar))
479510 if crossed
480511 then do
481512 sendMany sock [encodeInt32 ConnectionRequestCrossed]