diff options
Diffstat (limited to 'src/Network/BitTorrent')
-rw-r--r-- | src/Network/BitTorrent/Tracker/Protocol.hs | 113 |
1 files changed, 108 insertions, 5 deletions
diff --git a/src/Network/BitTorrent/Tracker/Protocol.hs b/src/Network/BitTorrent/Tracker/Protocol.hs index 51d713dd..5741c1d7 100644 --- a/src/Network/BitTorrent/Tracker/Protocol.hs +++ b/src/Network/BitTorrent/Tracker/Protocol.hs | |||
@@ -35,14 +35,14 @@ module Network.BitTorrent.Tracker.Protocol | |||
35 | import Control.Applicative | 35 | import Control.Applicative |
36 | import Control.Monad | 36 | import Control.Monad |
37 | import Data.Char as Char | 37 | import Data.Char as Char |
38 | import Data.Word (Word32) | ||
39 | import Data.Map as M | 38 | import Data.Map as M |
40 | import Data.Maybe | 39 | import Data.Maybe |
41 | import Data.Word | 40 | import Data.Word |
42 | import Data.Monoid | 41 | import Data.Monoid |
43 | import Data.BEncode | 42 | import Data.BEncode |
44 | import Data.ByteString as B | 43 | import Data.ByteString as B |
45 | import Data.Text as T | 44 | import Data.Text as T |
45 | import Data.Text.Encoding as T | ||
46 | import Data.Serialize hiding (Result) | 46 | import Data.Serialize hiding (Result) |
47 | import Data.URLEncoded as URL | 47 | import Data.URLEncoded as URL |
48 | import Data.Torrent | 48 | import Data.Torrent |
@@ -53,8 +53,10 @@ import Network.HTTP | |||
53 | import Network.URI | 53 | import Network.URI |
54 | 54 | ||
55 | import Network.BitTorrent.Peer | 55 | import Network.BitTorrent.Peer |
56 | import Network.BitTorrent.Exchange.Protocol hiding (Request) | ||
57 | 56 | ||
57 | {----------------------------------------------------------------------- | ||
58 | Tracker messages | ||
59 | -----------------------------------------------------------------------} | ||
58 | 60 | ||
59 | -- | Events used to specify which kind of tracker request is performed. | 61 | -- | Events used to specify which kind of tracker request is performed. |
60 | data Event = Started | 62 | data Event = Started |
@@ -138,6 +140,9 @@ data TResponse = | |||
138 | -- ^ Peers that must be contacted. | 140 | -- ^ Peers that must be contacted. |
139 | } deriving Show | 141 | } deriving Show |
140 | 142 | ||
143 | {----------------------------------------------------------------------- | ||
144 | HTTP Tracker encoding | ||
145 | -----------------------------------------------------------------------} | ||
141 | 146 | ||
142 | instance BEncodable TResponse where | 147 | instance BEncodable TResponse where |
143 | toBEncode (Failure t) = fromAssocs ["failure reason" --> t] | 148 | toBEncode (Failure t) = fromAssocs ["failure reason" --> t] |
@@ -196,8 +201,106 @@ encodeRequest req = URL.urlEncode req | |||
196 | `addToURI` reqAnnounce req | 201 | `addToURI` reqAnnounce req |
197 | `addHashToURI` reqInfoHash req | 202 | `addHashToURI` reqInfoHash req |
198 | 203 | ||
199 | 204 | {----------------------------------------------------------------------- | |
200 | -- | Ports typically reserved for bittorrent P2P communication. | 205 | UDP tracker encoding |
206 | -----------------------------------------------------------------------} | ||
207 | |||
208 | type EventId = Word32 | ||
209 | |||
210 | eventId :: Event -> EventId | ||
211 | eventId Completed = 1 | ||
212 | eventId Started = 2 | ||
213 | eventId Stopped = 3 | ||
214 | |||
215 | -- TODO add Regular event | ||
216 | putEvent :: Putter (Maybe Event) | ||
217 | putEvent Nothing = putWord32be 0 | ||
218 | putEvent (Just e) = putWord32be (eventId e) | ||
219 | |||
220 | getEvent :: Get (Maybe Event) | ||
221 | getEvent = do | ||
222 | eid <- getWord32be | ||
223 | case eid of | ||
224 | 0 -> return Nothing | ||
225 | 1 -> return $ Just Completed | ||
226 | 2 -> return $ Just Started | ||
227 | 3 -> return $ Just Stopped | ||
228 | _ -> fail "unknown event id" | ||
229 | |||
230 | instance Serialize TRequest where | ||
231 | put TRequest {..} = do | ||
232 | put reqInfoHash | ||
233 | put reqPeerId | ||
234 | |||
235 | putWord64be $ fromIntegral reqDownloaded | ||
236 | putWord64be $ fromIntegral reqLeft | ||
237 | putWord64be $ fromIntegral reqUploaded | ||
238 | |||
239 | putEvent reqEvent | ||
240 | putWord32be $ fromMaybe 0 reqIP | ||
241 | putWord32be $ 0 -- TODO what the fuck is "key"? | ||
242 | putWord32be $ fromIntegral $ fromMaybe (-1) reqNumWant | ||
243 | |||
244 | put reqPort | ||
245 | |||
246 | get = do | ||
247 | ih <- get | ||
248 | pid <- get | ||
249 | |||
250 | down <- getWord64be | ||
251 | left <- getWord64be | ||
252 | up <- getWord64be | ||
253 | |||
254 | ev <- getEvent | ||
255 | ip <- getWord32be | ||
256 | key <- getWord32be | ||
257 | want <- getWord32be | ||
258 | |||
259 | port <- get | ||
260 | |||
261 | return $ TRequest { | ||
262 | -- TODO remove reqAnnounce field from TRequest | ||
263 | reqAnnounce = error "tracker request decode" | ||
264 | , reqInfoHash = ih | ||
265 | , reqPeerId = pid | ||
266 | , reqPort = port | ||
267 | , reqUploaded = fromIntegral up | ||
268 | , reqDownloaded = fromIntegral down | ||
269 | , reqLeft = fromIntegral left | ||
270 | , reqIP = if ip == 0 then Nothing else Just ip | ||
271 | , reqNumWant = if want == -1 then Nothing else Just (fromIntegral want) | ||
272 | , reqEvent = ev | ||
273 | } | ||
274 | |||
275 | instance Serialize TResponse where | ||
276 | put (Failure msg) = put $ encodeUtf8 msg | ||
277 | put OK {..} = do | ||
278 | putWord32be $ fromIntegral respInterval | ||
279 | putWord32be $ fromIntegral $ fromMaybe 0 respIncomplete | ||
280 | putWord32be $ fromIntegral $ fromMaybe 0 respComplete | ||
281 | forM_ respPeers put | ||
282 | |||
283 | get = do | ||
284 | interval <- getWord32be | ||
285 | leechers <- getWord32be | ||
286 | seeders <- getWord32be | ||
287 | peers <- many get | ||
288 | |||
289 | return $ OK { | ||
290 | respWarning = Nothing | ||
291 | , respInterval = fromIntegral interval | ||
292 | , respMinInterval = Nothing | ||
293 | , respIncomplete = Just $ fromIntegral leechers | ||
294 | , respComplete = Just $ fromIntegral seeders | ||
295 | , respPeers = peers | ||
296 | } | ||
297 | |||
298 | |||
299 | {----------------------------------------------------------------------- | ||
300 | Tracker | ||
301 | -----------------------------------------------------------------------} | ||
302 | |||
303 | -- | Ports typically reserved for bittorrent P2P listener. | ||
201 | defaultPorts :: [PortNumber] | 304 | defaultPorts :: [PortNumber] |
202 | defaultPorts = [6881..6889] | 305 | defaultPorts = [6881..6889] |
203 | 306 | ||