summaryrefslogtreecommitdiff
path: root/src/Network
diff options
context:
space:
mode:
authorSam Truzjan <pxqr.sta@gmail.com>2013-12-28 18:30:44 +0400
committerSam Truzjan <pxqr.sta@gmail.com>2013-12-28 18:30:44 +0400
commit4a46766d5fb0882151e80f9137983a8c2dfb7869 (patch)
tree62d49c7c00858377275f321a590e2c36b7577062 /src/Network
parent0e3ed097d12e5fb82b594265a1adb6096fe556b4 (diff)
Add instance Alternative Routing
Diffstat (limited to 'src/Network')
-rw-r--r--src/Network/BitTorrent/DHT/Routing.hs33
-rw-r--r--src/Network/BitTorrent/DHT/Session.hs27
2 files changed, 37 insertions, 23 deletions
diff --git a/src/Network/BitTorrent/DHT/Routing.hs b/src/Network/BitTorrent/DHT/Routing.hs
index 984a61cc..af10513d 100644
--- a/src/Network/BitTorrent/DHT/Routing.hs
+++ b/src/Network/BitTorrent/DHT/Routing.hs
@@ -37,13 +37,12 @@ module Network.BitTorrent.DHT.Routing
37 , Network.BitTorrent.DHT.Routing.insert 37 , Network.BitTorrent.DHT.Routing.insert
38 ) where 38 ) where
39 39
40import Control.Applicative hiding (empty) 40import Control.Applicative as A
41import Control.Arrow 41import Control.Arrow
42import Control.Monad 42import Control.Monad
43import Data.Function 43import Data.Function
44import Data.List as L hiding (insert) 44import Data.List as L hiding (insert)
45import Data.Maybe 45import Data.Maybe
46import Data.Monoid
47import Data.PSQueue as PSQ 46import Data.PSQueue as PSQ
48import Data.Serialize as S hiding (Result, Done) 47import Data.Serialize as S hiding (Result, Done)
49import Data.Time 48import Data.Time
@@ -101,12 +100,14 @@ insert ping (k, v) = go 0
101type Timestamp = POSIXTime 100type Timestamp = POSIXTime
102 101
103data Routing ip result 102data Routing ip result
104 = Done result 103 = Full
104 | Done result
105 | GetTime ( Timestamp -> Routing ip result) 105 | GetTime ( Timestamp -> Routing ip result)
106 | NeedPing (NodeAddr ip) ( Bool -> Routing ip result) 106 | NeedPing (NodeAddr ip) ( Bool -> Routing ip result)
107 | Refresh NodeId ([NodeInfo ip] -> Routing ip result) 107 | Refresh NodeId ([NodeInfo ip] -> Routing ip result)
108 108
109instance Functor (Routing ip) where 109instance Functor (Routing ip) where
110 fmap _ Full = Full
110 fmap f (Done r) = Done ( f r) 111 fmap f (Done r) = Done ( f r)
111 fmap f (GetTime g) = GetTime (fmap f . g) 112 fmap f (GetTime g) = GetTime (fmap f . g)
112 fmap f (NeedPing addr g) = NeedPing addr (fmap f . g) 113 fmap f (NeedPing addr g) = NeedPing addr (fmap f . g)
@@ -115,20 +116,31 @@ instance Functor (Routing ip) where
115instance Monad (Routing ip) where 116instance Monad (Routing ip) where
116 return = Done 117 return = Done
117 118
119 Full >>= _ = Full
118 Done r >>= m = m r 120 Done r >>= m = m r
119 GetTime f >>= m = GetTime $ \ t -> f t >>= m 121 GetTime f >>= m = GetTime $ \ t -> f t >>= m
120 NeedPing a f >>= m = NeedPing a $ \ p -> f p >>= m 122 NeedPing a f >>= m = NeedPing a $ \ p -> f p >>= m
121 Refresh n f >>= m = Refresh n $ \ i -> f i >>= m 123 Refresh n f >>= m = Refresh n $ \ i -> f i >>= m
122 124
125instance Applicative (Routing ip) where
126 pure = return
127 (<*>) = ap
128
129instance Alternative (Routing ip) where
130 empty = Full
131 Full <|> m = m
132 m <|> _ = m
133
123runRouting :: (Monad m, Eq ip) 134runRouting :: (Monad m, Eq ip)
124 => (NodeAddr ip -> m Bool) -- ^ ping_node 135 => (NodeAddr ip -> m Bool) -- ^ ping_node
125 -> (NodeId -> m [NodeInfo ip]) -- ^ find_nodes 136 -> (NodeId -> m [NodeInfo ip]) -- ^ find_nodes
126 -> m Timestamp -- ^ timestamper 137 -> m Timestamp -- ^ timestamper
127 -> Routing ip f -- ^ action 138 -> Routing ip f -- ^ action
128 -> m f -- ^ result 139 -> m (Maybe f) -- ^ result
129runRouting ping_node find_nodes timestamper = go 140runRouting ping_node find_nodes timestamper = go
130 where 141 where
131 go (Done r) = return r 142 go Full = return (Nothing)
143 go (Done r) = return (Just r)
132 go (GetTime f) = do 144 go (GetTime f) = do
133 t <- timestamper 145 t <- timestamper
134 go (f t) 146 go (f t)
@@ -231,7 +243,7 @@ insertBucket curTime info bucket
231 return $ PSQ.insert info curTime bucket 243 return $ PSQ.insert info curTime bucket
232 244
233 -- bucket is full of good nodes => ignore new node 245 -- bucket is full of good nodes => ignore new node
234 | otherwise = return bucket 246 | otherwise = A.empty
235 247
236insertNode :: Eq ip => NodeInfo ip -> Bucket ip -> ip `Routing` Bucket ip 248insertNode :: Eq ip => NodeInfo ip -> Bucket ip -> ip `Routing` Bucket ip
237insertNode info bucket = do 249insertNode info bucket = do
@@ -348,8 +360,7 @@ insert info @ NodeInfo {..} = go (0 :: BitIx)
348 go i (One bucket table ) 360 go i (One bucket table )
349 | testIdBit nodeId i = One bucket <$> go (succ i) table 361 | testIdBit nodeId i = One bucket <$> go (succ i) table
350 | otherwise = (`One` table) <$> insertNode info bucket 362 | otherwise = (`One` table) <$> insertNode info bucket
351 go i (Tip nid n bucket) = case insertNode info bucket of 363 go i (Tip nid n bucket)
352 Done kbucket 364 | n == 0 = Tip nid n <$> insertNode info bucket
353 | n == 0 -> Tip nid n <$> Done kbucket 365 | otherwise = Tip nid n <$> insertNode info bucket
354 | otherwise -> go (succ i) (splitTip nid n i kbucket) 366 <|> go (succ i) (splitTip nid n i bucket)
355 result -> Tip nid n <$> result
diff --git a/src/Network/BitTorrent/DHT/Session.hs b/src/Network/BitTorrent/DHT/Session.hs
index 9243ef49..9db5947a 100644
--- a/src/Network/BitTorrent/DHT/Session.hs
+++ b/src/Network/BitTorrent/DHT/Session.hs
@@ -33,7 +33,7 @@ module Network.BitTorrent.DHT.Session
33 33
34import Control.Applicative 34import Control.Applicative
35import Control.Concurrent.STM 35import Control.Concurrent.STM
36import Control.Exception hiding (Handler) 36import Control.Exception.Lifted hiding (Handler)
37import Control.Monad.Base 37import Control.Monad.Base
38import Control.Monad.Logger 38import Control.Monad.Logger
39import Control.Monad.Reader 39import Control.Monad.Reader
@@ -145,15 +145,16 @@ runDHT naddr handlers action = runResourceT $ do
145-----------------------------------------------------------------------} 145-----------------------------------------------------------------------}
146 146
147-- TODO fork? 147-- TODO fork?
148routing :: Address ip => Routing ip a -> DHT ip a 148routing :: Address ip => Routing ip a -> DHT ip (Maybe a)
149routing = runRouting ping refreshNodes getTimestamp 149routing = runRouting ping refreshNodes getTimestamp
150 150
151-- TODO add timeout 151-- TODO add timeout
152ping :: Address ip => NodeAddr ip -> DHT ip Bool 152ping :: Address ip => NodeAddr ip -> DHT ip Bool
153ping addr = do 153ping addr = do
154 $(logDebugS) "routing.questionable_node" (T.pack (render (pretty addr))) 154 $(logDebugS) "routing.questionable_node" (T.pack (render (pretty addr)))
155 Ping <- Ping <@> addr 155 result <- try $ Ping <@> addr
156 return True 156 let _ = result :: Either SomeException Ping
157 return $ either (const False) (const True) result
157 158
158-- FIXME do not use getClosest sinse we should /refresh/ them 159-- FIXME do not use getClosest sinse we should /refresh/ them
159refreshNodes :: Address ip => NodeId -> DHT ip [NodeInfo ip] 160refreshNodes :: Address ip => NodeId -> DHT ip [NodeInfo ip]
@@ -167,9 +168,9 @@ refreshNodes nid = do
167 168
168getTimestamp :: DHT ip Timestamp 169getTimestamp :: DHT ip Timestamp
169getTimestamp = do 170getTimestamp = do
170 timestamp <- liftIO $ getCurrentTime 171 utcTime <- liftIO $ getCurrentTime
171 $(logDebugS) "routing.make_timestamp" (T.pack (render (pretty timestamp))) 172 $(logDebugS) "routing.make_timestamp" (T.pack (render (pretty utcTime)))
172 return $ utcTimeToPOSIXSeconds timestamp 173 return $ utcTimeToPOSIXSeconds utcTime
173 174
174{----------------------------------------------------------------------- 175{-----------------------------------------------------------------------
175-- Tokens 176-- Tokens
@@ -222,11 +223,13 @@ getClosestHash ih = kclosestHash 8 ih <$> getTable
222insertNode :: Address ip => NodeInfo ip -> DHT ip () 223insertNode :: Address ip => NodeInfo ip -> DHT ip ()
223insertNode info = do 224insertNode info = do
224 t <- getTable 225 t <- getTable
225 t' <- routing (R.insert info t) 226 mt <- routing (R.insert info t)
226 putTable t' 227 case mt of
227 228 Nothing -> $(logDebugS) "insertNode" "Routing table is full"
228 let logMsg = "Routing table updated: " <> pretty t <> " -> " <> pretty t' 229 Just t' -> do
229 $(logDebugS) "insertNode" (T.pack (render logMsg)) 230 putTable t'
231 let logMsg = "Routing table updated: " <> pretty t <> " -> " <> pretty t'
232 $(logDebugS) "insertNode" (T.pack (render logMsg))
230 233
231{----------------------------------------------------------------------- 234{-----------------------------------------------------------------------
232-- Peer storage 235-- Peer storage