summaryrefslogtreecommitdiff
path: root/src/Network/BitTorrent/DHT/Message.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Network/BitTorrent/DHT/Message.hs')
-rw-r--r--src/Network/BitTorrent/DHT/Message.hs46
1 files changed, 43 insertions, 3 deletions
diff --git a/src/Network/BitTorrent/DHT/Message.hs b/src/Network/BitTorrent/DHT/Message.hs
index 04cc0d41..e21e0e70 100644
--- a/src/Network/BitTorrent/DHT/Message.hs
+++ b/src/Network/BitTorrent/DHT/Message.hs
@@ -74,6 +74,8 @@ module Network.BitTorrent.DHT.Message
74 -- ** find_node 74 -- ** find_node
75 , FindNode (..) 75 , FindNode (..)
76 , NodeFound (..) 76 , NodeFound (..)
77 , bep42s
78 -- , bep42
77 79
78 80
79#ifdef VERSION_bencoding 81#ifdef VERSION_bencoding
@@ -92,7 +94,7 @@ import Control.Applicative
92import Data.Bool 94import Data.Bool
93#ifdef VERSION_bencoding 95#ifdef VERSION_bencoding
94import Data.BEncode as BE 96import Data.BEncode as BE
95import Data.BEncode.BDict as BDict 97import Data.BEncode.BDict as BDict hiding (map)
96#else 98#else
97import qualified Network.DatagramServer.Tox as Tox 99import qualified Network.DatagramServer.Tox as Tox
98import Network.DatagramServer.Tox (NodeId) 100import Network.DatagramServer.Tox (NodeId)
@@ -101,21 +103,24 @@ import Control.Monad
101#endif 103#endif
102import Network.KRPC.Method 104import Network.KRPC.Method
103import Network.Address hiding (NodeId) 105import Network.Address hiding (NodeId)
106import Data.Bits
104import Data.ByteString (ByteString) 107import Data.ByteString (ByteString)
108import qualified Data.ByteString as BS
109import Data.Digest.CRC32C
105import Data.List as L 110import Data.List as L
106import Data.Monoid 111import Data.Monoid
107import Data.Serialize as S 112import Data.Serialize as S
108import Data.Typeable 113import Data.Typeable
114import Data.Word
109import Network 115import Network
110import Network.DatagramServer 116import Network.DatagramServer
111import Network.DatagramServer.Mainline (KMessageOf) 117import Network.DatagramServer.Mainline
112import Data.Maybe 118import Data.Maybe
113 119
114import Data.Torrent (InfoHash) 120import Data.Torrent (InfoHash)
115import Network.BitTorrent.DHT.Token 121import Network.BitTorrent.DHT.Token
116#ifdef VERSION_bencoding 122#ifdef VERSION_bencoding
117import Network.DatagramServer () 123import Network.DatagramServer ()
118import Network.DHT.Mainline ()
119#endif 124#endif
120import Network.DatagramServer.Types hiding (Query,Response) 125import Network.DatagramServer.Types hiding (Query,Response)
121 126
@@ -467,3 +472,38 @@ instance KRPC (Query Announce) (Response Announced) where
467 472
468-- endif VERSION_bencoding 473-- endif VERSION_bencoding
469#endif 474#endif
475
476-- | Yields all 8 DHT neighborhoods available to you given a particular ip
477-- address.
478bep42s :: Address a => a -> NodeId KMessageOf -> [NodeId KMessageOf]
479bep42s addr (NodeId r) = mapMaybe (bep42 addr) rs
480 where
481 rs = map (NodeId . change3bits r) [0..7]
482
483-- change3bits :: ByteString -> Word8 -> ByteString
484-- change3bits bs n = BS.snoc (BS.init bs) (BS.last bs .&. 0xF8 .|. n)
485
486change3bits :: (Num b, Bits b) => b -> b -> b
487change3bits bs n = (bs .&. complement 7) .|. n
488
489-- | Modifies a purely random 'NodeId' to one that is related to a given
490-- routable address in accordance with BEP 42.
491bep42 :: Address a => a -> NodeId KMessageOf -> Maybe (NodeId KMessageOf)
492bep42 addr (NodeId r)
493 | Just ip <- fmap S.encode (fromAddr addr :: Maybe IPv4)
494 <|> fmap S.encode (fromAddr addr :: Maybe IPv6)
495 = genBucketSample' retr (NodeId $ crc $ applyMask ip) (3,0x07,0)
496 | otherwise
497 = Nothing
498 where
499 ip4mask = "\x03\x0f\x3f\xff" :: ByteString
500 ip6mask = "\x01\x03\x07\x0f\x1f\x3f\x7f\xff" :: ByteString
501 nbhood_select = (fromIntegral r :: Word8) .&. 7
502 retr n = pure $ BS.drop (nodeIdSize - n) $ S.encode r
503 crc = flip shiftL (finiteBitSize (NodeId undefined) - 32) . fromIntegral . crc32c . BS.pack
504 applyMask ip = case BS.zipWith (.&.) msk ip of
505 (b:bs) -> (b .|. shiftL nbhood_select 5) : bs
506 bs -> bs
507 where msk | BS.length ip == 4 = ip4mask
508 | otherwise = ip6mask
509