From f2adfde1a893c296850ecf24126d5893e6e59e05 Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Tue, 21 Oct 2014 08:40:05 +0200 Subject: [PATCH] Update xdr; handle marshalling errors --- Godeps/Godeps.json | 4 +- .../src/github.com/calmh/xdr/bench_test.go | 8 +- .../github.com/calmh/xdr/bench_xdr_test.go | 40 +- .../github.com/calmh/xdr/cmd/genxdr/main.go | 26 +- .../src/github.com/calmh/xdr/encdec_test.go | 12 +- .../github.com/calmh/xdr/encdec_xdr_test.go | 54 ++- .../src/github.com/calmh/xdr/reader.go | 10 +- .../src/github.com/calmh/xdr/xdr_test.go | 5 +- internal/discover/discover.go | 8 +- internal/discover/packets_xdr.go | 88 ++-- internal/files/leveldb.go | 9 +- internal/files/leveldb_xdr.go | 32 +- internal/protocol/message_xdr.go | 256 ++++++++---- internal/protocol/protocol.go | 8 +- internal/protocol/protocol_test.go | 3 +- test/h2/config.xml | 388 ++++++++++++++++++ 16 files changed, 781 insertions(+), 170 deletions(-) diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 48c3e99d4..33f7a1ce7 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -1,6 +1,6 @@ { "ImportPath": "github.com/syncthing/syncthing", - "GoVersion": "go1.3.1", + "GoVersion": "go1.3.3", "Packages": [ "./cmd/..." ], @@ -44,7 +44,7 @@ }, { "ImportPath": "github.com/calmh/xdr", - "Rev": "a597b63b87d6140f79084c8aab214b4d533833a1" + "Rev": "ec3d404f43731551258977b38dd72cf557d00398" }, { "ImportPath": "github.com/juju/ratelimit", diff --git a/Godeps/_workspace/src/github.com/calmh/xdr/bench_test.go b/Godeps/_workspace/src/github.com/calmh/xdr/bench_test.go index 4d6c3786a..678147cb9 100644 --- a/Godeps/_workspace/src/github.com/calmh/xdr/bench_test.go +++ b/Godeps/_workspace/src/github.com/calmh/xdr/bench_test.go @@ -33,11 +33,15 @@ var s = XDRBenchStruct{ S0: "Hello World! String one.", S1: "Hello World! String two.", } -var e = s.MarshalXDR() +var e []byte + +func init() { + e, _ = s.MarshalXDR() +} func BenchmarkThisMarshal(b *testing.B) { for i := 0; i < b.N; i++ { - res = s.MarshalXDR() + res, _ = s.MarshalXDR() } } diff --git a/Godeps/_workspace/src/github.com/calmh/xdr/bench_xdr_test.go b/Godeps/_workspace/src/github.com/calmh/xdr/bench_xdr_test.go index 05bcf7a46..d61dffec6 100644 --- a/Godeps/_workspace/src/github.com/calmh/xdr/bench_xdr_test.go +++ b/Godeps/_workspace/src/github.com/calmh/xdr/bench_xdr_test.go @@ -72,15 +72,23 @@ func (o XDRBenchStruct) EncodeXDR(w io.Writer) (int, error) { return o.encodeXDR(xw) } -func (o XDRBenchStruct) MarshalXDR() []byte { +func (o XDRBenchStruct) MarshalXDR() ([]byte, error) { return o.AppendXDR(make([]byte, 0, 128)) } -func (o XDRBenchStruct) AppendXDR(bs []byte) []byte { +func (o XDRBenchStruct) MustMarshalXDR() []byte { + bs, err := o.MarshalXDR() + if err != nil { + panic(err) + } + return bs +} + +func (o XDRBenchStruct) AppendXDR(bs []byte) ([]byte, error) { var aw = xdr.AppendWriter(bs) var xw = xdr.NewWriter(&aw) - o.encodeXDR(xw) - return []byte(aw) + _, err := o.encodeXDR(xw) + return []byte(aw), err } func (o XDRBenchStruct) encodeXDR(xw *xdr.Writer) (int, error) { @@ -88,13 +96,13 @@ func (o XDRBenchStruct) encodeXDR(xw *xdr.Writer) (int, error) { xw.WriteUint32(o.I2) xw.WriteUint16(o.I3) xw.WriteUint8(o.I4) - if len(o.Bs0) > 128 { - return xw.Tot(), xdr.ErrElementSizeExceeded + if l := len(o.Bs0); l > 128 { + return xw.Tot(), xdr.ElementSizeExceeded("Bs0", l, 128) } xw.WriteBytes(o.Bs0) xw.WriteBytes(o.Bs1) - if len(o.S0) > 128 { - return xw.Tot(), xdr.ErrElementSizeExceeded + if l := len(o.S0); l > 128 { + return xw.Tot(), xdr.ElementSizeExceeded("S0", l, 128) } xw.WriteString(o.S0) xw.WriteString(o.S1) @@ -150,15 +158,23 @@ func (o repeatReader) EncodeXDR(w io.Writer) (int, error) { return o.encodeXDR(xw) } -func (o repeatReader) MarshalXDR() []byte { +func (o repeatReader) MarshalXDR() ([]byte, error) { return o.AppendXDR(make([]byte, 0, 128)) } -func (o repeatReader) AppendXDR(bs []byte) []byte { +func (o repeatReader) MustMarshalXDR() []byte { + bs, err := o.MarshalXDR() + if err != nil { + panic(err) + } + return bs +} + +func (o repeatReader) AppendXDR(bs []byte) ([]byte, error) { var aw = xdr.AppendWriter(bs) var xw = xdr.NewWriter(&aw) - o.encodeXDR(xw) - return []byte(aw) + _, err := o.encodeXDR(xw) + return []byte(aw), err } func (o repeatReader) encodeXDR(xw *xdr.Writer) (int, error) { diff --git a/Godeps/_workspace/src/github.com/calmh/xdr/cmd/genxdr/main.go b/Godeps/_workspace/src/github.com/calmh/xdr/cmd/genxdr/main.go index 90941a730..1103d02a8 100644 --- a/Godeps/_workspace/src/github.com/calmh/xdr/cmd/genxdr/main.go +++ b/Godeps/_workspace/src/github.com/calmh/xdr/cmd/genxdr/main.go @@ -53,15 +53,23 @@ func (o {{.TypeName}}) EncodeXDR(w io.Writer) (int, error) { return o.encodeXDR(xw) }//+n -func (o {{.TypeName}}) MarshalXDR() []byte { +func (o {{.TypeName}}) MarshalXDR() ([]byte, error) { return o.AppendXDR(make([]byte, 0, 128)) }//+n -func (o {{.TypeName}}) AppendXDR(bs []byte) []byte { +func (o {{.TypeName}}) MustMarshalXDR() []byte { + bs, err := o.MarshalXDR() + if err != nil { + panic(err) + } + return bs +}//+n + +func (o {{.TypeName}}) AppendXDR(bs []byte) ([]byte, error) { var aw = xdr.AppendWriter(bs) var xw = xdr.NewWriter(&aw) - o.encodeXDR(xw) - return []byte(aw) + _, err := o.encodeXDR(xw) + return []byte(aw), err }//+n func (o {{.TypeName}}) encodeXDR(xw *xdr.Writer) (int, error) { @@ -71,8 +79,8 @@ func (o {{.TypeName}}) encodeXDR(xw *xdr.Writer) (int, error) { xw.Write{{$fieldInfo.Encoder}}({{$fieldInfo.Convert}}(o.{{$fieldInfo.Name}})) {{else if $fieldInfo.IsBasic}} {{if ge $fieldInfo.Max 1}} - if len(o.{{$fieldInfo.Name}}) > {{$fieldInfo.Max}} { - return xw.Tot(), xdr.ErrElementSizeExceeded + if l := len(o.{{$fieldInfo.Name}}); l > {{$fieldInfo.Max}} { + return xw.Tot(), xdr.ElementSizeExceeded("{{$fieldInfo.Name}}", l, {{$fieldInfo.Max}}) } {{end}} xw.Write{{$fieldInfo.Encoder}}(o.{{$fieldInfo.Name}}) @@ -84,8 +92,8 @@ func (o {{.TypeName}}) encodeXDR(xw *xdr.Writer) (int, error) { {{end}} {{else}} {{if ge $fieldInfo.Max 1}} - if len(o.{{$fieldInfo.Name}}) > {{$fieldInfo.Max}} { - return xw.Tot(), xdr.ErrElementSizeExceeded + if l := len(o.{{$fieldInfo.Name}}); l > {{$fieldInfo.Max}} { + return xw.Tot(), xdr.ElementSizeExceeded("{{$fieldInfo.Name}}", l, {{$fieldInfo.Max}}) } {{end}} xw.WriteUint32(uint32(len(o.{{$fieldInfo.Name}}))) @@ -135,7 +143,7 @@ func (o *{{.TypeName}}) decodeXDR(xr *xdr.Reader) error { _{{$fieldInfo.Name}}Size := int(xr.ReadUint32()) {{if ge $fieldInfo.Max 1}} if _{{$fieldInfo.Name}}Size > {{$fieldInfo.Max}} { - return xdr.ErrElementSizeExceeded + return xdr.ElementSizeExceeded("{{$fieldInfo.Name}}", _{{$fieldInfo.Name}}Size, {{$fieldInfo.Max}}) } {{end}} o.{{$fieldInfo.Name}} = make([]{{$fieldInfo.FieldType}}, _{{$fieldInfo.Name}}Size) diff --git a/Godeps/_workspace/src/github.com/calmh/xdr/encdec_test.go b/Godeps/_workspace/src/github.com/calmh/xdr/encdec_test.go index eb42705c9..7c0292220 100644 --- a/Godeps/_workspace/src/github.com/calmh/xdr/encdec_test.go +++ b/Godeps/_workspace/src/github.com/calmh/xdr/encdec_test.go @@ -24,9 +24,10 @@ type TestStruct struct { UI32 uint32 I64 int64 UI64 uint64 - BS []byte - S string + BS []byte // max:1024 + S string // max:1024 C Opaque + SS []string // max:1024 } type Opaque [32]byte @@ -49,9 +50,12 @@ func (Opaque) Generate(rand *rand.Rand, size int) reflect.Value { func TestEncDec(t *testing.T) { fn := func(t0 TestStruct) bool { - bs := t0.MarshalXDR() + bs, err := t0.MarshalXDR() + if err != nil { + t.Fatal(err) + } var t1 TestStruct - err := t1.UnmarshalXDR(bs) + err = t1.UnmarshalXDR(bs) if err != nil { t.Fatal(err) } diff --git a/Godeps/_workspace/src/github.com/calmh/xdr/encdec_xdr_test.go b/Godeps/_workspace/src/github.com/calmh/xdr/encdec_xdr_test.go index 35bd59af5..645e0e8d5 100644 --- a/Godeps/_workspace/src/github.com/calmh/xdr/encdec_xdr_test.go +++ b/Godeps/_workspace/src/github.com/calmh/xdr/encdec_xdr_test.go @@ -54,6 +54,14 @@ TestStruct Structure: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Opaque | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Number of SS | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Length of SS | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/ / +\ SS (variable length) \ +/ / ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ struct TestStruct { @@ -66,9 +74,10 @@ struct TestStruct { unsigned int UI32; hyper I64; unsigned hyper UI64; - opaque BS<>; - string S<>; + opaque BS<1024>; + string S<1024>; Opaque C; + string SS<1024>; } */ @@ -78,15 +87,23 @@ func (o TestStruct) EncodeXDR(w io.Writer) (int, error) { return o.encodeXDR(xw) } -func (o TestStruct) MarshalXDR() []byte { +func (o TestStruct) MarshalXDR() ([]byte, error) { return o.AppendXDR(make([]byte, 0, 128)) } -func (o TestStruct) AppendXDR(bs []byte) []byte { +func (o TestStruct) MustMarshalXDR() []byte { + bs, err := o.MarshalXDR() + if err != nil { + panic(err) + } + return bs +} + +func (o TestStruct) AppendXDR(bs []byte) ([]byte, error) { var aw = xdr.AppendWriter(bs) var xw = xdr.NewWriter(&aw) - o.encodeXDR(xw) - return []byte(aw) + _, err := o.encodeXDR(xw) + return []byte(aw), err } func (o TestStruct) encodeXDR(xw *xdr.Writer) (int, error) { @@ -99,12 +116,25 @@ func (o TestStruct) encodeXDR(xw *xdr.Writer) (int, error) { xw.WriteUint32(o.UI32) xw.WriteUint64(uint64(o.I64)) xw.WriteUint64(o.UI64) + if l := len(o.BS); l > 1024 { + return xw.Tot(), xdr.ElementSizeExceeded("BS", l, 1024) + } xw.WriteBytes(o.BS) + if l := len(o.S); l > 1024 { + return xw.Tot(), xdr.ElementSizeExceeded("S", l, 1024) + } xw.WriteString(o.S) _, err := o.C.encodeXDR(xw) if err != nil { return xw.Tot(), err } + if l := len(o.SS); l > 1024 { + return xw.Tot(), xdr.ElementSizeExceeded("SS", l, 1024) + } + xw.WriteUint32(uint32(len(o.SS))) + for i := range o.SS { + xw.WriteString(o.SS[i]) + } return xw.Tot(), xw.Error() } @@ -129,8 +159,16 @@ func (o *TestStruct) decodeXDR(xr *xdr.Reader) error { o.UI32 = xr.ReadUint32() o.I64 = int64(xr.ReadUint64()) o.UI64 = xr.ReadUint64() - o.BS = xr.ReadBytes() - o.S = xr.ReadString() + o.BS = xr.ReadBytesMax(1024) + o.S = xr.ReadStringMax(1024) (&o.C).decodeXDR(xr) + _SSSize := int(xr.ReadUint32()) + if _SSSize > 1024 { + return xdr.ElementSizeExceeded("SS", _SSSize, 1024) + } + o.SS = make([]string, _SSSize) + for i := range o.SS { + o.SS[i] = xr.ReadString() + } return xr.Error() } diff --git a/Godeps/_workspace/src/github.com/calmh/xdr/reader.go b/Godeps/_workspace/src/github.com/calmh/xdr/reader.go index a96e66a84..c21b9ce67 100644 --- a/Godeps/_workspace/src/github.com/calmh/xdr/reader.go +++ b/Godeps/_workspace/src/github.com/calmh/xdr/reader.go @@ -5,14 +5,12 @@ package xdr import ( - "errors" + "fmt" "io" "reflect" "unsafe" ) -var ErrElementSizeExceeded = errors.New("element size exceeded") - type Reader struct { r io.Reader err error @@ -71,7 +69,7 @@ func (r *Reader) ReadBytesMaxInto(max int, dst []byte) []byte { return nil } if max > 0 && l > max { - r.err = ErrElementSizeExceeded + r.err = ElementSizeExceeded("bytes field", l, max) return nil } @@ -162,3 +160,7 @@ func (r *Reader) Error() error { } return XDRError{"read", r.err} } + +func ElementSizeExceeded(field string, size, limit int) error { + return fmt.Errorf("%s exceeds size limit; %d > %d", field, size, limit) +} diff --git a/Godeps/_workspace/src/github.com/calmh/xdr/xdr_test.go b/Godeps/_workspace/src/github.com/calmh/xdr/xdr_test.go index bfc4bf8dd..7744db2c6 100644 --- a/Godeps/_workspace/src/github.com/calmh/xdr/xdr_test.go +++ b/Godeps/_workspace/src/github.com/calmh/xdr/xdr_test.go @@ -5,6 +5,7 @@ package xdr import ( "bytes" + "strings" "testing" "testing/quick" ) @@ -60,7 +61,7 @@ func TestReadBytesMaxInto(t *testing.T) { if read := len(bs); read != tot { t.Errorf("Incorrect read bytes, wrote=%d, buf=%d, max=%d, read=%d", tot, tot+diff, max, read) } - } else if r.err != ErrElementSizeExceeded { + } else if !strings.Contains(r.err.Error(), "exceeds size") { t.Errorf("Unexpected non-ErrElementSizeExceeded error for wrote=%d, max=%d: %v", tot, max, r.err) } } @@ -84,7 +85,7 @@ func TestReadStringMax(t *testing.T) { if read != tot { t.Errorf("Incorrect read bytes, wrote=%d, max=%d, read=%d", tot, max, read) } - } else if r.err != ErrElementSizeExceeded { + } else if !strings.Contains(r.err.Error(), "exceeds size") { t.Errorf("Unexpected non-ErrElementSizeExceeded error for wrote=%d, max=%d, read=%d: %v", tot, max, read, r.err) } } diff --git a/internal/discover/discover.go b/internal/discover/discover.go index 39365bbc6..71f2c500c 100644 --- a/internal/discover/discover.go +++ b/internal/discover/discover.go @@ -203,7 +203,7 @@ func (d *Discoverer) announcementPkt() []byte { Magic: AnnouncementMagic, This: Device{d.myID[:], addrs}, } - return pkt.MarshalXDR() + return pkt.MustMarshalXDR() } func (d *Discoverer) sendLocalAnnouncements() { @@ -213,7 +213,7 @@ func (d *Discoverer) sendLocalAnnouncements() { Magic: AnnouncementMagic, This: Device{d.myID[:], addrs}, } - msg := pkt.MarshalXDR() + msg := pkt.MustMarshalXDR() for { if d.multicastBeacon != nil { @@ -253,7 +253,7 @@ func (d *Discoverer) sendExternalAnnouncements() { Magic: AnnouncementMagic, This: Device{d.myID[:], []Address{{Port: d.extPort}}}, } - buf = pkt.MarshalXDR() + buf = pkt.MustMarshalXDR() } else { buf = d.announcementPkt() } @@ -425,7 +425,7 @@ func (d *Discoverer) externalLookup(device protocol.DeviceID) []string { return nil } - buf := Query{QueryMagic, device[:]}.MarshalXDR() + buf := Query{QueryMagic, device[:]}.MustMarshalXDR() _, err = conn.Write(buf) if err != nil { if debug { diff --git a/internal/discover/packets_xdr.go b/internal/discover/packets_xdr.go index ef004f05c..545b46fca 100644 --- a/internal/discover/packets_xdr.go +++ b/internal/discover/packets_xdr.go @@ -40,21 +40,29 @@ func (o Query) EncodeXDR(w io.Writer) (int, error) { return o.encodeXDR(xw) } -func (o Query) MarshalXDR() []byte { +func (o Query) MarshalXDR() ([]byte, error) { return o.AppendXDR(make([]byte, 0, 128)) } -func (o Query) AppendXDR(bs []byte) []byte { +func (o Query) MustMarshalXDR() []byte { + bs, err := o.MarshalXDR() + if err != nil { + panic(err) + } + return bs +} + +func (o Query) AppendXDR(bs []byte) ([]byte, error) { var aw = xdr.AppendWriter(bs) var xw = xdr.NewWriter(&aw) - o.encodeXDR(xw) - return []byte(aw) + _, err := o.encodeXDR(xw) + return []byte(aw), err } func (o Query) encodeXDR(xw *xdr.Writer) (int, error) { xw.WriteUint32(o.Magic) - if len(o.DeviceID) > 32 { - return xw.Tot(), xdr.ErrElementSizeExceeded + if l := len(o.DeviceID); l > 32 { + return xw.Tot(), xdr.ElementSizeExceeded("DeviceID", l, 32) } xw.WriteBytes(o.DeviceID) return xw.Tot(), xw.Error() @@ -109,15 +117,23 @@ func (o Announce) EncodeXDR(w io.Writer) (int, error) { return o.encodeXDR(xw) } -func (o Announce) MarshalXDR() []byte { +func (o Announce) MarshalXDR() ([]byte, error) { return o.AppendXDR(make([]byte, 0, 128)) } -func (o Announce) AppendXDR(bs []byte) []byte { +func (o Announce) MustMarshalXDR() []byte { + bs, err := o.MarshalXDR() + if err != nil { + panic(err) + } + return bs +} + +func (o Announce) AppendXDR(bs []byte) ([]byte, error) { var aw = xdr.AppendWriter(bs) var xw = xdr.NewWriter(&aw) - o.encodeXDR(xw) - return []byte(aw) + _, err := o.encodeXDR(xw) + return []byte(aw), err } func (o Announce) encodeXDR(xw *xdr.Writer) (int, error) { @@ -126,8 +142,8 @@ func (o Announce) encodeXDR(xw *xdr.Writer) (int, error) { if err != nil { return xw.Tot(), err } - if len(o.Extra) > 16 { - return xw.Tot(), xdr.ErrElementSizeExceeded + if l := len(o.Extra); l > 16 { + return xw.Tot(), xdr.ElementSizeExceeded("Extra", l, 16) } xw.WriteUint32(uint32(len(o.Extra))) for i := range o.Extra { @@ -155,7 +171,7 @@ func (o *Announce) decodeXDR(xr *xdr.Reader) error { (&o.This).decodeXDR(xr) _ExtraSize := int(xr.ReadUint32()) if _ExtraSize > 16 { - return xdr.ErrElementSizeExceeded + return xdr.ElementSizeExceeded("Extra", _ExtraSize, 16) } o.Extra = make([]Device, _ExtraSize) for i := range o.Extra { @@ -197,24 +213,32 @@ func (o Device) EncodeXDR(w io.Writer) (int, error) { return o.encodeXDR(xw) } -func (o Device) MarshalXDR() []byte { +func (o Device) MarshalXDR() ([]byte, error) { return o.AppendXDR(make([]byte, 0, 128)) } -func (o Device) AppendXDR(bs []byte) []byte { +func (o Device) MustMarshalXDR() []byte { + bs, err := o.MarshalXDR() + if err != nil { + panic(err) + } + return bs +} + +func (o Device) AppendXDR(bs []byte) ([]byte, error) { var aw = xdr.AppendWriter(bs) var xw = xdr.NewWriter(&aw) - o.encodeXDR(xw) - return []byte(aw) + _, err := o.encodeXDR(xw) + return []byte(aw), err } func (o Device) encodeXDR(xw *xdr.Writer) (int, error) { - if len(o.ID) > 32 { - return xw.Tot(), xdr.ErrElementSizeExceeded + if l := len(o.ID); l > 32 { + return xw.Tot(), xdr.ElementSizeExceeded("ID", l, 32) } xw.WriteBytes(o.ID) - if len(o.Addresses) > 16 { - return xw.Tot(), xdr.ErrElementSizeExceeded + if l := len(o.Addresses); l > 16 { + return xw.Tot(), xdr.ElementSizeExceeded("Addresses", l, 16) } xw.WriteUint32(uint32(len(o.Addresses))) for i := range o.Addresses { @@ -241,7 +265,7 @@ func (o *Device) decodeXDR(xr *xdr.Reader) error { o.ID = xr.ReadBytesMax(32) _AddressesSize := int(xr.ReadUint32()) if _AddressesSize > 16 { - return xdr.ErrElementSizeExceeded + return xdr.ElementSizeExceeded("Addresses", _AddressesSize, 16) } o.Addresses = make([]Address, _AddressesSize) for i := range o.Addresses { @@ -279,20 +303,28 @@ func (o Address) EncodeXDR(w io.Writer) (int, error) { return o.encodeXDR(xw) } -func (o Address) MarshalXDR() []byte { +func (o Address) MarshalXDR() ([]byte, error) { return o.AppendXDR(make([]byte, 0, 128)) } -func (o Address) AppendXDR(bs []byte) []byte { +func (o Address) MustMarshalXDR() []byte { + bs, err := o.MarshalXDR() + if err != nil { + panic(err) + } + return bs +} + +func (o Address) AppendXDR(bs []byte) ([]byte, error) { var aw = xdr.AppendWriter(bs) var xw = xdr.NewWriter(&aw) - o.encodeXDR(xw) - return []byte(aw) + _, err := o.encodeXDR(xw) + return []byte(aw), err } func (o Address) encodeXDR(xw *xdr.Writer) (int, error) { - if len(o.IP) > 16 { - return xw.Tot(), xdr.ErrElementSizeExceeded + if l := len(o.IP); l > 16 { + return xw.Tot(), xdr.ElementSizeExceeded("IP", l, 16) } xw.WriteBytes(o.IP) xw.WriteUint16(o.Port) diff --git a/internal/files/leveldb.go b/internal/files/leveldb.go index 06c8bba67..9d393c955 100644 --- a/internal/files/leveldb.go +++ b/internal/files/leveldb.go @@ -289,7 +289,8 @@ func ldbReplaceWithDelete(db *leveldb.DB, folder, device []byte, fs []protocol.F Flags: tf.Flags | protocol.FlagDeleted, Modified: tf.Modified, } - batch.Put(dbi.Key(), f.MarshalXDR()) + bs, _ := f.MarshalXDR() + batch.Put(dbi.Key(), bs) ldbUpdateGlobal(db, batch, folder, device, deviceKeyName(dbi.Key()), f.Version) return ts } @@ -362,7 +363,7 @@ func ldbInsert(batch dbWriter, folder, device []byte, file protocol.FileInfo) ui name := []byte(file.Name) nk := deviceKey(folder, device, name) - batch.Put(nk, file.MarshalXDR()) + batch.Put(nk, file.MustMarshalXDR()) return file.LocalVersion } @@ -416,7 +417,7 @@ func ldbUpdateGlobal(db dbReader, batch dbWriter, folder, device, file []byte, v fl.versions = append(fl.versions, nv) done: - batch.Put(gk, fl.MarshalXDR()) + batch.Put(gk, fl.MustMarshalXDR()) return true } @@ -453,7 +454,7 @@ func ldbRemoveFromGlobal(db dbReader, batch dbWriter, folder, device, file []byt if len(fl.versions) == 0 { batch.Delete(gk) } else { - batch.Put(gk, fl.MarshalXDR()) + batch.Put(gk, fl.MustMarshalXDR()) } } diff --git a/internal/files/leveldb_xdr.go b/internal/files/leveldb_xdr.go index 8933a6249..f8511c0a3 100644 --- a/internal/files/leveldb_xdr.go +++ b/internal/files/leveldb_xdr.go @@ -42,15 +42,23 @@ func (o fileVersion) EncodeXDR(w io.Writer) (int, error) { return o.encodeXDR(xw) } -func (o fileVersion) MarshalXDR() []byte { +func (o fileVersion) MarshalXDR() ([]byte, error) { return o.AppendXDR(make([]byte, 0, 128)) } -func (o fileVersion) AppendXDR(bs []byte) []byte { +func (o fileVersion) MustMarshalXDR() []byte { + bs, err := o.MarshalXDR() + if err != nil { + panic(err) + } + return bs +} + +func (o fileVersion) AppendXDR(bs []byte) ([]byte, error) { var aw = xdr.AppendWriter(bs) var xw = xdr.NewWriter(&aw) - o.encodeXDR(xw) - return []byte(aw) + _, err := o.encodeXDR(xw) + return []byte(aw), err } func (o fileVersion) encodeXDR(xw *xdr.Writer) (int, error) { @@ -102,15 +110,23 @@ func (o versionList) EncodeXDR(w io.Writer) (int, error) { return o.encodeXDR(xw) } -func (o versionList) MarshalXDR() []byte { +func (o versionList) MarshalXDR() ([]byte, error) { return o.AppendXDR(make([]byte, 0, 128)) } -func (o versionList) AppendXDR(bs []byte) []byte { +func (o versionList) MustMarshalXDR() []byte { + bs, err := o.MarshalXDR() + if err != nil { + panic(err) + } + return bs +} + +func (o versionList) AppendXDR(bs []byte) ([]byte, error) { var aw = xdr.AppendWriter(bs) var xw = xdr.NewWriter(&aw) - o.encodeXDR(xw) - return []byte(aw) + _, err := o.encodeXDR(xw) + return []byte(aw), err } func (o versionList) encodeXDR(xw *xdr.Writer) (int, error) { diff --git a/internal/protocol/message_xdr.go b/internal/protocol/message_xdr.go index 324125ea4..948e63c32 100644 --- a/internal/protocol/message_xdr.go +++ b/internal/protocol/message_xdr.go @@ -44,20 +44,28 @@ func (o IndexMessage) EncodeXDR(w io.Writer) (int, error) { return o.encodeXDR(xw) } -func (o IndexMessage) MarshalXDR() []byte { +func (o IndexMessage) MarshalXDR() ([]byte, error) { return o.AppendXDR(make([]byte, 0, 128)) } -func (o IndexMessage) AppendXDR(bs []byte) []byte { +func (o IndexMessage) MustMarshalXDR() []byte { + bs, err := o.MarshalXDR() + if err != nil { + panic(err) + } + return bs +} + +func (o IndexMessage) AppendXDR(bs []byte) ([]byte, error) { var aw = xdr.AppendWriter(bs) var xw = xdr.NewWriter(&aw) - o.encodeXDR(xw) - return []byte(aw) + _, err := o.encodeXDR(xw) + return []byte(aw), err } func (o IndexMessage) encodeXDR(xw *xdr.Writer) (int, error) { - if len(o.Folder) > 64 { - return xw.Tot(), xdr.ErrElementSizeExceeded + if l := len(o.Folder); l > 64 { + return xw.Tot(), xdr.ElementSizeExceeded("Folder", l, 64) } xw.WriteString(o.Folder) xw.WriteUint32(uint32(len(o.Files))) @@ -142,20 +150,28 @@ func (o FileInfo) EncodeXDR(w io.Writer) (int, error) { return o.encodeXDR(xw) } -func (o FileInfo) MarshalXDR() []byte { +func (o FileInfo) MarshalXDR() ([]byte, error) { return o.AppendXDR(make([]byte, 0, 128)) } -func (o FileInfo) AppendXDR(bs []byte) []byte { +func (o FileInfo) MustMarshalXDR() []byte { + bs, err := o.MarshalXDR() + if err != nil { + panic(err) + } + return bs +} + +func (o FileInfo) AppendXDR(bs []byte) ([]byte, error) { var aw = xdr.AppendWriter(bs) var xw = xdr.NewWriter(&aw) - o.encodeXDR(xw) - return []byte(aw) + _, err := o.encodeXDR(xw) + return []byte(aw), err } func (o FileInfo) encodeXDR(xw *xdr.Writer) (int, error) { - if len(o.Name) > 8192 { - return xw.Tot(), xdr.ErrElementSizeExceeded + if l := len(o.Name); l > 8192 { + return xw.Tot(), xdr.ElementSizeExceeded("Name", l, 8192) } xw.WriteString(o.Name) xw.WriteUint32(o.Flags) @@ -244,20 +260,28 @@ func (o FileInfoTruncated) EncodeXDR(w io.Writer) (int, error) { return o.encodeXDR(xw) } -func (o FileInfoTruncated) MarshalXDR() []byte { +func (o FileInfoTruncated) MarshalXDR() ([]byte, error) { return o.AppendXDR(make([]byte, 0, 128)) } -func (o FileInfoTruncated) AppendXDR(bs []byte) []byte { +func (o FileInfoTruncated) MustMarshalXDR() []byte { + bs, err := o.MarshalXDR() + if err != nil { + panic(err) + } + return bs +} + +func (o FileInfoTruncated) AppendXDR(bs []byte) ([]byte, error) { var aw = xdr.AppendWriter(bs) var xw = xdr.NewWriter(&aw) - o.encodeXDR(xw) - return []byte(aw) + _, err := o.encodeXDR(xw) + return []byte(aw), err } func (o FileInfoTruncated) encodeXDR(xw *xdr.Writer) (int, error) { - if len(o.Name) > 8192 { - return xw.Tot(), xdr.ErrElementSizeExceeded + if l := len(o.Name); l > 8192 { + return xw.Tot(), xdr.ElementSizeExceeded("Name", l, 8192) } xw.WriteString(o.Name) xw.WriteUint32(o.Flags) @@ -318,21 +342,29 @@ func (o BlockInfo) EncodeXDR(w io.Writer) (int, error) { return o.encodeXDR(xw) } -func (o BlockInfo) MarshalXDR() []byte { +func (o BlockInfo) MarshalXDR() ([]byte, error) { return o.AppendXDR(make([]byte, 0, 128)) } -func (o BlockInfo) AppendXDR(bs []byte) []byte { +func (o BlockInfo) MustMarshalXDR() []byte { + bs, err := o.MarshalXDR() + if err != nil { + panic(err) + } + return bs +} + +func (o BlockInfo) AppendXDR(bs []byte) ([]byte, error) { var aw = xdr.AppendWriter(bs) var xw = xdr.NewWriter(&aw) - o.encodeXDR(xw) - return []byte(aw) + _, err := o.encodeXDR(xw) + return []byte(aw), err } func (o BlockInfo) encodeXDR(xw *xdr.Writer) (int, error) { xw.WriteUint32(o.Size) - if len(o.Hash) > 64 { - return xw.Tot(), xdr.ErrElementSizeExceeded + if l := len(o.Hash); l > 64 { + return xw.Tot(), xdr.ElementSizeExceeded("Hash", l, 64) } xw.WriteBytes(o.Hash) return xw.Tot(), xw.Error() @@ -396,24 +428,32 @@ func (o RequestMessage) EncodeXDR(w io.Writer) (int, error) { return o.encodeXDR(xw) } -func (o RequestMessage) MarshalXDR() []byte { +func (o RequestMessage) MarshalXDR() ([]byte, error) { return o.AppendXDR(make([]byte, 0, 128)) } -func (o RequestMessage) AppendXDR(bs []byte) []byte { +func (o RequestMessage) MustMarshalXDR() []byte { + bs, err := o.MarshalXDR() + if err != nil { + panic(err) + } + return bs +} + +func (o RequestMessage) AppendXDR(bs []byte) ([]byte, error) { var aw = xdr.AppendWriter(bs) var xw = xdr.NewWriter(&aw) - o.encodeXDR(xw) - return []byte(aw) + _, err := o.encodeXDR(xw) + return []byte(aw), err } func (o RequestMessage) encodeXDR(xw *xdr.Writer) (int, error) { - if len(o.Folder) > 64 { - return xw.Tot(), xdr.ErrElementSizeExceeded + if l := len(o.Folder); l > 64 { + return xw.Tot(), xdr.ElementSizeExceeded("Folder", l, 64) } xw.WriteString(o.Folder) - if len(o.Name) > 8192 { - return xw.Tot(), xdr.ErrElementSizeExceeded + if l := len(o.Name); l > 8192 { + return xw.Tot(), xdr.ElementSizeExceeded("Name", l, 8192) } xw.WriteString(o.Name) xw.WriteUint64(o.Offset) @@ -466,15 +506,23 @@ func (o ResponseMessage) EncodeXDR(w io.Writer) (int, error) { return o.encodeXDR(xw) } -func (o ResponseMessage) MarshalXDR() []byte { +func (o ResponseMessage) MarshalXDR() ([]byte, error) { return o.AppendXDR(make([]byte, 0, 128)) } -func (o ResponseMessage) AppendXDR(bs []byte) []byte { +func (o ResponseMessage) MustMarshalXDR() []byte { + bs, err := o.MarshalXDR() + if err != nil { + panic(err) + } + return bs +} + +func (o ResponseMessage) AppendXDR(bs []byte) ([]byte, error) { var aw = xdr.AppendWriter(bs) var xw = xdr.NewWriter(&aw) - o.encodeXDR(xw) - return []byte(aw) + _, err := o.encodeXDR(xw) + return []byte(aw), err } func (o ResponseMessage) encodeXDR(xw *xdr.Writer) (int, error) { @@ -545,28 +593,36 @@ func (o ClusterConfigMessage) EncodeXDR(w io.Writer) (int, error) { return o.encodeXDR(xw) } -func (o ClusterConfigMessage) MarshalXDR() []byte { +func (o ClusterConfigMessage) MarshalXDR() ([]byte, error) { return o.AppendXDR(make([]byte, 0, 128)) } -func (o ClusterConfigMessage) AppendXDR(bs []byte) []byte { +func (o ClusterConfigMessage) MustMarshalXDR() []byte { + bs, err := o.MarshalXDR() + if err != nil { + panic(err) + } + return bs +} + +func (o ClusterConfigMessage) AppendXDR(bs []byte) ([]byte, error) { var aw = xdr.AppendWriter(bs) var xw = xdr.NewWriter(&aw) - o.encodeXDR(xw) - return []byte(aw) + _, err := o.encodeXDR(xw) + return []byte(aw), err } func (o ClusterConfigMessage) encodeXDR(xw *xdr.Writer) (int, error) { - if len(o.ClientName) > 64 { - return xw.Tot(), xdr.ErrElementSizeExceeded + if l := len(o.ClientName); l > 64 { + return xw.Tot(), xdr.ElementSizeExceeded("ClientName", l, 64) } xw.WriteString(o.ClientName) - if len(o.ClientVersion) > 64 { - return xw.Tot(), xdr.ErrElementSizeExceeded + if l := len(o.ClientVersion); l > 64 { + return xw.Tot(), xdr.ElementSizeExceeded("ClientVersion", l, 64) } xw.WriteString(o.ClientVersion) - if len(o.Folders) > 64 { - return xw.Tot(), xdr.ErrElementSizeExceeded + if l := len(o.Folders); l > 64 { + return xw.Tot(), xdr.ElementSizeExceeded("Folders", l, 64) } xw.WriteUint32(uint32(len(o.Folders))) for i := range o.Folders { @@ -575,8 +631,8 @@ func (o ClusterConfigMessage) encodeXDR(xw *xdr.Writer) (int, error) { return xw.Tot(), err } } - if len(o.Options) > 64 { - return xw.Tot(), xdr.ErrElementSizeExceeded + if l := len(o.Options); l > 64 { + return xw.Tot(), xdr.ElementSizeExceeded("Options", l, 64) } xw.WriteUint32(uint32(len(o.Options))) for i := range o.Options { @@ -604,7 +660,7 @@ func (o *ClusterConfigMessage) decodeXDR(xr *xdr.Reader) error { o.ClientVersion = xr.ReadStringMax(64) _FoldersSize := int(xr.ReadUint32()) if _FoldersSize > 64 { - return xdr.ErrElementSizeExceeded + return xdr.ElementSizeExceeded("Folders", _FoldersSize, 64) } o.Folders = make([]Folder, _FoldersSize) for i := range o.Folders { @@ -612,7 +668,7 @@ func (o *ClusterConfigMessage) decodeXDR(xr *xdr.Reader) error { } _OptionsSize := int(xr.ReadUint32()) if _OptionsSize > 64 { - return xdr.ErrElementSizeExceeded + return xdr.ElementSizeExceeded("Options", _OptionsSize, 64) } o.Options = make([]Option, _OptionsSize) for i := range o.Options { @@ -654,20 +710,28 @@ func (o Folder) EncodeXDR(w io.Writer) (int, error) { return o.encodeXDR(xw) } -func (o Folder) MarshalXDR() []byte { +func (o Folder) MarshalXDR() ([]byte, error) { return o.AppendXDR(make([]byte, 0, 128)) } -func (o Folder) AppendXDR(bs []byte) []byte { +func (o Folder) MustMarshalXDR() []byte { + bs, err := o.MarshalXDR() + if err != nil { + panic(err) + } + return bs +} + +func (o Folder) AppendXDR(bs []byte) ([]byte, error) { var aw = xdr.AppendWriter(bs) var xw = xdr.NewWriter(&aw) - o.encodeXDR(xw) - return []byte(aw) + _, err := o.encodeXDR(xw) + return []byte(aw), err } func (o Folder) encodeXDR(xw *xdr.Writer) (int, error) { - if len(o.ID) > 64 { - return xw.Tot(), xdr.ErrElementSizeExceeded + if l := len(o.ID); l > 64 { + return xw.Tot(), xdr.ElementSizeExceeded("ID", l, 64) } xw.WriteString(o.ID) xw.WriteUint32(uint32(len(o.Devices))) @@ -735,20 +799,28 @@ func (o Device) EncodeXDR(w io.Writer) (int, error) { return o.encodeXDR(xw) } -func (o Device) MarshalXDR() []byte { +func (o Device) MarshalXDR() ([]byte, error) { return o.AppendXDR(make([]byte, 0, 128)) } -func (o Device) AppendXDR(bs []byte) []byte { +func (o Device) MustMarshalXDR() []byte { + bs, err := o.MarshalXDR() + if err != nil { + panic(err) + } + return bs +} + +func (o Device) AppendXDR(bs []byte) ([]byte, error) { var aw = xdr.AppendWriter(bs) var xw = xdr.NewWriter(&aw) - o.encodeXDR(xw) - return []byte(aw) + _, err := o.encodeXDR(xw) + return []byte(aw), err } func (o Device) encodeXDR(xw *xdr.Writer) (int, error) { - if len(o.ID) > 32 { - return xw.Tot(), xdr.ErrElementSizeExceeded + if l := len(o.ID); l > 32 { + return xw.Tot(), xdr.ElementSizeExceeded("ID", l, 32) } xw.WriteBytes(o.ID) xw.WriteUint32(o.Flags) @@ -807,24 +879,32 @@ func (o Option) EncodeXDR(w io.Writer) (int, error) { return o.encodeXDR(xw) } -func (o Option) MarshalXDR() []byte { +func (o Option) MarshalXDR() ([]byte, error) { return o.AppendXDR(make([]byte, 0, 128)) } -func (o Option) AppendXDR(bs []byte) []byte { +func (o Option) MustMarshalXDR() []byte { + bs, err := o.MarshalXDR() + if err != nil { + panic(err) + } + return bs +} + +func (o Option) AppendXDR(bs []byte) ([]byte, error) { var aw = xdr.AppendWriter(bs) var xw = xdr.NewWriter(&aw) - o.encodeXDR(xw) - return []byte(aw) + _, err := o.encodeXDR(xw) + return []byte(aw), err } func (o Option) encodeXDR(xw *xdr.Writer) (int, error) { - if len(o.Key) > 64 { - return xw.Tot(), xdr.ErrElementSizeExceeded + if l := len(o.Key); l > 64 { + return xw.Tot(), xdr.ElementSizeExceeded("Key", l, 64) } xw.WriteString(o.Key) - if len(o.Value) > 1024 { - return xw.Tot(), xdr.ErrElementSizeExceeded + if l := len(o.Value); l > 1024 { + return xw.Tot(), xdr.ElementSizeExceeded("Value", l, 1024) } xw.WriteString(o.Value) return xw.Tot(), xw.Error() @@ -873,20 +953,28 @@ func (o CloseMessage) EncodeXDR(w io.Writer) (int, error) { return o.encodeXDR(xw) } -func (o CloseMessage) MarshalXDR() []byte { +func (o CloseMessage) MarshalXDR() ([]byte, error) { return o.AppendXDR(make([]byte, 0, 128)) } -func (o CloseMessage) AppendXDR(bs []byte) []byte { +func (o CloseMessage) MustMarshalXDR() []byte { + bs, err := o.MarshalXDR() + if err != nil { + panic(err) + } + return bs +} + +func (o CloseMessage) AppendXDR(bs []byte) ([]byte, error) { var aw = xdr.AppendWriter(bs) var xw = xdr.NewWriter(&aw) - o.encodeXDR(xw) - return []byte(aw) + _, err := o.encodeXDR(xw) + return []byte(aw), err } func (o CloseMessage) encodeXDR(xw *xdr.Writer) (int, error) { - if len(o.Reason) > 1024 { - return xw.Tot(), xdr.ErrElementSizeExceeded + if l := len(o.Reason); l > 1024 { + return xw.Tot(), xdr.ElementSizeExceeded("Reason", l, 1024) } xw.WriteString(o.Reason) return xw.Tot(), xw.Error() @@ -927,15 +1015,23 @@ func (o EmptyMessage) EncodeXDR(w io.Writer) (int, error) { return o.encodeXDR(xw) } -func (o EmptyMessage) MarshalXDR() []byte { +func (o EmptyMessage) MarshalXDR() ([]byte, error) { return o.AppendXDR(make([]byte, 0, 128)) } -func (o EmptyMessage) AppendXDR(bs []byte) []byte { +func (o EmptyMessage) MustMarshalXDR() []byte { + bs, err := o.MarshalXDR() + if err != nil { + panic(err) + } + return bs +} + +func (o EmptyMessage) AppendXDR(bs []byte) ([]byte, error) { var aw = xdr.AppendWriter(bs) var xw = xdr.NewWriter(&aw) - o.encodeXDR(xw) - return []byte(aw) + _, err := o.encodeXDR(xw) + return []byte(aw), err } func (o EmptyMessage) encodeXDR(xw *xdr.Writer) (int, error) { diff --git a/internal/protocol/protocol.go b/internal/protocol/protocol.go index 19cdfbb16..08ef226f0 100644 --- a/internal/protocol/protocol.go +++ b/internal/protocol/protocol.go @@ -126,7 +126,7 @@ type hdrMsg struct { } type encodable interface { - AppendXDR([]byte) []byte + AppendXDR([]byte) ([]byte, error) } const ( @@ -483,7 +483,11 @@ func (c *rawConnection) writerLoop() { case hm := <-c.outbox: if hm.msg != nil { // Uncompressed message in uncBuf - uncBuf = hm.msg.AppendXDR(uncBuf[:0]) + uncBuf, err = hm.msg.AppendXDR(uncBuf[:0]) + if err != nil { + c.close(err) + return + } if len(uncBuf) >= c.compressionThreshold { // Use compression for large messages diff --git a/internal/protocol/protocol_test.go b/internal/protocol/protocol_test.go index cc6f9472a..a7bb1416c 100644 --- a/internal/protocol/protocol_test.go +++ b/internal/protocol/protocol_test.go @@ -25,6 +25,7 @@ import ( "io/ioutil" "os" "reflect" + "strings" "testing" "testing/quick" @@ -369,7 +370,7 @@ func testMarshal(t *testing.T, prefix string, m1, m2 message) bool { } _, err := m1.EncodeXDR(&buf) - if err == xdr.ErrElementSizeExceeded { + if err != nil && strings.Contains(err.Error(), "exceeds size") { return true } if err != nil { diff --git a/test/h2/config.xml b/test/h2/config.xml index 172f29be5..4e4fcfe70 100644 --- a/test/h2/config.xml +++ b/test/h2/config.xml @@ -1,8 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false @@ -18,15 +115,306 @@ false + +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
127.0.0.1:22001
127.0.0.1:22002
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
127.0.0.1:22003
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
+ +
dynamic
+
127.0.0.1:8082
abc123