messages.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. package protocol
  2. import (
  3. "errors"
  4. "io"
  5. "github.com/calmh/syncthing/buffers"
  6. "github.com/calmh/syncthing/xdr"
  7. )
  8. const (
  9. maxNumFiles = 100000 // More than 100000 files is a protocol error
  10. maxNumBlocks = 100000 // 100000 * 128KB = 12.5 GB max acceptable file size
  11. )
  12. var (
  13. ErrMaxFilesExceeded = errors.New("Protocol error: number of files per index exceeds limit")
  14. ErrMaxBlocksExceeded = errors.New("Protocol error: number of blocks per file exceeds limit")
  15. )
  16. type request struct {
  17. repo string
  18. name string
  19. offset int64
  20. size uint32
  21. hash []byte
  22. }
  23. type header struct {
  24. version int
  25. msgID int
  26. msgType int
  27. }
  28. func encodeHeader(h header) uint32 {
  29. return uint32(h.version&0xf)<<28 +
  30. uint32(h.msgID&0xfff)<<16 +
  31. uint32(h.msgType&0xff)<<8
  32. }
  33. func decodeHeader(u uint32) header {
  34. return header{
  35. version: int(u>>28) & 0xf,
  36. msgID: int(u>>16) & 0xfff,
  37. msgType: int(u>>8) & 0xff,
  38. }
  39. }
  40. func WriteIndex(w io.Writer, repo string, idx []FileInfo) (int, error) {
  41. mw := newMarshalWriter(w)
  42. mw.writeIndex(repo, idx)
  43. return int(mw.Tot()), mw.Err()
  44. }
  45. type marshalWriter struct {
  46. *xdr.Writer
  47. }
  48. func newMarshalWriter(w io.Writer) marshalWriter {
  49. return marshalWriter{xdr.NewWriter(w)}
  50. }
  51. func (w *marshalWriter) writeHeader(h header) {
  52. w.WriteUint32(encodeHeader(h))
  53. }
  54. func (w *marshalWriter) writeIndex(repo string, idx []FileInfo) {
  55. w.WriteString(repo)
  56. w.WriteUint32(uint32(len(idx)))
  57. for _, f := range idx {
  58. w.WriteString(f.Name)
  59. w.WriteUint32(f.Flags)
  60. w.WriteUint64(uint64(f.Modified))
  61. w.WriteUint32(f.Version)
  62. w.WriteUint32(uint32(len(f.Blocks)))
  63. for _, b := range f.Blocks {
  64. w.WriteUint32(b.Size)
  65. w.WriteBytes(b.Hash)
  66. }
  67. }
  68. }
  69. func (w *marshalWriter) writeRequest(r request) {
  70. w.WriteString(r.repo)
  71. w.WriteString(r.name)
  72. w.WriteUint64(uint64(r.offset))
  73. w.WriteUint32(r.size)
  74. w.WriteBytes(r.hash)
  75. }
  76. func (w *marshalWriter) writeResponse(data []byte) {
  77. w.WriteBytes(data)
  78. }
  79. func (w *marshalWriter) writeOptions(opts map[string]string) {
  80. w.WriteUint32(uint32(len(opts)))
  81. for k, v := range opts {
  82. w.WriteString(k)
  83. w.WriteString(v)
  84. }
  85. }
  86. func ReadIndex(r io.Reader) (string, []FileInfo, error) {
  87. mr := newMarshalReader(r)
  88. repo, idx := mr.readIndex()
  89. return repo, idx, mr.Err()
  90. }
  91. type marshalReader struct {
  92. *xdr.Reader
  93. err error
  94. }
  95. func newMarshalReader(r io.Reader) marshalReader {
  96. return marshalReader{
  97. Reader: xdr.NewReader(r),
  98. err: nil,
  99. }
  100. }
  101. func (r marshalReader) Err() error {
  102. if r.err != nil {
  103. return r.err
  104. }
  105. return r.Reader.Err()
  106. }
  107. func (r marshalReader) readHeader() header {
  108. return decodeHeader(r.ReadUint32())
  109. }
  110. func (r marshalReader) readIndex() (string, []FileInfo) {
  111. var files []FileInfo
  112. repo := r.ReadString()
  113. nfiles := r.ReadUint32()
  114. if nfiles > maxNumFiles {
  115. r.err = ErrMaxFilesExceeded
  116. return "", nil
  117. }
  118. if nfiles > 0 {
  119. files = make([]FileInfo, nfiles)
  120. for i := range files {
  121. files[i].Name = r.ReadString()
  122. files[i].Flags = r.ReadUint32()
  123. files[i].Modified = int64(r.ReadUint64())
  124. files[i].Version = r.ReadUint32()
  125. nblocks := r.ReadUint32()
  126. if nblocks > maxNumBlocks {
  127. r.err = ErrMaxBlocksExceeded
  128. return "", nil
  129. }
  130. blocks := make([]BlockInfo, nblocks)
  131. for j := range blocks {
  132. blocks[j].Size = r.ReadUint32()
  133. blocks[j].Hash = r.ReadBytes(buffers.Get(32))
  134. }
  135. files[i].Blocks = blocks
  136. }
  137. }
  138. return repo, files
  139. }
  140. func (r marshalReader) readRequest() request {
  141. var req request
  142. req.repo = r.ReadString()
  143. req.name = r.ReadString()
  144. req.offset = int64(r.ReadUint64())
  145. req.size = r.ReadUint32()
  146. req.hash = r.ReadBytes(buffers.Get(32))
  147. return req
  148. }
  149. func (r marshalReader) readResponse() []byte {
  150. return r.ReadBytes(buffers.Get(128 * 1024))
  151. }
  152. func (r marshalReader) readOptions() map[string]string {
  153. n := r.ReadUint32()
  154. opts := make(map[string]string, n)
  155. for i := 0; i < int(n); i++ {
  156. k := r.ReadString()
  157. v := r.ReadString()
  158. opts[k] = v
  159. }
  160. return opts
  161. }