11 "github.com/pkg/errors"
17 MaxLength Integer // TODO: Should this include the length header or not?
20 // io.EOF is returned if the source terminates cleanly on a message boundary.
21 func (d *Decoder) Decode(msg *Message) (err error) {
23 err = length.Read(d.R)
25 return fmt.Errorf("reading message length: %w", err)
27 if length > d.MaxLength {
28 return errors.New("message too long")
35 r := &io.LimitedReader{R: d.R, N: int64(length)}
36 // Check that all of r was utilized.
42 err = fmt.Errorf("%d bytes unused in message type %d", r.N, msg.Type)
50 msg.Type = MessageType(c)
52 case Choke, Unchoke, Interested, NotInterested, HaveAll, HaveNone:
54 case Have, AllowedFast, Suggest:
55 err = msg.Index.Read(r)
56 case Request, Cancel, Reject:
57 for _, data := range []*Integer{&msg.Index, &msg.Begin, &msg.Length} {
64 b := make([]byte, length-1)
65 _, err = io.ReadFull(r, b)
66 msg.Bitfield = unmarshalBitfield(b)
68 for _, pi := range []*Integer{&msg.Index, &msg.Begin} {
75 msg.Piece = (*d.Pool.Get().(*[]byte))
76 if int64(cap(msg.Piece)) < dataLen {
77 return errors.New("piece data longer than expected")
79 msg.Piece = msg.Piece[:dataLen]
80 _, err := io.ReadFull(r, msg.Piece)
82 return errors.Wrap(err, "reading piece data")
90 msg.ExtendedID = ExtensionNumber(b)
91 msg.ExtendedPayload, err = ioutil.ReadAll(r)
93 err = binary.Read(r, binary.BigEndian, &msg.Port)
95 err = fmt.Errorf("unknown message type %#v", c)
100 func readByte(r io.Reader) (b byte, err error) {
102 n, err := r.Read(arr[:])
114 func unmarshalBitfield(b []byte) (bf []bool) {
115 for _, c := range b {
116 for i := 7; i >= 0; i-- {
117 bf = append(bf, (c>>uint(i))&1 == 1)