summaryrefslogtreecommitdiff
path: root/src/Network/BitTorrent/DHT
diff options
context:
space:
mode:
Diffstat (limited to 'src/Network/BitTorrent/DHT')
-rw-r--r--src/Network/BitTorrent/DHT/Session.hs48
1 files changed, 39 insertions, 9 deletions
diff --git a/src/Network/BitTorrent/DHT/Session.hs b/src/Network/BitTorrent/DHT/Session.hs
index 71400609..9243ef49 100644
--- a/src/Network/BitTorrent/DHT/Session.hs
+++ b/src/Network/BitTorrent/DHT/Session.hs
@@ -5,8 +5,7 @@
5{-# LANGUAGE MultiParamTypeClasses #-} 5{-# LANGUAGE MultiParamTypeClasses #-}
6{-# LANGUAGE ScopedTypeVariables #-} 6{-# LANGUAGE ScopedTypeVariables #-}
7{-# LANGUAGE TypeFamilies #-} 7{-# LANGUAGE TypeFamilies #-}
8 8{-# LANGUAGE TemplateHaskell #-}
9{-# LANGUAGE RankNTypes #-} -- TODO remove
10module Network.BitTorrent.DHT.Session 9module Network.BitTorrent.DHT.Session
11 ( -- * Session 10 ( -- * Session
12 DHT 11 DHT
@@ -35,19 +34,27 @@ module Network.BitTorrent.DHT.Session
35import Control.Applicative 34import Control.Applicative
36import Control.Concurrent.STM 35import Control.Concurrent.STM
37import Control.Exception hiding (Handler) 36import Control.Exception hiding (Handler)
38import Control.Monad.Reader
39import Control.Monad.Base 37import Control.Monad.Base
38import Control.Monad.Logger
39import Control.Monad.Reader
40import Control.Monad.Trans.Control 40import Control.Monad.Trans.Control
41import Control.Monad.Trans.Resource 41import Control.Monad.Trans.Resource
42import Data.Default 42import Data.Default
43import Data.Hashable 43import Data.Hashable
44import Data.List as L 44import Data.List as L
45import Data.Monoid
46import Data.Text as T
47import Data.Text.Encoding as T
45import Data.Time 48import Data.Time
46import Data.Time.Clock.POSIX 49import Data.Time.Clock.POSIX
50import System.Log.FastLogger
47import System.Random (randomIO) 51import System.Random (randomIO)
52import Text.PrettyPrint as PP hiding ((<>))
53import Text.PrettyPrint.Class
48 54
49import Data.Torrent.InfoHash 55import Data.Torrent.InfoHash
50import Network.KRPC 56import Network.KRPC
57import Network.KRPC.Method
51import Network.BitTorrent.Core 58import Network.BitTorrent.Core
52import Network.BitTorrent.Core.PeerAddr as P 59import Network.BitTorrent.Core.PeerAddr as P
53import Network.BitTorrent.DHT.Message 60import Network.BitTorrent.DHT.Message
@@ -89,6 +96,7 @@ data Node ip = Node
89 , routingTable :: !(TVar (Table ip)) 96 , routingTable :: !(TVar (Table ip))
90 , contactInfo :: !(TVar (PeerStore ip)) 97 , contactInfo :: !(TVar (PeerStore ip))
91 , sessionTokens :: !(TVar SessionTokens) 98 , sessionTokens :: !(TVar SessionTokens)
99 , loggerFun :: !(Loc -> LogSource -> LogLevel -> LogStr -> IO ())
92 } 100 }
93 101
94newtype DHT ip a = DHT { unDHT :: ReaderT (Node ip) (ResourceT IO) a } 102newtype DHT ip a = DHT { unDHT :: ReaderT (Node ip) (ResourceT IO) a }
@@ -96,6 +104,7 @@ newtype DHT ip a = DHT { unDHT :: ReaderT (Node ip) (ResourceT IO) a }
96 , MonadIO, MonadBase IO 104 , MonadIO, MonadBase IO
97 , MonadReader (Node ip) 105 , MonadReader (Node ip)
98 ) 106 )
107
99instance MonadBaseControl IO (DHT ip) where 108instance MonadBaseControl IO (DHT ip) where
100 newtype StM (DHT ip) a = StM { 109 newtype StM (DHT ip) a = StM {
101 unSt :: StM (ReaderT (Node ip) (ResourceT IO)) a 110 unSt :: StM (ReaderT (Node ip) (ResourceT IO)) a
@@ -110,19 +119,26 @@ instance MonadBaseControl IO (DHT ip) where
110instance MonadKRPC (DHT ip) (DHT ip) where 119instance MonadKRPC (DHT ip) (DHT ip) where
111 getManager = asks manager 120 getManager = asks manager
112 121
122instance MonadLogger (DHT ip) where
123 monadLoggerLog loc src lvl msg = do
124 logger <- asks loggerFun
125 liftIO $ logger loc src lvl (toLogStr msg)
126
113runDHT :: forall ip a. Address ip 127runDHT :: forall ip a. Address ip
114 => NodeAddr ip -- ^ node address to bind; 128 => NodeAddr ip -- ^ node address to bind;
115 -> [Handler (DHT ip)] -- ^ handlers to run on accepted queries; 129 -> [Handler (DHT ip)] -- ^ handlers to run on accepted queries;
116 -> DHT ip a -- ^ DHT action to run; 130 -> DHT ip a -- ^ DHT action to run;
117 -> IO a -- ^ result. 131 -> IO a -- ^ result.
118runDHT naddr handlers action = runResourceT $ do 132runDHT naddr handlers action = runResourceT $ do
119 (_, m) <- allocate (newManager (toSockAddr naddr) handlers) closeManager 133 runStderrLoggingT $ LoggingT $ \ logger -> do
120 myId <- liftIO genNodeId 134 (_, m) <- allocate (newManager (toSockAddr naddr) handlers) closeManager
121 node <- liftIO $ Node m 135 myId <- liftIO genNodeId
136 node <- liftIO $ Node m
122 <$> newTVarIO (nullTable myId) 137 <$> newTVarIO (nullTable myId)
123 <*> newTVarIO def 138 <*> newTVarIO def
124 <*> (newTVarIO =<< nullSessionTokens) 139 <*> (newTVarIO =<< nullSessionTokens)
125 runReaderT (unDHT (listen >> action)) node 140 <*> pure logger
141 runReaderT (unDHT (listen >> action)) node
126 142
127{----------------------------------------------------------------------- 143{-----------------------------------------------------------------------
128-- Routing 144-- Routing
@@ -135,12 +151,14 @@ routing = runRouting ping refreshNodes getTimestamp
135-- TODO add timeout 151-- TODO add timeout
136ping :: Address ip => NodeAddr ip -> DHT ip Bool 152ping :: Address ip => NodeAddr ip -> DHT ip Bool
137ping addr = do 153ping addr = do
154 $(logDebugS) "routing.questionable_node" (T.pack (render (pretty addr)))
138 Ping <- Ping <@> addr 155 Ping <- Ping <@> addr
139 return True 156 return True
140 157
141-- FIXME do not use getClosest sinse we should /refresh/ them 158-- FIXME do not use getClosest sinse we should /refresh/ them
142refreshNodes :: Address ip => NodeId -> DHT ip [NodeInfo ip] 159refreshNodes :: Address ip => NodeId -> DHT ip [NodeInfo ip]
143refreshNodes nid = do 160refreshNodes nid = do
161 $(logDebugS) "routing.refresh_bucket" (T.pack (render (pretty nid)))
144 nodes <- getClosest nid 162 nodes <- getClosest nid
145 nss <- forM (nodeAddr <$> nodes) $ \ addr -> do 163 nss <- forM (nodeAddr <$> nodes) $ \ addr -> do
146 NodeFound ns <- FindNode nid <@> addr 164 NodeFound ns <- FindNode nid <@> addr
@@ -148,7 +166,10 @@ refreshNodes nid = do
148 return $ L.concat nss 166 return $ L.concat nss
149 167
150getTimestamp :: DHT ip Timestamp 168getTimestamp :: DHT ip Timestamp
151getTimestamp = liftIO $ utcTimeToPOSIXSeconds <$> getCurrentTime 169getTimestamp = do
170 timestamp <- liftIO $ getCurrentTime
171 $(logDebugS) "routing.make_timestamp" (T.pack (render (pretty timestamp)))
172 return $ utcTimeToPOSIXSeconds timestamp
152 173
153{----------------------------------------------------------------------- 174{-----------------------------------------------------------------------
154-- Tokens 175-- Tokens
@@ -204,6 +225,9 @@ insertNode info = do
204 t' <- routing (R.insert info t) 225 t' <- routing (R.insert info t)
205 putTable t' 226 putTable t'
206 227
228 let logMsg = "Routing table updated: " <> pretty t <> " -> " <> pretty t'
229 $(logDebugS) "insertNode" (T.pack (render logMsg))
230
207{----------------------------------------------------------------------- 231{-----------------------------------------------------------------------
208-- Peer storage 232-- Peer storage
209-----------------------------------------------------------------------} 233-----------------------------------------------------------------------}
@@ -231,11 +255,17 @@ getPeerList ih = do
231-- Messaging 255-- Messaging
232-----------------------------------------------------------------------} 256-----------------------------------------------------------------------}
233 257
234(<@>) :: Address ip => KRPC (Query a) (Response b) 258(<@>) :: forall a b ip. Address ip => KRPC (Query a) (Response b)
235 => a -> NodeAddr ip -> DHT ip b 259 => a -> NodeAddr ip -> DHT ip b
236q <@> addr = do 260q <@> addr = do
237 nid <- getNodeId 261 nid <- getNodeId
262
263 let Method name = method :: Method (Query a) (Response b)
264 let signature = T.decodeUtf8 name <> " @ " <> T.pack (render (pretty addr))
265 $(logDebugS) "queryNode" $ "Query sent | " <> signature
238 Response remoteId r <- query (toSockAddr addr) (Query nid q) 266 Response remoteId r <- query (toSockAddr addr) (Query nid q)
267 $(logDebugS) "queryNode" $ "Query recv | " <> signature
268
239 insertNode (NodeInfo remoteId addr) 269 insertNode (NodeInfo remoteId addr)
240 return r 270 return r
241 271