summaryrefslogtreecommitdiff
path: root/src/Network/BitTorrent/DHT.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Network/BitTorrent/DHT.hs')
-rw-r--r--src/Network/BitTorrent/DHT.hs52
1 files changed, 39 insertions, 13 deletions
diff --git a/src/Network/BitTorrent/DHT.hs b/src/Network/BitTorrent/DHT.hs
index 2e8164bd..e7b9ec13 100644
--- a/src/Network/BitTorrent/DHT.hs
+++ b/src/Network/BitTorrent/DHT.hs
@@ -15,6 +15,7 @@ module Network.BitTorrent.DHT
15import Control.Applicative 15import Control.Applicative
16import Control.Concurrent.STM 16import Control.Concurrent.STM
17import Control.Monad 17import Control.Monad
18import Control.Exception
18import Data.ByteString 19import Data.ByteString
19import Data.Serialize as S 20import Data.Serialize as S
20import Data.Function 21import Data.Function
@@ -28,6 +29,7 @@ import Network.Socket
28import System.Entropy 29import System.Entropy
29 30
30import Remote.KRPC 31import Remote.KRPC
32import Remote.KRPC.Protocol
31import Data.BEncode 33import Data.BEncode
32import Data.Torrent 34import Data.Torrent
33import Network.BitTorrent.Peer 35import Network.BitTorrent.Peer
@@ -159,6 +161,12 @@ assignToken _ _ = return ""
159checkToken :: NodeId -> Token -> NodeSession -> IO Bool 161checkToken :: NodeId -> Token -> NodeSession -> IO Bool
160checkToken nid token _ = return True 162checkToken nid token _ = return True
161 163
164updateTimestamp :: NodeSession -> NodeId -> IO ()
165updateTimestamp = error "updateTimestamp"
166
167updateToken :: NodeSession -> NodeId -> Token -> IO ()
168updateToken _ _ _ = error "updateToken"
169
162{----------------------------------------------------------------------- 170{-----------------------------------------------------------------------
163 DHT Queries 171 DHT Queries
164-----------------------------------------------------------------------} 172-----------------------------------------------------------------------}
@@ -207,6 +215,7 @@ announcePeerM = method "announce_peer" ["id", "info_hash", "port", "token"] ["id
207-----------------------------------------------------------------------} 215-----------------------------------------------------------------------}
208-- TODO: update node timestamp on each successful call 216-- TODO: update node timestamp on each successful call
209 217
218-- | Note that tracker side query functions could throw RPCException.
210type DHT a b = NodeSession -> NodeAddr -> a -> IO b 219type DHT a b = NodeSession -> NodeAddr -> a -> IO b
211 220
212ping :: DHT () () 221ping :: DHT () ()
@@ -215,34 +224,48 @@ ping NodeSession {..} addr @ NodeAddr {..} () = do
215 atomically $ modifyTVar' routingTable $ HM.insert nid addr 224 atomically $ modifyTVar' routingTable $ HM.insert nid addr
216 225
217findNode :: DHT NodeId [NodeInfo] 226findNode :: DHT NodeId [NodeInfo]
218findNode NodeSession {..} NodeAddr {..} qnid = do 227findNode ses @ NodeSession {..} NodeAddr {..} qnid = do
219 (_, info) <- call (nodeIP, nodePort) findNodeM (nodeId, qnid) 228 (nid, info) <- call (nodeIP, nodePort) findNodeM (nodeId, qnid)
229 updateTimestamp ses nid
220 return (decodeCompact info) 230 return (decodeCompact info)
221 231
222getPeers :: DHT InfoHash (Either [NodeInfo] [PeerAddr]) 232getPeers :: DHT InfoHash (Either [NodeInfo] [PeerAddr])
223getPeers NodeSession {..} NodeAddr {..} ih = do 233getPeers ses @ NodeSession {..} NodeAddr {..} ih = do
224 extrResp <$> call (nodeIP, nodePort) getPeersM (nodeId, ih) 234 resp <- call (nodeIP, nodePort) getPeersM (nodeId, ih)
235 (nid, tok, res) <- extrResp resp
236 updateTimestamp ses nid
237 updateToken ses nid tok
238 return res
225 where 239 where
226 extrResp (BDict d) 240 extrResp (BDict d)
227 | Just (BList values) <- M.lookup "values" d 241 | Just (BString nid ) <- M.lookup "id" d
228 = Right $ decodePeerList values 242 , Just (BString tok ) <- M.lookup "token" d
229 | Just (BString nodes) <- M.lookup "nodes" d 243 , Just (BList values) <- M.lookup "values" d
230 = Left $ decodeCompact nodes 244 = return $ (nid, tok, Right $ decodePeerList values)
231 extrResp _ = return undefined 245
246 | Just (BString nid ) <- M.lookup "id" d
247 , Just (BString tok ) <- M.lookup "token" d
248 , Just (BString nodes) <- M.lookup "nodes" d
249 = return (nid, tok, Left $ decodeCompact nodes)
250
251 extrResp _ = throw $ RPCException msg
252 where msg = ProtocolError "unable to extract getPeers resp"
232 253
233-- remove token from signature, handle the all token stuff by NodeSession 254-- remove token from signature, handle the all token stuff by NodeSession
234 255
235-- | Note that before ever calling this method you should call the 256-- | Note that before ever calling this method you should call the
236-- getPeerList. 257-- getPeerList.
237announcePeer :: DHT (InfoHash, Token) NodeId 258announcePeer :: DHT (InfoHash, Token) NodeId
238announcePeer NodeSession {..} NodeAddr {..} (ih, tok) = do 259announcePeer ses @ NodeSession {..} NodeAddr {..} (ih, tok) = do
239 call (nodeIP, nodePort) announcePeerM (nodeId, ih, listenerPort, tok) 260 nid <- call (nodeIP, nodePort) announcePeerM (nodeId, ih, listenerPort, tok)
261 updateTimestamp ses nid
262 return nid
240 263
241{----------------------------------------------------------------------- 264{-----------------------------------------------------------------------
242 DHT Server 265 DHT Server
243-----------------------------------------------------------------------} 266-----------------------------------------------------------------------}
244-- TODO: update node timestamp on each successful call 267-- TODO: update node timestamp on each successful call
245-- NOTE: ensure all server operations should run in O(1) 268-- NOTE: ensure all server operations run in O(1)
246 269
247type ServerHandler a b = NodeSession -> NodeAddr -> a -> IO b 270type ServerHandler a b = NodeSession -> NodeAddr -> a -> IO b
248 271
@@ -252,12 +275,14 @@ pingS NodeSession {..} addr nid = do
252 return nodeId 275 return nodeId
253 276
254findNodeS :: ServerHandler (NodeId, NodeId) (NodeId, CompactInfo) 277findNodeS :: ServerHandler (NodeId, NodeId) (NodeId, CompactInfo)
255findNodeS NodeSession {..} _ (_, qnid) = do 278findNodeS ses @ NodeSession {..} _ (nid, qnid) = do
279 updateTimestamp ses nid
256 rt <- atomically $ readTVar routingTable 280 rt <- atomically $ readTVar routingTable
257 return (nodeId, encodeCompact $ kclosest alpha qnid rt) 281 return (nodeId, encodeCompact $ kclosest alpha qnid rt)
258 282
259getPeersS :: ServerHandler (NodeId, InfoHash) BEncode 283getPeersS :: ServerHandler (NodeId, InfoHash) BEncode
260getPeersS ses @ NodeSession {..} _ (nid, ih) = do 284getPeersS ses @ NodeSession {..} _ (nid, ih) = do
285 updateTimestamp ses nid
261 mkResp <$> assignToken ses nid <*> findPeers 286 mkResp <$> assignToken ses nid <*> findPeers
262 where 287 where
263 findPeers = do 288 findPeers = do
@@ -276,6 +301,7 @@ getPeersS ses @ NodeSession {..} _ (nid, ih) = do
276 301
277announcePeerS :: ServerHandler (NodeId, InfoHash, PortNumber, Token) NodeId 302announcePeerS :: ServerHandler (NodeId, InfoHash, PortNumber, Token) NodeId
278announcePeerS ses @ NodeSession {..} NodeAddr {..} (nid, ih, port, token) = do 303announcePeerS ses @ NodeSession {..} NodeAddr {..} (nid, ih, port, token) = do
304 updateTimestamp ses nid
279 registered <- checkToken nid token ses 305 registered <- checkToken nid token ses
280 when registered $ do 306 when registered $ do
281 atomically $ do 307 atomically $ do