summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Network/DHT/Routing.hs58
1 files changed, 53 insertions, 5 deletions
diff --git a/src/Network/DHT/Routing.hs b/src/Network/DHT/Routing.hs
index ecd427b8..631761ac 100644
--- a/src/Network/DHT/Routing.hs
+++ b/src/Network/DHT/Routing.hs
@@ -173,8 +173,8 @@ bucketQ = seqQ
173-- very unlikely that all nodes in bucket fail within an hour of 173-- very unlikely that all nodes in bucket fail within an hour of
174-- each other. 174-- each other.
175-- 175--
176data Bucket ni = Bucket { bktNodes :: !(PSQ ni Timestamp) 176data Bucket ni = Bucket { bktNodes :: !(PSQ ni Timestamp) -- current routing nodes
177 , bktQ :: !(BucketQueue ni) 177 , bktQ :: !(BucketQueue ni) -- replacements pending time-outs
178 } deriving Generic 178 } deriving Generic
179 179
180deriving instance Show ni => Show (Bucket ni) 180deriving instance Show ni => Show (Bucket ni)
@@ -230,7 +230,12 @@ delta = 15 * 60
230insertBucket :: (Alternative f, Ord ni) => -- (Eq ip, Alternative f, Ord (NodeId)) => 230insertBucket :: (Alternative f, Ord ni) => -- (Eq ip, Alternative f, Ord (NodeId)) =>
231 Timestamp -> Event ni -> Bucket ni -> f ([CheckPing ni], Bucket ni) 231 Timestamp -> Event ni -> Bucket ni -> f ([CheckPing ni], Bucket ni)
232insertBucket curTime (TryInsert info) bucket 232insertBucket curTime (TryInsert info) bucket
233 -- just update timestamp if a node is already in bucket 233 -- Just update timestamp if a node is already in bucket.
234 --
235 -- Note PingResult events should only occur for nodes we requested a ping for,
236 -- and those will always already be in the routing queue and will get their
237 -- timestamp updated here, since 'TryInsert' is called on every inbound packet,
238 -- including ping results.
234 | already_have 239 | already_have
235 = pure ( [], map_ns $ PSQ.insertWith max info curTime ) 240 = pure ( [], map_ns $ PSQ.insertWith max info curTime )
236 -- bucket is good, but not full => we can insert a new node 241 -- bucket is good, but not full => we can insert a new node
@@ -271,11 +276,20 @@ insertBucket curTime (PingResult bad_node got_response) bucket
271 = pure ([], Bucket (upd $ bktNodes bucket) popped) 276 = pure ([], Bucket (upd $ bktNodes bucket) popped)
272 where 277 where
273 (top, popped) = runIdentity $ popFront bucketQ (bktQ bucket) 278 (top, popped) = runIdentity $ popFront bucketQ (bktQ bucket)
274 upd | got_response = id 279 upd | got_response = id -- Timestamp was already updated by TryInsert.
275 | Just info <- top = \nodes -> 280 | Just info <- top = \nodes ->
276 fromMaybe nodes $ do 281 fromMaybe nodes $ do
277 _ <- PSQ.lookup bad_node nodes -- Insert only if there's a removal. 282 _ <- PSQ.lookup bad_node nodes -- Insert only if there's a removal.
278 let nodes' = PSQ.delete bad_node nodes 283 let nodes' = PSQ.delete bad_node nodes
284 -- XXX: curTime is the time somebody pinged out, not the time
285 -- of which the popped node was originally queued. That's not
286 -- quite right.
287 --
288 -- It's the best we can do atm since the overflow BucketQueue
289 -- does not include timestamps.
290 --
291 -- This means that initial time-outs for replacement nodes are up to
292 -- twice as long as for the originals.
279 pure $ PSQ.insert info curTime nodes' 293 pure $ PSQ.insert info curTime nodes'
280 | otherwise = id 294 | otherwise = id
281 295
@@ -614,13 +628,47 @@ deriving instance ( Show ip
614#endif 628#endif
615 629
616-- | Atomic 'Table' update 630-- | Atomic 'Table' update
631--
632-- Deprecated, use these two functions instead:
633--
634-- [ 'updateForInbound' ]
635--
636-- [ 'updateForPingResult' ]
637--
617insert :: -- ( Eq ip , Applicative m , Ord (NodeId) , FiniteBits (NodeId)) => 638insert :: -- ( Eq ip , Applicative m , Ord (NodeId) , FiniteBits (NodeId)) =>
618 (Applicative m, Ord ni) => 639 (Applicative m, Ord ni) =>
619 (nid -> Word -> Bool) 640 (nid -> Word -> Bool)
620 -> (ni -> nid) 641 -> (ni -> nid)
621 -> Timestamp -> Event ni -> Table ni nid -> m ([CheckPing ni], Table ni nid) 642 -> Timestamp -> Event ni -> Table ni nid -> m ([CheckPing ni], Table ni nid)
622insert testIdBit nodeId tm event tbl = pure $ fromMaybe ([],tbl) $ modifyBucket testIdBit (\ni -> testIdBit $ nodeId ni) (eventId nodeId event) (insertBucket tm event) tbl 643insert testIdBit nodeId tm event tbl
644 = pure $ fromMaybe ([],tbl)
645 $ modifyBucket testIdBit (\ni -> testIdBit $ nodeId ni)
646 (eventId nodeId event)
647 (insertBucket tm event)
648 tbl
649
650
651-- | Call on every inbound packet (including requested ping results). Returns
652-- a list of nodes to ping and an updated routing table. The caller should
653-- also invoke 'updateForPingResult' on each node in the to-ping list to update
654-- the routing table with that information as it becomes available.
655updateForInbound :: Ord ni =>
656 (nid -> Word -> Bool)
657 -> (ni -> nid)
658 -> Timestamp -> ni -> Table ni nid -> ([ni], Table ni nid)
659updateForInbound testIdBit nodeId tm ni tbl =
660 let Identity (ps, tbl') = Network.DHT.Routing.insert testIdBit nodeId tm (TryInsert ni) tbl
661 decon (CheckPing ns) = ns
662 in (concatMap decon ps, tbl')
623 663
664updateForPingResult :: Ord ni =>
665 (nid -> Word -> Bool)
666 -> (ni -> nid)
667 -> Timestamp -> ni -> Bool -> Table ni nid -> Table ni nid
668updateForPingResult testIdBit nodeId tm ni got_reply tbl =
669 -- The _ should always be empty in this case.
670 let Identity (_, tbl') = Network.DHT.Routing.insert testIdBit nodeId tm (PingResult ni got_reply) tbl
671 in tbl'
624 672
625 673
626{----------------------------------------------------------------------- 674{-----------------------------------------------------------------------