You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

106 lines
3.5 KiB

  1. // Protocol Buffers for Go with Gadgets
  2. //
  3. // Copyright (c) 2013, The GoGo Authors. All rights reserved.
  4. // http://github.com/gogo/protobuf
  5. //
  6. // Redistribution and use in source and binary forms, with or without
  7. // modification, are permitted provided that the following conditions are
  8. // met:
  9. //
  10. // * Redistributions of source code must retain the above copyright
  11. // notice, this list of conditions and the following disclaimer.
  12. // * Redistributions in binary form must reproduce the above
  13. // copyright notice, this list of conditions and the following disclaimer
  14. // in the documentation and/or other materials provided with the
  15. // distribution.
  16. //
  17. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  20. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  21. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  22. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  23. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  24. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  25. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  27. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. //
  29. // Modified from original GoGo Protobuf to not buffer the reader.
  30. package protoio
  31. import (
  32. "bytes"
  33. "encoding/binary"
  34. "fmt"
  35. "io"
  36. "github.com/gogo/protobuf/proto"
  37. )
  38. // NewDelimitedReader reads varint-delimited Protobuf messages from a reader.
  39. // Unlike the gogoproto NewDelimitedReader, this does not buffer the reader,
  40. // which may cause poor performance but is necessary when only reading single
  41. // messages (e.g. in the p2p package). It also returns the number of bytes
  42. // read, which is necessary for the p2p package.
  43. func NewDelimitedReader(r io.Reader, maxSize int) ReadCloser {
  44. var closer io.Closer
  45. if c, ok := r.(io.Closer); ok {
  46. closer = c
  47. }
  48. return &varintReader{r, nil, maxSize, closer}
  49. }
  50. type varintReader struct {
  51. r io.Reader
  52. buf []byte
  53. maxSize int
  54. closer io.Closer
  55. }
  56. func (r *varintReader) ReadMsg(msg proto.Message) (int, error) {
  57. // ReadUvarint needs an io.ByteReader, and we also need to keep track of the
  58. // number of bytes read, so we use our own byteReader. This can't be
  59. // buffered, so the caller should pass a buffered io.Reader to avoid poor
  60. // performance.
  61. byteReader := newByteReader(r.r)
  62. l, err := binary.ReadUvarint(byteReader)
  63. n := byteReader.bytesRead
  64. if err != nil {
  65. return n, err
  66. }
  67. // Make sure length doesn't overflow the native int size (e.g. 32-bit),
  68. // and that the returned sum of n+length doesn't overflow either.
  69. length := int(l)
  70. if l >= uint64(^uint(0)>>1) || length < 0 || n+length < 0 {
  71. return n, fmt.Errorf("invalid out-of-range message length %v", l)
  72. }
  73. if length > r.maxSize {
  74. return n, fmt.Errorf("message exceeds max size (%v > %v)", length, r.maxSize)
  75. }
  76. if len(r.buf) < length {
  77. r.buf = make([]byte, length)
  78. }
  79. buf := r.buf[:length]
  80. nr, err := io.ReadFull(r.r, buf)
  81. n += nr
  82. if err != nil {
  83. return n, err
  84. }
  85. return n, proto.Unmarshal(buf, msg)
  86. }
  87. func (r *varintReader) Close() error {
  88. if r.closer != nil {
  89. return r.closer.Close()
  90. }
  91. return nil
  92. }
  93. func UnmarshalDelimited(data []byte, msg proto.Message) error {
  94. _, err := NewDelimitedReader(bytes.NewReader(data), len(data)).ReadMsg(msg)
  95. return err
  96. }