summaryrefslogtreecommitdiff
path: root/src/Network/BitTorrent/Exchange/Message.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Network/BitTorrent/Exchange/Message.hs')
-rw-r--r--src/Network/BitTorrent/Exchange/Message.hs124
1 files changed, 106 insertions, 18 deletions
diff --git a/src/Network/BitTorrent/Exchange/Message.hs b/src/Network/BitTorrent/Exchange/Message.hs
index 38a8ac33..b3100269 100644
--- a/src/Network/BitTorrent/Exchange/Message.hs
+++ b/src/Network/BitTorrent/Exchange/Message.hs
@@ -46,10 +46,15 @@ module Network.BitTorrent.Exchange.Message
46 , handshakeSize 46 , handshakeSize
47 , handshakeMaxSize 47 , handshakeMaxSize
48 48
49 -- * Stats
50 , ByteCount
51 , ByteStats (..)
52 , byteLength
53
49 -- * Messages 54 -- * Messages
50 , Message (..) 55 , Message (..)
51 , PeerMessage (..)
52 , defaultKeepAliveInterval 56 , defaultKeepAliveInterval
57 , PeerMessage (..)
53 58
54 -- ** Core messages 59 -- ** Core messages
55 , StatusUpdate (..) 60 , StatusUpdate (..)
@@ -292,6 +297,47 @@ defaultHandshake :: InfoHash -> PeerId -> Handshake
292defaultHandshake = Handshake def def 297defaultHandshake = Handshake def def
293 298
294{----------------------------------------------------------------------- 299{-----------------------------------------------------------------------
300-- Stats
301-----------------------------------------------------------------------}
302
303-- | Number of bytes.
304type ByteCount = Int
305
306-- | Summary of encoded message byte layout can be used to collect
307-- stats about message flow in both directions. This data can be
308-- retrieved using 'stats' function.
309data ByteStats = ByteStats
310 { -- | Number of bytes used to help encode 'control' and 'payload'
311 -- bytes: message size, message ID's, etc
312 overhead :: {-# UNPACK #-} !ByteCount
313
314 -- | Number of bytes used to exchange peers state\/options: piece
315 -- and block indexes, infohash, port numbers, peer ID\/IP, etc.
316 , control :: {-# UNPACK #-} !ByteCount
317
318 -- | Number of payload bytes: torrent data blocks and infodict
319 -- metadata.
320 , payload :: {-# UNPACK #-} !ByteCount
321 } deriving Show
322
323-- | Empty byte sequences.
324instance Default ByteStats where
325 def = ByteStats 0 0 0
326
327-- | Monoid under addition.
328instance Monoid ByteStats where
329 mempty = def
330 mappend a b = ByteStats
331 { overhead = overhead a + overhead b
332 , control = control a + control b
333 , payload = payload a + payload b
334 }
335
336-- | Sum of the all byte sequences.
337byteLength :: ByteStats -> Int
338byteLength ByteStats {..} = overhead + control + payload
339
340{-----------------------------------------------------------------------
295-- Regular messages 341-- Regular messages
296-----------------------------------------------------------------------} 342-----------------------------------------------------------------------}
297 343
@@ -311,6 +357,17 @@ class PeerMessage a where
311 requires :: a -> Maybe Extension 357 requires :: a -> Maybe Extension
312 requires _ = Nothing 358 requires _ = Nothing
313 359
360 -- | Get sizes of overhead\/control\/payload byte sequences of
361 -- binary message representation without encoding message to binary
362 -- bytestring.
363 --
364 -- This function should obey one law:
365 --
366 -- * 'byteLength' ('stats' msg) == 'BL.length' ('encode' msg)
367 --
368 stats :: a -> ByteStats
369 stats _ = ByteStats 4 0 0
370
314{----------------------------------------------------------------------- 371{-----------------------------------------------------------------------
315-- Status messages 372-- Status messages
316-----------------------------------------------------------------------} 373-----------------------------------------------------------------------}
@@ -337,6 +394,9 @@ instance PeerMessage StatusUpdate where
337 envelop _ = Status 394 envelop _ = Status
338 {-# INLINE envelop #-} 395 {-# INLINE envelop #-}
339 396
397 stats _ = ByteStats 4 1 0
398 {-# INLINE stats #-}
399
340{----------------------------------------------------------------------- 400{-----------------------------------------------------------------------
341-- Available messages 401-- Available messages
342-----------------------------------------------------------------------} 402-----------------------------------------------------------------------}
@@ -361,12 +421,14 @@ instance Pretty Available where
361 421
362instance PeerMessage Available where 422instance PeerMessage Available where
363 envelop _ = Available 423 envelop _ = Available
364
365-- | BITFIELD message.
366instance PeerMessage Bitfield where
367 envelop c = envelop c . Bitfield
368 {-# INLINE envelop #-} 424 {-# INLINE envelop #-}
369 425
426 stats (Have _) = ByteStats (4 + 1) 4 0
427 stats (Bitfield bf) = ByteStats (4 + 1) (q + trailing) 0
428 where
429 trailing = if r == 0 then 0 else 1
430 (q, r) = quotRem (totalCount bf) 8
431
370{----------------------------------------------------------------------- 432{-----------------------------------------------------------------------
371-- Transfer messages 433-- Transfer messages
372-----------------------------------------------------------------------} 434-----------------------------------------------------------------------}
@@ -395,15 +457,9 @@ instance PeerMessage Transfer where
395 envelop _ = Transfer 457 envelop _ = Transfer
396 {-# INLINE envelop #-} 458 {-# INLINE envelop #-}
397 459
398-- | REQUEST message. 460 stats (Request _ ) = ByteStats (4 + 1) (3 * 4) 0
399instance PeerMessage BlockIx where 461 stats (Piece pi ) = ByteStats (4 + 1) (4 + 4 + blockSize pi) 0
400 envelop c = envelop c . Request 462 stats (Cancel _ ) = ByteStats (4 + 1) (3 * 4) 0
401 {-# INLINE envelop #-}
402
403-- | PIECE message.
404instance PeerMessage (Block BL.ByteString) where
405 envelop c = envelop c . Piece
406 {-# INLINE envelop #-}
407 463
408{----------------------------------------------------------------------- 464{-----------------------------------------------------------------------
409-- Fast messages 465-- Fast messages
@@ -424,11 +480,12 @@ data FastMessage =
424 -- amount of IO. 480 -- amount of IO.
425 | SuggestPiece !PieceIx 481 | SuggestPiece !PieceIx
426 482
427 -- | Notifies a requesting peer that its request will not be satisfied. 483 -- | Notifies a requesting peer that its request will not be
484 -- satisfied.
428 | RejectRequest !BlockIx 485 | RejectRequest !BlockIx
429 486
430 -- | This is an advisory messsage meaning "if you ask for this 487 -- | This is an advisory messsage meaning \"if you ask for this
431 -- piece, I'll give it to you even if you're choked." Used to 488 -- piece, I'll give it to you even if you're choked.\" Used to
432 -- shorten starting phase. 489 -- shorten starting phase.
433 | AllowedFast !PieceIx 490 | AllowedFast !PieceIx
434 deriving (Show, Eq) 491 deriving (Show, Eq)
@@ -447,6 +504,12 @@ instance PeerMessage FastMessage where
447 requires _ = Just ExtFast 504 requires _ = Just ExtFast
448 {-# INLINE requires #-} 505 {-# INLINE requires #-}
449 506
507 stats HaveAll = ByteStats 4 1 0
508 stats HaveNone = ByteStats 4 1 0
509 stats (SuggestPiece _) = ByteStats 5 4 0
510 stats (RejectRequest _) = ByteStats 5 12 0
511 stats (AllowedFast _) = ByteStats 5 4 0
512
450{----------------------------------------------------------------------- 513{-----------------------------------------------------------------------
451-- Extension protocol 514-- Extension protocol
452-----------------------------------------------------------------------} 515-----------------------------------------------------------------------}
@@ -588,7 +651,7 @@ extHandshakeId = 0
588 651
589-- | Default 'Request' queue size. 652-- | Default 'Request' queue size.
590defaultQueueLength :: Int 653defaultQueueLength :: Int
591defaultQueueLength = 0 654defaultQueueLength = 1
592 655
593-- | All fields are empty. 656-- | All fields are empty.
594instance Default ExtendedHandshake where 657instance Default ExtendedHandshake where
@@ -619,6 +682,7 @@ instance BEncode ExtendedHandshake where
619instance Pretty ExtendedHandshake where 682instance Pretty ExtendedHandshake where
620 pretty = PP.text . show 683 pretty = PP.text . show
621 684
685-- | NOTE: Approximated 'stats'.
622instance PeerMessage ExtendedHandshake where 686instance PeerMessage ExtendedHandshake where
623 envelop c = envelop c . EHandshake 687 envelop c = envelop c . EHandshake
624 {-# INLINE envelop #-} 688 {-# INLINE envelop #-}
@@ -626,6 +690,9 @@ instance PeerMessage ExtendedHandshake where
626 requires _ = Just ExtExtended 690 requires _ = Just ExtExtended
627 {-# INLINE requires #-} 691 {-# INLINE requires #-}
628 692
693 stats _ = ByteStats (4 + 1 + 1) 100 {- is it ok? -} 0 -- FIXME
694 {-# INLINE stats #-}
695
629-- | Set default values and the specified 'ExtendedCaps'. 696-- | Set default values and the specified 'ExtendedCaps'.
630nullExtendedHandshake :: ExtendedCaps -> ExtendedHandshake 697nullExtendedHandshake :: ExtendedCaps -> ExtendedHandshake
631nullExtendedHandshake caps = ExtendedHandshake 698nullExtendedHandshake caps = ExtendedHandshake
@@ -721,6 +788,7 @@ instance Pretty ExtendedMetadata where
721 pretty (MetadataReject pix ) = "Reject" <+> PP.int pix 788 pretty (MetadataReject pix ) = "Reject" <+> PP.int pix
722 pretty (MetadataUnknown bval ) = "Unknown" <+> ppBEncode bval 789 pretty (MetadataUnknown bval ) = "Unknown" <+> ppBEncode bval
723 790
791-- | NOTE: Approximated 'stats'.
724instance PeerMessage ExtendedMetadata where 792instance PeerMessage ExtendedMetadata where
725 envelop c = envelop c . EMetadata (remoteMessageId ExtMetadata c) 793 envelop c = envelop c . EMetadata (remoteMessageId ExtMetadata c)
726 {-# INLINE envelop #-} 794 {-# INLINE envelop #-}
@@ -728,6 +796,14 @@ instance PeerMessage ExtendedMetadata where
728 requires _ = Just ExtExtended 796 requires _ = Just ExtExtended
729 {-# INLINE requires #-} 797 {-# INLINE requires #-}
730 798
799 stats (MetadataRequest _) = ByteStats (4 + 1 + 1) {- ~ -} 25 0
800 stats (MetadataData pi t) = ByteStats (4 + 1 + 1) {- ~ -} 41 $
801 BS.length (Data.pieceData pi)
802 stats (MetadataReject _) = ByteStats (4 + 1 + 1) {- ~ -} 25 0
803 stats (MetadataUnknown _) = ByteStats (4 + 1 + 1) {- ? -} 0 0
804
805-- | All 'Piece's in 'MetadataData' messages MUST have size equal to
806-- this value. The last trailing piece can be shorter.
731metadataPieceSize :: Int 807metadataPieceSize :: Int
732metadataPieceSize = 16 * 1024 808metadataPieceSize = 16 * 1024
733 809
@@ -791,6 +867,10 @@ instance PeerMessage ExtendedMessage where
791 requires _ = Just ExtExtended 867 requires _ = Just ExtExtended
792 {-# INLINE requires #-} 868 {-# INLINE requires #-}
793 869
870 stats (EHandshake hs) = stats hs
871 stats (EMetadata _ msg) = stats msg
872 stats (EUnknown _ msg) = ByteStats (4 + 1 + 1) (BS.length msg) 0
873
794{----------------------------------------------------------------------- 874{-----------------------------------------------------------------------
795-- The message datatype 875-- The message datatype
796-----------------------------------------------------------------------} 876-----------------------------------------------------------------------}
@@ -849,6 +929,14 @@ instance PeerMessage Message where
849 requires (Fast _) = Just ExtFast 929 requires (Fast _) = Just ExtFast
850 requires (Extended _) = Just ExtExtended 930 requires (Extended _) = Just ExtExtended
851 931
932 stats KeepAlive = ByteStats 4 0 0
933 stats (Status m) = stats m
934 stats (Available m) = stats m
935 stats (Transfer m) = stats m
936 stats (Port _) = ByteStats 5 2 0
937 stats (Fast m) = stats m
938 stats (Extended m) = stats m
939
852-- | PORT message. 940-- | PORT message.
853instance PeerMessage PortNumber where 941instance PeerMessage PortNumber where
854 envelop _ = Port 942 envelop _ = Port