summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Network/BitTorrent/DHT/Message.hs29
-rw-r--r--tests/Network/BitTorrent/DHT/MessageSpec.hs19
2 files changed, 37 insertions, 11 deletions
diff --git a/src/Network/BitTorrent/DHT/Message.hs b/src/Network/BitTorrent/DHT/Message.hs
index 15d1099c..49629755 100644
--- a/src/Network/BitTorrent/DHT/Message.hs
+++ b/src/Network/BitTorrent/DHT/Message.hs
@@ -214,8 +214,15 @@ instance (Typeable ip, Serialize ip) =>
214-- | Announce that the peer, controlling the querying node, is 214-- | Announce that the peer, controlling the querying node, is
215-- downloading a torrent on a port. 215-- downloading a torrent on a port.
216data Announce = Announce 216data Announce = Announce
217 { -- | infohash of the torrent; 217 { -- | If set, the 'port' field should be ignored and the source
218 topic :: InfoHash 218 -- port of the UDP packet should be used as the peer's port
219 -- instead. This is useful for peers behind a NAT that may not
220 -- know their external port, and supporting uTP, they accept
221 -- incoming connections on the same port as the DHT port.
222 impliedPort :: Bool
223
224 -- | infohash of the torrent;
225 , topic :: InfoHash
219 226
220 -- | the port /this/ peer is listening; 227 -- | the port /this/ peer is listening;
221 , port :: PortNumber 228 , port :: PortNumber
@@ -227,16 +234,26 @@ data Announce = Announce
227port_key :: BKey 234port_key :: BKey
228port_key = "port" 235port_key = "port"
229 236
237implied_port_key :: BKey
238implied_port_key = "implied_port"
239
230instance BEncode Announce where 240instance BEncode Announce where
231 toBEncode Announce {..} = toDict $ 241 toBEncode Announce {..} = toDict $
232 info_hash_key .=! topic 242 implied_port_key .=? flagField impliedPort
233 .: port_key .=! port 243 .: info_hash_key .=! topic
234 .: token_key .=! sessionToken 244 .: port_key .=! port
245 .: token_key .=! sessionToken
235 .: endDict 246 .: endDict
247 where
248 flagField flag = if flag then Just (1 :: Int) else Nothing
249
236 fromBEncode = fromDict $ do 250 fromBEncode = fromDict $ do
237 Announce <$>! info_hash_key 251 Announce <$> (boolField <$> optional (field (req implied_port_key)))
252 <*>! info_hash_key
238 <*>! port_key 253 <*>! port_key
239 <*>! token_key 254 <*>! token_key
255 where
256 boolField = maybe False (/= (0 :: Int))
240 257
241-- | The queried node must verify that the token was previously sent 258-- | The queried node must verify that the token was previously sent
242-- to the same IP address as the querying node. Then the queried node 259-- to the same IP address as the querying node. Then the queried node
diff --git a/tests/Network/BitTorrent/DHT/MessageSpec.hs b/tests/Network/BitTorrent/DHT/MessageSpec.hs
index 52bda932..11a8fb15 100644
--- a/tests/Network/BitTorrent/DHT/MessageSpec.hs
+++ b/tests/Network/BitTorrent/DHT/MessageSpec.hs
@@ -143,15 +143,24 @@ spec = do
143 \5:token8:aoeusnth\ 143 \5:token8:aoeusnth\
144 \e" `shouldBe` Right 144 \e" `shouldBe` Right
145 (Query "abcdefghij0123456789" 145 (Query "abcdefghij0123456789"
146 (Announce "mnopqrstuvwxyz123456" 6881 "aoeusnth")) 146 (Announce False "mnopqrstuvwxyz123456" 6881 "aoeusnth"))
147
148 BE.decode "d2:id20:abcdefghij0123456789\
149 \12:implied_porti1e\
150 \9:info_hash20:mnopqrstuvwxyz123456\
151 \4:porti6881e\
152 \5:token8:aoeusnth\
153 \e" `shouldBe` Right
154 (Query "abcdefghij0123456789"
155 (Announce True "mnopqrstuvwxyz123456" 6881 "aoeusnth"))
147 156
148 157
149 BE.decode "d2:id20:mnopqrstuvwxyz123456e" 158 BE.decode "d2:id20:mnopqrstuvwxyz123456e"
150 `shouldBe` Right 159 `shouldBe` Right
151 (Response "mnopqrstuvwxyz123456" Announced) 160 (Response "mnopqrstuvwxyz123456" Announced)
152 161
153 it "properly bencoded (iso)" $ property $ \ nid topic port token -> do 162 it "properly bencoded (iso)" $ property $ \ nid flag topic port token -> do
154 prop_bencode (Query nid (Announce topic port token)) 163 prop_bencode (Query nid (Announce flag topic port token))
155 prop_bencode (Response nid (Announced)) 164 prop_bencode (Response nid (Announced))
156 165
157 166
@@ -160,7 +169,7 @@ spec = do
160 Response _remoteId Announced <- rpc $ do 169 Response _remoteId Announced <- rpc $ do
161 Response _ GotPeers {..} <- query remoteAddr (Query nid (GetPeers def)) 170 Response _ GotPeers {..} <- query remoteAddr (Query nid (GetPeers def))
162 let _ = peers :: Either [NodeInfo IPv4] [PeerAddr IPv4] 171 let _ = peers :: Either [NodeInfo IPv4] [PeerAddr IPv4]
163 query remoteAddr (Query nid (Announce def thisPort grantedToken)) 172 query remoteAddr (Query nid (Announce False def thisPort grantedToken))
164 return () 173 return ()
165 174
166 it "does fail on invalid token" $ do 175 it "does fail on invalid token" $ do
@@ -169,6 +178,6 @@ spec = do
169 Response _ GotPeers {..} <- query remoteAddr (Query nid (GetPeers def)) 178 Response _ GotPeers {..} <- query remoteAddr (Query nid (GetPeers def))
170 let _ = peers :: Either [NodeInfo IPv4] [PeerAddr IPv4] 179 let _ = peers :: Either [NodeInfo IPv4] [PeerAddr IPv4]
171 let invalidToken = "" 180 let invalidToken = ""
172 query remoteAddr (Query nid (Announce def thisPort invalidToken))) 181 query remoteAddr (Query nid (Announce False def thisPort invalidToken)))
173 `shouldThrow` isProtocolError 182 `shouldThrow` isProtocolError
174 return () 183 return ()