diff options
author | Sam Truzjan <pxqr.sta@gmail.com> | 2013-11-27 13:32:19 +0400 |
---|---|---|
committer | Sam Truzjan <pxqr.sta@gmail.com> | 2013-11-27 13:32:19 +0400 |
commit | 2bd418d50f7f0dd5ff1db7e65a7727ed22edb4fe (patch) | |
tree | a69cd99e816ccdf64ec7afd80f6ea94f012dfa75 /src/Network/BitTorrent/Exchange | |
parent | c95d9bb584d928c2aaa9b96b0be6ff70e75ce1fd (diff) |
Use Pretty class in exchange protocol
Diffstat (limited to 'src/Network/BitTorrent/Exchange')
-rw-r--r-- | src/Network/BitTorrent/Exchange/Protocol.hs | 98 |
1 files changed, 51 insertions, 47 deletions
diff --git a/src/Network/BitTorrent/Exchange/Protocol.hs b/src/Network/BitTorrent/Exchange/Protocol.hs index 4db1e315..7af99335 100644 --- a/src/Network/BitTorrent/Exchange/Protocol.hs +++ b/src/Network/BitTorrent/Exchange/Protocol.hs | |||
@@ -29,17 +29,20 @@ | |||
29 | {-# OPTIONS -fno-warn-orphans #-} | 29 | {-# OPTIONS -fno-warn-orphans #-} |
30 | module Network.BitTorrent.Exchange.Protocol | 30 | module Network.BitTorrent.Exchange.Protocol |
31 | ( -- * Initial handshake | 31 | ( -- * Initial handshake |
32 | Handshake(..), ppHandshake | 32 | Handshake(..) |
33 | , handshake, handshakeCaps | 33 | , handshake |
34 | , recvHandshake, sendHandshake | 34 | , handshakeCaps |
35 | , recvHandshake | ||
36 | , sendHandshake | ||
35 | 37 | ||
36 | -- ** Defaults | 38 | -- ** Defaults |
37 | , defaultHandshake, defaultBTProtocol, defaultReserved | 39 | , defaultHandshake |
40 | , defaultBTProtocol | ||
41 | , defaultReserved | ||
38 | , handshakeMaxSize | 42 | , handshakeMaxSize |
39 | 43 | ||
40 | -- * Regular messages | 44 | -- * Regular messages |
41 | , Message(..) | 45 | , Message(..) |
42 | , ppMessage | ||
43 | 46 | ||
44 | -- * control | 47 | -- * control |
45 | , PeerStatus(..) | 48 | , PeerStatus(..) |
@@ -58,31 +61,29 @@ import Control.Applicative | |||
58 | import Control.Exception | 61 | import Control.Exception |
59 | import Control.Monad | 62 | import Control.Monad |
60 | import Control.Lens | 63 | import Control.Lens |
61 | |||
62 | import Data.Aeson.TH | 64 | import Data.Aeson.TH |
63 | import Data.ByteString (ByteString) | ||
64 | import qualified Data.ByteString as B | ||
65 | import qualified Data.ByteString.Char8 as BC | ||
66 | import qualified Data.ByteString.Lazy as Lazy | ||
67 | import Data.Default | ||
68 | import Data.List as L | ||
69 | import Data.Word | ||
70 | |||
71 | import Data.Binary as B | 65 | import Data.Binary as B |
72 | import Data.Binary.Get as B | 66 | import Data.Binary.Get as B |
73 | import Data.Binary.Put as B | 67 | import Data.Binary.Put as B |
68 | import Data.ByteString as BS | ||
69 | import Data.ByteString.Char8 as BC | ||
70 | import Data.ByteString.Lazy as BL | ||
71 | import Data.Default | ||
72 | import Data.List as L | ||
74 | import Data.Serialize as S | 73 | import Data.Serialize as S |
75 | 74 | import Data.Word | |
76 | import Text.PrettyPrint | ||
77 | |||
78 | import Network | 75 | import Network |
79 | import Network.Socket.ByteString | 76 | import Network.Socket.ByteString |
77 | import Text.PrettyPrint | ||
78 | import Text.PrettyPrint.Class | ||
80 | 79 | ||
81 | import Data.Torrent.Bitfield | 80 | import Data.Torrent.Bitfield |
82 | import Data.Torrent.Block | 81 | import Data.Torrent.Block |
82 | import Data.Torrent.InfoHash | ||
83 | import Data.Torrent | 83 | import Data.Torrent |
84 | import Network.BitTorrent.Extension | 84 | import Network.BitTorrent.Extension |
85 | import Network.BitTorrent.Peer | 85 | import Network.BitTorrent.Core.PeerId |
86 | import Network.BitTorrent.Core.PeerAddr | ||
86 | 87 | ||
87 | 88 | ||
88 | getInt :: S.Get Int | 89 | getInt :: S.Get Int |
@@ -110,7 +111,7 @@ putIntB = B.putWord32be . fromIntegral | |||
110 | -- | 111 | -- |
111 | data Handshake = Handshake { | 112 | data Handshake = Handshake { |
112 | -- | Identifier of the protocol. | 113 | -- | Identifier of the protocol. |
113 | hsProtocol :: ByteString | 114 | hsProtocol :: BS.ByteString |
114 | 115 | ||
115 | -- | Reserved bytes used to specify supported BEP's. | 116 | -- | Reserved bytes used to specify supported BEP's. |
116 | , hsReserved :: Capabilities | 117 | , hsReserved :: Capabilities |
@@ -131,7 +132,7 @@ data Handshake = Handshake { | |||
131 | 132 | ||
132 | instance Serialize Handshake where | 133 | instance Serialize Handshake where |
133 | put hs = do | 134 | put hs = do |
134 | S.putWord8 (fromIntegral (B.length (hsProtocol hs))) | 135 | S.putWord8 (fromIntegral (BS.length (hsProtocol hs))) |
135 | S.putByteString (hsProtocol hs) | 136 | S.putByteString (hsProtocol hs) |
136 | S.putWord64be (hsReserved hs) | 137 | S.putWord64be (hsReserved hs) |
137 | S.put (hsInfoHash hs) | 138 | S.put (hsInfoHash hs) |
@@ -144,14 +145,14 @@ instance Serialize Handshake where | |||
144 | <*> S.get | 145 | <*> S.get |
145 | <*> S.get | 146 | <*> S.get |
146 | 147 | ||
148 | instance Pretty Handshake where | ||
149 | pretty Handshake {..} | ||
150 | = text (BC.unpack hsProtocol) <+> pretty (clientInfo hsPeerId) | ||
151 | |||
147 | -- | Extract capabilities from a peer handshake message. | 152 | -- | Extract capabilities from a peer handshake message. |
148 | handshakeCaps :: Handshake -> Capabilities | 153 | handshakeCaps :: Handshake -> Capabilities |
149 | handshakeCaps = hsReserved | 154 | handshakeCaps = hsReserved |
150 | 155 | ||
151 | -- | Format handshake in human readable form. | ||
152 | ppHandshake :: Handshake -> Doc | ||
153 | ppHandshake Handshake {..} = | ||
154 | text (BC.unpack hsProtocol) <+> ppClientInfo (clientInfo hsPeerId) | ||
155 | 156 | ||
156 | -- | Get handshake message size in bytes from the length of protocol | 157 | -- | Get handshake message size in bytes from the length of protocol |
157 | -- string. | 158 | -- string. |
@@ -163,7 +164,7 @@ handshakeMaxSize :: Int | |||
163 | handshakeMaxSize = handshakeSize 255 | 164 | handshakeMaxSize = handshakeSize 255 |
164 | 165 | ||
165 | -- | Default protocol string "BitTorrent protocol" as is. | 166 | -- | Default protocol string "BitTorrent protocol" as is. |
166 | defaultBTProtocol :: ByteString | 167 | defaultBTProtocol :: BS.ByteString |
167 | defaultBTProtocol = "BitTorrent protocol" | 168 | defaultBTProtocol = "BitTorrent protocol" |
168 | 169 | ||
169 | -- | Default reserved word is 0. | 170 | -- | Default reserved word is 0. |
@@ -181,14 +182,14 @@ sendHandshake sock hs = sendAll sock (S.encode hs) | |||
181 | recvHandshake :: Socket -> IO Handshake | 182 | recvHandshake :: Socket -> IO Handshake |
182 | recvHandshake sock = do | 183 | recvHandshake sock = do |
183 | header <- recv sock 1 | 184 | header <- recv sock 1 |
184 | unless (B.length header == 1) $ | 185 | unless (BS.length header == 1) $ |
185 | throw $ userError "Unable to receive handshake header." | 186 | throw $ userError "Unable to receive handshake header." |
186 | 187 | ||
187 | let protocolLen = B.head header | 188 | let protocolLen = BS.head header |
188 | let restLen = handshakeSize protocolLen - 1 | 189 | let restLen = handshakeSize protocolLen - 1 |
189 | 190 | ||
190 | body <- recv sock restLen | 191 | body <- recv sock restLen |
191 | let resp = B.cons protocolLen body | 192 | let resp = BS.cons protocolLen body |
192 | either (throwIO . userError) return $ S.decode resp | 193 | either (throwIO . userError) return $ S.decode resp |
193 | 194 | ||
194 | -- | Handshaking with a peer specified by the second argument. | 195 | -- | Handshaking with a peer specified by the second argument. |
@@ -211,6 +212,7 @@ handshake sock hs = do | |||
211 | -- extension then the client MUST close the connection. | 212 | -- extension then the client MUST close the connection. |
212 | -- | 213 | -- |
213 | data Message = KeepAlive | 214 | data Message = KeepAlive |
215 | -- TODO data PeerStatusUpdate = Choke | Unchoke | Interested | NotInterested | ||
214 | | Choke | 216 | | Choke |
215 | | Unchoke | 217 | | Unchoke |
216 | | Interested | 218 | | Interested |
@@ -232,7 +234,7 @@ data Message = KeepAlive | |||
232 | | Request !BlockIx | 234 | | Request !BlockIx |
233 | 235 | ||
234 | -- | Response for a request for a block. | 236 | -- | Response for a request for a block. |
235 | | Piece !Block | 237 | | Piece !(Block BL.ByteString) |
236 | 238 | ||
237 | -- | Used to cancel block requests. It is typically | 239 | -- | Used to cancel block requests. It is typically |
238 | -- used during "End Game". | 240 | -- used during "End Game". |
@@ -240,6 +242,7 @@ data Message = KeepAlive | |||
240 | 242 | ||
241 | | Port !PortNumber | 243 | | Port !PortNumber |
242 | 244 | ||
245 | -- TODO data FastMessage = HaveAll | HaveNone | ... | ||
243 | -- | BEP 6: Then peer have all pieces it might send the | 246 | -- | BEP 6: Then peer have all pieces it might send the |
244 | -- 'HaveAll' message instead of 'Bitfield' | 247 | -- 'HaveAll' message instead of 'Bitfield' |
245 | -- message. Used to save bandwidth. | 248 | -- message. Used to save bandwidth. |
@@ -265,6 +268,19 @@ data Message = KeepAlive | |||
265 | | AllowedFast !PieceIx | 268 | | AllowedFast !PieceIx |
266 | deriving (Show, Eq) | 269 | deriving (Show, Eq) |
267 | 270 | ||
271 | instance Default Message where | ||
272 | def = KeepAlive | ||
273 | {-# INLINE def #-} | ||
274 | |||
275 | -- | Payload bytes are omitted. | ||
276 | instance Pretty Message where | ||
277 | pretty (Bitfield _) = "Bitfield" | ||
278 | pretty (Piece blk) = "Piece" <+> pretty blk | ||
279 | pretty (Cancel i ) = "Cancel" <+> pretty i | ||
280 | pretty (SuggestPiece pix) = "Suggest" <+> int pix | ||
281 | pretty (RejectRequest i ) = "Reject" <+> pretty i | ||
282 | pretty msg = text (show msg) | ||
283 | |||
268 | instance Serialize Message where | 284 | instance Serialize Message where |
269 | get = do | 285 | get = do |
270 | len <- getInt | 286 | len <- getInt |
@@ -294,7 +310,7 @@ instance Serialize Message where | |||
294 | ++ "remaining available bytes: " ++ show rm | 310 | ++ "remaining available bytes: " ++ show rm |
295 | 311 | ||
296 | where | 312 | where |
297 | getBlock :: Int -> S.Get Block | 313 | getBlock :: Int -> S.Get (Block BL.ByteString) |
298 | getBlock len = Block <$> getInt <*> getInt <*> S.getLazyByteString (fromIntegral len) | 314 | getBlock len = Block <$> getInt <*> getInt <*> S.getLazyByteString (fromIntegral len) |
299 | {-# INLINE getBlock #-} | 315 | {-# INLINE getBlock #-} |
300 | 316 | ||
@@ -307,11 +323,11 @@ instance Serialize Message where | |||
307 | put (Have i) = putInt 5 >> S.putWord8 0x04 >> putInt i | 323 | put (Have i) = putInt 5 >> S.putWord8 0x04 >> putInt i |
308 | put (Bitfield bf) = putInt l >> S.putWord8 0x05 >> S.putLazyByteString b | 324 | put (Bitfield bf) = putInt l >> S.putWord8 0x05 >> S.putLazyByteString b |
309 | where b = toBitmap bf | 325 | where b = toBitmap bf |
310 | l = succ (fromIntegral (Lazy.length b)) | 326 | l = succ (fromIntegral (BL.length b)) |
311 | {-# INLINE l #-} | 327 | {-# INLINE l #-} |
312 | put (Request blk) = putInt 13 >> S.putWord8 0x06 >> S.put blk | 328 | put (Request blk) = putInt 13 >> S.putWord8 0x06 >> S.put blk |
313 | put (Piece blk) = putInt l >> S.putWord8 0x07 >> putBlock | 329 | put (Piece blk) = putInt l >> S.putWord8 0x07 >> putBlock |
314 | where l = 9 + fromIntegral (Lazy.length (blkData blk)) | 330 | where l = 9 + fromIntegral (BL.length (blkData blk)) |
315 | {-# INLINE l #-} | 331 | {-# INLINE l #-} |
316 | putBlock = do putInt (blkPiece blk) | 332 | putBlock = do putInt (blkPiece blk) |
317 | putInt (blkOffset blk) | 333 | putInt (blkOffset blk) |
@@ -351,7 +367,7 @@ instance Binary Message where | |||
351 | 0x11 -> AllowedFast <$> getIntB | 367 | 0x11 -> AllowedFast <$> getIntB |
352 | _ -> fail $ "unknown message ID: " ++ show mid | 368 | _ -> fail $ "unknown message ID: " ++ show mid |
353 | where | 369 | where |
354 | getBlock :: Int -> B.Get Block | 370 | getBlock :: Int -> B.Get (Block BL.ByteString) |
355 | getBlock len = Block <$> getIntB <*> getIntB | 371 | getBlock len = Block <$> getIntB <*> getIntB |
356 | <*> B.getLazyByteString (fromIntegral len) | 372 | <*> B.getLazyByteString (fromIntegral len) |
357 | {-# INLINE getBlock #-} | 373 | {-# INLINE getBlock #-} |
@@ -364,11 +380,11 @@ instance Binary Message where | |||
364 | put (Have i) = putIntB 5 >> B.putWord8 0x04 >> putIntB i | 380 | put (Have i) = putIntB 5 >> B.putWord8 0x04 >> putIntB i |
365 | put (Bitfield bf) = putIntB l >> B.putWord8 0x05 >> B.putLazyByteString b | 381 | put (Bitfield bf) = putIntB l >> B.putWord8 0x05 >> B.putLazyByteString b |
366 | where b = toBitmap bf | 382 | where b = toBitmap bf |
367 | l = succ (fromIntegral (Lazy.length b)) | 383 | l = succ (fromIntegral (BL.length b)) |
368 | {-# INLINE l #-} | 384 | {-# INLINE l #-} |
369 | put (Request blk) = putIntB 13 >> B.putWord8 0x06 >> B.put blk | 385 | put (Request blk) = putIntB 13 >> B.putWord8 0x06 >> B.put blk |
370 | put (Piece blk) = putIntB l >> B.putWord8 0x07 >> putBlock | 386 | put (Piece blk) = putIntB l >> B.putWord8 0x07 >> putBlock |
371 | where l = 9 + fromIntegral (Lazy.length (blkData blk)) | 387 | where l = 9 + fromIntegral (BL.length (blkData blk)) |
372 | {-# INLINE l #-} | 388 | {-# INLINE l #-} |
373 | putBlock = do putIntB (blkPiece blk) | 389 | putBlock = do putIntB (blkPiece blk) |
374 | putIntB (blkOffset blk) | 390 | putIntB (blkOffset blk) |
@@ -383,18 +399,6 @@ instance Binary Message where | |||
383 | put (RejectRequest i ) = putIntB 13 >> B.putWord8 0x10 >> B.put i | 399 | put (RejectRequest i ) = putIntB 13 >> B.putWord8 0x10 >> B.put i |
384 | put (AllowedFast i ) = putIntB 5 >> B.putWord8 0x11 >> putIntB i | 400 | put (AllowedFast i ) = putIntB 5 >> B.putWord8 0x11 >> putIntB i |
385 | 401 | ||
386 | -- | Format messages in human readable form. Note that output is | ||
387 | -- compact and suitable for logging: only useful information but not | ||
388 | -- payload bytes. | ||
389 | -- | ||
390 | ppMessage :: Message -> Doc | ||
391 | ppMessage (Bitfield _) = "Bitfield" | ||
392 | ppMessage (Piece blk) = "Piece" <+> ppBlock blk | ||
393 | ppMessage (Cancel i ) = "Cancel" <+> ppBlockIx i | ||
394 | ppMessage (SuggestPiece pix) = "Suggest" <+> int pix | ||
395 | ppMessage (RejectRequest i ) = "Reject" <+> ppBlockIx i | ||
396 | ppMessage msg = text (show msg) | ||
397 | |||
398 | {----------------------------------------------------------------------- | 402 | {----------------------------------------------------------------------- |
399 | Peer Status | 403 | Peer Status |
400 | -----------------------------------------------------------------------} | 404 | -----------------------------------------------------------------------} |