9 // This is a lazy union representing all the possible fields for messages. Go doesn't have ADTs, and
10 // I didn't choose to use type-assertions.
14 Index, Begin, Length Integer
17 ExtendedID ExtensionNumber
18 ExtendedPayload []byte
22 func MakeCancelMessage(piece, offset, length Integer) Message {
31 func (msg Message) RequestSpec() (ret RequestSpec) {
36 if msg.Type == Piece {
37 return Integer(len(msg.Piece))
45 func (msg Message) MustMarshalBinary() []byte {
46 b, err := msg.MarshalBinary()
53 func (msg Message) MarshalBinary() (data []byte, err error) {
54 buf := &bytes.Buffer{}
56 err = buf.WriteByte(byte(msg.Type))
61 case Choke, Unchoke, Interested, NotInterested, HaveAll, HaveNone:
63 err = binary.Write(buf, binary.BigEndian, msg.Index)
64 case Request, Cancel, Reject:
65 for _, i := range []Integer{msg.Index, msg.Begin, msg.Length} {
66 err = binary.Write(buf, binary.BigEndian, i)
72 _, err = buf.Write(marshalBitfield(msg.Bitfield))
74 for _, i := range []Integer{msg.Index, msg.Begin} {
75 err = binary.Write(buf, binary.BigEndian, i)
80 n, err := buf.Write(msg.Piece)
84 if n != len(msg.Piece) {
88 err = buf.WriteByte(byte(msg.ExtendedID))
92 _, err = buf.Write(msg.ExtendedPayload)
94 err = binary.Write(buf, binary.BigEndian, msg.Port)
96 err = fmt.Errorf("unknown message type: %v", msg.Type)
99 data = make([]byte, 4+buf.Len())
100 binary.BigEndian.PutUint32(data, uint32(buf.Len()))
101 if buf.Len() != copy(data[4:], buf.Bytes()) {
107 func marshalBitfield(bf []bool) (b []byte) {
108 b = make([]byte, (len(bf)+7)/8)
109 for i, have := range bf {
114 c |= 1 << uint(7-i%8)