From a30bb766e8f2bea19e5a8f1739354d5f7894df1d Mon Sep 17 00:00:00 2001 From: Sam T Date: Fri, 7 Jun 2013 23:27:31 +0400 Subject: ~ Fix bitfield encoding. --- src/Data/Bitfield.hs | 39 ++++++++++++++++++++---------- src/Network/BitTorrent/PeerWire/Message.hs | 8 +++--- src/Network/BitTorrent/Tracker.hs | 2 +- 3 files changed, 32 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/Data/Bitfield.hs b/src/Data/Bitfield.hs index ee0570e7..56365bf7 100644 --- a/src/Data/Bitfield.hs +++ b/src/Data/Bitfield.hs @@ -17,6 +17,7 @@ module Data.Bitfield -- * Construction , haveAll, haveNone, have + , adjustSize -- * Query , Data.Bitfield.null @@ -31,8 +32,7 @@ module Data.Bitfield , difference -- * Serialization - , getBitfield, putBitfield - , bitfieldByteCount + , fromBitmap, toBitmap #if defined (TESTING) -- * Debug @@ -42,15 +42,18 @@ module Data.Bitfield import Control.Monad import Control.Monad.ST +import Data.ByteString (ByteString) +import qualified Data.ByteString as B +import qualified Data.ByteString.Lazy as Lazy import Data.Vector.Unboxed (Vector) import qualified Data.Vector.Unboxed as V import qualified Data.Vector.Unboxed.Mutable as VM import Data.IntervalSet (IntSet) import qualified Data.IntervalSet as S +import qualified Data.IntervalSet.ByteString as S import Data.List (foldl') import Data.Monoid import Data.Ratio -import Data.Serialize import Network.BitTorrent.PeerWire.Block @@ -97,6 +100,11 @@ have ix Bitfield {..} | 0 <= ix && ix < bfSize = Bitfield bfSize (S.insert ix bfSet) | otherwise = Bitfield bfSize bfSet +-- | Assign new size to bitfield. FIXME Normally, size should be only +-- decreased, otherwise exception raised. +adjustSize :: PieceCount -> Bitfield -> Bitfield +adjustSize s Bitfield {..} = Bitfield s bfSet + {----------------------------------------------------------------------- Query -----------------------------------------------------------------------} @@ -200,17 +208,22 @@ unions = foldl' union (haveNone 0) Serialization -----------------------------------------------------------------------} --- | -getBitfield :: Int -> Get Bitfield -getBitfield = error "getBitfield" - --- | -putBitfield :: Bitfield -> Put -putBitfield = error "putBitfield" +-- | Unpack 'Bitfield' from tightly packed bit array. Note resulting +-- size might be more than real bitfield size, use 'adjustSize'. +fromBitmap :: ByteString -> Bitfield +fromBitmap bs = Bitfield { + bfSize = B.length bs * 8 + , bfSet = S.fromByteString bs + } +{-# INLINE fromBitmap #-} --- | -bitfieldByteCount :: Bitfield -> Int -bitfieldByteCount = error "bitfieldByteCount" +-- | Pack a 'Bitfield' to tightly packed bit array. +toBitmap :: Bitfield -> Lazy.ByteString +toBitmap Bitfield {..} = Lazy.fromChunks [intsetBM, alignment] + where + byteSize = bfSize `div` 8 + if bfSize `mod` 8 == 0 then 0 else 1 + alignment = B.replicate (byteSize - B.length intsetBM) 0 + intsetBM = S.toByteString bfSet {----------------------------------------------------------------------- Debug diff --git a/src/Network/BitTorrent/PeerWire/Message.hs b/src/Network/BitTorrent/PeerWire/Message.hs index 6515fdf2..3895ed5f 100644 --- a/src/Network/BitTorrent/PeerWire/Message.hs +++ b/src/Network/BitTorrent/PeerWire/Message.hs @@ -7,6 +7,7 @@ module Network.BitTorrent.PeerWire.Message import Control.Applicative import qualified Data.ByteString as B +import qualified Data.ByteString.Lazy as Lazy import Data.Serialize import Text.PrettyPrint import Network @@ -91,7 +92,7 @@ instance Serialize Message where 0x02 -> return Interested 0x03 -> return NotInterested 0x04 -> Have <$> getInt - 0x05 -> Bitfield <$> getBitfield (pred len) + 0x05 -> (Bitfield . fromBitmap) <$> getByteString (pred len) 0x06 -> Request <$> get 0x07 -> Piece <$> getBlock (len - 9) 0x08 -> Cancel <$> get @@ -118,8 +119,9 @@ instance Serialize Message where put Interested = putInt 1 >> putWord8 0x02 put NotInterested = putInt 1 >> putWord8 0x03 put (Have i) = putInt 5 >> putWord8 0x04 >> putInt i - put (Bitfield b) = putInt l >> putWord8 0x05 >> putBitfield b - where l = succ (bitfieldByteCount b) + put (Bitfield bf) = putInt l >> putWord8 0x05 >> putLazyByteString b + where b = toBitmap bf + l = succ (fromIntegral (Lazy.length b)) {-# INLINE l #-} put (Request blk) = putInt 13 >> putWord8 0x06 >> put blk put (Piece blk) = putInt l >> putWord8 0x07 >> putBlock diff --git a/src/Network/BitTorrent/Tracker.hs b/src/Network/BitTorrent/Tracker.hs index 2e599002..aaa08f3c 100644 --- a/src/Network/BitTorrent/Tracker.hs +++ b/src/Network/BitTorrent/Tracker.hs @@ -145,7 +145,7 @@ data TSession = TSession { newSession :: Progress -> Int -> [PeerAddr] -> IO TSession newSession pr i ps = TSession <$> newTVarIO pr <*> newIORef i - <*> newTVarIO psx + <*> newTVarIO ps getPeerList :: TSession -> IO [PeerAddr] getPeerList = readTVarIO . sePeers -- cgit v1.2.3