summaryrefslogtreecommitdiff
path: root/src/Network/BitTorrent
diff options
context:
space:
mode:
authorSam T <pxqr.sta@gmail.com>2013-06-30 21:24:06 +0400
committerSam T <pxqr.sta@gmail.com>2013-06-30 21:24:06 +0400
commit7641ea42ed7c35d9babfe270e5a93dd8cb4922ae (patch)
tree017d17163dab0236c75cf947bab08125399b7df3 /src/Network/BitTorrent
parent03197ae3eead914726c259f40ff53d275c39e0e2 (diff)
+ Add instances for Binary.
Diffstat (limited to 'src/Network/BitTorrent')
-rw-r--r--src/Network/BitTorrent/Exchange/Protocol.hs162
1 files changed, 122 insertions, 40 deletions
diff --git a/src/Network/BitTorrent/Exchange/Protocol.hs b/src/Network/BitTorrent/Exchange/Protocol.hs
index 4cf4685d..83774f06 100644
--- a/src/Network/BitTorrent/Exchange/Protocol.hs
+++ b/src/Network/BitTorrent/Exchange/Protocol.hs
@@ -72,9 +72,14 @@ import qualified Data.ByteString as B
72import qualified Data.ByteString.Char8 as BC 72import qualified Data.ByteString.Char8 as BC
73import qualified Data.ByteString.Lazy as Lazy 73import qualified Data.ByteString.Lazy as Lazy
74import Data.Default 74import Data.Default
75import Data.Serialize as S
76import Data.Int 75import Data.Int
77import Data.Word 76import Data.Word
77
78import Data.Binary as B
79import Data.Binary.Get as B
80import Data.Binary.Put as B
81import Data.Serialize as S
82
78import Text.PrettyPrint 83import Text.PrettyPrint
79 84
80import Network 85import Network
@@ -117,18 +122,18 @@ data Handshake = Handshake {
117 122
118instance Serialize Handshake where 123instance Serialize Handshake where
119 put hs = do 124 put hs = do
120 putWord8 (fromIntegral (B.length (hsProtocol hs))) 125 S.putWord8 (fromIntegral (B.length (hsProtocol hs)))
121 putByteString (hsProtocol hs) 126 S.putByteString (hsProtocol hs)
122 putWord64be (hsReserved hs) 127 S.putWord64be (hsReserved hs)
123 put (hsInfoHash hs) 128 S.put (hsInfoHash hs)
124 put (hsPeerID hs) 129 S.put (hsPeerID hs)
125 130
126 get = do 131 get = do
127 len <- getWord8 132 len <- S.getWord8
128 Handshake <$> getBytes (fromIntegral len) 133 Handshake <$> S.getBytes (fromIntegral len)
129 <*> getWord64be 134 <*> S.getWord64be
130 <*> get 135 <*> S.get
131 <*> get 136 <*> S.get
132 137
133-- | Extract capabilities from a peer handshake message. 138-- | Extract capabilities from a peer handshake message.
134handshakeCaps :: Handshake -> Capabilities 139handshakeCaps :: Handshake -> Capabilities
@@ -204,14 +209,22 @@ data BlockIx = BlockIx {
204 , ixLength :: {-# UNPACK #-} !Int 209 , ixLength :: {-# UNPACK #-} !Int
205 } deriving (Show, Eq) 210 } deriving (Show, Eq)
206 211
207getInt :: Get Int 212getInt :: S.Get Int
208getInt = fromIntegral <$> getWord32be 213getInt = fromIntegral <$> S.getWord32be
209{-# INLINE getInt #-} 214{-# INLINE getInt #-}
210 215
211putInt :: Putter Int 216putInt :: S.Putter Int
212putInt = putWord32be . fromIntegral 217putInt = S.putWord32be . fromIntegral
213{-# INLINE putInt #-} 218{-# INLINE putInt #-}
214 219
220getIntB :: B.Get Int
221getIntB = fromIntegral <$> B.getWord32be
222{-# INLINE getIntB #-}
223
224putIntB :: Int -> B.Put
225putIntB = B.putWord32be . fromIntegral
226{-# INLINE putIntB #-}
227
215instance Serialize BlockIx where 228instance Serialize BlockIx where
216 {-# SPECIALIZE instance Serialize BlockIx #-} 229 {-# SPECIALIZE instance Serialize BlockIx #-}
217 get = BlockIx <$> getInt <*> getInt <*> getInt 230 get = BlockIx <$> getInt <*> getInt <*> getInt
@@ -222,6 +235,16 @@ instance Serialize BlockIx where
222 putInt (ixLength i) 235 putInt (ixLength i)
223 {-# INLINE put #-} 236 {-# INLINE put #-}
224 237
238instance Binary BlockIx where
239 {-# SPECIALIZE instance Binary BlockIx #-}
240 get = BlockIx <$> getIntB <*> getIntB <*> getIntB
241 {-# INLINE get #-}
242
243 put BlockIx {..} = do
244 putIntB ixPiece
245 putIntB ixOffset
246 putIntB ixLength
247
225-- | Format block index in human readable form. 248-- | Format block index in human readable form.
226ppBlockIx :: BlockIx -> Doc 249ppBlockIx :: BlockIx -> Doc
227ppBlockIx BlockIx {..} = 250ppBlockIx BlockIx {..} =
@@ -355,61 +378,120 @@ instance Serialize Message where
355-- _ <- lookAhead $ ensure len 378-- _ <- lookAhead $ ensure len
356 if len == 0 then return KeepAlive 379 if len == 0 then return KeepAlive
357 else do 380 else do
358 mid <- getWord8 381 mid <- S.getWord8
359 case mid of 382 case mid of
360 0x00 -> return Choke 383 0x00 -> return Choke
361 0x01 -> return Unchoke 384 0x01 -> return Unchoke
362 0x02 -> return Interested 385 0x02 -> return Interested
363 0x03 -> return NotInterested 386 0x03 -> return NotInterested
364 0x04 -> Have <$> getInt 387 0x04 -> Have <$> getInt
365 0x05 -> (Bitfield . fromBitmap) <$> getByteString (pred len) 388 0x05 -> (Bitfield . fromBitmap) <$> S.getByteString (pred len)
366 0x06 -> Request <$> get 389 0x06 -> Request <$> S.get
367 0x07 -> Piece <$> getBlock (len - 9) 390 0x07 -> Piece <$> getBlock (len - 9)
368 0x08 -> Cancel <$> get 391 0x08 -> Cancel <$> S.get
369 0x09 -> (Port . fromIntegral) <$> getWord16be 392 0x09 -> (Port . fromIntegral) <$> S.getWord16be
370 0x0E -> return HaveAll 393 0x0E -> return HaveAll
371 0x0F -> return HaveNone 394 0x0F -> return HaveNone
372 0x0D -> SuggestPiece <$> getInt 395 0x0D -> SuggestPiece <$> getInt
373 0x10 -> RejectRequest <$> get 396 0x10 -> RejectRequest <$> S.get
374 0x11 -> AllowedFast <$> getInt 397 0x11 -> AllowedFast <$> getInt
375 _ -> do 398 _ -> do
376 rm <- remaining >>= getBytes 399 rm <- S.remaining >>= S.getBytes
377 fail $ "unknown message ID: " ++ show mid ++ "\n" 400 fail $ "unknown message ID: " ++ show mid ++ "\n"
378 ++ "remaining available bytes: " ++ show rm 401 ++ "remaining available bytes: " ++ show rm
379 402
380 where 403 where
381 getBlock :: Int -> Get Block 404 getBlock :: Int -> S.Get Block
382 getBlock len = Block <$> getInt <*> getInt <*> getBytes len 405 getBlock len = Block <$> getInt <*> getInt <*> S.getBytes len
383 {-# INLINE getBlock #-} 406 {-# INLINE getBlock #-}
384 407
385 408
386 put KeepAlive = putInt 0 409 put KeepAlive = putInt 0
387 put Choke = putInt 1 >> putWord8 0x00 410 put Choke = putInt 1 >> S.putWord8 0x00
388 put Unchoke = putInt 1 >> putWord8 0x01 411 put Unchoke = putInt 1 >> S.putWord8 0x01
389 put Interested = putInt 1 >> putWord8 0x02 412 put Interested = putInt 1 >> S.putWord8 0x02
390 put NotInterested = putInt 1 >> putWord8 0x03 413 put NotInterested = putInt 1 >> S.putWord8 0x03
391 put (Have i) = putInt 5 >> putWord8 0x04 >> putInt i 414 put (Have i) = putInt 5 >> S.putWord8 0x04 >> putInt i
392 put (Bitfield bf) = putInt l >> putWord8 0x05 >> putLazyByteString b 415 put (Bitfield bf) = putInt l >> S.putWord8 0x05 >> S.putLazyByteString b
393 where b = toBitmap bf 416 where b = toBitmap bf
394 l = succ (fromIntegral (Lazy.length b)) 417 l = succ (fromIntegral (Lazy.length b))
395 {-# INLINE l #-} 418 {-# INLINE l #-}
396 put (Request blk) = putInt 13 >> putWord8 0x06 >> put blk 419 put (Request blk) = putInt 13 >> S.putWord8 0x06 >> S.put blk
397 put (Piece blk) = putInt l >> putWord8 0x07 >> putBlock 420 put (Piece blk) = putInt l >> S.putWord8 0x07 >> putBlock
398 where l = 9 + B.length (blkData blk) 421 where l = 9 + B.length (blkData blk)
399 {-# INLINE l #-} 422 {-# INLINE l #-}
400 putBlock = do putInt (blkPiece blk) 423 putBlock = do putInt (blkPiece blk)
401 putInt (blkOffset blk) 424 putInt (blkOffset blk)
402 putByteString (blkData blk) 425 S.putByteString (blkData blk)
403 {-# INLINE putBlock #-} 426 {-# INLINE putBlock #-}
404 427
405 put (Cancel blk) = putInt 13 >> putWord8 0x08 >> put blk 428 put (Cancel blk) = putInt 13 >> S.putWord8 0x08 >> S.put blk
406 put (Port p ) = putInt 3 >> putWord8 0x09 >> putWord16be (fromIntegral p) 429 put (Port p ) = putInt 3 >> S.putWord8 0x09 >> S.putWord16be (fromIntegral p)
407 put HaveAll = putInt 1 >> putWord8 0x0E 430 put HaveAll = putInt 1 >> S.putWord8 0x0E
408 put HaveNone = putInt 1 >> putWord8 0x0F 431 put HaveNone = putInt 1 >> S.putWord8 0x0F
409 put (SuggestPiece pix) = putInt 5 >> putWord8 0x0D >> putInt pix 432 put (SuggestPiece pix) = putInt 5 >> S.putWord8 0x0D >> putInt pix
410 put (RejectRequest i ) = putInt 13 >> putWord8 0x10 >> put i 433 put (RejectRequest i ) = putInt 13 >> S.putWord8 0x10 >> S.put i
411 put (AllowedFast i ) = putInt 5 >> putWord8 0x11 >> putInt i 434 put (AllowedFast i ) = putInt 5 >> S.putWord8 0x11 >> putInt i
435
436instance Binary Message where
437 get = do
438 len <- undefined --getInt
439-- _ <- lookAhead $ ensure len
440 if len == 0 then return KeepAlive
441 else do
442 mid <- B.getWord8
443 case mid of
444 0x00 -> return Choke
445 0x01 -> return Unchoke
446 0x02 -> return Interested
447 0x03 -> return NotInterested
448 0x04 -> Have <$> getIntB
449 0x05 -> (Bitfield . fromBitmap) <$> B.getByteString (pred len)
450 0x06 -> Request <$> B.get
451 0x07 -> Piece <$> getBlock (len - 9)
452 0x08 -> Cancel <$> B.get
453 0x09 -> (Port . fromIntegral) <$> B.getWord16be
454 0x0E -> return HaveAll
455 0x0F -> return HaveNone
456 0x0D -> SuggestPiece <$> getIntB
457 0x10 -> RejectRequest <$> B.get
458 0x11 -> AllowedFast <$> getIntB
459 _ -> do
460 rm <- B.remaining >>= B.getBytes . fromIntegral
461 fail $ "unknown message ID: " ++ show mid ++ "\n"
462 ++ "remaining available bytes: " ++ show rm
463
464 where
465 getBlock :: Int -> B.Get Block
466 getBlock len = Block <$> getIntB <*> getIntB <*> B.getBytes len
467 {-# INLINE getBlock #-}
468
469 put KeepAlive = putIntB 0
470 put Choke = putIntB 1 >> B.putWord8 0x00
471 put Unchoke = putIntB 1 >> B.putWord8 0x01
472 put Interested = putIntB 1 >> B.putWord8 0x02
473 put NotInterested = putIntB 1 >> B.putWord8 0x03
474 put (Have i) = putIntB 5 >> B.putWord8 0x04 >> putIntB i
475 put (Bitfield bf) = putIntB l >> B.putWord8 0x05 >> B.putLazyByteString b
476 where b = toBitmap bf
477 l = succ (fromIntegral (Lazy.length b))
478 {-# INLINE l #-}
479 put (Request blk) = putIntB 13 >> B.putWord8 0x06 >> B.put blk
480 put (Piece blk) = putIntB l >> B.putWord8 0x07 >> putBlock
481 where l = 9 + B.length (blkData blk)
482 {-# INLINE l #-}
483 putBlock = do putIntB (blkPiece blk)
484 putIntB (blkOffset blk)
485 B.putByteString (blkData blk)
486 {-# INLINE putBlock #-}
412 487
488 put (Cancel blk) = putIntB 13 >> B.putWord8 0x08 >> B.put blk
489 put (Port p ) = putIntB 3 >> B.putWord8 0x09 >> B.putWord16be (fromIntegral p)
490 put HaveAll = putIntB 1 >> B.putWord8 0x0E
491 put HaveNone = putIntB 1 >> B.putWord8 0x0F
492 put (SuggestPiece pix) = putIntB 5 >> B.putWord8 0x0D >> putIntB pix
493 put (RejectRequest i ) = putIntB 13 >> B.putWord8 0x10 >> B.put i
494 put (AllowedFast i ) = putIntB 5 >> B.putWord8 0x11 >> putIntB i
413 495
414-- | Format messages in human readable form. Note that output is 496-- | Format messages in human readable form. Note that output is
415-- compact and suitable for logging: only useful information but not 497-- compact and suitable for logging: only useful information but not