diff options
-rw-r--r-- | src/Network/BitTorrent/DHT.hs | 52 |
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 | |||
15 | import Control.Applicative | 15 | import Control.Applicative |
16 | import Control.Concurrent.STM | 16 | import Control.Concurrent.STM |
17 | import Control.Monad | 17 | import Control.Monad |
18 | import Control.Exception | ||
18 | import Data.ByteString | 19 | import Data.ByteString |
19 | import Data.Serialize as S | 20 | import Data.Serialize as S |
20 | import Data.Function | 21 | import Data.Function |
@@ -28,6 +29,7 @@ import Network.Socket | |||
28 | import System.Entropy | 29 | import System.Entropy |
29 | 30 | ||
30 | import Remote.KRPC | 31 | import Remote.KRPC |
32 | import Remote.KRPC.Protocol | ||
31 | import Data.BEncode | 33 | import Data.BEncode |
32 | import Data.Torrent | 34 | import Data.Torrent |
33 | import Network.BitTorrent.Peer | 35 | import Network.BitTorrent.Peer |
@@ -159,6 +161,12 @@ assignToken _ _ = return "" | |||
159 | checkToken :: NodeId -> Token -> NodeSession -> IO Bool | 161 | checkToken :: NodeId -> Token -> NodeSession -> IO Bool |
160 | checkToken nid token _ = return True | 162 | checkToken nid token _ = return True |
161 | 163 | ||
164 | updateTimestamp :: NodeSession -> NodeId -> IO () | ||
165 | updateTimestamp = error "updateTimestamp" | ||
166 | |||
167 | updateToken :: NodeSession -> NodeId -> Token -> IO () | ||
168 | updateToken _ _ _ = 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. | ||
210 | type DHT a b = NodeSession -> NodeAddr -> a -> IO b | 219 | type DHT a b = NodeSession -> NodeAddr -> a -> IO b |
211 | 220 | ||
212 | ping :: DHT () () | 221 | ping :: 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 | ||
217 | findNode :: DHT NodeId [NodeInfo] | 226 | findNode :: DHT NodeId [NodeInfo] |
218 | findNode NodeSession {..} NodeAddr {..} qnid = do | 227 | findNode 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 | ||
222 | getPeers :: DHT InfoHash (Either [NodeInfo] [PeerAddr]) | 232 | getPeers :: DHT InfoHash (Either [NodeInfo] [PeerAddr]) |
223 | getPeers NodeSession {..} NodeAddr {..} ih = do | 233 | getPeers 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. |
237 | announcePeer :: DHT (InfoHash, Token) NodeId | 258 | announcePeer :: DHT (InfoHash, Token) NodeId |
238 | announcePeer NodeSession {..} NodeAddr {..} (ih, tok) = do | 259 | announcePeer 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 | ||
247 | type ServerHandler a b = NodeSession -> NodeAddr -> a -> IO b | 270 | type 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 | ||
254 | findNodeS :: ServerHandler (NodeId, NodeId) (NodeId, CompactInfo) | 277 | findNodeS :: ServerHandler (NodeId, NodeId) (NodeId, CompactInfo) |
255 | findNodeS NodeSession {..} _ (_, qnid) = do | 278 | findNodeS 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 | ||
259 | getPeersS :: ServerHandler (NodeId, InfoHash) BEncode | 283 | getPeersS :: ServerHandler (NodeId, InfoHash) BEncode |
260 | getPeersS ses @ NodeSession {..} _ (nid, ih) = do | 284 | getPeersS 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 | ||
277 | announcePeerS :: ServerHandler (NodeId, InfoHash, PortNumber, Token) NodeId | 302 | announcePeerS :: ServerHandler (NodeId, InfoHash, PortNumber, Token) NodeId |
278 | announcePeerS ses @ NodeSession {..} NodeAddr {..} (nid, ih, port, token) = do | 303 | announcePeerS 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 |