diff options
Diffstat (limited to 'src/Network/BitTorrent')
-rw-r--r-- | src/Network/BitTorrent/Tracker/Message.hs | 57 |
1 files changed, 34 insertions, 23 deletions
diff --git a/src/Network/BitTorrent/Tracker/Message.hs b/src/Network/BitTorrent/Tracker/Message.hs index 22733a51..e49a9e58 100644 --- a/src/Network/BitTorrent/Tracker/Message.hs +++ b/src/Network/BitTorrent/Tracker/Message.hs | |||
@@ -6,7 +6,7 @@ | |||
6 | -- Portability : portable | 6 | -- Portability : portable |
7 | -- | 7 | -- |
8 | -- Every tracker should support announce query. This query is used | 8 | -- Every tracker should support announce query. This query is used |
9 | -- to discover peers within swarm and have two-fold effect: | 9 | -- to discover peers within a swarm and have two-fold effect: |
10 | -- | 10 | -- |
11 | -- * peer doing announce discover other peers using peer list from | 11 | -- * peer doing announce discover other peers using peer list from |
12 | -- the response to the announce query. | 12 | -- the response to the announce query. |
@@ -14,8 +14,8 @@ | |||
14 | -- * tracker store peer information and use it in the succeeding | 14 | -- * tracker store peer information and use it in the succeeding |
15 | -- requests made by other peers, until the peer info expires. | 15 | -- requests made by other peers, until the peer info expires. |
16 | -- | 16 | -- |
17 | -- By convention most trackers support another form of request -- | 17 | -- By convention most trackers support another form of request — |
18 | -- scrape query -- which queries the state of a given torrent (or | 18 | -- scrape query — which queries the state of a given torrent (or |
19 | -- a list of torrents) that the tracker is managing. | 19 | -- a list of torrents) that the tracker is managing. |
20 | -- | 20 | -- |
21 | {-# LANGUAGE FlexibleInstances #-} | 21 | {-# LANGUAGE FlexibleInstances #-} |
@@ -77,7 +77,7 @@ import Network.BitTorrent.Core.PeerAddr | |||
77 | -- Events | 77 | -- Events |
78 | -----------------------------------------------------------------------} | 78 | -----------------------------------------------------------------------} |
79 | 79 | ||
80 | -- | Events used to specify which kind of tracker request is performed. | 80 | -- | Events used to specify which kind of announce query is performed. |
81 | data Event = Started | 81 | data Event = Started |
82 | -- ^ For the first request: when a peer join the swarm. | 82 | -- ^ For the first request: when a peer join the swarm. |
83 | | Stopped | 83 | | Stopped |
@@ -127,32 +127,34 @@ getEvent = do | |||
127 | -- the torrent. The most important, requests are used by the tracker | 127 | -- the torrent. The most important, requests are used by the tracker |
128 | -- to keep track lists of active peer for a particular torrent. | 128 | -- to keep track lists of active peer for a particular torrent. |
129 | -- | 129 | -- |
130 | data AnnounceQuery = AnnounceQuery { | 130 | data AnnounceQuery = AnnounceQuery |
131 | reqInfoHash :: !InfoHash | 131 | { |
132 | -- ^ Hash of info part of the torrent usually obtained from | 132 | -- | Hash of info part of the torrent usually obtained from |
133 | -- 'Torrent'. | 133 | -- 'Torrent'. |
134 | reqInfoHash :: !InfoHash | ||
134 | 135 | ||
136 | -- | ID of the peer doing request. | ||
135 | , reqPeerId :: !PeerId | 137 | , reqPeerId :: !PeerId |
136 | -- ^ ID of the peer doing request. | ||
137 | 138 | ||
139 | -- | Port to listen to for connections from other | ||
140 | -- peers. Tracker should respond with this port when | ||
141 | -- some /other/ peer request the tracker with the same info hash. | ||
142 | -- Normally, this port is choosed from 'defaultPorts'. | ||
138 | , reqPort :: !PortNumber | 143 | , reqPort :: !PortNumber |
139 | -- ^ Port to listen to for connections from other | ||
140 | -- peers. Normally, tracker should respond with this port when | ||
141 | -- some peer request the tracker with the same info hash. | ||
142 | 144 | ||
145 | -- | Current progress of peer doing request. | ||
143 | , reqProgress :: !Progress | 146 | , reqProgress :: !Progress |
144 | -- ^ Current progress of peer doing request. | ||
145 | 147 | ||
146 | , reqIP :: Maybe HostAddress | 148 | -- | The peer IP. Needed only when client communicated with |
147 | -- ^ The peer IP. Needed only when client communicated with | ||
148 | -- tracker throught a proxy. | 149 | -- tracker throught a proxy. |
150 | , reqIP :: Maybe HostAddress | ||
149 | 151 | ||
150 | , reqNumWant :: Maybe Int | 152 | -- | Number of peers that the peers wants to receive from. See |
151 | -- ^ Number of peers that the peers wants to receive from. See | ||
152 | -- note for 'defaultNumWant'. | 153 | -- note for 'defaultNumWant'. |
154 | , reqNumWant :: Maybe Int | ||
153 | 155 | ||
156 | -- | If not specified, the request is regular periodic request. | ||
154 | , reqEvent :: Maybe Event | 157 | , reqEvent :: Maybe Event |
155 | -- ^ If not specified, the request is regular periodic request. | ||
156 | } deriving (Show, Typeable) | 158 | } deriving (Show, Typeable) |
157 | 159 | ||
158 | $(deriveJSON (L.map toLower . L.dropWhile isLower) ''AnnounceQuery) | 160 | $(deriveJSON (L.map toLower . L.dropWhile isLower) ''AnnounceQuery) |
@@ -208,11 +210,12 @@ instance Serialize AnnounceQuery where | |||
208 | , reqPort = port | 210 | , reqPort = port |
209 | , reqProgress = progress | 211 | , reqProgress = progress |
210 | , reqIP = if ip == 0 then Nothing else Just ip | 212 | , reqIP = if ip == 0 then Nothing else Just ip |
211 | , reqNumWant = if want == -1 then Nothing else Just (fromIntegral want) | 213 | , reqNumWant = if want == -1 then Nothing |
214 | else Just (fromIntegral want) | ||
212 | , reqEvent = ev | 215 | , reqEvent = ev |
213 | } | 216 | } |
214 | 217 | ||
215 | -- | Encoding announce query and add it to the base tracker URL. | 218 | -- | Encode announce query and add it to the base tracker URL. |
216 | renderAnnounceQuery :: URI -> AnnounceQuery -> URI | 219 | renderAnnounceQuery :: URI -> AnnounceQuery -> URI |
217 | renderAnnounceQuery announceURI req | 220 | renderAnnounceQuery announceURI req |
218 | = URL.urlEncode req | 221 | = URL.urlEncode req |
@@ -230,7 +233,7 @@ data QueryParam | |||
230 | deriving (Show, Eq, Ord, Enum) | 233 | deriving (Show, Eq, Ord, Enum) |
231 | 234 | ||
232 | data ParamParseFailure | 235 | data ParamParseFailure |
233 | = Missing QueryParam -- ^ param not found in query string | 236 | = Missing QueryParam -- ^ param not found in query string; |
234 | | Invalid QueryParam -- ^ param present but not valid. | 237 | | Invalid QueryParam -- ^ param present but not valid. |
235 | 238 | ||
236 | type ParamResult = Either ParamParseFailure | 239 | type ParamResult = Either ParamParseFailure |
@@ -255,7 +258,7 @@ paramName ParamInfoHash = "info_hash" | |||
255 | paramName ParamPeerId = "peer_id" | 258 | paramName ParamPeerId = "peer_id" |
256 | paramName ParamPort = "port" | 259 | paramName ParamPort = "port" |
257 | 260 | ||
258 | -- | Parse announce request from a query string. | 261 | -- | Parse announce request from a decoded query string. |
259 | parseAnnounceQuery :: [(Text, Text)] -> Either ParamParseFailure AnnounceQuery | 262 | parseAnnounceQuery :: [(Text, Text)] -> Either ParamParseFailure AnnounceQuery |
260 | parseAnnounceQuery params = AnnounceQuery | 263 | parseAnnounceQuery params = AnnounceQuery |
261 | <$> reqParam ParamInfoHash textToInfoHash params | 264 | <$> reqParam ParamInfoHash textToInfoHash params |
@@ -280,11 +283,17 @@ parseAnnounceQuery params = AnnounceQuery | |||
280 | numwant = undefined | 283 | numwant = undefined |
281 | event = undefined | 284 | event = undefined |
282 | 285 | ||
286 | -- TODO add extension datatype | ||
287 | |||
283 | {----------------------------------------------------------------------- | 288 | {----------------------------------------------------------------------- |
284 | -- Announce response | 289 | -- Announce response |
285 | -----------------------------------------------------------------------} | 290 | -----------------------------------------------------------------------} |
286 | 291 | ||
287 | -- | For more info see: <http://www.bittorrent.org/beps/bep_0023.html> | 292 | -- | Tracker can return peer list in either compact(BEP23) or not |
293 | -- compact form. | ||
294 | -- | ||
295 | -- For more info see: <http://www.bittorrent.org/beps/bep_0023.html> | ||
296 | -- | ||
288 | data PeerList | 297 | data PeerList |
289 | = PeerList { getPeerList :: [PeerAddr] } | 298 | = PeerList { getPeerList :: [PeerAddr] } |
290 | | CompactPeerList { getPeerList :: [PeerAddr] } | 299 | | CompactPeerList { getPeerList :: [PeerAddr] } |
@@ -408,10 +417,12 @@ missingOffset = 101 | |||
408 | invalidOffset :: Int | 417 | invalidOffset :: Int |
409 | invalidOffset = 150 | 418 | invalidOffset = 150 |
410 | 419 | ||
411 | -- | Get | 420 | -- | Get HTTP response error code from a announce params parse |
421 | -- failure. | ||
412 | -- | 422 | -- |
413 | -- For more info see: | 423 | -- For more info see: |
414 | -- <https://wiki.theory.org/BitTorrent_Tracker_Protocol#Response_Codes> | 424 | -- <https://wiki.theory.org/BitTorrent_Tracker_Protocol#Response_Codes> |
425 | -- | ||
415 | paramFailureCode :: ParamParseFailure -> Int | 426 | paramFailureCode :: ParamParseFailure -> Int |
416 | paramFailureCode (Missing param) = missingOffset + fromEnum param | 427 | paramFailureCode (Missing param) = missingOffset + fromEnum param |
417 | paramFailureCode (Invalid param) = invalidOffset + fromEnum param | 428 | paramFailureCode (Invalid param) = invalidOffset + fromEnum param |