diff options
Diffstat (limited to 'src/Network/BitTorrent/DHT/Message.hs')
-rw-r--r-- | src/Network/BitTorrent/DHT/Message.hs | 46 |
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 | |||
92 | import Data.Bool | 94 | import Data.Bool |
93 | #ifdef VERSION_bencoding | 95 | #ifdef VERSION_bencoding |
94 | import Data.BEncode as BE | 96 | import Data.BEncode as BE |
95 | import Data.BEncode.BDict as BDict | 97 | import Data.BEncode.BDict as BDict hiding (map) |
96 | #else | 98 | #else |
97 | import qualified Network.DatagramServer.Tox as Tox | 99 | import qualified Network.DatagramServer.Tox as Tox |
98 | import Network.DatagramServer.Tox (NodeId) | 100 | import Network.DatagramServer.Tox (NodeId) |
@@ -101,21 +103,24 @@ import Control.Monad | |||
101 | #endif | 103 | #endif |
102 | import Network.KRPC.Method | 104 | import Network.KRPC.Method |
103 | import Network.Address hiding (NodeId) | 105 | import Network.Address hiding (NodeId) |
106 | import Data.Bits | ||
104 | import Data.ByteString (ByteString) | 107 | import Data.ByteString (ByteString) |
108 | import qualified Data.ByteString as BS | ||
109 | import Data.Digest.CRC32C | ||
105 | import Data.List as L | 110 | import Data.List as L |
106 | import Data.Monoid | 111 | import Data.Monoid |
107 | import Data.Serialize as S | 112 | import Data.Serialize as S |
108 | import Data.Typeable | 113 | import Data.Typeable |
114 | import Data.Word | ||
109 | import Network | 115 | import Network |
110 | import Network.DatagramServer | 116 | import Network.DatagramServer |
111 | import Network.DatagramServer.Mainline (KMessageOf) | 117 | import Network.DatagramServer.Mainline |
112 | import Data.Maybe | 118 | import Data.Maybe |
113 | 119 | ||
114 | import Data.Torrent (InfoHash) | 120 | import Data.Torrent (InfoHash) |
115 | import Network.BitTorrent.DHT.Token | 121 | import Network.BitTorrent.DHT.Token |
116 | #ifdef VERSION_bencoding | 122 | #ifdef VERSION_bencoding |
117 | import Network.DatagramServer () | 123 | import Network.DatagramServer () |
118 | import Network.DHT.Mainline () | ||
119 | #endif | 124 | #endif |
120 | import Network.DatagramServer.Types hiding (Query,Response) | 125 | import 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. | ||
478 | bep42s :: Address a => a -> NodeId KMessageOf -> [NodeId KMessageOf] | ||
479 | bep42s 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 | |||
486 | change3bits :: (Num b, Bits b) => b -> b -> b | ||
487 | change3bits 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. | ||
491 | bep42 :: Address a => a -> NodeId KMessageOf -> Maybe (NodeId KMessageOf) | ||
492 | bep42 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 | |||