From 482f4f28b106d08ed20843a81c93efd3995e1439 Mon Sep 17 00:00:00 2001 From: Sam T Date: Sat, 20 Apr 2013 23:40:25 +0400 Subject: + Move message and block to separated files. --- src/Network/Torrent/PeerWire/Block.hs | 17 ++++++ src/Network/Torrent/PeerWire/Message.hs | 91 +++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 src/Network/Torrent/PeerWire/Block.hs create mode 100644 src/Network/Torrent/PeerWire/Message.hs (limited to 'src/Network/Torrent/PeerWire') diff --git a/src/Network/Torrent/PeerWire/Block.hs b/src/Network/Torrent/PeerWire/Block.hs new file mode 100644 index 00000000..b2fe8c31 --- /dev/null +++ b/src/Network/Torrent/PeerWire/Block.hs @@ -0,0 +1,17 @@ +module Network.Torrent.PeerWire.Block + ( BlockIx(..), Block(..) + ) where + +import Data.ByteString (ByteString) + +data BlockIx = BlockIx { + ixPiece :: {-# UNPACK #-} !Int -- ^ Zero-based piece index. + , ixOffset :: {-# UNPACK #-} !Int -- ^ Zero-based byte offset within the piece. + , ixLength :: {-# UNPACK #-} !Int -- ^ Block size starting from offset. + } deriving (Show, Eq) + +data Block = Block { + blkPiece :: Int -- ^ Zero-based piece index. + , blkOffset :: Int -- ^ Zero-based byte offset within the piece. + , blkData :: ByteString -- ^ Payload. + } deriving (Show, Eq) diff --git a/src/Network/Torrent/PeerWire/Message.hs b/src/Network/Torrent/PeerWire/Message.hs new file mode 100644 index 00000000..e04038ff --- /dev/null +++ b/src/Network/Torrent/PeerWire/Message.hs @@ -0,0 +1,91 @@ +module Network.Torrent.PeerWire.Message + ( Message(..) + ) where + +import Control.Applicative +import Data.ByteString (ByteString) +import qualified Data.ByteString as B + +import Data.Serialize + +import Network.Torrent.PeerWire.Block + + +-- TODO comment message constructors +data Message = KeepAlive + | Choke + | Unchoke + | Interested + | NotInterested + | Have Int + | Bitfield ByteString + | Request BlockIx + | Piece Block + | Cancel BlockIx + | Port Int + deriving (Show, Eq) + +instance Serialize BlockIx where + {-# SPECIALIZE instance Serialize BlockIx #-} + get = BlockIx <$> getInt <*> getInt <*> getInt + {-# INLINE get #-} + + put ix = do putInt (ixPiece ix) + putInt (ixOffset ix) + putInt (ixLength ix) + {-# INLINE put #-} + +instance Serialize Message where + get = do + len <- getInt + lookAhead $ ensure len + if len == 0 then return KeepAlive -- FIX check if BS is empty instead of reading len + else do + mid <- getWord8 + case mid of + 0 -> return Choke + 1 -> return Unchoke + 2 -> return Interested + 3 -> return NotInterested + 4 -> Have <$> getInt + 5 -> Bitfield <$> getBytes (pred len) + 6 -> Request <$> get + 7 -> Piece <$> getBlock (len - 9) + 8 -> Cancel <$> get + 9 -> (Port . fromIntegral) <$> getWord16be + _ -> fail $ "unknown message ID: " ++ show mid + + where + getBlock :: Int -> Get Block + getBlock len = Block <$> getInt <*> getInt <*> getBytes len + {-# INLINE getBlock #-} + + put KeepAlive = putInt 0 + put Choke = putInt 1 >> putWord8 0 + put Unchoke = putInt 1 >> putWord8 1 + put Interested = putInt 1 >> putWord8 2 + put NotInterested = putInt 1 >> putWord8 3 + put (Have i) = putInt 5 >> putWord8 4 >> putInt i + put (Bitfield b) = putInt l >> putWord8 5 >> putByteString b + where l = succ (B.length b) + {-# INLINE l #-} + put (Request blk) = putInt 13 >> putWord8 6 >> put blk + put (Piece blk) = putInt l >> putWord8 7 >> putBlock + where l = 9 + B.length (blkData blk) + {-# INLINE l #-} + putBlock = do putInt (blkPiece blk) + putInt (blkOffset blk) + putByteString (blkData blk) + {-# INLINE putBlock #-} + + put (Cancel blk) = putInt 13 >> putWord8 8 >> put blk + put (Port p ) = putInt 3 >> putWord8 9 >> putWord16be (fromIntegral p) + + +getInt :: Get Int +getInt = fromIntegral <$> getWord32be +{-# INLINE getInt #-} + +putInt :: Putter Int +putInt = putWord32be . fromIntegral +{-# INLINE putInt #-} -- cgit v1.2.3