11 // This is a lazy union representing all the possible fields for messages. Go doesn't have ADTs, and
12 // I didn't choose to use type-assertions.
16 Index, Begin, Length Integer
19 ExtendedID ExtensionNumber
20 ExtendedPayload []byte
25 encoding.BinaryUnmarshaler
26 encoding.BinaryMarshaler
29 func MakeCancelMessage(piece, offset, length Integer) Message {
38 func (msg Message) RequestSpec() (ret RequestSpec) {
43 if msg.Type == Piece {
44 return Integer(len(msg.Piece))
52 func (msg Message) MustMarshalBinary() []byte {
53 b, err := msg.MarshalBinary()
60 func (msg Message) MarshalBinary() (data []byte, err error) {
63 err = buf.WriteByte(byte(msg.Type))
68 case Choke, Unchoke, Interested, NotInterested, HaveAll, HaveNone:
70 err = binary.Write(&buf, binary.BigEndian, msg.Index)
71 case Request, Cancel, Reject:
72 for _, i := range []Integer{msg.Index, msg.Begin, msg.Length} {
73 err = binary.Write(&buf, binary.BigEndian, i)
79 _, err = buf.Write(marshalBitfield(msg.Bitfield))
81 for _, i := range []Integer{msg.Index, msg.Begin} {
82 err = binary.Write(&buf, binary.BigEndian, i)
87 n, err := buf.Write(msg.Piece)
91 if n != len(msg.Piece) {
95 err = buf.WriteByte(byte(msg.ExtendedID))
99 _, err = buf.Write(msg.ExtendedPayload)
101 err = binary.Write(&buf, binary.BigEndian, msg.Port)
103 err = fmt.Errorf("unknown message type: %v", msg.Type)
106 data = make([]byte, 4+buf.Len())
107 binary.BigEndian.PutUint32(data, uint32(buf.Len()))
108 if buf.Len() != copy(data[4:], buf.Bytes()) {
114 func marshalBitfield(bf []bool) (b []byte) {
115 b = make([]byte, (len(bf)+7)/8)
116 for i, have := range bf {
121 c |= 1 << uint(7-i%8)
127 func (me *Message) UnmarshalBinary(b []byte) error {
129 R: bufio.NewReader(bytes.NewReader(b)),
135 if d.R.Buffered() != 0 {
136 return fmt.Errorf("%d trailing bytes", d.R.Buffered())