summaryrefslogtreecommitdiff
path: root/src/Network/BitTorrent/DHT
diff options
context:
space:
mode:
Diffstat (limited to 'src/Network/BitTorrent/DHT')
-rw-r--r--src/Network/BitTorrent/DHT/Message.hs100
-rw-r--r--src/Network/BitTorrent/DHT/Query.hs13
-rw-r--r--src/Network/BitTorrent/DHT/Session.hs5
-rw-r--r--src/Network/BitTorrent/DHT/Token.hs10
4 files changed, 123 insertions, 5 deletions
diff --git a/src/Network/BitTorrent/DHT/Message.hs b/src/Network/BitTorrent/DHT/Message.hs
index 1f835fa6..44dc9b2f 100644
--- a/src/Network/BitTorrent/DHT/Message.hs
+++ b/src/Network/BitTorrent/DHT/Message.hs
@@ -55,6 +55,7 @@
55-- For Kamelia messages see original Kademlia paper: 55-- For Kamelia messages see original Kademlia paper:
56-- <http://pdos.csail.mit.edu/~petar/papers/maymounkov-kademlia-lncs.pdf> 56-- <http://pdos.csail.mit.edu/~petar/papers/maymounkov-kademlia-lncs.pdf>
57-- 57--
58{-# LANGUAGE CPP #-}
58{-# LANGUAGE DeriveDataTypeable #-} 59{-# LANGUAGE DeriveDataTypeable #-}
59{-# LANGUAGE FlexibleInstances #-} 60{-# LANGUAGE FlexibleInstances #-}
60{-# LANGUAGE MultiParamTypeClasses #-} 61{-# LANGUAGE MultiParamTypeClasses #-}
@@ -73,6 +74,8 @@ module Network.BitTorrent.DHT.Message
73 , FindNode (..) 74 , FindNode (..)
74 , NodeFound (..) 75 , NodeFound (..)
75 76
77
78#ifdef VERSION_bencoding
76 -- ** get_peers 79 -- ** get_peers
77 , PeerList 80 , PeerList
78 , GetPeers (..) 81 , GetPeers (..)
@@ -81,12 +84,23 @@ module Network.BitTorrent.DHT.Message
81 -- ** announce_peer 84 -- ** announce_peer
82 , Announce (..) 85 , Announce (..)
83 , Announced (..) 86 , Announced (..)
87#endif
84 ) where 88 ) where
85 89
86import Control.Applicative 90import Control.Applicative
87import Data.Bool 91import Data.Bool
92#ifdef VERSION_bencoding
88import Data.BEncode as BE 93import Data.BEncode as BE
89import Data.BEncode.BDict as BDict 94import Data.BEncode.BDict as BDict
95import Network.BitTorrent.Address
96#else
97import qualified Data.Tox as Tox
98import Data.Tox (NodeId)
99import Data.Word
100import Control.Monad
101import Network.KRPC.Method
102import Network.BitTorrent.Address hiding (NodeId)
103#endif
90import Data.ByteString (ByteString) 104import Data.ByteString (ByteString)
91import Data.List as L 105import Data.List as L
92import Data.Monoid 106import Data.Monoid
@@ -97,7 +111,6 @@ import Network.KRPC
97import Data.Maybe 111import Data.Maybe
98 112
99import Data.Torrent (InfoHash) 113import Data.Torrent (InfoHash)
100import Network.BitTorrent.Address
101import Network.BitTorrent.DHT.Token 114import Network.BitTorrent.DHT.Token
102import Network.KRPC () 115import Network.KRPC ()
103 116
@@ -105,6 +118,10 @@ import Network.KRPC ()
105-- envelopes 118-- envelopes
106-----------------------------------------------------------------------} 119-----------------------------------------------------------------------}
107 120
121#ifndef VERSION_bencoding
122type BKey = ByteString
123#endif
124
108node_id_key :: BKey 125node_id_key :: BKey
109node_id_key = "id" 126node_id_key = "id"
110 127
@@ -112,6 +129,7 @@ read_only_key :: BKey
112read_only_key = "ro" 129read_only_key = "ro"
113 130
114 131
132#ifdef VERSION_bencoding
115-- | All queries have an \"id\" key and value containing the node ID 133-- | All queries have an \"id\" key and value containing the node ID
116-- of the querying node. 134-- of the querying node.
117data Query a = Query 135data Query a = Query
@@ -134,7 +152,11 @@ instance BEncode a => BEncode (Query a) where
134 Query <$> fromDict (field (req node_id_key)) v 152 Query <$> fromDict (field (req node_id_key)) v
135 <*> fromDict (fromMaybe False <$>? read_only_key) v 153 <*> fromDict (fromMaybe False <$>? read_only_key) v
136 <*> fromBEncode v 154 <*> fromBEncode v
155#else
156data Query a = Query a
157#endif
137 158
159#ifdef VERSION_bencoding
138-- | All responses have an \"id\" key and value containing the node ID 160-- | All responses have an \"id\" key and value containing the node ID
139-- of the responding node. 161-- of the responding node.
140data Response a = Response 162data Response a = Response
@@ -150,7 +172,9 @@ instance BEncode a => BEncode (Response a) where
150 fromBEncode b = fromQuery <$> fromBEncode b 172 fromBEncode b = fromQuery <$> fromBEncode b
151 where 173 where
152 fromQuery (Query nid _ a) = Response nid a 174 fromQuery (Query nid _ a) = Response nid a
153 175#else
176data Response a = Response a
177#endif
154 178
155{----------------------------------------------------------------------- 179{-----------------------------------------------------------------------
156-- ping method 180-- ping method
@@ -158,16 +182,45 @@ instance BEncode a => BEncode (Response a) where
158 182
159-- | The most basic query is a ping. Ping query is used to check if a 183-- | The most basic query is a ping. Ping query is used to check if a
160-- quered node is still alive. 184-- quered node is still alive.
185#ifdef VERSION_bencoding
161data Ping = Ping 186data Ping = Ping
187#else
188data Ping = Ping Tox.Nonce8
189#endif
162 deriving (Show, Eq, Typeable) 190 deriving (Show, Eq, Typeable)
163 191
192#ifdef VERSION_bencoding
164instance BEncode Ping where 193instance BEncode Ping where
165 toBEncode Ping = toDict endDict 194 toBEncode Ping = toDict endDict
166 fromBEncode _ = pure Ping 195 fromBEncode _ = pure Ping
196#else
197instance Serialize (Query Ping) where
198 get = do
199 b <- get
200 when ( (b::Word8) /= 0) $ fail "Bad ping request"
201 nonce <- get
202 return $ Query (Ping nonce)
203 put (Query (Ping nonce)) = do
204 put (0 :: Word8)
205 put nonce
206instance Serialize (Response Ping) where
207 get = do
208 b <- get
209 when ( (b::Word8) /= 1) $ fail "Bad ping response"
210 nonce <- get
211 return $ Response (Ping nonce)
212 put (Response (Ping nonce)) = do
213 put (1 :: Word8)
214 put nonce
215#endif
167 216
168-- | \"q\" = \"ping\" 217-- | \"q\" = \"ping\"
169instance KRPC (Query Ping) (Response Ping) where 218instance KRPC (Query Ping) (Response Ping) where
219#ifdef VERSION_bencoding
170 method = "ping" 220 method = "ping"
221#else
222 method = Method Tox.Ping -- response: Tox.Pong
223#endif
171 224
172{----------------------------------------------------------------------- 225{-----------------------------------------------------------------------
173-- find_node method 226-- find_node method
@@ -175,21 +228,41 @@ instance KRPC (Query Ping) (Response Ping) where
175 228
176-- | Find node is used to find the contact information for a node 229-- | Find node is used to find the contact information for a node
177-- given its ID. 230-- given its ID.
231#ifdef VERSION_bencoding
178newtype FindNode = FindNode NodeId 232newtype FindNode = FindNode NodeId
233#else
234data FindNode = FindNode NodeId Tox.Nonce8 -- Tox: Get Nodes
235#endif
179 deriving (Show, Eq, Typeable) 236 deriving (Show, Eq, Typeable)
180 237
181target_key :: BKey 238target_key :: BKey
182target_key = "target" 239target_key = "target"
183 240
241#ifdef VERSION_bencoding
184instance BEncode FindNode where 242instance BEncode FindNode where
185 toBEncode (FindNode nid) = toDict $ target_key .=! nid .: endDict 243 toBEncode (FindNode nid) = toDict $ target_key .=! nid .: endDict
186 fromBEncode = fromDict $ FindNode <$>! target_key 244 fromBEncode = fromDict $ FindNode <$>! target_key
245#else
246instance Serialize (Query FindNode) where
247 get = do
248 nid <- get
249 nonce <- get
250 return $ Query (FindNode nid nonce)
251 put (Query (FindNode nid nonce)) = do
252 put nid
253 put nonce
254#endif
187 255
188-- | When a node receives a 'FindNode' query, it should respond with a 256-- | When a node receives a 'FindNode' query, it should respond with a
189-- the compact node info for the target node or the K (8) closest good 257-- the compact node info for the target node or the K (8) closest good
190-- nodes in its own routing table. 258-- nodes in its own routing table.
191-- 259--
260#ifdef VERSION_bencoding
192newtype NodeFound ip = NodeFound [NodeInfo ip] 261newtype NodeFound ip = NodeFound [NodeInfo ip]
262#else
263data NodeFound ip = NodeFound [Tox.NodeFormat] Tox.Nonce8
264#endif
265-- Tox: send_nodes
193 deriving (Show, Eq, Typeable) 266 deriving (Show, Eq, Typeable)
194 267
195nodes_key :: BKey 268nodes_key :: BKey
@@ -200,6 +273,7 @@ from4 :: forall s. Address s => NodeInfo IPv4 -> Either String (NodeInfo s)
200from4 n = maybe (Left "Error converting IPv4") Right 273from4 n = maybe (Left "Error converting IPv4") Right
201 $ traverse (fromAddr :: IPv4 -> Maybe s) n 274 $ traverse (fromAddr :: IPv4 -> Maybe s) n
202 275
276#ifdef VERSION_bencoding
203binary :: Serialize a => BKey -> BE.Get [a] 277binary :: Serialize a => BKey -> BE.Get [a]
204binary k = field (req k) >>= either (fail . format) return . 278binary k = field (req k) >>= either (fail . format) return .
205 runGet (many get) 279 runGet (many get)
@@ -213,12 +287,31 @@ instance Address ip => BEncode (NodeFound ip) where
213 287
214 -- TODO: handle IPv6 by reading the "nodes6" key (see bep 32) 288 -- TODO: handle IPv6 by reading the "nodes6" key (see bep 32)
215 fromBEncode bval = NodeFound <$> (traverse from4 =<< fromDict (binary nodes_key) bval) 289 fromBEncode bval = NodeFound <$> (traverse from4 =<< fromDict (binary nodes_key) bval)
290#else
291instance Serialize (Response (NodeFound ip)) where
292 get = do
293 count <- get :: Get Word8
294 nodes <- sequence $ replicate (fromIntegral count) get
295 nonce <- get :: Get Tox.Nonce8
296 return $ Response $ NodeFound nodes nonce
297
298 put (Response (NodeFound nodes nonce)) = do
299 put (fromIntegral (length nodes) :: Word8)
300 mapM_ put nodes
301 put nonce
302
303#endif
216 304
217-- | \"q\" == \"find_node\" 305-- | \"q\" == \"find_node\"
218instance (Address ip, Typeable ip) 306instance (Address ip, Typeable ip)
219 => KRPC (Query FindNode) (Response (NodeFound ip)) where 307 => KRPC (Query FindNode) (Response (NodeFound ip)) where
308#ifdef VERSION_bencoding
220 method = "find_node" 309 method = "find_node"
310#else
311 method = Method Tox.GetNodes -- response: Tox.SendNodes
312#endif
221 313
314#ifdef VERSION_bencoding
222{----------------------------------------------------------------------- 315{-----------------------------------------------------------------------
223-- get_peers method 316-- get_peers method
224-----------------------------------------------------------------------} 317-----------------------------------------------------------------------}
@@ -354,3 +447,6 @@ instance BEncode Announced where
354-- | \"q" = \"announce\" 447-- | \"q" = \"announce\"
355instance KRPC (Query Announce) (Response Announced) where 448instance KRPC (Query Announce) (Response Announced) where
356 method = "announce_peer" 449 method = "announce_peer"
450
451-- endif VERSION_bencoding
452#endif
diff --git a/src/Network/BitTorrent/DHT/Query.hs b/src/Network/BitTorrent/DHT/Query.hs
index 5345f8b1..c7e48920 100644
--- a/src/Network/BitTorrent/DHT/Query.hs
+++ b/src/Network/BitTorrent/DHT/Query.hs
@@ -96,7 +96,10 @@ import qualified Network.BitTorrent.DHT.Search as Search
96 96
97nodeHandler :: Address ip => KRPC (Query a) (Response b) 97nodeHandler :: Address ip => KRPC (Query a) (Response b)
98 => (NodeAddr ip -> a -> DHT ip b) -> NodeHandler ip 98 => (NodeAddr ip -> a -> DHT ip b) -> NodeHandler ip
99nodeHandler action = handler $ \ sockAddr (Query remoteId read_only q) -> do 99nodeHandler action = handler $ \ sockAddr qry -> do
100 let remoteId = queringNodeId qry
101 read_only = queryIsReadOnly qry
102 q = queryParams qry
100 case fromSockAddr sockAddr of 103 case fromSockAddr sockAddr of
101 Nothing -> throwIO BadAddress 104 Nothing -> throwIO BadAddress
102 Just naddr -> do 105 Just naddr -> do
@@ -119,6 +122,7 @@ findNodeH :: Address ip => NodeHandler ip
119findNodeH = nodeHandler $ \ _ (FindNode nid) -> do 122findNodeH = nodeHandler $ \ _ (FindNode nid) -> do
120 NodeFound <$> getClosest nid 123 NodeFound <$> getClosest nid
121 124
125#ifdef VERSION_bencoding
122-- | Default 'GetPeers' handler. 126-- | Default 'GetPeers' handler.
123getPeersH :: Ord ip => Address ip => NodeHandler ip 127getPeersH :: Ord ip => Address ip => NodeHandler ip
124getPeersH = nodeHandler $ \ naddr (GetPeers ih) -> do 128getPeersH = nodeHandler $ \ naddr (GetPeers ih) -> do
@@ -141,6 +145,11 @@ announceH = nodeHandler $ \ naddr @ NodeAddr {..} (Announce {..}) -> do
141-- | Includes all default query handlers. 145-- | Includes all default query handlers.
142defaultHandlers :: Ord ip => Address ip => [NodeHandler ip] 146defaultHandlers :: Ord ip => Address ip => [NodeHandler ip]
143defaultHandlers = [pingH, findNodeH, getPeersH, announceH] 147defaultHandlers = [pingH, findNodeH, getPeersH, announceH]
148#else
149-- | Includes all default query handlers.
150defaultHandlers :: Ord ip => Address ip => [NodeHandler ip]
151defaultHandlers = [pingH, findNodeH]
152#endif
144 153
145{----------------------------------------------------------------------- 154{-----------------------------------------------------------------------
146-- Basic queries 155-- Basic queries
@@ -165,6 +174,7 @@ findNodeQ key NodeInfo {..} = do
165 <> T.pack (L.unlines $ L.map ((' ' :) . show . pPrint) closest) 174 <> T.pack (L.unlines $ L.map ((' ' :) . show . pPrint) closest)
166 return $ Right closest 175 return $ Right closest
167 176
177#ifdef VERSION_bencoding
168getPeersQ :: Address ip => InfoHash -> Iteration ip PeerAddr 178getPeersQ :: Address ip => InfoHash -> Iteration ip PeerAddr
169getPeersQ topic NodeInfo {..} = do 179getPeersQ topic NodeInfo {..} = do
170 GotPeers {..} <- GetPeers topic <@> nodeAddr 180 GotPeers {..} <- GetPeers topic <@> nodeAddr
@@ -184,6 +194,7 @@ announceQ ih p NodeInfo {..} = do
184 Right _ -> do -- TODO *probably* add to peer cache 194 Right _ -> do -- TODO *probably* add to peer cache
185 Announced <- Announce False ih Nothing p grantedToken <@> nodeAddr 195 Announced <- Announce False ih Nothing p grantedToken <@> nodeAddr
186 return (Right [nodeAddr]) 196 return (Right [nodeAddr])
197#endif
187 198
188{----------------------------------------------------------------------- 199{-----------------------------------------------------------------------
189-- Iterative queries 200-- Iterative queries
diff --git a/src/Network/BitTorrent/DHT/Session.hs b/src/Network/BitTorrent/DHT/Session.hs
index bad783a5..82926b28 100644
--- a/src/Network/BitTorrent/DHT/Session.hs
+++ b/src/Network/BitTorrent/DHT/Session.hs
@@ -55,6 +55,7 @@ module Network.BitTorrent.DHT.Session
55 , getTable 55 , getTable
56 , getClosest 56 , getClosest
57 57
58#ifdef VERSION_bencoding
58 -- ** Peer storage 59 -- ** Peer storage
59 , insertPeer 60 , insertPeer
60 , getPeerList 61 , getPeerList
@@ -64,6 +65,7 @@ module Network.BitTorrent.DHT.Session
64 , savePeerStore 65 , savePeerStore
65 , mergeSavedPeers 66 , mergeSavedPeers
66 , allPeers 67 , allPeers
68#endif
67 69
68 -- ** Messaging 70 -- ** Messaging
69 , queryParallel 71 , queryParallel
@@ -482,6 +484,7 @@ getTimestamp = do
482 return $ utcTimeToPOSIXSeconds utcTime 484 return $ utcTimeToPOSIXSeconds utcTime
483 485
484 486
487#ifdef VERSION_bencoding
485-- | Prepare result for 'get_peers' query. 488-- | Prepare result for 'get_peers' query.
486-- 489--
487-- This operation use 'getClosest' as failback so it may block. 490-- This operation use 'getClosest' as failback so it may block.
@@ -503,6 +506,8 @@ deleteTopic ih p = do
503 var <- asks announceInfo 506 var <- asks announceInfo
504 liftIO $ atomically $ modifyTVar' var (S.delete (ih, p)) 507 liftIO $ atomically $ modifyTVar' var (S.delete (ih, p))
505 508
509#endif
510
506{----------------------------------------------------------------------- 511{-----------------------------------------------------------------------
507-- Messaging 512-- Messaging
508-----------------------------------------------------------------------} 513-----------------------------------------------------------------------}
diff --git a/src/Network/BitTorrent/DHT/Token.hs b/src/Network/BitTorrent/DHT/Token.hs
index 3f71aabe..4c930cbc 100644
--- a/src/Network/BitTorrent/DHT/Token.hs
+++ b/src/Network/BitTorrent/DHT/Token.hs
@@ -17,7 +17,7 @@
17-- must be accepted for a reasonable amount of time after they have 17-- must be accepted for a reasonable amount of time after they have
18-- been distributed. 18-- been distributed.
19-- 19--
20{-# LANGUAGE GeneralizedNewtypeDeriving #-} 20{-# LANGUAGE GeneralizedNewtypeDeriving, CPP #-}
21module Network.BitTorrent.DHT.Token 21module Network.BitTorrent.DHT.Token
22 ( -- * Token 22 ( -- * Token
23 Token 23 Token
@@ -38,7 +38,9 @@ module Network.BitTorrent.DHT.Token
38 ) where 38 ) where
39 39
40import Control.Monad.State 40import Control.Monad.State
41#ifdef VERSION_bencoding
41import Data.BEncode (BEncode) 42import Data.BEncode (BEncode)
43#endif
42import Data.ByteString as BS 44import Data.ByteString as BS
43import Data.ByteString.Char8 as B8 45import Data.ByteString.Char8 as B8
44import Data.ByteString.Lazy as BL 46import Data.ByteString.Lazy as BL
@@ -57,7 +59,11 @@ import Network.BitTorrent.Address
57 59
58-- | An opaque value. 60-- | An opaque value.
59newtype Token = Token BS.ByteString 61newtype Token = Token BS.ByteString
60 deriving (Eq, BEncode, IsString) 62 deriving ( Eq, IsString
63#ifdef VERSION_bencoding
64 , BEncode
65#endif
66 )
61 67
62instance Show Token where 68instance Show Token where
63 show (Token bs) = B8.unpack $ Base16.encode bs 69 show (Token bs) = B8.unpack $ Base16.encode bs