message.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. package p2p
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "fmt"
  6. "io"
  7. "io/ioutil"
  8. "math/big"
  9. "github.com/ethereum/go-ethereum/ethutil"
  10. )
  11. type MsgCode uint64
  12. // Msg defines the structure of a p2p message.
  13. //
  14. // Note that a Msg can only be sent once since the Payload reader is
  15. // consumed during sending. It is not possible to create a Msg and
  16. // send it any number of times. If you want to reuse an encoded
  17. // structure, encode the payload into a byte array and create a
  18. // separate Msg with a bytes.Reader as Payload for each send.
  19. type Msg struct {
  20. Code MsgCode
  21. Size uint32 // size of the paylod
  22. Payload io.Reader
  23. }
  24. // NewMsg creates an RLP-encoded message with the given code.
  25. func NewMsg(code MsgCode, params ...interface{}) Msg {
  26. buf := new(bytes.Buffer)
  27. for _, p := range params {
  28. buf.Write(ethutil.Encode(p))
  29. }
  30. return Msg{Code: code, Size: uint32(buf.Len()), Payload: buf}
  31. }
  32. func encodePayload(params ...interface{}) []byte {
  33. buf := new(bytes.Buffer)
  34. for _, p := range params {
  35. buf.Write(ethutil.Encode(p))
  36. }
  37. return buf.Bytes()
  38. }
  39. // Data returns the decoded RLP payload items in a message.
  40. func (msg Msg) Data() (*ethutil.Value, error) {
  41. // TODO: avoid copying when we have a better RLP decoder
  42. buf := new(bytes.Buffer)
  43. var s []interface{}
  44. if _, err := buf.ReadFrom(msg.Payload); err != nil {
  45. return nil, err
  46. }
  47. for buf.Len() > 0 {
  48. s = append(s, ethutil.DecodeWithReader(buf))
  49. }
  50. return ethutil.NewValue(s), nil
  51. }
  52. // Discard reads any remaining payload data into a black hole.
  53. func (msg Msg) Discard() error {
  54. _, err := io.Copy(ioutil.Discard, msg.Payload)
  55. return err
  56. }
  57. var magicToken = []byte{34, 64, 8, 145}
  58. func writeMsg(w io.Writer, msg Msg) error {
  59. // TODO: handle case when Size + len(code) + len(listhdr) overflows uint32
  60. code := ethutil.Encode(uint32(msg.Code))
  61. listhdr := makeListHeader(msg.Size + uint32(len(code)))
  62. payloadLen := uint32(len(listhdr)) + uint32(len(code)) + msg.Size
  63. start := make([]byte, 8)
  64. copy(start, magicToken)
  65. binary.BigEndian.PutUint32(start[4:], payloadLen)
  66. for _, b := range [][]byte{start, listhdr, code} {
  67. if _, err := w.Write(b); err != nil {
  68. return err
  69. }
  70. }
  71. _, err := io.CopyN(w, msg.Payload, int64(msg.Size))
  72. return err
  73. }
  74. func makeListHeader(length uint32) []byte {
  75. if length < 56 {
  76. return []byte{byte(length + 0xc0)}
  77. }
  78. enc := big.NewInt(int64(length)).Bytes()
  79. lenb := byte(len(enc)) + 0xf7
  80. return append([]byte{lenb}, enc...)
  81. }
  82. type byteReader interface {
  83. io.Reader
  84. io.ByteReader
  85. }
  86. // readMsg reads a message header.
  87. func readMsg(r byteReader) (msg Msg, err error) {
  88. // read magic and payload size
  89. start := make([]byte, 8)
  90. if _, err = io.ReadFull(r, start); err != nil {
  91. return msg, NewPeerError(ReadError, "%v", err)
  92. }
  93. if !bytes.HasPrefix(start, magicToken) {
  94. return msg, NewPeerError(MagicTokenMismatch, "got %x, want %x", start[:4], magicToken)
  95. }
  96. size := binary.BigEndian.Uint32(start[4:])
  97. // decode start of RLP message to get the message code
  98. _, hdrlen, err := readListHeader(r)
  99. if err != nil {
  100. return msg, err
  101. }
  102. code, codelen, err := readMsgCode(r)
  103. if err != nil {
  104. return msg, err
  105. }
  106. rlpsize := size - hdrlen - codelen
  107. return Msg{
  108. Code: code,
  109. Size: rlpsize,
  110. Payload: io.LimitReader(r, int64(rlpsize)),
  111. }, nil
  112. }
  113. // readListHeader reads an RLP list header from r.
  114. func readListHeader(r byteReader) (len uint64, hdrlen uint32, err error) {
  115. b, err := r.ReadByte()
  116. if err != nil {
  117. return 0, 0, err
  118. }
  119. if b < 0xC0 {
  120. return 0, 0, fmt.Errorf("expected list start byte >= 0xC0, got %x", b)
  121. } else if b < 0xF7 {
  122. len = uint64(b - 0xc0)
  123. hdrlen = 1
  124. } else {
  125. lenlen := b - 0xF7
  126. lenbuf := make([]byte, 8)
  127. if _, err := io.ReadFull(r, lenbuf[8-lenlen:]); err != nil {
  128. return 0, 0, err
  129. }
  130. len = binary.BigEndian.Uint64(lenbuf)
  131. hdrlen = 1 + uint32(lenlen)
  132. }
  133. return len, hdrlen, nil
  134. }
  135. // readUint reads an RLP-encoded unsigned integer from r.
  136. func readMsgCode(r byteReader) (code MsgCode, codelen uint32, err error) {
  137. b, err := r.ReadByte()
  138. if err != nil {
  139. return 0, 0, err
  140. }
  141. if b < 0x80 {
  142. return MsgCode(b), 1, nil
  143. } else if b < 0x89 { // max length for uint64 is 8 bytes
  144. codelen = uint32(b - 0x80)
  145. if codelen == 0 {
  146. return 0, 1, nil
  147. }
  148. buf := make([]byte, 8)
  149. if _, err := io.ReadFull(r, buf[8-codelen:]); err != nil {
  150. return 0, 0, err
  151. }
  152. return MsgCode(binary.BigEndian.Uint64(buf)), codelen, nil
  153. }
  154. return 0, 0, fmt.Errorf("bad RLP type for message code: %x", b)
  155. }