summaryrefslogtreecommitdiff
path: root/src/Network/BitTorrent/DHT/Session.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Network/BitTorrent/DHT/Session.hs')
-rw-r--r--src/Network/BitTorrent/DHT/Session.hs91
1 files changed, 22 insertions, 69 deletions
diff --git a/src/Network/BitTorrent/DHT/Session.hs b/src/Network/BitTorrent/DHT/Session.hs
index f96ba707..d94f028f 100644
--- a/src/Network/BitTorrent/DHT/Session.hs
+++ b/src/Network/BitTorrent/DHT/Session.hs
@@ -35,9 +35,10 @@ module Network.BitTorrent.DHT.Session
35 , routingInfo 35 , routingInfo
36 , routableAddress 36 , routableAddress
37 , getTimestamp 37 , getTimestamp
38 , SessionTokens 38 -- , SessionTokens
39 , sessionTokens 39 -- , sessionTokens
40 , contactInfo 40 -- , contactInfo
41 , dhtData
41 , PeerStore 42 , PeerStore
42 , manager 43 , manager
43 44
@@ -55,8 +56,8 @@ module Network.BitTorrent.DHT.Session
55 , runDHT 56 , runDHT
56 57
57 -- ** Tokens 58 -- ** Tokens
58 , grantToken 59 -- , grantToken
59 , checkToken 60 -- , checkToken
60 61
61 -- ** Routing table 62 -- ** Routing table
62 , getTable 63 , getTable
@@ -68,6 +69,7 @@ module Network.BitTorrent.DHT.Session
68 , insertPeer 69 , insertPeer
69 , getPeerList 70 , getPeerList
70 , getPeerList1 71 , getPeerList1
72 , lookupPeers
71 , insertTopic 73 , insertTopic
72 , deleteTopic 74 , deleteTopic
73 , getSwarms 75 , getSwarms
@@ -113,6 +115,7 @@ import Data.Time.Clock.POSIX
113import Data.Text as Text 115import Data.Text as Text
114import Text.PrettyPrint.HughesPJClass hiding ((<>),($$)) 116import Text.PrettyPrint.HughesPJClass hiding ((<>),($$))
115import Data.Serialize as S 117import Data.Serialize as S
118import Network.DHT.Types
116 119
117 120
118import Data.Torrent as Torrent 121import Data.Torrent as Torrent
@@ -228,33 +231,6 @@ instance Default Options where
228 231
229seconds :: NominalDiffTime -> Int 232seconds :: NominalDiffTime -> Int
230seconds dt = fromEnum (realToFrac dt :: Uni) 233seconds dt = fromEnum (realToFrac dt :: Uni)
231
232{-----------------------------------------------------------------------
233-- Tokens policy
234-----------------------------------------------------------------------}
235
236data SessionTokens = SessionTokens
237 { tokenMap :: !TokenMap
238 , lastUpdate :: !UTCTime
239 , maxInterval :: !NominalDiffTime
240 }
241
242nullSessionTokens :: IO SessionTokens
243nullSessionTokens = SessionTokens
244 <$> (tokens <$> liftIO randomIO)
245 <*> liftIO getCurrentTime
246 <*> pure defaultUpdateInterval
247
248-- TODO invalidate *twice* if needed
249invalidateTokens :: UTCTime -> SessionTokens -> SessionTokens
250invalidateTokens curTime ts @ SessionTokens {..}
251 | curTime `diffUTCTime` lastUpdate > maxInterval = SessionTokens
252 { tokenMap = update tokenMap
253 , lastUpdate = curTime
254 , maxInterval = maxInterval
255 }
256 | otherwise = ts
257
258{----------------------------------------------------------------------- 234{-----------------------------------------------------------------------
259-- Session 235-- Session
260-----------------------------------------------------------------------} 236-----------------------------------------------------------------------}
@@ -277,9 +253,8 @@ data Node raw dht u ip = Node
277 , resources :: !InternalState 253 , resources :: !InternalState
278 , manager :: !(Manager raw dht) -- ^ RPC manager; 254 , manager :: !(Manager raw dht) -- ^ RPC manager;
279 , routingInfo :: !(TVar (Maybe (R.Info dht ip u))) -- ^ search table; 255 , routingInfo :: !(TVar (Maybe (R.Info dht ip u))) -- ^ search table;
280 , contactInfo :: !(TVar (PeerStore ip )) -- ^ published by other nodes;
281 , announceInfo :: !(TVar AnnounceSet ) -- ^ to publish by this node; 256 , announceInfo :: !(TVar AnnounceSet ) -- ^ to publish by this node;
282 , sessionTokens :: !(TVar SessionTokens ) -- ^ query session IDs. 257 , dhtData :: DHTData dht ip
283 , loggerFun :: !LogFun 258 , loggerFun :: !LogFun
284 } 259 }
285 260
@@ -371,6 +346,7 @@ locFromCS cs = case getCallStack cs of
371newNode :: ( Address ip 346newNode :: ( Address ip
372 , FiniteBits (NodeId dht) 347 , FiniteBits (NodeId dht)
373 , Serialize (NodeId dht) 348 , Serialize (NodeId dht)
349 , Kademlia dht
374 ) 350 )
375 => -- [NodeHandler] -- ^ handlers to run on accepted queries; 351 => -- [NodeHandler] -- ^ handlers to run on accepted queries;
376 Options -- ^ various dht options; 352 Options -- ^ various dht options;
@@ -389,12 +365,12 @@ newNode opts naddr logger mbid = do
389 s <- getInternalState 365 s <- getInternalState
390 (_, m) <- allocate (newManager rpcOpts (logt logger) nodeAddr []) closeManager 366 (_, m) <- allocate (newManager rpcOpts (logt logger) nodeAddr []) closeManager
391 liftIO $ do 367 liftIO $ do
368 dta <- initializeDHTData
392 myId <- maybe genNodeId return mbid 369 myId <- maybe genNodeId return mbid
393 node <- Node opts myId s m 370 node <- Node opts myId s m
394 <$> atomically (newTVar Nothing) 371 <$> atomically (newTVar Nothing)
395 <*> newTVarIO def
396 <*> newTVarIO S.empty 372 <*> newTVarIO S.empty
397 <*> (newTVarIO =<< nullSessionTokens) 373 <*> pure dta
398 <*> pure logger 374 <*> pure logger
399 return node 375 return node
400 376
@@ -415,29 +391,6 @@ runDHT node action = runReaderT (unDHT action) node
415-- /pick a random ID/ in the range of the bucket and perform a 391-- /pick a random ID/ in the range of the bucket and perform a
416-- find_nodes search on it. 392-- find_nodes search on it.
417 393
418{-----------------------------------------------------------------------
419-- Tokens
420-----------------------------------------------------------------------}
421
422tryUpdateSecret :: TVar SessionTokens -> IO ()
423tryUpdateSecret toks = do
424 curTime <- liftIO getCurrentTime
425 liftIO $ atomically $ modifyTVar' toks (invalidateTokens curTime)
426
427grantToken :: Hashable a => TVar SessionTokens -> NodeAddr a -> IO Token
428grantToken sessionTokens addr = do
429 tryUpdateSecret sessionTokens
430 toks <- readTVarIO sessionTokens
431 return $ T.lookup addr $ tokenMap toks
432
433-- | Throws 'HandlerError' if the token is invalid or already
434-- expired. See 'TokenMap' for details.
435checkToken :: Hashable a => TVar SessionTokens -> NodeAddr a -> Token -> IO Bool
436checkToken sessionTokens addr questionableToken = do
437 tryUpdateSecret sessionTokens
438 toks <- readTVarIO sessionTokens
439 return $ T.member addr questionableToken (tokenMap toks)
440
441 394
442{----------------------------------------------------------------------- 395{-----------------------------------------------------------------------
443-- Routing table 396-- Routing table
@@ -475,28 +428,28 @@ getTable = do
475 let nil = nullTable myId (optBucketCount opts) 428 let nil = nullTable myId (optBucketCount opts)
476 liftIO (maybe nil R.myBuckets <$> atomically (readTVar var)) 429 liftIO (maybe nil R.myBuckets <$> atomically (readTVar var))
477 430
478getSwarms :: Ord ip => DHT raw dht u ip [ (InfoHash, Int, Maybe ByteString) ] 431getSwarms :: Ord ip => DHT raw KMessageOf u ip [ (InfoHash, Int, Maybe ByteString) ]
479getSwarms = do 432getSwarms = do
480 store <- asks contactInfo >>= liftIO . atomically . readTVar 433 store <- asks (contactInfo . dhtData) >>= liftIO . atomically . readTVar
481 return $ P.knownSwarms store 434 return $ P.knownSwarms store
482 435
483savePeerStore :: (Ord ip, Address ip) => DHT raw dht u ip ByteString 436savePeerStore :: (Ord ip, Address ip) => DHT raw KMessageOf u ip ByteString
484savePeerStore = do 437savePeerStore = do
485 var <- asks contactInfo 438 var <- asks (contactInfo . dhtData)
486 peers <- liftIO $ atomically $ readTVar var 439 peers <- liftIO $ atomically $ readTVar var
487 return $ S.encode peers 440 return $ S.encode peers
488 441
489mergeSavedPeers :: (Ord ip, Address ip) => ByteString -> DHT raw dht u ip () 442mergeSavedPeers :: (Ord ip, Address ip) => ByteString -> DHT raw KMessageOf u ip ()
490mergeSavedPeers bs = do 443mergeSavedPeers bs = do
491 var <- asks contactInfo 444 var <- asks (contactInfo . dhtData)
492 case S.decode bs of 445 case S.decode bs of
493 Right newbies -> liftIO $ atomically $ modifyTVar' var (<> newbies) 446 Right newbies -> liftIO $ atomically $ modifyTVar' var (<> newbies)
494 Left _ -> return () 447 Left _ -> return ()
495 448
496 449
497allPeers :: Ord ip => InfoHash -> DHT raw dht u ip [ PeerAddr ip ] 450allPeers :: Ord ip => InfoHash -> DHT raw KMessageOf u ip [ PeerAddr ip ]
498allPeers ih = do 451allPeers ih = do
499 store <- asks contactInfo >>= liftIO . atomically . readTVar 452 store <- asks (contactInfo . dhtData) >>= liftIO . atomically . readTVar
500 return $ P.lookup ih store 453 return $ P.lookup ih store
501 454
502-- | Find a set of closest nodes from routing table of this node. (in 455-- | Find a set of closest nodes from routing table of this node. (in
@@ -566,7 +519,7 @@ getTimestamp = do
566-- 519--
567getPeerList :: Ord ip => InfoHash -> DHT raw KMessageOf () ip (PeerList ip) 520getPeerList :: Ord ip => InfoHash -> DHT raw KMessageOf () ip (PeerList ip)
568getPeerList ih = do 521getPeerList ih = do
569 var <- asks contactInfo 522 var <- asks (contactInfo . dhtData)
570 ps <- liftIO $ lookupPeers var ih 523 ps <- liftIO $ lookupPeers var ih
571 if L.null ps 524 if L.null ps
572 then Left <$> getClosest ih 525 then Left <$> getClosest ih
@@ -574,7 +527,7 @@ getPeerList ih = do
574 527
575getPeerList1 :: Ord ip => DHT raw KMessageOf () ip (InfoHash -> IO (PeerList ip)) 528getPeerList1 :: Ord ip => DHT raw KMessageOf () ip (InfoHash -> IO (PeerList ip))
576getPeerList1 = do 529getPeerList1 = do
577 var <- asks contactInfo 530 var <- asks (contactInfo . dhtData)
578 getclosest <- getClosest1 531 getclosest <- getClosest1
579 return $ \ih -> do 532 return $ \ih -> do
580 ps <- lookupPeers var ih 533 ps <- lookupPeers var ih