summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Data/Torrent.hs51
-rw-r--r--src/Network/BitTorrent/Exchange/Protocol.hs6
-rw-r--r--src/Network/BitTorrent/Tracker.hs6
-rw-r--r--src/Network/BitTorrent/Tracker/Protocol.hs33
4 files changed, 55 insertions, 41 deletions
diff --git a/src/Data/Torrent.hs b/src/Data/Torrent.hs
index 068e9cb6..ad57403e 100644
--- a/src/Data/Torrent.hs
+++ b/src/Data/Torrent.hs
@@ -21,6 +21,7 @@
21{-# LANGUAGE FlexibleInstances #-} 21{-# LANGUAGE FlexibleInstances #-}
22{-# LANGUAGE OverloadedStrings #-} 22{-# LANGUAGE OverloadedStrings #-}
23{-# LANGUAGE RecordWildCards #-} 23{-# LANGUAGE RecordWildCards #-}
24{-# LANGUAGE BangPatterns #-}
24-- TODO refine interface 25-- TODO refine interface
25module Data.Torrent 26module Data.Torrent
26 ( -- * Torrent 27 ( -- * Torrent
@@ -83,14 +84,14 @@ type Time = Text
83-- TODO more convenient form of torrent info. 84-- TODO more convenient form of torrent info.
84-- | Metainfo about particular torrent. 85-- | Metainfo about particular torrent.
85data Torrent = Torrent { 86data Torrent = Torrent {
86 tInfoHash :: InfoHash 87 tInfoHash :: !InfoHash
87 -- ^ SHA1 hash of the 'TorrentInfo' of the 'Torrent'. 88 -- ^ SHA1 hash of the 'TorrentInfo' of the 'Torrent'.
88 89
89 , tAnnounce :: URI 90 , tAnnounce :: !URI
90 -- ^ The URL of the tracker. 91 -- ^ The URL of the tracker.
91 92
92 -- NOTE: out of lexicographic order! 93 -- NOTE: out of lexicographic order!
93 , tInfo :: ContentInfo 94 , tInfo :: !ContentInfo
94 -- ^ Info about each content file. 95 -- ^ Info about each content file.
95 96
96 , tAnnounceList :: Maybe [[URI]] 97 , tAnnounceList :: Maybe [[URI]]
@@ -112,9 +113,9 @@ data Torrent = Torrent {
112 -- the info dictionary in the .torrent metafile. 113 -- the info dictionary in the .torrent metafile.
113 114
114 , tPublisher :: Maybe URI 115 , tPublisher :: Maybe URI
115 -- ^ Containing the RSA public key of the publisher of the torrent. 116 -- ^ Containing the RSA public key of the publisher of the
116 -- Private counterpart of this key that has the authority to allow 117 -- torrent. Private counterpart of this key that has the
117 -- new peers onto the swarm. 118 -- authority to allow new peers onto the swarm.
118 119
119 , tPublisherURL :: Maybe URI 120 , tPublisherURL :: Maybe URI
120 , tSignature :: Maybe ByteString 121 , tSignature :: Maybe ByteString
@@ -144,22 +145,22 @@ simpleTorrent announce info = torrent announce info
144-- | Info part of the .torrent file contain info about each content file. 145-- | Info part of the .torrent file contain info about each content file.
145data ContentInfo = 146data ContentInfo =
146 SingleFile { 147 SingleFile {
147 ciLength :: Integer 148 ciLength :: !Integer
148 -- ^ Length of the file in bytes. 149 -- ^ Length of the file in bytes.
149 150
150 , ciMD5sum :: Maybe ByteString 151 , ciMD5sum :: Maybe ByteString
151 -- ^ 32 character long MD5 sum of the file. 152 -- ^ 32 character long MD5 sum of the file.
152 -- Used by third-party tools, not by bittorrent protocol itself. 153 -- Used by third-party tools, not by bittorrent protocol itself.
153 154
154 , ciName :: ByteString 155 , ciName :: !ByteString
155 -- ^ Suggested name of the file single file. 156 -- ^ Suggested name of the file single file.
156 157
157 158
158 159
159 , ciPieceLength :: Int 160 , ciPieceLength :: !Int
160 -- ^ Number of bytes in each piece. 161 -- ^ Number of bytes in each piece.
161 162
162 , ciPieces :: ByteString 163 , ciPieces :: !ByteString
163 -- ^ Concatenation of all 20-byte SHA1 hash values. 164 -- ^ Concatenation of all 20-byte SHA1 hash values.
164 165
165 , ciPrivate :: Maybe Bool 166 , ciPrivate :: Maybe Bool
@@ -171,28 +172,28 @@ data ContentInfo =
171 } 172 }
172 173
173 | MultiFile { 174 | MultiFile {
174 ciFiles :: [FileInfo] 175 ciFiles :: ![FileInfo]
175 -- ^ List of the all files that torrent contains. 176 -- ^ List of the all files that torrent contains.
176 177
177 , ciName :: ByteString 178 , ciName :: !ByteString
178 -- | The file path of the directory in which to store all the files. 179 -- | The file path of the directory in which to store all the files.
179 180
180 , ciPieceLength :: Int 181 , ciPieceLength :: !Int
181 , ciPieces :: ByteString 182 , ciPieces :: !ByteString
182 , ciPrivate :: Maybe Bool 183 , ciPrivate :: Maybe Bool
183 } deriving (Show, Read, Eq) 184 } deriving (Show, Read, Eq)
184 185
185 186
186-- | Contain info about one single file. 187-- | Contain info about one single file.
187data FileInfo = FileInfo { 188data FileInfo = FileInfo {
188 fiLength :: Integer 189 fiLength :: !Integer
189 -- ^ Length of the file in bytes. 190 -- ^ Length of the file in bytes.
190 191
191 , fiMD5sum :: Maybe ByteString 192 , fiMD5sum :: Maybe ByteString
192 -- ^ 32 character long MD5 sum of the file. 193 -- ^ 32 character long MD5 sum of the file.
193 -- Used by third-party tools, not by bittorrent protocol itself. 194 -- Used by third-party tools, not by bittorrent protocol itself.
194 195
195 , fiPath :: [ByteString] 196 , fiPath :: ![ByteString]
196 -- ^ One or more string elements that together represent the 197 -- ^ One or more string elements that together represent the
197 -- path and filename. Each element in the list corresponds to 198 -- path and filename. Each element in the list corresponds to
198 -- either a directory name or (in the case of the last 199 -- either a directory name or (in the case of the last
@@ -323,16 +324,18 @@ blockCount :: Int -- ^ Block size.
323 -> Int -- ^ Number of blocks. 324 -> Int -- ^ Number of blocks.
324blockCount blkSize ci = contentLength ci `sizeInBase` blkSize 325blockCount blkSize ci = contentLength ci `sizeInBase` blkSize
325 326
326-- | File layout specifies the order and the size of each file in the storage. 327-- | File layout specifies the order and the size of each file in the
327-- Note that order of files is highly important since we coalesce all 328-- storage. Note that order of files is highly important since we
328-- the files in the given order to get the linear block address space. 329-- coalesce all the files in the given order to get the linear block
330-- address space.
329-- 331--
330type Layout = [(FilePath, Int)] 332type Layout = [(FilePath, Int)]
331 333
332-- | Extract files layout from torrent info with the given root path. 334-- | Extract files layout from torrent info with the given root path.
333contentLayout :: FilePath -- ^ Root path for the all torrent files. 335contentLayout :: FilePath -- ^ Root path for the all torrent files.
334 -> ContentInfo -- ^ Torrent content information. 336 -> ContentInfo -- ^ Torrent content information.
335 -> Layout -- ^ The all file paths prefixed with the given root. 337 -> Layout -- ^ The all file paths prefixed with the
338 -- given root.
336contentLayout rootPath = filesLayout 339contentLayout rootPath = filesLayout
337 where 340 where
338 filesLayout (SingleFile { ciName = name, ciLength = len }) 341 filesLayout (SingleFile { ciName = name, ciLength = len })
@@ -356,7 +359,11 @@ isMultiFile _ = False
356 359
357-- | Read and decode a .torrent file. 360-- | Read and decode a .torrent file.
358fromFile :: FilePath -> IO Torrent 361fromFile :: FilePath -> IO Torrent
359fromFile = B.readFile >=> either (throwIO . userError) return . decoded 362fromFile path = do
363 contents <- B.readFile path
364 case decoded contents of
365 Right !t -> return t
366 Left msg -> throwIO $ userError $ msg ++ " while reading torrent"
360 367
361{----------------------------------------------------------------------- 368{-----------------------------------------------------------------------
362 Info hash 369 Info hash
diff --git a/src/Network/BitTorrent/Exchange/Protocol.hs b/src/Network/BitTorrent/Exchange/Protocol.hs
index 6b97d8d1..d2d3da6c 100644
--- a/src/Network/BitTorrent/Exchange/Protocol.hs
+++ b/src/Network/BitTorrent/Exchange/Protocol.hs
@@ -181,7 +181,7 @@ handshake sock hs = do
181 181
182 case checkIH (S.decode resp) of 182 case checkIH (S.decode resp) of
183 Right hs' -> return hs' 183 Right hs' -> return hs'
184 Left msg -> throw $ userError msg 184 Left msg -> throwIO $ userError $ msg ++ " in handshake body."
185 where 185 where
186 checkIH (Right hs') 186 checkIH (Right hs')
187 | hsInfoHash hs /= hsInfoHash hs' 187 | hsInfoHash hs /= hsInfoHash hs'
@@ -234,10 +234,10 @@ ppBlockIx BlockIx {..} =
234 234
235data Block = Block { 235data Block = Block {
236 -- | Zero-based piece index. 236 -- | Zero-based piece index.
237 blkPiece :: !PieceLIx 237 blkPiece :: {-# UNPACK #-} !PieceLIx
238 238
239 -- | Zero-based byte offset within the piece. 239 -- | Zero-based byte offset within the piece.
240 , blkOffset :: !Int 240 , blkOffset :: {-# UNPACK #-} !Int
241 241
242 -- | Payload. 242 -- | Payload.
243 , blkData :: !ByteString 243 , blkData :: !ByteString
diff --git a/src/Network/BitTorrent/Tracker.hs b/src/Network/BitTorrent/Tracker.hs
index cb776431..e1f9ff76 100644
--- a/src/Network/BitTorrent/Tracker.hs
+++ b/src/Network/BitTorrent/Tracker.hs
@@ -172,6 +172,7 @@ withTracker initProgress conn action = bracket start end (action . fst)
172 where 172 where
173 start = do 173 start = do
174 resp <- askTracker (startedReq conn initProgress) 174 resp <- askTracker (startedReq conn initProgress)
175 print resp
175 se <- newSession initProgress (respInterval resp) (respPeers resp) 176 se <- newSession initProgress (respInterval resp) (respPeers resp)
176 tid <- forkIO (syncSession se) 177 tid <- forkIO (syncSession se)
177 return (se, tid) 178 return (se, tid)
@@ -179,10 +180,13 @@ withTracker initProgress conn action = bracket start end (action . fst)
179 syncSession se @ TSession {..} = forever $ do 180 syncSession se @ TSession {..} = forever $ do
180 waitInterval se 181 waitInterval se
181 pr <- getProgress se 182 pr <- getProgress se
183 print "tracker req"
182 resp <- tryJust isIOException $ do 184 resp <- tryJust isIOException $ do
183 askTracker (regularReq defaultNumWant conn pr) 185 askTracker (regularReq defaultNumWant conn pr)
186 print "tracker resp"
184 case resp of 187 case resp of
185 Right (OK {..}) -> do 188 Right (ok @ OK {..}) -> do
189 print ok
186 writeIORef seInterval respInterval 190 writeIORef seInterval respInterval
187 writeList2Chan sePeers respPeers 191 writeList2Chan sePeers respPeers
188 _ -> return () 192 _ -> return ()
diff --git a/src/Network/BitTorrent/Tracker/Protocol.hs b/src/Network/BitTorrent/Tracker/Protocol.hs
index c94a2dfc..13127e7c 100644
--- a/src/Network/BitTorrent/Tracker/Protocol.hs
+++ b/src/Network/BitTorrent/Tracker/Protocol.hs
@@ -67,28 +67,28 @@ data Event = Started
67-- to keep track lists of active peer for a particular torrent. 67-- to keep track lists of active peer for a particular torrent.
68-- 68--
69data TRequest = TRequest { -- TODO peer here -- TODO detach announce 69data TRequest = TRequest { -- TODO peer here -- TODO detach announce
70 reqAnnounce :: URI 70 reqAnnounce :: !URI
71 -- ^ Announce url of the torrent usually obtained from 'Torrent'. 71 -- ^ Announce url of the torrent usually obtained from 'Torrent'.
72 72
73 , reqInfoHash :: InfoHash 73 , reqInfoHash :: !InfoHash
74 -- ^ Hash of info part of the torrent usually obtained from 74 -- ^ Hash of info part of the torrent usually obtained from
75 -- 'Torrent'. 75 -- 'Torrent'.
76 76
77 , reqPeerID :: PeerID 77 , reqPeerID :: !PeerID
78 -- ^ ID of the peer doing request. 78 -- ^ ID of the peer doing request.
79 79
80 , reqPort :: PortNumber 80 , reqPort :: !PortNumber
81 -- ^ Port to listen to for connections from other 81 -- ^ Port to listen to for connections from other
82 -- peers. Normally, tracker should respond with this port when 82 -- peers. Normally, tracker should respond with this port when
83 -- some peer request the tracker with the same info hash. 83 -- some peer request the tracker with the same info hash.
84 84
85 , reqUploaded :: Integer 85 , reqUploaded :: !Integer
86 -- ^ Number of bytes that the peer has uploaded in the swarm. 86 -- ^ Number of bytes that the peer has uploaded in the swarm.
87 87
88 , reqDownloaded :: Integer 88 , reqDownloaded :: !Integer
89 -- ^ Number of bytes downloaded in the swarm by the peer. 89 -- ^ Number of bytes downloaded in the swarm by the peer.
90 90
91 , reqLeft :: Integer 91 , reqLeft :: !Integer
92 -- ^ Number of bytes needed in order to complete download. 92 -- ^ Number of bytes needed in order to complete download.
93 93
94 , reqIP :: Maybe HostAddress 94 , reqIP :: Maybe HostAddress
@@ -111,25 +111,25 @@ data TRequest = TRequest { -- TODO peer here -- TODO detach announce
111data TResponse = 111data TResponse =
112 Failure Text -- ^ Failure reason in human readable form. 112 Failure Text -- ^ Failure reason in human readable form.
113 | OK { 113 | OK {
114 respWarning :: Maybe Text 114 respWarning :: Maybe Text
115 -- ^ Human readable warning. 115 -- ^ Human readable warning.
116 116
117 , respInterval :: Int 117 , respInterval :: !Int
118 -- ^ Recommended interval to wait between requests. 118 -- ^ Recommended interval to wait between requests.
119 119
120 , respMinInterval :: Maybe Int 120 , respMinInterval :: Maybe Int
121 -- ^ Minimal amount of time between requests. A peer /should/ 121 -- ^ Minimal amount of time between requests. A peer /should/
122 -- make timeout with at least 'respMinInterval' value, 122 -- make timeout with at least 'respMinInterval' value,
123 -- otherwise tracker might not respond. If not specified the 123 -- otherwise tracker might not respond. If not specified the
124 -- same applies to 'respInterval'. 124 -- same applies to 'respInterval'.
125 125
126 , respComplete :: Maybe Int 126 , respComplete :: Maybe Int
127 -- ^ Number of peers completed the torrent. (seeders) 127 -- ^ Number of peers completed the torrent. (seeders)
128 128
129 , respIncomplete :: Maybe Int 129 , respIncomplete :: Maybe Int
130 -- ^ Number of peers downloading the torrent. (leechers) 130 -- ^ Number of peers downloading the torrent. (leechers)
131 131
132 , respPeers :: [PeerAddr] 132 , respPeers :: ![PeerAddr]
133 -- ^ Peers that must be contacted. 133 -- ^ Peers that must be contacted.
134 } deriving Show 134 } deriving Show
135 135
@@ -227,11 +227,14 @@ askTracker req = do
227 227
228 rawResp <- simpleHTTP r 228 rawResp <- simpleHTTP r
229 respBody <- getResponseBody rawResp 229 respBody <- getResponseBody rawResp
230 print $ respBody
230 checkResult $ decoded respBody 231 checkResult $ decoded respBody
231 where 232 where
232 mkHTTPRequest :: URI -> Request ByteString 233 mkHTTPRequest :: URI -> Request ByteString
233 mkHTTPRequest uri = Request uri GET [] "" 234 mkHTTPRequest uri = Request uri GET [] ""
234 235
235 checkResult (Left err) = ioError (userError err) 236 checkResult (Left err)
236 checkResult (Right (Failure err)) = ioError (userError (show err)) 237 = ioError $ userError $ err ++ " in tracker response"
238 checkResult (Right (Failure err))
239 = ioError $ userError $ show err ++ " in tracker response"
237 checkResult (Right resp) = return resp 240 checkResult (Right resp) = return resp