summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--OnionRouter.hs45
-rw-r--r--examples/dhtd.hs3
2 files changed, 29 insertions, 19 deletions
diff --git a/OnionRouter.hs b/OnionRouter.hs
index 330e083a..2391e13c 100644
--- a/OnionRouter.hs
+++ b/OnionRouter.hs
@@ -12,8 +12,10 @@ import Network.Tox.NodeId
12import Network.Tox.Onion.Transport 12import Network.Tox.Onion.Transport
13 13
14import Control.Concurrent.STM 14import Control.Concurrent.STM
15import Control.Concurrent.STM.TArray
15import Control.Monad 16import Control.Monad
16import Crypto.Random 17import Crypto.Random
18import Data.Array.MArray
17import Data.Bits 19import Data.Bits
18import qualified Data.ByteString as B 20import qualified Data.ByteString as B
19import qualified Data.HashMap.Strict as HashMap 21import qualified Data.HashMap.Strict as HashMap
@@ -47,7 +49,7 @@ data OnionRouter = OnionRouter
47 -- so we can decrypt the response. 49 -- so we can decrypt the response.
48 pendingQueries :: TVar (Word64Map PendingQuery) 50 pendingQueries :: TVar (Word64Map PendingQuery)
49 -- | The current 12 routes that may be assigned to outgoing packets. 51 -- | The current 12 routes that may be assigned to outgoing packets.
50 , routeMap :: TVar (IntMap RouteRecord) 52 , routeMap :: TArray Int (Maybe RouteRecord)
51 -- | A set of nodes used to query for random route nodes. These aren't 53 -- | A set of nodes used to query for random route nodes. These aren't
52 -- used directly in onion routes, they are queried for route nodes that 54 -- used directly in onion routes, they are queried for route nodes that
53 -- are nearby randomly selected ids. 55 -- are nearby randomly selected ids.
@@ -115,6 +117,12 @@ freshRoute birthday r mrec = Just $ RouteRecord
115 , routeBirthTime = birthday 117 , routeBirthTime = birthday
116 } 118 }
117 119
120modifyArray :: TArray Int r -> (r -> r) -> Int -> STM ()
121modifyArray a f i = do
122 mx <- readArray a i
123 writeArray a i $ f mx
124{-# INLINE modifyArray #-}
125
118gotResponse :: RouteRecord -> RouteRecord 126gotResponse :: RouteRecord -> RouteRecord
119gotResponse rr = rr 127gotResponse rr = rr
120 { responseCount = succ $ responseCount rr 128 { responseCount = succ $ responseCount rr
@@ -136,7 +144,7 @@ newOnionRouter perror = do
136 drg <- newTVar drg0 144 drg <- newTVar drg0
137 -- forM_ [0..11] $ \n -> writeTChan chan $ BuildRoute (RouteId n) 145 -- forM_ [0..11] $ \n -> writeTChan chan $ BuildRoute (RouteId n)
138 pq <- newTVar W64.empty 146 pq <- newTVar W64.empty
139 rm <- newTVar IntMap.empty 147 rm <- newArray (0,11) Nothing
140 tn <- newTVar IntMap.empty 148 tn <- newTVar IntMap.empty
141 ti <- newTVar HashMap.empty 149 ti <- newTVar HashMap.empty
142 tc <- newTVar 0 150 tc <- newTVar 0
@@ -164,7 +172,7 @@ forkRouteBuilder or getnodes = do
164 forever $ do 172 forever $ do
165 let checkRebuild rid want_build stm = flip orElse stm $ do 173 let checkRebuild rid want_build stm = flip orElse stm $ do
166 wanted_ver <- readTVar want_build 174 wanted_ver <- readTVar want_build
167 current_ver <- fmap routeVersion . IntMap.lookup rid <$> readTVar (routeMap or) 175 current_ver <- fmap routeVersion <$> readArray (routeMap or) rid
168 writeTChan (routeLog or) $ "ONION checkRebuild "++show(current_ver,wanted_ver) 176 writeTChan (routeLog or) $ "ONION checkRebuild "++show(current_ver,wanted_ver)
169 check $ maybe True (< wanted_ver) current_ver 177 check $ maybe True (< wanted_ver) current_ver
170 return $ BuildRoute $ RouteId rid 178 return $ BuildRoute $ RouteId rid
@@ -335,9 +343,10 @@ handleEvent getnodes or e@(BuildRoute (RouteId rid)) = do
335 return $ getr 343 return $ getr
336 now <- getPOSIXTime 344 now <- getPOSIXTime
337 atomically $ maybe (return ()) -- writeTVar (pendingRoutes or IntMap.! rid) True) 345 atomically $ maybe (return ()) -- writeTVar (pendingRoutes or IntMap.! rid) True)
338 (\r -> do modifyTVar' (routeMap or) 346 (\r -> do modifyArray (routeMap or)
339 (IntMap.alter (freshRoute now r) rid) 347 (freshRoute now r)
340 v <- routeVersion . (IntMap.! rid) <$> readTVar (routeMap or) 348 rid
349 v <- routeVersion . fromJust <$> readArray (routeMap or) rid
341 writeTVar (pendingRoutes or IntMap.! rid) v 350 writeTVar (pendingRoutes or IntMap.! rid) v
342 ) 351 )
343 mb 352 mb
@@ -362,14 +371,14 @@ lookupSender or saddr (Nonce8 w8) = do
362 371
363lookupRoute :: OnionRouter -> NodeInfo -> RouteId -> IO (Maybe OnionRoute) 372lookupRoute :: OnionRouter -> NodeInfo -> RouteId -> IO (Maybe OnionRoute)
364lookupRoute or ni (RouteId rid) = do 373lookupRoute or ni (RouteId rid) = do
365 mb <- atomically $ IntMap.lookup rid <$> readTVar (routeMap or) 374 mb <- atomically $ readArray (routeMap or) rid
366 return $ storedRoute <$> mb 375 return $ storedRoute <$> mb
367 376
368lookupTimeout :: OnionRouter -> Nonce8 -> OnionDestination r -> STM (OnionDestination RouteId, Int) 377lookupTimeout :: OnionRouter -> Nonce8 -> OnionDestination r -> STM (OnionDestination RouteId, Int)
369lookupTimeout or n8 (OnionDestination asel ni Nothing) = do 378lookupTimeout or n8 (OnionDestination asel ni Nothing) = do
370 let RouteId rid = routeId (nodeId ni) 379 let RouteId rid = routeId (nodeId ni)
371 mrr <- IntMap.lookup rid <$> readTVar (routeMap or) 380 mrr <- readArray (routeMap or) rid
372 readTVar (routeMap or) >>= \rm -> writeTChan (routeLog or) $ "ONION lookupTimeout " ++ unwords [show rid,show (IntMap.keys rm)] 381 writeTChan (routeLog or) $ unwords ["ONION lookupTimeout " ,show rid]
373 case mrr of 382 case mrr of
374 Just rr -> return ( OnionDestination asel ni (Just $ RouteId rid), timeoutForRoute rr) 383 Just rr -> return ( OnionDestination asel ni (Just $ RouteId rid), timeoutForRoute rr)
375 Nothing -> return ( OnionDestination asel ni Nothing , 0 ) 384 Nothing -> return ( OnionDestination asel ni Nothing , 0 )
@@ -378,7 +387,7 @@ hookQueries :: OnionRouter -> (tid -> Nonce8)
378 -> TransactionMethods d tid (OnionDestination RouteId) x 387 -> TransactionMethods d tid (OnionDestination RouteId) x
379 -> TransactionMethods d tid (OnionDestination RouteId) x 388 -> TransactionMethods d tid (OnionDestination RouteId) x
380hookQueries or t8 tmethods = TransactionMethods 389hookQueries or t8 tmethods = TransactionMethods
381 { dispatchRegister = \mvar od d -> do -- :: MVar x -> d -> STM (tid, d) 390 { dispatchRegister = \mvar od d -> {-# SCC "hookQ.dispatchRegister" #-} do -- :: MVar x -> d -> STM (tid, d)
382 (tid,d') <- dispatchRegister tmethods mvar od d 391 (tid,d') <- dispatchRegister tmethods mvar od d
383 let Nonce8 w8 = t8 tid 392 let Nonce8 w8 = t8 tid
384 ni = onionNodeInfo od 393 ni = onionNodeInfo od
@@ -386,11 +395,11 @@ hookQueries or t8 tmethods = TransactionMethods
386 od' = case od of 395 od' = case od of
387 OnionDestination {} -> od { onionRouteSpec = Just rid } 396 OnionDestination {} -> od { onionRouteSpec = Just rid }
388 OnionToOwner a b -> OnionToOwner a b -- Type cast. 397 OnionToOwner a b -> OnionToOwner a b -- Type cast.
389 wanted <- readTVar (pendingRoutes or IntMap.! ridn) 398 wanted <- {-# SCC "hookQ.wanted" #-} (readTVar (pendingRoutes or IntMap.! ridn))
390 mr <- IntMap.lookup ridn <$> readTVar (routeMap or) 399 mr <- {-# SCC "hookQ.mr_action" #-} (readArray (routeMap or) ridn)
391 -- Block query until a route is ready. 400 -- Block query until a route is ready.
392 check $ fromMaybe False $ do 401 check $ fromMaybe False $ do
393 RouteRecord{routeVersion=rv} <- mr 402 RouteRecord{routeVersion=rv} <- {-# SCC "hookQ.mr" #-} mr
394 return $ wanted <= rv 403 return $ wanted <= rv
395 let pq = PendingQuery { pendingDestination = od' 404 let pq = PendingQuery { pendingDestination = od'
396 , pendingVersion = maybe 0 routeVersion mr 405 , pendingVersion = maybe 0 routeVersion mr
@@ -400,7 +409,7 @@ hookQueries or t8 tmethods = TransactionMethods
400 modifyTVar' (pendingQueries or) (W64.insert w8 pq) 409 modifyTVar' (pendingQueries or) (W64.insert w8 pq)
401 writeTChan (routeLog or) $ "ONION query add " ++ unwords [ show (Just $ pendingVersion pq,w8), ":=", show ni ] 410 writeTChan (routeLog or) $ "ONION query add " ++ unwords [ show (Just $ pendingVersion pq,w8), ":=", show ni ]
402 return (tid,d') 411 return (tid,d')
403 , dispatchResponse = \tid x d -> do -- :: tid -> x -> d -> STM (d, IO ()) 412 , dispatchResponse = \tid x d -> {-# SCC "hookQ.dispatchResponse" #-} do -- :: tid -> x -> d -> STM (d, IO ())
404 let Nonce8 w8 = t8 tid 413 let Nonce8 w8 = t8 tid
405 mb <- W64.lookup w8 <$> readTVar (pendingQueries or) 414 mb <- W64.lookup w8 <$> readTVar (pendingQueries or)
406 modifyTVar' (pendingQueries or) (W64.delete w8) 415 modifyTVar' (pendingQueries or) (W64.delete w8)
@@ -408,10 +417,10 @@ hookQueries or t8 tmethods = TransactionMethods
408 let od = pendingDestination pq 417 let od = pendingDestination pq
409 RouteId rid = fromMaybe (routeId (nodeId (onionNodeInfo od))) 418 RouteId rid = fromMaybe (routeId (nodeId (onionNodeInfo od)))
410 $ onionRouteSpec od 419 $ onionRouteSpec od
411 modifyTVar' (routeMap or) (IntMap.adjust gotResponse rid) 420 modifyArray (routeMap or) (fmap gotResponse) rid
412 writeTChan (routeLog or) $ "ONION query del " ++ show (fmap pendingVersion mb, w8) 421 writeTChan (routeLog or) $ "ONION query del " ++ show (fmap pendingVersion mb, w8)
413 dispatchResponse tmethods tid x d 422 dispatchResponse tmethods tid x d
414 , dispatchCancel = \tid d -> do -- :: tid -> d -> STM d 423 , dispatchCancel = \tid d -> {-# SCC "hookQ.dispatchCancel" #-} do -- :: tid -> d -> STM d
415 let Nonce8 w8 = t8 tid 424 let Nonce8 w8 = t8 tid
416 mb <- W64.lookup w8 <$> readTVar (pendingQueries or) 425 mb <- W64.lookup w8 <$> readTVar (pendingQueries or)
417 modifyTVar' (pendingQueries or) (W64.delete w8) 426 modifyTVar' (pendingQueries or) (W64.delete w8)
@@ -419,13 +428,13 @@ hookQueries or t8 tmethods = TransactionMethods
419 let od = pendingDestination pq 428 let od = pendingDestination pq
420 RouteId rid = fromMaybe (routeId (nodeId (onionNodeInfo od))) 429 RouteId rid = fromMaybe (routeId (nodeId (onionNodeInfo od)))
421 $ onionRouteSpec od 430 $ onionRouteSpec od
422 mrr <- IntMap.lookup rid <$> readTVar (routeMap or) 431 mrr <- readArray (routeMap or) rid
423 forM_ mrr $ \rr -> do 432 forM_ mrr $ \rr -> do
424 when (routeVersion rr == pendingVersion pq) $ do 433 when (routeVersion rr == pendingVersion pq) $ do
425 let expireRoute = modifyTVar' (pendingRoutes or IntMap.! rid) expire 434 let expireRoute = modifyTVar' (pendingRoutes or IntMap.! rid) expire
426 expire ver | ver <= succ (pendingVersion pq) = succ (pendingVersion pq) 435 expire ver | ver <= succ (pendingVersion pq) = succ (pendingVersion pq)
427 | otherwise = ver 436 | otherwise = ver
428 modifyTVar' (routeMap or) (IntMap.adjust gotTimeout rid) 437 modifyArray (routeMap or) (fmap gotTimeout) rid
429 case rr of 438 case rr of
430 RouteRecord{ responseCount = 0 439 RouteRecord{ responseCount = 0
431 , timeoutCount = c 440 , timeoutCount = c
diff --git a/examples/dhtd.hs b/examples/dhtd.hs
index 3f2a6a63..8e9e7692 100644
--- a/examples/dhtd.hs
+++ b/examples/dhtd.hs
@@ -27,6 +27,7 @@ import Control.Concurrent.STM.TMChan
27import Control.Exception 27import Control.Exception
28import Control.Monad 28import Control.Monad
29import Control.Monad.IO.Class (liftIO) 29import Control.Monad.IO.Class (liftIO)
30import Data.Array.MArray (getAssocs)
30import Data.Bool 31import Data.Bool
31import Data.Char 32import Data.Char
32import Data.Conduit as C 33import Data.Conduit as C
@@ -930,7 +931,7 @@ clientSession s@Session{..} sock cnum h = do
930 ("onion", s) -> cmd0 $ do 931 ("onion", s) -> cmd0 $ do
931 now <- getPOSIXTime 932 now <- getPOSIXTime
932 join $ atomically $ do 933 join $ atomically $ do
933 rm <- readTVar $ routeMap onionRouter 934 rm <- IntMap.fromList . catMaybes . map (\(i,m) -> fmap (i,) m) <$> getAssocs (routeMap onionRouter)
934 ts <- readTVar $ trampolineNodes onionRouter 935 ts <- readTVar $ trampolineNodes onionRouter
935 tcnt <- readTVar $ trampolineCount onionRouter 936 tcnt <- readTVar $ trampolineCount onionRouter
936 icnt <- HashMap.size <$> readTVar (trampolineIds onionRouter) 937 icnt <- HashMap.size <$> readTVar (trampolineIds onionRouter)