diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Network/BitTorrent/PeerWire/Block.hs | 4 | ||||
-rw-r--r-- | src/Network/BitTorrent/PeerWire/Message.hs | 106 |
2 files changed, 84 insertions, 26 deletions
diff --git a/src/Network/BitTorrent/PeerWire/Block.hs b/src/Network/BitTorrent/PeerWire/Block.hs index 8e4a1f24..ddbc1020 100644 --- a/src/Network/BitTorrent/PeerWire/Block.hs +++ b/src/Network/BitTorrent/PeerWire/Block.hs | |||
@@ -1,5 +1,5 @@ | |||
1 | module Network.BitTorrent.PeerWire.Block | 1 | module Network.BitTorrent.PeerWire.Block |
2 | ( BlockIx(..), Block(..) | 2 | ( BlockIx(..), Block(..), PieceIx |
3 | , BlockLIx, PieceLIx | 3 | , BlockLIx, PieceLIx |
4 | , defaultBlockSize | 4 | , defaultBlockSize |
5 | , pieceIx, blockIx | 5 | , pieceIx, blockIx |
@@ -17,7 +17,7 @@ import Data.Serialize | |||
17 | 17 | ||
18 | type BlockLIx = Int | 18 | type BlockLIx = Int |
19 | type PieceLIx = Int | 19 | type PieceLIx = Int |
20 | 20 | type PieceIx = Int | |
21 | 21 | ||
22 | data BlockIx = BlockIx { | 22 | data BlockIx = BlockIx { |
23 | -- ^ Zero-based piece index. | 23 | -- ^ Zero-based piece index. |
diff --git a/src/Network/BitTorrent/PeerWire/Message.hs b/src/Network/BitTorrent/PeerWire/Message.hs index 66021487..650e0082 100644 --- a/src/Network/BitTorrent/PeerWire/Message.hs +++ b/src/Network/BitTorrent/PeerWire/Message.hs | |||
@@ -11,18 +11,65 @@ import Data.Serialize | |||
11 | import Network.BitTorrent.PeerWire.Block | 11 | import Network.BitTorrent.PeerWire.Block |
12 | 12 | ||
13 | 13 | ||
14 | -- TODO comment message constructors | 14 | -- | Messages used in communication between peers. |
15 | -- | ||
16 | -- Note: If some extensions are disabled (not present in extension | ||
17 | -- mask) and client receive message used by the disabled | ||
18 | -- extension then the client MUST close the connection. | ||
19 | -- | ||
15 | data Message = KeepAlive | 20 | data Message = KeepAlive |
16 | | Choke | 21 | | Choke |
17 | | Unchoke | 22 | | Unchoke |
18 | | Interested | 23 | | Interested |
19 | | NotInterested | 24 | | NotInterested |
20 | | Have Int | 25 | |
26 | -- | Zero-based index of a piece that has just been | ||
27 | -- successfully downloaded and verified via the hash. | ||
28 | | Have PieceIx | ||
29 | |||
30 | -- | The bitfield message may only be sent immediately | ||
31 | -- after the handshaking sequence is complete, and | ||
32 | -- before any other message are sent. If client have no | ||
33 | -- pieces then bitfield need not to be sent. | ||
21 | | Bitfield ByteString | 34 | | Bitfield ByteString |
35 | |||
36 | -- | Request for a particular block. If a client is | ||
37 | -- requested a block that another peer do not have the | ||
38 | -- peer might not answer at all. | ||
22 | | Request BlockIx | 39 | | Request BlockIx |
40 | |||
41 | -- | Response for a request for a block. | ||
23 | | Piece Block | 42 | | Piece Block |
43 | |||
44 | -- | Used to cancel block requests. It is typically | ||
45 | -- used during "End Game". | ||
24 | | Cancel BlockIx | 46 | | Cancel BlockIx |
47 | |||
25 | | Port Int | 48 | | Port Int |
49 | |||
50 | -- | BEP 6: Then peer have all pieces it might send the | ||
51 | -- 'HaveAll' message instead of 'Bitfield' | ||
52 | -- message. Used to save bandwidth. | ||
53 | | HaveAll | ||
54 | |||
55 | -- | BEP 6: Then peer have no pieces it might send | ||
56 | -- 'HaveNone' message intead of 'Bitfield' | ||
57 | -- message. Used to save bandwidth. | ||
58 | | HaveNone | ||
59 | |||
60 | -- | BEP 6: This is an advisory message meaning "you | ||
61 | -- might like to download this piece." Used to avoid | ||
62 | -- excessive disk seeks and amount of IO. | ||
63 | | SuggestPiece PieceIx | ||
64 | |||
65 | -- | BEP 6: Notifies a requesting peer that its request | ||
66 | -- will not be satisfied. | ||
67 | | RejectRequest BlockIx | ||
68 | |||
69 | -- | BEP 6: This is an advisory messsage meaning "if | ||
70 | -- you ask for this piece, I'll give it to you even if | ||
71 | -- you're choked." Used to shorten starting phase. | ||
72 | | AllowedFast PieceIx | ||
26 | deriving (Show, Eq) | 73 | deriving (Show, Eq) |
27 | 74 | ||
28 | 75 | ||
@@ -30,38 +77,44 @@ instance Serialize Message where | |||
30 | get = do | 77 | get = do |
31 | len <- getInt | 78 | len <- getInt |
32 | lookAhead $ ensure len | 79 | lookAhead $ ensure len |
33 | if len == 0 then return KeepAlive -- FIX check if BS is empty instead of reading len | 80 | if len == 0 then return KeepAlive |
34 | else do | 81 | else do |
35 | mid <- getWord8 | 82 | mid <- getWord8 |
36 | case mid of | 83 | case mid of |
37 | 0 -> return Choke | 84 | 0x00 -> return Choke |
38 | 1 -> return Unchoke | 85 | 0x01 -> return Unchoke |
39 | 2 -> return Interested | 86 | 0x02 -> return Interested |
40 | 3 -> return NotInterested | 87 | 0x03 -> return NotInterested |
41 | 4 -> Have <$> getInt | 88 | 0x04 -> Have <$> getInt |
42 | 5 -> Bitfield <$> getBytes (pred len) | 89 | 0x05 -> Bitfield <$> getBytes (pred len) |
43 | 6 -> Request <$> get | 90 | 0x06 -> Request <$> get |
44 | 7 -> Piece <$> getBlock (len - 9) | 91 | 0x07 -> Piece <$> getBlock (len - 9) |
45 | 8 -> Cancel <$> get | 92 | 0x08 -> Cancel <$> get |
46 | 9 -> (Port . fromIntegral) <$> getWord16be | 93 | 0x09 -> (Port . fromIntegral) <$> getWord16be |
47 | _ -> fail $ "unknown message ID: " ++ show mid | 94 | 0x0E -> return HaveAll |
95 | 0x0F -> return HaveNone | ||
96 | 0x0D -> SuggestPiece <$> getInt | ||
97 | 0x10 -> RejectRequest <$> get | ||
98 | 0x11 -> AllowedFast <$> getInt | ||
99 | _ -> fail $ "unknown message ID: " ++ show mid | ||
48 | 100 | ||
49 | where | 101 | where |
50 | getBlock :: Int -> Get Block | 102 | getBlock :: Int -> Get Block |
51 | getBlock len = Block <$> getInt <*> getInt <*> getBytes len | 103 | getBlock len = Block <$> getInt <*> getInt <*> getBytes len |
52 | {-# INLINE getBlock #-} | 104 | {-# INLINE getBlock #-} |
53 | 105 | ||
106 | |||
54 | put KeepAlive = putInt 0 | 107 | put KeepAlive = putInt 0 |
55 | put Choke = putInt 1 >> putWord8 0 | 108 | put Choke = putInt 1 >> putWord8 0x00 |
56 | put Unchoke = putInt 1 >> putWord8 1 | 109 | put Unchoke = putInt 1 >> putWord8 0x01 |
57 | put Interested = putInt 1 >> putWord8 2 | 110 | put Interested = putInt 1 >> putWord8 0x02 |
58 | put NotInterested = putInt 1 >> putWord8 3 | 111 | put NotInterested = putInt 1 >> putWord8 0x03 |
59 | put (Have i) = putInt 5 >> putWord8 4 >> putInt i | 112 | put (Have i) = putInt 5 >> putWord8 0x04 >> putInt i |
60 | put (Bitfield b) = putInt l >> putWord8 5 >> putByteString b | 113 | put (Bitfield b) = putInt l >> putWord8 0x05 >> putByteString b |
61 | where l = succ (B.length b) | 114 | where l = succ (B.length b) |
62 | {-# INLINE l #-} | 115 | {-# INLINE l #-} |
63 | put (Request blk) = putInt 13 >> putWord8 6 >> put blk | 116 | put (Request blk) = putInt 13 >> putWord8 0x06 >> put blk |
64 | put (Piece blk) = putInt l >> putWord8 7 >> putBlock | 117 | put (Piece blk) = putInt l >> putWord8 0x07 >> putBlock |
65 | where l = 9 + B.length (blkData blk) | 118 | where l = 9 + B.length (blkData blk) |
66 | {-# INLINE l #-} | 119 | {-# INLINE l #-} |
67 | putBlock = do putInt (blkPiece blk) | 120 | putBlock = do putInt (blkPiece blk) |
@@ -69,5 +122,10 @@ instance Serialize Message where | |||
69 | putByteString (blkData blk) | 122 | putByteString (blkData blk) |
70 | {-# INLINE putBlock #-} | 123 | {-# INLINE putBlock #-} |
71 | 124 | ||
72 | put (Cancel blk) = putInt 13 >> putWord8 8 >> put blk | 125 | put (Cancel blk) = putInt 13 >> putWord8 0x08 >> put blk |
73 | put (Port p ) = putInt 3 >> putWord8 9 >> putWord16be (fromIntegral p) | 126 | put (Port p ) = putInt 3 >> putWord8 0x09 >> putWord16be (fromIntegral p) |
127 | put HaveAll = putInt 1 >> putWord8 0x0E | ||
128 | put HaveNone = putInt 1 >> putWord8 0x0F | ||
129 | put (SuggestPiece pix) = putInt 5 >> putWord8 0x0D >> putInt pix | ||
130 | put (RejectRequest ix) = putInt 13 >> putWord8 0x10 >> put ix | ||
131 | put (AllowedFast ix) = putInt 5 >> putWord8 0x11 >> putInt ix | ||