syncthing-arm/protocol/messages.go

187 lines
3.8 KiB
Go
Raw Normal View History

2013-12-15 11:43:31 +01:00
package protocol
import (
"errors"
"io"
2014-02-15 12:08:55 +01:00
"github.com/calmh/syncthing/buffers"
"github.com/calmh/syncthing/xdr"
)
const (
maxNumFiles = 100000 // More than 100000 files is a protocol error
maxNumBlocks = 100000 // 100000 * 128KB = 12.5 GB max acceptable file size
)
var (
ErrMaxFilesExceeded = errors.New("Protocol error: number of files per index exceeds limit")
ErrMaxBlocksExceeded = errors.New("Protocol error: number of blocks per file exceeds limit")
)
2013-12-15 11:43:31 +01:00
type request struct {
repo string
2013-12-15 11:43:31 +01:00
name string
offset int64
2013-12-15 11:43:31 +01:00
size uint32
hash []byte
}
type header struct {
version int
msgID int
msgType int
}
func encodeHeader(h header) uint32 {
return uint32(h.version&0xf)<<28 +
uint32(h.msgID&0xfff)<<16 +
uint32(h.msgType&0xff)<<8
}
func decodeHeader(u uint32) header {
return header{
version: int(u>>28) & 0xf,
msgID: int(u>>16) & 0xfff,
msgType: int(u>>8) & 0xff,
}
}
2014-02-15 12:08:55 +01:00
func WriteIndex(w io.Writer, repo string, idx []FileInfo) (int, error) {
mw := newMarshalWriter(w)
mw.writeIndex(repo, idx)
return int(mw.Tot()), mw.Err()
}
type marshalWriter struct {
*xdr.Writer
}
func newMarshalWriter(w io.Writer) marshalWriter {
return marshalWriter{xdr.NewWriter(w)}
}
2013-12-15 11:43:31 +01:00
func (w *marshalWriter) writeHeader(h header) {
2014-02-15 12:08:55 +01:00
w.WriteUint32(encodeHeader(h))
2013-12-15 11:43:31 +01:00
}
func (w *marshalWriter) writeIndex(repo string, idx []FileInfo) {
2014-02-15 12:08:55 +01:00
w.WriteString(repo)
w.WriteUint32(uint32(len(idx)))
2013-12-15 11:43:31 +01:00
for _, f := range idx {
2014-02-15 12:08:55 +01:00
w.WriteString(f.Name)
w.WriteUint32(f.Flags)
w.WriteUint64(uint64(f.Modified))
w.WriteUint32(f.Version)
w.WriteUint32(uint32(len(f.Blocks)))
2013-12-15 11:43:31 +01:00
for _, b := range f.Blocks {
2014-02-15 12:08:55 +01:00
w.WriteUint32(b.Size)
w.WriteBytes(b.Hash)
2013-12-15 11:43:31 +01:00
}
}
}
func (w *marshalWriter) writeRequest(r request) {
2014-02-15 12:08:55 +01:00
w.WriteString(r.repo)
w.WriteString(r.name)
w.WriteUint64(uint64(r.offset))
w.WriteUint32(r.size)
w.WriteBytes(r.hash)
2013-12-15 11:43:31 +01:00
}
func (w *marshalWriter) writeResponse(data []byte) {
2014-02-15 12:08:55 +01:00
w.WriteBytes(data)
2013-12-15 11:43:31 +01:00
}
2014-01-23 13:12:45 +01:00
func (w *marshalWriter) writeOptions(opts map[string]string) {
2014-02-15 12:08:55 +01:00
w.WriteUint32(uint32(len(opts)))
2014-01-23 13:12:45 +01:00
for k, v := range opts {
2014-02-15 12:08:55 +01:00
w.WriteString(k)
w.WriteString(v)
2014-01-23 13:12:45 +01:00
}
}
2014-02-15 12:08:55 +01:00
func ReadIndex(r io.Reader) (string, []FileInfo, error) {
mr := newMarshalReader(r)
repo, idx := mr.readIndex()
return repo, idx, mr.Err()
2013-12-15 11:43:31 +01:00
}
2014-02-15 12:08:55 +01:00
type marshalReader struct {
*xdr.Reader
err error
}
func newMarshalReader(r io.Reader) marshalReader {
return marshalReader{
Reader: xdr.NewReader(r),
err: nil,
}
}
func (r marshalReader) Err() error {
if r.err != nil {
return r.err
}
return r.Reader.Err()
}
func (r marshalReader) readHeader() header {
return decodeHeader(r.ReadUint32())
}
func (r marshalReader) readIndex() (string, []FileInfo) {
2013-12-15 13:12:32 +01:00
var files []FileInfo
2014-02-15 12:08:55 +01:00
repo := r.ReadString()
nfiles := r.ReadUint32()
if nfiles > maxNumFiles {
r.err = ErrMaxFilesExceeded
return "", nil
}
2013-12-15 13:12:32 +01:00
if nfiles > 0 {
files = make([]FileInfo, nfiles)
for i := range files {
2014-02-15 12:08:55 +01:00
files[i].Name = r.ReadString()
files[i].Flags = r.ReadUint32()
files[i].Modified = int64(r.ReadUint64())
files[i].Version = r.ReadUint32()
nblocks := r.ReadUint32()
if nblocks > maxNumBlocks {
r.err = ErrMaxBlocksExceeded
return "", nil
}
2013-12-15 13:12:32 +01:00
blocks := make([]BlockInfo, nblocks)
for j := range blocks {
2014-02-15 12:08:55 +01:00
blocks[j].Size = r.ReadUint32()
blocks[j].Hash = r.ReadBytes(buffers.Get(32))
2013-12-15 13:12:32 +01:00
}
files[i].Blocks = blocks
2013-12-15 11:43:31 +01:00
}
}
return repo, files
2013-12-15 11:43:31 +01:00
}
2014-02-15 12:08:55 +01:00
func (r marshalReader) readRequest() request {
2013-12-15 11:43:31 +01:00
var req request
2014-02-15 12:08:55 +01:00
req.repo = r.ReadString()
req.name = r.ReadString()
req.offset = int64(r.ReadUint64())
req.size = r.ReadUint32()
req.hash = r.ReadBytes(buffers.Get(32))
2013-12-15 11:43:31 +01:00
return req
}
2014-02-15 12:08:55 +01:00
func (r marshalReader) readResponse() []byte {
return r.ReadBytes(buffers.Get(128 * 1024))
2013-12-15 11:43:31 +01:00
}
2014-01-23 13:12:45 +01:00
2014-02-15 12:08:55 +01:00
func (r marshalReader) readOptions() map[string]string {
n := r.ReadUint32()
2014-01-23 13:12:45 +01:00
opts := make(map[string]string, n)
for i := 0; i < int(n); i++ {
2014-02-15 12:08:55 +01:00
k := r.ReadString()
v := r.ReadString()
2014-01-23 13:12:45 +01:00
opts[k] = v
}
return opts
}