summaryrefslogtreecommitdiff
path: root/src/Network/BitTorrent
diff options
context:
space:
mode:
authorSam Truzjan <pxqr.sta@gmail.com>2013-12-07 03:19:45 +0400
committerSam Truzjan <pxqr.sta@gmail.com>2013-12-07 03:19:45 +0400
commitce5bf09a79da18cb7eccab359b1d80af5b304dda (patch)
tree2282710d40ed2b8118d741ecaf875f290b7acdf9 /src/Network/BitTorrent
parent100f8d432b550e3538941ab675d3ec0b3a082d77 (diff)
Decode extended metadata message
Diffstat (limited to 'src/Network/BitTorrent')
-rw-r--r--src/Network/BitTorrent/Exchange/Message.hs100
-rw-r--r--src/Network/BitTorrent/Exchange/Wire.hs2
2 files changed, 77 insertions, 25 deletions
diff --git a/src/Network/BitTorrent/Exchange/Message.hs b/src/Network/BitTorrent/Exchange/Message.hs
index 8f6e1a5a..af212c3b 100644
--- a/src/Network/BitTorrent/Exchange/Message.hs
+++ b/src/Network/BitTorrent/Exchange/Message.hs
@@ -73,6 +73,7 @@ module Network.BitTorrent.Exchange.Message
73 73
74 -- *** Metadata 74 -- *** Metadata
75 , ExtendedMetadata (..) 75 , ExtendedMetadata (..)
76 , metadataPieceSize
76 ) where 77 ) where
77 78
78import Control.Applicative 79import Control.Applicative
@@ -508,6 +509,9 @@ instance Capabilities ExtendedCaps where
508 allowed e (ExtendedCaps caps) = M.member e caps 509 allowed e (ExtendedCaps caps) = M.member e caps
509 {-# INLINE allowed #-} 510 {-# INLINE allowed #-}
510 511
512remoteMessageId :: ExtendedExtension -> ExtendedCaps -> ExtendedMessageId
513remoteMessageId ext = fromMaybe (extId ext) . M.lookup ext . extendedCaps
514
511{----------------------------------------------------------------------- 515{-----------------------------------------------------------------------
512-- Extended handshake 516-- Extended handshake
513-----------------------------------------------------------------------} 517-----------------------------------------------------------------------}
@@ -532,6 +536,11 @@ data ExtendedHandshake = ExtendedHandshake
532 -- message. 536 -- message.
533 , ehsCaps :: ExtendedCaps 537 , ehsCaps :: ExtendedCaps
534 538
539 -- | Size of 'Data.Torrent.InfoDict' in bytes. This field should
540 -- be added if ExtMetadata is enabled in current session /and/
541 -- peer have the torrent file.
542 , ehsMetadataSize :: Maybe Int
543
535 -- | Local TCP /listen/ port. Allows each side to learn about the 544 -- | Local TCP /listen/ port. Allows each side to learn about the
536 -- TCP port number of the other side. 545 -- TCP port number of the other side.
537 , ehsPort :: Maybe PortNumber 546 , ehsPort :: Maybe PortNumber
@@ -556,13 +565,14 @@ defaultQueueLength = 0
556 565
557-- | All fields are empty. 566-- | All fields are empty.
558instance Default ExtendedHandshake where 567instance Default ExtendedHandshake where
559 def = ExtendedHandshake def def def def def def 568 def = ExtendedHandshake def def def def def def def
560 569
561instance BEncode ExtendedHandshake where 570instance BEncode ExtendedHandshake where
562 toBEncode ExtendedHandshake {..} = toDict $ 571 toBEncode ExtendedHandshake {..} = toDict $
563 "ipv4" .=? ehsIPv4 -- FIXME invalid encoding 572 "ipv4" .=? ehsIPv4 -- FIXME invalid encoding
564 .: "ipv6" .=? ehsIPv6 -- FIXME invalid encoding 573 .: "ipv6" .=? ehsIPv6 -- FIXME invalid encoding
565 .: "m" .=! ehsCaps 574 .: "m" .=! ehsCaps
575 .: "metadata_size" .=? ehsMetadataSize
566 .: "p" .=? ehsPort 576 .: "p" .=? ehsPort
567 .: "reqq" .=? ehsQueueLength 577 .: "reqq" .=? ehsQueueLength
568 .: "v" .=? ehsVersion 578 .: "v" .=? ehsVersion
@@ -573,6 +583,7 @@ instance BEncode ExtendedHandshake where
573 <$>? "ipv4" 583 <$>? "ipv4"
574 <*>? "ipv6" 584 <*>? "ipv6"
575 <*>! "m" 585 <*>! "m"
586 <*>? "metadata_size"
576 <*>? "p" 587 <*>? "p"
577 <*>? "reqq" 588 <*>? "reqq"
578 <*>? "v" 589 <*>? "v"
@@ -591,56 +602,92 @@ instance PeerMessage ExtendedHandshake where
591-- | Set default values and the specified 'ExtendedCaps'. 602-- | Set default values and the specified 'ExtendedCaps'.
592nullExtendedHandshake :: ExtendedCaps -> ExtendedHandshake 603nullExtendedHandshake :: ExtendedCaps -> ExtendedHandshake
593nullExtendedHandshake caps = ExtendedHandshake 604nullExtendedHandshake caps = ExtendedHandshake
594 { ehsIPv4 = Nothing 605 { ehsIPv4 = Nothing
595 , ehsIPv6 = Nothing 606 , ehsIPv6 = Nothing
596 , ehsCaps = caps 607 , ehsCaps = caps
597 , ehsPort = Nothing 608 , ehsMetadataSize = Nothing
598 , ehsQueueLength = Just defaultQueueLength 609 , ehsPort = Nothing
599 , ehsVersion = Just $ T.pack $ render $ pretty libFingerprint 610 , ehsQueueLength = Just defaultQueueLength
611 , ehsVersion = Just $ T.pack $ render $ pretty libFingerprint
600 } 612 }
601 613
602{----------------------------------------------------------------------- 614{-----------------------------------------------------------------------
603-- Metadata exchange extension 615-- Metadata exchange extension
604-----------------------------------------------------------------------} 616-----------------------------------------------------------------------}
605 617
606type MetadataId = Int 618-- | A peer MUST verify that any piece it sends passes the info-hash
607 619-- verification. i.e. until the peer has the entire metadata, it
608metadataPieceSize :: Int 620-- cannot run SHA-1 to verify that it yields the same hash as the
609metadataPieceSize = 16 * 1024 621-- info-hash.
610 622--
611data ExtendedMetadata 623data ExtendedMetadata
624 -- | This message requests the a specified metadata piece. The
625 -- response to this message, from a peer supporting the extension,
626 -- is either a 'MetadataReject' or a 'MetadataData' message.
612 = MetadataRequest PieceIx 627 = MetadataRequest PieceIx
613 | MetadataData PieceIx Int 628
629 | MetadataData
630 { -- | FIXME add piece data
631 piece :: PieceIx
632
633 -- | This key has the same semantics as the 'ehsMetadataSize' in
634 -- the 'ExtendedHandshake' — it is size of the torrent info
635 -- dict.
636 , totalSize :: Int
637 }
638
639 -- | Peers that do not have the entire metadata MUST respond with
640 -- a reject message to any metadata request.
641 --
642 -- Clients MAY implement flood protection by rejecting request
643 -- messages after a certain number of them have been
644 -- served. Typically the number of pieces of metadata times a
645 -- factor.
614 | MetadataReject PieceIx 646 | MetadataReject PieceIx
647
648 -- | Reserved.
615 | MetadataUnknown BValue 649 | MetadataUnknown BValue
616 deriving (Show, Eq, Typeable) 650 deriving (Show, Eq, Typeable)
617 651
652-- | Extended metadata message id used in 'msg_type_key'.
653type MetadataId = Int
654
655msg_type_key, piece_key, total_size_key :: BKey
656msg_type_key = "msg_type"
657piece_key = "piece"
658total_size_key = "total_size"
659
660-- | BEP9 compatible encoding.
618instance BEncode ExtendedMetadata where 661instance BEncode ExtendedMetadata where
619 toBEncode (MetadataRequest pix) = toDict $ 662 toBEncode (MetadataRequest pix) = toDict $
620 "msg_type" .=! (0 :: MetadataId) 663 msg_type_key .=! (0 :: MetadataId)
621 .: "piece" .=! pix 664 .: piece_key .=! pix
622 .: endDict 665 .: endDict
623 toBEncode (MetadataData pix totalSize) = toDict $ 666 toBEncode (MetadataData pix totalSize) = toDict $
624 "msg_type" .=! (1 :: MetadataId) 667 msg_type_key .=! (1 :: MetadataId)
625 .: "piece" .=! pix 668 .: piece_key .=! pix
626 .: "total_size" .=! totalSize 669 .: total_size_key .=! totalSize
627 .: endDict 670 .: endDict
628 toBEncode (MetadataReject pix) = toDict $ 671 toBEncode (MetadataReject pix) = toDict $
629 "msg_type" .=! (2 :: MetadataId) 672 msg_type_key .=! (2 :: MetadataId)
630 .: "piece" .=! pix 673 .: piece_key .=! pix
631 .: endDict 674 .: endDict
632 toBEncode (MetadataUnknown bval) = bval 675 toBEncode (MetadataUnknown bval) = bval
633 676
634 fromBEncode = undefined 677 fromBEncode bval = (`fromDict` bval) $ do
678 mid <- field $ req msg_type_key
679 case mid :: MetadataId of
680 0 -> MetadataRequest <$>! piece_key
681 1 -> MetadataData <$>! piece_key <*>! total_size_key
682 2 -> MetadataReject <$>! piece_key
683 _ -> pure (MetadataUnknown bval)
635 684
685-- | Piece data bytes are omitted.
636instance Pretty ExtendedMetadata where 686instance Pretty ExtendedMetadata where
637 pretty (MetadataRequest pix ) = "Request" <+> PP.int pix 687 pretty (MetadataRequest pix ) = "Request" <+> PP.int pix
638 pretty (MetadataData pix s) = "Data" <+> PP.int pix <+> PP.int s 688 pretty (MetadataData pix s) = "Data" <+> PP.int pix <+> PP.int s
639 pretty (MetadataReject pix ) = "Reject" <+> PP.int pix 689 pretty (MetadataReject pix ) = "Reject" <+> PP.int pix
640 pretty (MetadataUnknown bval ) = ppBEncode bval 690 pretty (MetadataUnknown bval ) = "Unknown" <+> ppBEncode bval
641
642remoteMessageId :: ExtendedExtension -> ExtendedCaps -> ExtendedMessageId
643remoteMessageId ext = fromMaybe (extId ext) . M.lookup ext . extendedCaps
644 691
645instance PeerMessage ExtendedMetadata where 692instance PeerMessage ExtendedMetadata where
646 envelop c = envelop c . EMetadata (remoteMessageId ExtMetadata c) 693 envelop c = envelop c . EMetadata (remoteMessageId ExtMetadata c)
@@ -649,6 +696,9 @@ instance PeerMessage ExtendedMetadata where
649 requires _ = Just ExtExtended 696 requires _ = Just ExtExtended
650 {-# INLINE requires #-} 697 {-# INLINE requires #-}
651 698
699metadataPieceSize :: Int
700metadataPieceSize = 16 * 1024
701
652{----------------------------------------------------------------------- 702{-----------------------------------------------------------------------
653-- Extension protocol messages 703-- Extension protocol messages
654-----------------------------------------------------------------------} 704-----------------------------------------------------------------------}
diff --git a/src/Network/BitTorrent/Exchange/Wire.hs b/src/Network/BitTorrent/Exchange/Wire.hs
index 6f80a567..1cf14809 100644
--- a/src/Network/BitTorrent/Exchange/Wire.hs
+++ b/src/Network/BitTorrent/Exchange/Wire.hs
@@ -54,6 +54,8 @@ import Network.BitTorrent.Exchange.Message
54-- TODO handle port message? 54-- TODO handle port message?
55-- TODO handle limits? 55-- TODO handle limits?
56-- TODO filter not requested PIECE messages 56-- TODO filter not requested PIECE messages
57-- TODO metadata piece request flood protection
58-- TODO piece request flood protection
57{----------------------------------------------------------------------- 59{-----------------------------------------------------------------------
58-- Exceptions 60-- Exceptions
59-----------------------------------------------------------------------} 61-----------------------------------------------------------------------}