summaryrefslogtreecommitdiff
path: root/src/Network/BitTorrent
diff options
context:
space:
mode:
authorjoe <joe@jerkface.net>2017-07-08 22:10:40 -0400
committerjoe <joe@jerkface.net>2017-07-08 22:10:40 -0400
commit8fe93b8e1d1d968bdf0b8a35335b060d92a9d7d7 (patch)
tree6e9a4b35f11de5ad0e4f422e0a6d268b5270befd /src/Network/BitTorrent
parentf75d515bc0100e5ca372d592aa2f5f4ff2fc858c (diff)
WIP: Tox encryption.
Diffstat (limited to 'src/Network/BitTorrent')
-rw-r--r--src/Network/BitTorrent/DHT.hs6
-rw-r--r--src/Network/BitTorrent/DHT/Query.hs103
2 files changed, 81 insertions, 28 deletions
diff --git a/src/Network/BitTorrent/DHT.hs b/src/Network/BitTorrent/DHT.hs
index fa8071d5..2535c05c 100644
--- a/src/Network/BitTorrent/DHT.hs
+++ b/src/Network/BitTorrent/DHT.hs
@@ -234,7 +234,7 @@ bootstrap :: forall raw dht u ip.
234 , Show u 234 , Show u
235 , Default u 235 , Default u
236 , Serialize u 236 , Serialize u
237 ) => Maybe BS.ByteString -> [NodeAddr ip] -> DHT raw dht u ip () 237 ) => Maybe BS.ByteString -> [PacketDestination dht] -> DHT raw dht u ip ()
238bootstrap mbs startNodes = do 238bootstrap mbs startNodes = do
239 restored <- 239 restored <-
240 case decode <$> mbs of 240 case decode <$> mbs of
@@ -250,7 +250,7 @@ bootstrap mbs startNodes = do
250 return ( ns :: [NodeInfo dht ip u] ) 250 return ( ns :: [NodeInfo dht ip u] )
251 input_nodes <- (restored ++) . T.toList <$> getTable 251 input_nodes <- (restored ++) . T.toList <$> getTable
252 -- Step 1: Use iterative searches to flesh out the table.. 252 -- Step 1: Use iterative searches to flesh out the table..
253 do let knowns = map (map $ nodeAddr . fst) input_nodes 253 do let knowns = map (map $ fst) input_nodes
254 -- Below, we reverse the nodes since the table serialization puts the 254 -- Below, we reverse the nodes since the table serialization puts the
255 -- nearest nodes last and we want to choose a similar node id to bootstrap 255 -- nearest nodes last and we want to choose a similar node id to bootstrap
256 -- faster. 256 -- faster.
@@ -265,7 +265,7 @@ bootstrap mbs startNodes = do
265 when (null ns) $ do 265 when (null ns) $ do
266 -- TODO filter duplicated in startNodes list 266 -- TODO filter duplicated in startNodes list
267 -- TODO retransmissions for startNodes 267 -- TODO retransmissions for startNodes
268 (aliveNodes,_) <- unzip <$> queryParallel (pingQ <$> startNodes) 268 (aliveNodes,_) <- unzip <$> queryParallel (coldPingQ <$> startNodes)
269 _ <- searchAll $ take 2 aliveNodes 269 _ <- searchAll $ take 2 aliveNodes
270 return () 270 return ()
271 -- Step 2: Repeatedly refresh incomplete buckets until the table is full. 271 -- Step 2: Repeatedly refresh incomplete buckets until the table is full.
diff --git a/src/Network/BitTorrent/DHT/Query.hs b/src/Network/BitTorrent/DHT/Query.hs
index 77fede94..60b772b3 100644
--- a/src/Network/BitTorrent/DHT/Query.hs
+++ b/src/Network/BitTorrent/DHT/Query.hs
@@ -35,6 +35,7 @@ module Network.BitTorrent.DHT.Query
35 -- single response. 35 -- single response.
36 , Iteration 36 , Iteration
37 , pingQ 37 , pingQ
38 , coldPingQ
38 , findNodeQ 39 , findNodeQ
39 , getPeersQ 40 , getPeersQ
40 , announceQ 41 , announceQ
@@ -316,44 +317,72 @@ pingQ :: forall raw dht u ip.
316 , FiniteBits (NodeId dht) 317 , FiniteBits (NodeId dht)
317 , Show (NodeId dht) 318 , Show (NodeId dht)
318 , Show (QueryMethod dht) 319 , Show (QueryMethod dht)
319 ) => NodeAddr ip -> DHT raw dht u ip (NodeInfo dht ip u , Maybe ReflectedIP) 320 ) => NodeInfo dht ip u -> DHT raw dht u ip (NodeInfo dht ip u , Maybe ReflectedIP)
320pingQ addr = do 321pingQ ni = do
321 let ping = DHT.pingMessage (Proxy :: Proxy dht) 322 let ping = DHT.pingMessage (Proxy :: Proxy dht)
322 (nid, pong, mip) <- queryNode' addr ping 323 (nid, pong, mip) <- queryNode' ni ping
323 let _ = pong `asTypeOf` ping 324 let _ = pong `asTypeOf` ping
324 -- (nid, PingPayload{}, mip) <- queryNode' addr PingPayload {isPong=False, pingId=pid} 325 -- (nid, PingPayload{}, mip) <- queryNode' addr PingPayload {isPong=False, pingId=pid}
325 return (NodeInfo nid addr def, mip) 326 return (NodeInfo nid (nodeAddr ni) def, mip)
327
328-- | The most basic query. May be used to check if the given node is
329-- alive or get its 'NodeId'.
330coldPingQ :: forall raw dht u ip.
331 ( DHT.Kademlia dht
332 , Address ip
333 , KRPC dht (Query dht (Ping dht)) (Response dht (Ping dht))
334 , Default u
335 , Show u
336 , Ord (TransactionID dht)
337 , Serialize (TransactionID dht)
338 , WireFormat raw dht
339 , SerializableTo raw (Response dht (Ping dht))
340 , SerializableTo raw (Query dht (Ping dht))
341 , Ord (NodeId dht)
342 , FiniteBits (NodeId dht)
343 , Show (NodeId dht)
344 , Show (QueryMethod dht)
345 ) => PacketDestination dht -> DHT raw dht u ip (NodeInfo dht ip u , Maybe ReflectedIP)
346coldPingQ dest = do
347 let ping = DHT.pingMessage (Proxy :: Proxy dht)
348 naddr <- maybe (throwIO $ QueryFailed ProtocolError "unable to construct NodeAddr from PacketDestination")
349 return
350 $ fromAddr dest
351 (nid, pong, mip) <- coldQueryNode' naddr dest ping
352 let _ = pong `asTypeOf` ping
353 -- (nid, PingPayload{}, mip) <- queryNode' addr PingPayload {isPong=False, pingId=pid}
354 return (NodeInfo nid naddr def, mip)
326 355
327-- TODO [robustness] match range of returned node ids with the 356-- TODO [robustness] match range of returned node ids with the
328-- expected range and either filter bad nodes or discard response at 357-- expected range and either filter bad nodes or discard response at
329-- all throwing an exception 358-- all throwing an exception
330-- findNodeQ :: Address ip => TableKey key => key -> IterationI ip NodeInfo 359-- findNodeQ :: Address ip => TableKey key => key -> IterationI ip NodeInfo
331findNodeQ proxy key NodeInfo {..} = do 360findNodeQ proxy key ni = do
332 closest <- fmap DHT.foundNodes $ DHT.findNodeMessage proxy key <@> nodeAddr 361 closest <- fmap DHT.foundNodes $ DHT.findNodeMessage proxy key <@> ni
333 $(logInfoS) "findNodeQ" $ "NodeFound\n" 362 $(logInfoS) "findNodeQ" $ "NodeFound\n"
334 <> T.pack (L.unlines $ L.map ((' ' :) . show . pPrint) closest) 363 <> T.pack (L.unlines $ L.map ((' ' :) . show . pPrint) closest)
335 return $ Right closest 364 return $ Right closest
336 365
337#ifdef VERSION_bencoding 366#ifdef VERSION_bencoding
338getPeersQ :: Address ip => InfoHash -> Iteration BValue KMessageOf () ip PeerAddr 367getPeersQ :: Address ip => InfoHash -> Iteration BValue KMessageOf () ip PeerAddr
339getPeersQ topic NodeInfo {..} = do 368getPeersQ topic ni = do
340 GotPeers {..} <- GetPeers topic <@> nodeAddr 369 GotPeers {..} <- GetPeers topic <@> ni
341 let dist = distance (toNodeId topic) nodeId 370 let dist = distance (toNodeId topic) (nodeId ni)
342 $(logInfoS) "getPeersQ" $ T.pack 371 $(logInfoS) "getPeersQ" $ T.pack
343 $ "distance: " <> render (pPrint dist) <> " , result: " 372 $ "distance: " <> render (pPrint dist) <> " , result: "
344 <> case peers of { Left _ -> "NODES"; Right _ -> "PEERS" } 373 <> case peers of { Left _ -> "NODES"; Right _ -> "PEERS" }
345 return peers 374 return peers
346 375
347announceQ :: Address ip => InfoHash -> PortNumber -> Iteration BValue KMessageOf () ip NodeAddr 376announceQ :: Address ip => InfoHash -> PortNumber -> Iteration BValue KMessageOf () ip NodeAddr
348announceQ ih p NodeInfo {..} = do 377announceQ ih p ni = do
349 GotPeers {..} <- GetPeers ih <@> nodeAddr 378 GotPeers {..} <- GetPeers ih <@> ni
350 case peers of 379 case peers of
351 Left ns 380 Left ns
352 | False -> undefined -- TODO check if we can announce 381 | False -> undefined -- TODO check if we can announce
353 | otherwise -> return (Left ns) 382 | otherwise -> return (Left ns)
354 Right _ -> do -- TODO *probably* add to peer cache 383 Right _ -> do -- TODO *probably* add to peer cache
355 Announced <- Announce False ih Nothing p grantedToken <@> nodeAddr 384 Announced <- Announce False ih Nothing p grantedToken <@> ni
356 return (Right [nodeAddr]) 385 return (Right [nodeAddr ni])
357#endif 386#endif
358 387
359{----------------------------------------------------------------------- 388{-----------------------------------------------------------------------
@@ -393,7 +422,7 @@ ioFindNode :: ( DHT.Kademlia dht
393ioFindNode ih = do 422ioFindNode ih = do
394 session <- ask 423 session <- ask
395 return $ \ni -> runDHT session $ do 424 return $ \ni -> runDHT session $ do
396 ns <- fmap DHT.foundNodes $ DHT.findNodeMessage Proxy ih <@> nodeAddr ni 425 ns <- fmap DHT.foundNodes $ DHT.findNodeMessage Proxy ih <@> ni
397 let ns' = L.map (fmap (const def)) ns 426 let ns' = L.map (fmap (const def)) ns
398 return $ L.partition (\n -> nodeId n /= toNodeId ih) ns' 427 return $ L.partition (\n -> nodeId n /= toNodeId ih) ns'
399 428
@@ -422,7 +451,7 @@ ioFindNodes :: ( DHT.Kademlia dht
422ioFindNodes ih = do 451ioFindNodes ih = do
423 session <- ask 452 session <- ask
424 return $ \ni -> runDHT session $ do 453 return $ \ni -> runDHT session $ do
425 ns <- fmap DHT.foundNodes $ DHT.findNodeMessage Proxy ih <@> nodeAddr ni 454 ns <- fmap DHT.foundNodes $ DHT.findNodeMessage Proxy ih <@> ni
426 let ns' = L.map (fmap (const def)) ns 455 let ns' = L.map (fmap (const def)) ns
427 return ([], ns') 456 return ([], ns')
428 457
@@ -504,9 +533,9 @@ probeNode :: ( Default u
504 , FiniteBits (NodeId dht) 533 , FiniteBits (NodeId dht)
505 , Show (NodeId dht) 534 , Show (NodeId dht)
506 , Show (QueryMethod dht) 535 , Show (QueryMethod dht)
507 ) => NodeAddr ip -> DHT raw dht u ip (Bool , Maybe ReflectedIP) 536 ) => NodeInfo dht ip u -> DHT raw dht u ip (Bool , Maybe ReflectedIP)
508probeNode addr = do 537probeNode addr = do
509 $(logDebugS) "routing.questionable_node" (T.pack (render (pPrint addr))) 538 $(logDebugS) "routing.questionable_node" (T.pack (render (pPrint $ nodeAddr addr)))
510 result <- try $ pingQ addr 539 result <- try $ pingQ addr
511 let _ = fmap (const ()) result :: Either QueryFailure () 540 let _ = fmap (const ()) result :: Either QueryFailure ()
512 return $ either (const (False,Nothing)) (\(_,mip)->(True,mip)) result 541 return $ either (const (False,Nothing)) (\(_,mip)->(True,mip)) result
@@ -549,7 +578,7 @@ refreshNodes nid = do
549 $(logWarnS) "refreshNodes" $ "received " <> T.pack (show (L.length ns)) <> " nodes." 578 $(logWarnS) "refreshNodes" $ "received " <> T.pack (show (L.length ns)) <> " nodes."
550 _ <- queryParallel $ flip L.map ns $ \n -> do 579 _ <- queryParallel $ flip L.map ns $ \n -> do
551 $(logWarnS) "refreshNodes" $ "received node: " <> T.pack (show (pPrint n)) 580 $(logWarnS) "refreshNodes" $ "received node: " <> T.pack (show (pPrint n))
552 pingQ (nodeAddr n) 581 pingQ n
553 -- pingQ takes care of inserting the node. 582 -- pingQ takes care of inserting the node.
554 return () 583 return ()
555 return () -- \$ L.concat nss 584 return () -- \$ L.concat nss
@@ -622,7 +651,7 @@ insertNode1 = do
622 , fallbackID = nid :: NodeId dht 651 , fallbackID = nid :: NodeId dht
623 , adjustID = dhtAdjustID Proxy (DHT.fallbackID params) :: SockAddr -> Event dht ip u -> NodeId dht 652 , adjustID = dhtAdjustID Proxy (DHT.fallbackID params) :: SockAddr -> Event dht ip u -> NodeId dht
624 , logMessage = logm :: Char -> String -> IO () 653 , logMessage = logm :: Char -> String -> IO ()
625 , pingProbe = probe :: NodeAddr ip -> IO (Bool, Maybe ReflectedIP) 654 , pingProbe = probe :: NodeInfo dht ip u -> IO (Bool, Maybe ReflectedIP)
626 } 655 }
627 tbl <- asks routingInfo 656 tbl <- asks routingInfo
628 let state = DHT.TableKeeper 657 let state = DHT.TableKeeper
@@ -651,7 +680,7 @@ queryNode :: forall raw dht u a b ip.
651 , Show (QueryMethod dht) 680 , Show (QueryMethod dht)
652 , SerializableTo raw (Response dht (Ping dht)) 681 , SerializableTo raw (Response dht (Ping dht))
653 , SerializableTo raw (Query dht (Ping dht)) 682 , SerializableTo raw (Query dht (Ping dht))
654 ) => NodeAddr ip -> a -> DHT raw dht u ip (NodeId dht, b) 683 ) => NodeInfo dht ip u -> a -> DHT raw dht u ip (NodeId dht, b)
655queryNode addr q = fmap (\(n,b,_) -> (n,b)) $ queryNode' addr q 684queryNode addr q = fmap (\(n,b,_) -> (n,b)) $ queryNode' addr q
656 685
657queryNode' :: forall raw dht u a b ip. 686queryNode' :: forall raw dht u a b ip.
@@ -672,15 +701,39 @@ queryNode' :: forall raw dht u a b ip.
672 , Show (QueryMethod dht) 701 , Show (QueryMethod dht)
673 , SerializableTo raw (Response dht (Ping dht)) 702 , SerializableTo raw (Response dht (Ping dht))
674 , SerializableTo raw (Query dht (Ping dht)) 703 , SerializableTo raw (Query dht (Ping dht))
675 ) => NodeAddr ip -> a -> DHT raw dht u ip (NodeId dht, b, Maybe ReflectedIP) 704 ) => NodeInfo dht ip u -> a -> DHT raw dht u ip (NodeId dht, b, Maybe ReflectedIP)
676queryNode' addr q = do 705queryNode' ni q = do
677 nid <- myNodeIdAccordingTo addr 706 let addr = nodeAddr ni
707 dest = makeAddress (Left $ nodeId ni) (toSockAddr addr)
708 coldQueryNode' addr dest q
709
710coldQueryNode' :: forall raw dht u a b ip.
711 ( Address ip
712 , Default u
713 , Show u
714 , DHT.Kademlia dht
715 , KRPC dht (Query dht a) (Response dht b)
716 , KRPC dht (Query dht (Ping dht)) (Response dht (Ping dht))
717 , Ord (TransactionID dht)
718 , Serialize (TransactionID dht)
719 , WireFormat raw dht
720 , SerializableTo raw (Response dht b)
721 , SerializableTo raw (Query dht a)
722 , Ord (NodeId dht)
723 , FiniteBits (NodeId dht)
724 , Show (NodeId dht)
725 , Show (QueryMethod dht)
726 , SerializableTo raw (Response dht (Ping dht))
727 , SerializableTo raw (Query dht (Ping dht))
728 ) => NodeAddr ip -> PacketDestination dht -> a -> DHT raw dht u ip (NodeId dht, b, Maybe ReflectedIP)
729coldQueryNode' addr dest q = do
730 nid <- myNodeIdAccordingTo $ fromMaybe (error "TODO: coldQueryNode' myNodeIdAccordingTo") $ fromAddr dest
678 dta <- asks dhtData 731 dta <- asks dhtData
679 qextra <- liftIO $ makeQueryExtra dta nid (Proxy :: Proxy (Query dht q)) (Proxy :: Proxy (Response dht b)) 732 qextra <- liftIO $ makeQueryExtra dta nid (Proxy :: Proxy (Query dht q)) (Proxy :: Proxy (Response dht b))
680 let read_only = False -- TODO: check for NAT issues. (BEP 43) 733 let read_only = False -- TODO: check for NAT issues. (BEP 43)
681 -- let KRPC.Method name = KRPC.method :: KRPC.Method dht (Query dht a) (Response dht b) 734 -- let KRPC.Method name = KRPC.method :: KRPC.Method dht (Query dht a) (Response dht b)
682 mgr <- asks manager 735 mgr <- asks manager
683 (Response rextra r, remoteId, witnessed_ip) <- liftIO $ query' mgr (toSockAddr addr) (Query qextra q) 736 (Response rextra r, remoteId, witnessed_ip) <- liftIO $ query' mgr dest (Query qextra q)
684 -- \$(logDebugS) "queryNode" $ "Witnessed address: " <> T.pack (show witnessed_ip) 737 -- \$(logDebugS) "queryNode" $ "Witnessed address: " <> T.pack (show witnessed_ip)
685 -- <> " by " <> T.pack (show (toSockAddr addr)) 738 -- <> " by " <> T.pack (show (toSockAddr addr))
686 _ <- insertNode (NodeInfo remoteId addr def) witnessed_ip 739 _ <- insertNode (NodeInfo remoteId addr def) witnessed_ip
@@ -704,6 +757,6 @@ queryNode' addr q = do
704 , SerializableTo raw (Query dht (Ping dht)) 757 , SerializableTo raw (Query dht (Ping dht))
705 , WireFormat raw dht 758 , WireFormat raw dht
706 , Kademlia dht 759 , Kademlia dht
707 ) => a -> NodeAddr ip -> DHT raw dht u ip b 760 ) => a -> NodeInfo dht ip u -> DHT raw dht u ip b
708q <@> addr = snd <$> queryNode addr q 761q <@> addr = snd <$> queryNode addr q
709{-# INLINE (<@>) #-} 762{-# INLINE (<@>) #-}