summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJakob Borg <jakob@kastelo.net>2023-09-06 12:52:01 +0200
committerGitHub <noreply@github.com>2023-09-06 12:52:01 +0200
commitc6334e61aa56575db6b274d45d55f7ada4dcd0fe (patch)
tree1267b2b1e67c09d80843b45b88049892dbedef7f
parent38bbdebffa74df9e5937749a3780d39b24adc331 (diff)
all: Support multiple device connections (fixes #141) (#8918)
This adds the ability to have multiple concurrent connections to a single device. This is primarily useful when the network has multiple physical links for aggregated bandwidth. A single connection will never see a higher rate than a single link can give, but multiple connections are load-balanced over multiple links. It is also incidentally useful for older multi-core CPUs, where bandwidth could be limited by the TLS performance of a single CPU core -- using multiple connections achieves concurrency in the required crypto calculations... Co-authored-by: Simon Frei <freisim93@gmail.com> Co-authored-by: tomasz1986 <twilczynski@naver.com> Co-authored-by: bt90 <btom1990@googlemail.com>
-rw-r--r--cmd/stdiscosrv/database.go10
-rw-r--r--cmd/stdiscosrv/database_test.go2
-rw-r--r--gui/default/index.html7
-rw-r--r--gui/default/syncthing/device/editDeviceModalView.html20
-rw-r--r--lib/api/api.go10
-rw-r--r--lib/config/config.go8
-rw-r--r--lib/config/deviceconfiguration.go13
-rw-r--r--lib/config/deviceconfiguration.pb.go166
-rw-r--r--lib/config/wrapper.go5
-rw-r--r--lib/connections/quic_dial.go4
-rw-r--r--lib/connections/quic_listen.go4
-rw-r--r--lib/connections/registry/registry.go5
-rw-r--r--lib/connections/service.go268
-rw-r--r--lib/connections/structs.go19
-rw-r--r--lib/connections/tcp_dial.go4
-rw-r--r--lib/model/fakeconns_test.go1
-rw-r--r--lib/model/folder_recvonly_test.go2
-rw-r--r--lib/model/folder_sendrecv.go2
-rw-r--r--lib/model/mocks/model.go240
-rw-r--r--lib/model/model.go569
-rw-r--r--lib/model/model_test.go26
-rw-r--r--lib/model/requests_test.go4
-rw-r--r--lib/model/testutils_test.go8
-rw-r--r--lib/protocol/bep.pb.go502
-rw-r--r--lib/protocol/encryption.go4
-rw-r--r--lib/protocol/hello.go15
-rw-r--r--lib/protocol/hello_test.go6
-rw-r--r--lib/protocol/mocked_connection_info_test.go65
-rw-r--r--lib/protocol/mocks/connection.go65
-rw-r--r--lib/protocol/mocks/connection_info.go65
-rw-r--r--lib/protocol/nativemodel_darwin.go10
-rw-r--r--lib/protocol/nativemodel_unix.go2
-rw-r--r--lib/protocol/nativemodel_windows.go10
-rw-r--r--lib/protocol/protocol.go26
-rw-r--r--lib/sliceutil/sliceutil.go16
-rw-r--r--lib/sliceutil/sliceutil_test.go28
-rw-r--r--lib/syncthing/syncthing.go2
-rw-r--r--proto/lib/config/deviceconfiguration.proto3
-rw-r--r--proto/lib/protocol/bep.proto11
-rw-r--r--test/h1/config.xml157
-rw-r--r--test/h2/config.xml183
41 files changed, 1637 insertions, 930 deletions
diff --git a/cmd/stdiscosrv/database.go b/cmd/stdiscosrv/database.go
index ce151da3c2..92ed45db6a 100644
--- a/cmd/stdiscosrv/database.go
+++ b/cmd/stdiscosrv/database.go
@@ -15,6 +15,7 @@ import (
"sort"
"time"
+ "github.com/syncthing/syncthing/lib/sliceutil"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/storage"
"github.com/syndtr/goleveldb/leveldb/util"
@@ -352,14 +353,7 @@ func expire(addrs []DatabaseAddress, now int64) []DatabaseAddress {
i := 0
for i < len(addrs) {
if addrs[i].Expires < now {
- // This item is expired. Replace it with the last in the list
- // (noop if we are at the last item).
- addrs[i] = addrs[len(addrs)-1]
- // Wipe the last item of the list to release references to
- // strings and stuff.
- addrs[len(addrs)-1] = DatabaseAddress{}
- // Shorten the slice.
- addrs = addrs[:len(addrs)-1]
+ addrs = sliceutil.RemoveAndZero(addrs, i)
continue
}
i++
diff --git a/cmd/stdiscosrv/database_test.go b/cmd/stdiscosrv/database_test.go
index 2596b6b170..14b15059d4 100644
--- a/cmd/stdiscosrv/database_test.go
+++ b/cmd/stdiscosrv/database_test.go
@@ -185,7 +185,7 @@ func TestFilter(t *testing.T) {
},
{
a: []DatabaseAddress{{Address: "a", Expires: 5}, {Address: "b", Expires: 15}, {Address: "c", Expires: 5}, {Address: "d", Expires: 15}, {Address: "e", Expires: 5}},
- b: []DatabaseAddress{{Address: "d", Expires: 15}, {Address: "b", Expires: 15}}, // gets reordered
+ b: []DatabaseAddress{{Address: "b", Expires: 15}, {Address: "d", Expires: 15}},
},
}
diff --git a/gui/default/index.html b/gui/default/index.html
index e9691a02bf..5b151cb002 100644
--- a/gui/default/index.html
+++ b/gui/default/index.html
@@ -871,6 +871,13 @@
</span>
</td>
</tr>
+ <tr ng-if="connections[deviceCfg.deviceID].connected">
+ <th><span class="fas fa-fw fa-random"></span>&nbsp;<span translate>Number of Connections</span></th>
+ <td class="text-right">
+ <span ng-if="connections[deviceCfg.deviceID].secondary.length">1 + {{connections[deviceCfg.deviceID].secondary.length | alwaysNumber}}</span>
+ <span ng-if="!connections[deviceCfg.deviceID].secondary.length">1</span>
+ </td>
+ </tr>
<tr ng-if="deviceCfg.allowedNetworks.length > 0">
<th><span class="fas fa-fw fa-filter"></span>&nbsp;<span translate>Allowed Networks</span></th>
<td class="text-right">
diff --git a/gui/default/syncthing/device/editDeviceModalView.html b/gui/default/syncthing/device/editDeviceModalView.html
index 39d037e047..160cb0f217 100644
--- a/gui/default/syncthing/device/editDeviceModalView.html
+++ b/gui/default/syncthing/device/editDeviceModalView.html
@@ -137,11 +137,22 @@
</div>
</div>
</div>
- <div class="row form-group">
- <div class="col-md-12">
+ <div class="row">
+ <div class="col-md-6" ng-class="{'has-error': deviceEditor.numConnections.$invalid && deviceEditor.numConnections.$dirty}">
+ <label translate>Connection Management</label>
+ <div class="row">
+ <span class="col-md-8" translate>Number of Connections</span>
+ <div class="col-md-4">
+ <input name="numConnections" id="numConnections" class="form-control" type="number" pattern="\d+" ng-model="currentDevice.numConnections" min="0" />
+ </div>
+ </div>
+ <p class="help-block" ng-if="!deviceEditor.numConnections.$valid && deviceEditor.numConnections.$dirty" translate>The number of connections must be a non-negative number.</p>
+ <p class="help-block" ng-if="deviceEditor.numConnections.$valid || deviceEditor.numConnections.$pristine" translate>When set to more than one on both devices, Syncthing will attempt to establish multiple concurrent connections. If the values differ, the highest will be used. Set to zero to let Syncthing decide.</p>
+ </div>
+ <div class="col-md-6 form-group">
<label translate>Device rate limits</label>
<div class="row">
- <div class="col-md-6" ng-class="{'has-error': deviceEditor.maxRecvKbps.$invalid && deviceEditor.maxRecvKbps.$dirty}">
+ <div class="col-md-12" ng-class="{'has-error': deviceEditor.maxRecvKbps.$invalid && deviceEditor.maxRecvKbps.$dirty}">
<div class="row">
<span class="col-md-8" translate>Incoming Rate Limit (KiB/s)</span>
<div class="col-md-4">
@@ -150,7 +161,7 @@
</div>
<p class="help-block" ng-if="!deviceEditor.maxRecvKbps.$valid && deviceEditor.maxRecvKbps.$dirty" translate>The rate limit must be a non-negative number (0: no limit)</p>
</div>
- <div class="col-md-6" ng-class="{'has-error': deviceEditor.maxSendKbps.$invalid && deviceEditor.maxSendKbps.$dirty}">
+ <div class="col-md-12" ng-class="{'has-error': deviceEditor.maxSendKbps.$invalid && deviceEditor.maxSendKbps.$dirty}">
<div class="row">
<span class="col-md-8" translate>Outgoing Rate Limit (KiB/s)</span>
<div class="col-md-4">
@@ -158,6 +169,7 @@
</div>
</div>
<p class="help-block" ng-if="!deviceEditor.maxSendKbps.$valid && deviceEditor.maxSendKbps.$dirty" translate>The rate limit must be a non-negative number (0: no limit)</p>
+ <p class="help-block" ng-if="(deviceEditor.maxSendKbps.$valid || deviceEditor.maxSendKbps.$pristine) && (deviceEditor.maxRecvKbps.$valid || deviceEditor.maxRecvKbps.$pristine)">The rate limit is applied to the accumulated traffic of all connections to this device.</p>
</div>
</div>
</div>
diff --git a/lib/api/api.go b/lib/api/api.go
index 363c6a162a..67ebf0fcee 100644
--- a/lib/api/api.go
+++ b/lib/api/api.go
@@ -1230,6 +1230,14 @@ func (s *service) getSupportBundle(w http.ResponseWriter, r *http.Request) {
promhttp.Handler().ServeHTTP(wr, &http.Request{Method: http.MethodGet})
files = append(files, fileEntry{name: "metrics.txt", data: buf.Bytes()})
+ // Connection data as JSON
+ connStats := s.model.ConnectionStats()
+ if connStatsJSON, err := json.MarshalIndent(connStats, "", " "); err != nil {
+ l.Warnln("Support bundle: failed to serialize connection-stats.json.txt", err)
+ } else {
+ files = append(files, fileEntry{name: "connection-stats.json.txt", data: connStatsJSON})
+ }
+
// Heap and CPU Proofs as a pprof extension
var heapBuffer, cpuBuffer bytes.Buffer
filename := fmt.Sprintf("syncthing-heap-%s-%s-%s-%s.pprof", runtime.GOOS, runtime.GOARCH, build.Version, time.Now().Format("150405")) // hhmmss
@@ -1607,7 +1615,7 @@ func (s *service) getPeerCompletion(w http.ResponseWriter, _ *http.Request) {
for _, folder := range s.cfg.Folders() {
for _, device := range folder.DeviceIDs() {
deviceStr := device.String()
- if _, ok := s.model.Connection(device); ok {
+ if s.model.ConnectedTo(device) {
comp, err := s.model.Completion(device, folder.ID)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
diff --git a/lib/config/config.go b/lib/config/config.go
index 4f02085fce..62f2b278b4 100644
--- a/lib/config/config.go
+++ b/lib/config/config.go
@@ -25,6 +25,7 @@ import (
"github.com/syncthing/syncthing/lib/fs"
"github.com/syncthing/syncthing/lib/netutil"
"github.com/syncthing/syncthing/lib/protocol"
+ "github.com/syncthing/syncthing/lib/sliceutil"
"github.com/syncthing/syncthing/lib/structutil"
)
@@ -564,8 +565,7 @@ func ensureNoUntrustedTrustingSharing(f *FolderConfiguration, devices []FolderDe
}
if devCfg := existingDevices[dev.DeviceID]; devCfg.Untrusted {
l.Warnf("Folder %s (%s) is shared in trusted mode with untrusted device %s (%s); unsharing.", f.ID, f.Label, dev.DeviceID.Short(), devCfg.Name)
- copy(devices[i:], devices[i+1:])
- devices = devices[:len(devices)-1]
+ devices = sliceutil.RemoveAndZero(devices, i)
i--
}
}
@@ -601,9 +601,7 @@ func filterURLSchemePrefix(addrs []string, prefix string) []string {
continue
}
if strings.HasPrefix(uri.Scheme, prefix) {
- // Remove this entry
- copy(addrs[i:], addrs[i+1:])
- addrs = addrs[:len(addrs)-1]
+ addrs = sliceutil.RemoveAndZero(addrs, i)
i--
}
}
diff --git a/lib/config/deviceconfiguration.go b/lib/config/deviceconfiguration.go
index 54a30affc4..8635bcc39c 100644
--- a/lib/config/deviceconfiguration.go
+++ b/lib/config/deviceconfiguration.go
@@ -11,6 +11,8 @@ import (
"sort"
)
+const defaultNumConnections = 1 // number of connections to use by default; may change in the future.
+
func (cfg DeviceConfiguration) Copy() DeviceConfiguration {
c := cfg
c.Addresses = make([]string, len(cfg.Addresses))
@@ -49,6 +51,17 @@ func (cfg *DeviceConfiguration) prepare(sharedFolders []string) {
}
}
+func (cfg *DeviceConfiguration) NumConnections() int {
+ switch {
+ case cfg.RawNumConnections == 0:
+ return defaultNumConnections
+ case cfg.RawNumConnections < 0:
+ return 1
+ default:
+ return cfg.RawNumConnections
+ }
+}
+
func (cfg *DeviceConfiguration) IgnoredFolder(folder string) bool {
for _, ignoredFolder := range cfg.IgnoredFolders {
if ignoredFolder.ID == folder {
diff --git a/lib/config/deviceconfiguration.pb.go b/lib/config/deviceconfiguration.pb.go
index e07bb1eb02..1f5d2a1a22 100644
--- a/lib/config/deviceconfiguration.pb.go
+++ b/lib/config/deviceconfiguration.pb.go
@@ -28,7 +28,7 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
type DeviceConfiguration struct {
DeviceID github_com_syncthing_syncthing_lib_protocol.DeviceID `protobuf:"bytes,1,opt,name=device_id,json=deviceId,proto3,customtype=github.com/syncthing/syncthing/lib/protocol.DeviceID" json:"deviceID" xml:"id,attr" nodefault:"true"`
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name" xml:"name,attr,omitempty"`
- Addresses []string `protobuf:"bytes,3,rep,name=addresses,proto3" json:"addresses" xml:"address,omitempty" default:"dynamic"`
+ Addresses []string `protobuf:"bytes,3,rep,name=addresses,proto3" json:"addresses" xml:"address,omitempty"`
Compression protocol.Compression `protobuf:"varint,4,opt,name=compression,proto3,enum=protocol.Compression" json:"compression" xml:"compression,attr"`
CertName string `protobuf:"bytes,5,opt,name=cert_name,json=certName,proto3" json:"certName" xml:"certName,attr,omitempty"`
Introducer bool `protobuf:"varint,6,opt,name=introducer,proto3" json:"introducer" xml:"introducer,attr"`
@@ -44,6 +44,7 @@ type DeviceConfiguration struct {
MaxRequestKiB int `protobuf:"varint,16,opt,name=max_request_kib,json=maxRequestKib,proto3,casttype=int" json:"maxRequestKiB" xml:"maxRequestKiB"`
Untrusted bool `protobuf:"varint,17,opt,name=untrusted,proto3" json:"untrusted" xml:"untrusted"`
RemoteGUIPort int `protobuf:"varint,18,opt,name=remote_gui_port,json=remoteGuiPort,proto3,casttype=int" json:"remoteGUIPort" xml:"remoteGUIPort"`
+ RawNumConnections int `protobuf:"varint,19,opt,name=num_connections,json=numConnections,proto3,casttype=int" json:"numConnections" xml:"numConnections"`
}
func (m *DeviceConfiguration) Reset() { *m = DeviceConfiguration{} }
@@ -88,72 +89,74 @@ func init() {
}
var fileDescriptor_744b782bd13071dd = []byte{
- // 1026 bytes of a gzipped FileDescriptorProto
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x55, 0xbf, 0x6f, 0xdb, 0x46,
- 0x18, 0x15, 0xeb, 0xc4, 0xb6, 0xce, 0x3f, 0x64, 0xd3, 0x88, 0xc3, 0x18, 0x88, 0x4e, 0x50, 0x35,
- 0x28, 0x68, 0x22, 0x17, 0x6e, 0x27, 0xa3, 0x2d, 0x50, 0xc6, 0x68, 0x63, 0x18, 0x4d, 0x5c, 0x16,
- 0x5d, 0xbc, 0xb0, 0x24, 0xef, 0xac, 0x1c, 0x2c, 0xf2, 0x58, 0xf2, 0xa8, 0x58, 0x40, 0xff, 0x80,
- 0x76, 0x2b, 0x02, 0x74, 0xea, 0x92, 0xf6, 0xdf, 0xe8, 0xd0, 0xd5, 0x9b, 0x35, 0x16, 0x1d, 0x0e,
- 0x88, 0xbd, 0x71, 0x29, 0xc0, 0x31, 0x53, 0x71, 0x77, 0x14, 0x45, 0xca, 0x51, 0x50, 0xa0, 0x1b,
- 0xef, 0xbd, 0x77, 0xef, 0xdd, 0xf7, 0xe9, 0xbb, 0x13, 0xe8, 0x0c, 0x88, 0xbb, 0xeb, 0xd1, 0xe0,
- 0x94, 0xf4, 0x77, 0x11, 0x1e, 0x12, 0x0f, 0xab, 0x45, 0x12, 0x39, 0x8c, 0xd0, 0xa0, 0x17, 0x46,
- 0x94, 0x51, 0x7d, 0x51, 0x81, 0x3b, 0xdb, 0x42, 0x2d, 0x21, 0x8f, 0x0e, 0x76, 0x5d, 0x1c, 0x2a,
- 0x7e, 0xe7, 0x5e, 0xc9, 0x85, 0xba, 0x31, 0x8e, 0x86, 0x18, 0xe5, 0x54, 0x1d, 0x9f, 0x33, 0xf5,
- 0xd9, 0xfe, 0x67, 0x03, 0x6c, 0x1d, 0xc8, 0x8c, 0xc7, 0xe5, 0x0c, 0xfd, 0x4f, 0x0d, 0xd4, 0x55,
- 0xb6, 0x4d, 0x90, 0xa1, 0xb5, 0xb4, 0xee, 0xaa, 0xf9, 0x9b, 0x76, 0xc1, 0x61, 0xed, 0x6f, 0x0e,
- 0x3f, 0xee, 0x13, 0xf6, 0x3c, 0x71, 0x7b, 0x1e, 0xf5, 0x77, 0xe3, 0x51, 0xe0, 0xb1, 0xe7, 0x24,
- 0xe8, 0x97, 0xbe, 0xca, 0x27, 0xea, 0x29, 0xf7, 0xc3, 0x83, 0x2b, 0x0e, 0x97, 0x27, 0xdf, 0x29,
- 0x87, 0xcb, 0x28, 0xff, 0xce, 0x38, 0x6c, 0x9e, 0xfb, 0x83, 0xfd, 0x36, 0x41, 0x0f, 0x1d, 0xc6,
- 0xa2, 0x76, 0x2b, 0xa0, 0x08, 0x9f, 0x3a, 0xc9, 0x80, 0xed, 0xb7, 0x59, 0x94, 0xe0, 0x76, 0x7a,
- 0xd9, 0x59, 0xca, 0xc9, 0xec, 0xb2, 0x53, 0x6c, 0xfc, 0x71, 0xdc, 0xd1, 0x5e, 0x8e, 0x3b, 0x85,
- 0xe9, 0xab, 0x71, 0x47, 0xb3, 0x26, 0x2c, 0xd2, 0x8f, 0xc1, 0xad, 0xc0, 0xf1, 0xb1, 0xf1, 0x5e,
- 0x4b, 0xeb, 0xd6, 0xcd, 0x4f, 0x52, 0x0e, 0xe5, 0x3a, 0xe3, 0xf0, 0x9e, 0x8c, 0x13, 0x0b, 0xe9,
- 0xf9, 0x90, 0xfa, 0x84, 0x61, 0x3f, 0x64, 0x23, 0x91, 0xb4, 0xf5, 0x16, 0xdc, 0x92, 0x3b, 0xf5,
- 0x73, 0x50, 0x77, 0x10, 0x8a, 0x70, 0x1c, 0xe3, 0xd8, 0x58, 0x68, 0x2d, 0x74, 0xeb, 0xe6, 0x49,
- 0xca, 0xe1, 0x14, 0xcc, 0x38, 0x7c, 0x20, 0xbd, 0x73, 0xa4, 0xe4, 0xdc, 0x2a, 0x4a, 0x42, 0xa3,
- 0xc0, 0xf1, 0x89, 0x27, 0xb2, 0x36, 0x6f, 0xe8, 0xde, 0x5c, 0x76, 0x96, 0x72, 0x81, 0x35, 0xf5,
- 0xd5, 0x87, 0x60, 0xc5, 0xa3, 0x7e, 0x28, 0x56, 0x84, 0x06, 0xc6, 0xad, 0x96, 0xd6, 0x5d, 0xdf,
- 0xbb, 0xd3, 0x2b, 0x7a, 0xfc, 0x78, 0x4a, 0x9a, 0x9f, 0xa6, 0x1c, 0x96, 0xd5, 0x19, 0x87, 0xdb,
- 0xf2, 0x50, 0x25, 0x4c, 0x35, 0x3a, 0xbd, 0xec, 0x6c, 0xcc, 0x82, 0x56, 0x79, 0xab, 0x8e, 0x41,
- 0xdd, 0xc3, 0x11, 0xb3, 0x65, 0x23, 0x6f, 0xcb, 0x46, 0x3e, 0x11, 0xbf, 0x9d, 0x00, 0x9f, 0xaa,
- 0x66, 0xde, 0x57, 0xde, 0x39, 0xf0, 0x96, 0x86, 0xde, 0x9d, 0xc3, 0x59, 0x85, 0x8b, 0x7e, 0x02,
- 0x00, 0x09, 0x58, 0x44, 0x51, 0xe2, 0xe1, 0xc8, 0x58, 0x6c, 0x69, 0xdd, 0x65, 0x73, 0x3f, 0xe5,
- 0xb0, 0x84, 0x66, 0x1c, 0xde, 0x51, 0x53, 0x52, 0x40, 0x45, 0x11, 0x8d, 0x19, 0xcc, 0x2a, 0xed,
- 0xd3, 0x7f, 0xd7, 0xc0, 0x4e, 0x7c, 0x46, 0x42, 0x7b, 0x82, 0x89, 0xf1, 0xb6, 0x23, 0xec, 0xd3,
- 0xa1, 0x33, 0x88, 0x8d, 0x25, 0x19, 0x86, 0x52, 0x0e, 0x0d, 0xa1, 0x3a, 0x2c, 0x89, 0xac, 0x5c,
- 0x93, 0x71, 0xf8, 0xbe, 0x8c, 0x9e, 0x27, 0x28, 0x0e, 0x72, 0xff, 0x9d, 0x0a, 0x6b, 0x6e, 0x82,
- 0xfe, 0x87, 0x06, 0xd6, 0x8a, 0x33, 0x23, 0xdb, 0x1d, 0x19, 0xcb, 0xf2, 0xc6, 0xfd, 0xf2, 0xbf,
- 0x6e, 0x5c, 0xca, 0xe1, 0xea, 0xd4, 0xd5, 0x1c, 0x65, 0x1c, 0x76, 0xab, 0x3d, 0x44, 0xe6, 0x68,
- 0xfe, 0x9d, 0xdb, 0xbc, 0x21, 0x13, 0x37, 0x4e, 0xde, 0xb2, 0x8a, 0xad, 0xbe, 0x07, 0x16, 0x43,
- 0x27, 0x89, 0x31, 0x32, 0xea, 0xb2, 0x9b, 0x3b, 0x29, 0x87, 0x39, 0x92, 0x71, 0xb8, 0x2a, 0x23,
- 0xd5, 0xb2, 0x6d, 0xe5, 0xb8, 0xfe, 0x03, 0xd8, 0x70, 0x06, 0x03, 0xfa, 0x02, 0x23, 0x3b, 0xc0,
- 0xec, 0x05, 0x8d, 0xce, 0x62, 0x03, 0xc8, 0x2b, 0xf5, 0x75, 0xca, 0x61, 0x23, 0xe7, 0x9e, 0xe6,
- 0x54, 0xf1, 0x46, 0x54, 0xf1, 0xea, 0xa0, 0x19, 0xf3, 0x48, 0x6b, 0xd6, 0x4e, 0xff, 0x0e, 0x6c,
- 0x39, 0x09, 0xa3, 0xb6, 0xe3, 0x79, 0x38, 0x64, 0xf6, 0x29, 0x1d, 0x20, 0x1c, 0xc5, 0xc6, 0x8a,
- 0x3c, 0xfe, 0x87, 0x29, 0x87, 0x9b, 0x82, 0xfe, 0x5c, 0xb2, 0x5f, 0x28, 0x32, 0xe3, 0xf0, 0xae,
- 0x3a, 0xc2, 0x2c, 0xd3, 0xb6, 0x6e, 0xaa, 0xf5, 0x67, 0x60, 0xcd, 0x77, 0xce, 0xed, 0x18, 0x07,
- 0xc8, 0x3e, 0x73, 0xc3, 0xd8, 0x58, 0x6d, 0x69, 0xdd, 0xdb, 0xe6, 0x07, 0xe2, 0x72, 0xfa, 0xce,
- 0xf9, 0x37, 0x38, 0x40, 0x47, 0x6e, 0x28, 0x5c, 0x37, 0xa5, 0x6b, 0x09, 0x6b, 0xbf, 0xe1, 0x70,
- 0x81, 0x04, 0xcc, 0x2a, 0x0b, 0x27, 0x86, 0x11, 0xf6, 0x86, 0xca, 0x70, 0xad, 0x62, 0x68, 0x61,
- 0x6f, 0x38, 0x6b, 0x38, 0xc1, 0x2a, 0x86, 0x13, 0x50, 0x0f, 0x40, 0x83, 0xf4, 0x03, 0x1a, 0x61,
- 0x54, 0xd4, 0xbf, 0xde, 0x5a, 0xe8, 0xae, 0xec, 0x6d, 0xf7, 0xd4, 0xbf, 0x46, 0xef, 0x59, 0xfe,
- 0xaf, 0xa1, 0x6a, 0x32, 0x1f, 0x89, 0x59, 0x4c, 0x39, 0x5c, 0xcf, 0xb7, 0x4d, 0x1b, 0xb3, 0xa5,
- 0xa6, 0xaa, 0x0c, 0xb7, 0xad, 0x19, 0x99, 0xfe, 0x93, 0x06, 0x1a, 0x21, 0x0e, 0x10, 0x09, 0xfa,
- 0x45, 0x60, 0xe3, 0x9d, 0x81, 0x4f, 0x44, 0xe0, 0x15, 0x87, 0xc6, 0x01, 0x0e, 0x23, 0xec, 0x39,
- 0x0c, 0xa3, 0x63, 0x65, 0x90, 0x7b, 0xa6, 0x1c, 0x6a, 0x8f, 0x8a, 0x37, 0x28, 0x2c, 0x73, 0xa5,
- 0xd1, 0x30, 0x34, 0x6b, 0xbd, 0xc2, 0xc5, 0xfa, 0xaf, 0x1a, 0x68, 0xa8, 0x6e, 0x7e, 0x9f, 0xe0,
- 0x98, 0xd9, 0x67, 0xc4, 0x35, 0x36, 0x64, 0x3f, 0xe3, 0x2b, 0x0e, 0xd7, 0xbe, 0x12, 0x6d, 0x92,
- 0xcc, 0x11, 0x31, 0x53, 0x0e, 0xd7, 0xfc, 0x32, 0x50, 0x14, 0x5c, 0x41, 0x27, 0x4d, 0x4e, 0x2f,
- 0x3b, 0x33, 0xf2, 0x59, 0xe0, 0xe5, 0xb8, 0x53, 0x4d, 0xb0, 0x2a, 0xbc, 0xab, 0x7f, 0x06, 0xea,
- 0x49, 0xc0, 0xa2, 0x24, 0x66, 0x18, 0x19, 0x9b, 0x72, 0x26, 0x5b, 0xe2, 0x7f, 0xa6, 0x00, 0x33,
- 0x0e, 0x1b, 0xf2, 0x04, 0x05, 0xd2, 0xb6, 0xa6, 0xac, 0xac, 0x4e, 0x3c, 0x70, 0x0c, 0xdb, 0xfd,
- 0x84, 0xd8, 0x21, 0x8d, 0x98, 0xa1, 0x4f, 0xab, 0xb3, 0x24, 0xf5, 0xe5, 0xb7, 0x87, 0xc7, 0x34,
- 0x62, 0xa2, 0xba, 0xa8, 0x0c, 0x14, 0xd5, 0x55, 0xd0, 0x72, 0x75, 0x55, 0xf9, 0x2c, 0x20, 0xaa,
- 0xab, 0x24, 0x58, 0x13, 0x3e, 0x21, 0x62, 0x69, 0x1e, 0x5d, 0xbc, 0x6e, 0xd6, 0xc6, 0xaf, 0x9b,
- 0xb5, 0x8b, 0xab, 0xa6, 0x36, 0xbe, 0x6a, 0x6a, 0x3f, 0x5f, 0x37, 0x6b, 0xaf, 0xae, 0x9b, 0xda,
- 0xf8, 0xba, 0x59, 0xfb, 0xeb, 0xba, 0x59, 0x3b, 0x79, 0xf0, 0x1f, 0x1e, 0x3b, 0x35, 0x31, 0xee,
- 0xa2, 0x7c, 0xf4, 0x3e, 0xfa, 0x37, 0x00, 0x00, 0xff, 0xff, 0xbf, 0x4a, 0x4f, 0x60, 0x33, 0x09,
- 0x00, 0x00,
+ // 1057 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x55, 0x41, 0x6f, 0xe3, 0x44,
+ 0x14, 0x8e, 0xe9, 0x6e, 0xb7, 0x99, 0x6d, 0x9b, 0xc6, 0x65, 0xbb, 0xde, 0x4a, 0x9b, 0x89, 0x42,
+ 0x0e, 0x41, 0xec, 0xa6, 0xa8, 0x70, 0xaa, 0x00, 0x89, 0xb4, 0x82, 0xad, 0x2a, 0xba, 0x65, 0x10,
+ 0x97, 0xdd, 0x83, 0x71, 0x3c, 0xd3, 0xac, 0xd5, 0x78, 0xc6, 0xd8, 0xe3, 0xb4, 0x95, 0x38, 0x72,
+ 0x80, 0x1b, 0xaa, 0xc4, 0x89, 0xcb, 0xc2, 0xdf, 0xe0, 0xc0, 0xb5, 0xb7, 0xe6, 0x08, 0x1c, 0x46,
+ 0xda, 0xf4, 0xe6, 0xa3, 0x8f, 0x9c, 0xd0, 0x8c, 0x1d, 0xc7, 0x76, 0x37, 0x2b, 0x24, 0x6e, 0x9e,
+ 0xef, 0x7b, 0xf3, 0x7d, 0xf3, 0x9e, 0xdf, 0x9b, 0x01, 0xed, 0xa1, 0xd3, 0xdf, 0xb2, 0x19, 0x3d,
+ 0x76, 0x06, 0x5b, 0x98, 0x8c, 0x1c, 0x9b, 0x24, 0x8b, 0xd0, 0xb7, 0xb8, 0xc3, 0x68, 0xd7, 0xf3,
+ 0x19, 0x67, 0xfa, 0x62, 0x02, 0x6e, 0x6e, 0xc8, 0x68, 0x05, 0xd9, 0x6c, 0xb8, 0xd5, 0x27, 0x5e,
+ 0xc2, 0x6f, 0x3e, 0xc8, 0xa9, 0xb0, 0x7e, 0x40, 0xfc, 0x11, 0xc1, 0x29, 0x55, 0x25, 0x67, 0x3c,
+ 0xf9, 0x6c, 0xfd, 0x55, 0x07, 0xeb, 0x7b, 0xca, 0x63, 0x37, 0xef, 0xa1, 0xff, 0xa1, 0x81, 0x6a,
+ 0xe2, 0x6d, 0x3a, 0xd8, 0xd0, 0x9a, 0x5a, 0x67, 0xb9, 0xf7, 0xab, 0x76, 0x29, 0x60, 0xe5, 0x6f,
+ 0x01, 0x3f, 0x1c, 0x38, 0xfc, 0x45, 0xd8, 0xef, 0xda, 0xcc, 0xdd, 0x0a, 0xce, 0xa9, 0xcd, 0x5f,
+ 0x38, 0x74, 0x90, 0xfb, 0xca, 0x9f, 0xa8, 0x9b, 0xa8, 0xef, 0xef, 0x4d, 0x04, 0x5c, 0x9a, 0x7e,
+ 0x47, 0x02, 0x2e, 0xe1, 0xf4, 0x3b, 0x16, 0xb0, 0x71, 0xe6, 0x0e, 0x77, 0x5a, 0x0e, 0x7e, 0x64,
+ 0x71, 0xee, 0xb7, 0x9a, 0x94, 0x61, 0x72, 0x6c, 0x85, 0x43, 0xbe, 0xd3, 0xe2, 0x7e, 0x48, 0x5a,
+ 0xd1, 0x55, 0xfb, 0x4e, 0x4a, 0xc6, 0x57, 0xed, 0x6c, 0xe3, 0x0f, 0xe3, 0xb6, 0x76, 0x31, 0x6e,
+ 0x67, 0xa2, 0x2f, 0xc7, 0x6d, 0x0d, 0x4d, 0x59, 0xac, 0x1f, 0x81, 0x5b, 0xd4, 0x72, 0x89, 0xf1,
+ 0x56, 0x53, 0xeb, 0x54, 0x7b, 0x1f, 0x45, 0x02, 0xaa, 0x75, 0x2c, 0xe0, 0x03, 0x65, 0x27, 0x17,
+ 0x4a, 0xf3, 0x11, 0x73, 0x1d, 0x4e, 0x5c, 0x8f, 0x9f, 0x4b, 0xa7, 0xf5, 0xd7, 0xe0, 0x48, 0xed,
+ 0xd4, 0x9f, 0x83, 0xaa, 0x85, 0xb1, 0x4f, 0x82, 0x80, 0x04, 0xc6, 0x42, 0x73, 0xa1, 0x53, 0xed,
+ 0x7d, 0x1c, 0x09, 0x38, 0x03, 0x63, 0x01, 0xef, 0x2b, 0xed, 0x14, 0x29, 0x2a, 0xd7, 0x6f, 0xa0,
+ 0x68, 0xb6, 0x55, 0x1f, 0x81, 0xbb, 0x36, 0x73, 0x3d, 0xb9, 0x72, 0x18, 0x35, 0x6e, 0x35, 0xb5,
+ 0xce, 0xea, 0xf6, 0xbd, 0x6e, 0x56, 0xc6, 0xdd, 0x19, 0xa9, 0x5c, 0xf3, 0xd1, 0xb1, 0x80, 0x1b,
+ 0xca, 0x37, 0x87, 0x25, 0xb5, 0x8c, 0xae, 0xda, 0x6b, 0x65, 0x10, 0xe5, 0xb7, 0xea, 0x04, 0x54,
+ 0x6d, 0xe2, 0x73, 0x53, 0xd5, 0xea, 0xb6, 0xaa, 0xd5, 0x13, 0xf9, 0x7b, 0x24, 0x78, 0x98, 0xd4,
+ 0xeb, 0x61, 0xa2, 0x9d, 0x02, 0xaf, 0xa9, 0xd9, 0xfd, 0x39, 0x1c, 0xca, 0x54, 0xf4, 0x67, 0x00,
+ 0x38, 0x94, 0xfb, 0x0c, 0x87, 0x36, 0xf1, 0x8d, 0xc5, 0xa6, 0xd6, 0x59, 0xea, 0xed, 0x44, 0x02,
+ 0xe6, 0xd0, 0x58, 0xc0, 0x7b, 0x49, 0x23, 0x64, 0x50, 0x96, 0x44, 0xad, 0x84, 0xa1, 0xdc, 0x3e,
+ 0xfd, 0x37, 0x0d, 0x6c, 0x06, 0x27, 0x8e, 0x67, 0x4e, 0x31, 0xd9, 0xc1, 0xa6, 0x4f, 0x5c, 0x36,
+ 0xb2, 0x86, 0x81, 0x71, 0x47, 0x99, 0xe1, 0x48, 0x40, 0x43, 0x46, 0xed, 0xe7, 0x82, 0x50, 0x1a,
+ 0x13, 0x0b, 0xf8, 0x8e, 0xb2, 0x9e, 0x17, 0x90, 0x1d, 0xe4, 0xe1, 0x1b, 0x23, 0xd0, 0x5c, 0x07,
+ 0xfd, 0x77, 0x0d, 0xac, 0x64, 0x67, 0xc6, 0x66, 0xff, 0xdc, 0x58, 0x52, 0x43, 0xf5, 0xf3, 0xff,
+ 0x1a, 0xaa, 0x48, 0xc0, 0xe5, 0x99, 0x6a, 0xef, 0x3c, 0x16, 0xb0, 0x53, 0xac, 0x21, 0xee, 0x9d,
+ 0xcf, 0x1f, 0xab, 0xfa, 0x8d, 0x30, 0x39, 0x54, 0x6a, 0x90, 0x0a, 0xb2, 0xfa, 0x36, 0x58, 0xf4,
+ 0xac, 0x30, 0x20, 0xd8, 0xa8, 0xaa, 0x6a, 0x6e, 0x46, 0x02, 0xa6, 0x48, 0x2c, 0xe0, 0xb2, 0xb2,
+ 0x4c, 0x96, 0x2d, 0x94, 0xe2, 0xfa, 0x77, 0x60, 0xcd, 0x1a, 0x0e, 0xd9, 0x29, 0xc1, 0x26, 0x25,
+ 0xfc, 0x94, 0xf9, 0x27, 0x81, 0x01, 0xd4, 0xd4, 0x7c, 0x19, 0x09, 0x58, 0x4b, 0xb9, 0xc3, 0x94,
+ 0xca, 0xae, 0x81, 0x22, 0x5e, 0x6c, 0x34, 0x63, 0x1e, 0x89, 0xca, 0x72, 0xfa, 0x37, 0x60, 0xdd,
+ 0x0a, 0x39, 0x33, 0x2d, 0xdb, 0x26, 0x1e, 0x37, 0x8f, 0xd9, 0x10, 0x13, 0x3f, 0x30, 0xee, 0xaa,
+ 0xe3, 0xbf, 0x1f, 0x09, 0x58, 0x97, 0xf4, 0xa7, 0x8a, 0xfd, 0x2c, 0x21, 0x67, 0xe3, 0x5b, 0x66,
+ 0x5a, 0xe8, 0x66, 0xb4, 0xfe, 0x14, 0xac, 0xb8, 0xd6, 0x99, 0x19, 0x10, 0x8a, 0xcd, 0x93, 0xbe,
+ 0x17, 0x18, 0xcb, 0x4d, 0xad, 0x73, 0xbb, 0xf7, 0x9e, 0x1c, 0x4e, 0xd7, 0x3a, 0xfb, 0x8a, 0x50,
+ 0x7c, 0xd0, 0xf7, 0xa4, 0x6a, 0x5d, 0xa9, 0xe6, 0xb0, 0xd6, 0x3f, 0x02, 0x2e, 0x38, 0x94, 0xa3,
+ 0x7c, 0xe0, 0x54, 0xd0, 0x27, 0xf6, 0x28, 0x11, 0x5c, 0x29, 0x08, 0x22, 0x62, 0x8f, 0xca, 0x82,
+ 0x53, 0xac, 0x20, 0x38, 0x05, 0x75, 0x0a, 0x6a, 0xce, 0x80, 0x32, 0x9f, 0xe0, 0x2c, 0xff, 0xd5,
+ 0xe6, 0x42, 0xe7, 0xee, 0xf6, 0x46, 0x37, 0x79, 0x18, 0xba, 0x4f, 0xd3, 0x87, 0x21, 0xc9, 0xa9,
+ 0xf7, 0x58, 0xf6, 0x62, 0x24, 0xe0, 0x6a, 0xba, 0x6d, 0x56, 0x98, 0xf5, 0xa4, 0xab, 0xf2, 0x70,
+ 0x0b, 0x95, 0xc2, 0xf4, 0x1f, 0x35, 0x50, 0xf3, 0x08, 0xc5, 0x0e, 0x1d, 0x64, 0x86, 0xb5, 0x37,
+ 0x1a, 0x3e, 0x91, 0x86, 0x13, 0x01, 0x8d, 0x3d, 0xe2, 0xf9, 0xc4, 0xb6, 0x38, 0xc1, 0x47, 0x89,
+ 0x40, 0xaa, 0x19, 0x09, 0xa8, 0x3d, 0xce, 0xee, 0x20, 0x2f, 0xcf, 0xe5, 0x5a, 0xc3, 0xd0, 0xd0,
+ 0x6a, 0x81, 0x0b, 0xf4, 0x5f, 0x34, 0x50, 0x4b, 0xaa, 0xf9, 0x6d, 0x48, 0x02, 0x6e, 0x9e, 0x38,
+ 0x7d, 0x63, 0x4d, 0xd5, 0x33, 0x98, 0x08, 0xb8, 0xf2, 0x85, 0x2c, 0x93, 0x62, 0x0e, 0x9c, 0x5e,
+ 0x24, 0xe0, 0x8a, 0x9b, 0x07, 0xb2, 0x84, 0x0b, 0xe8, 0xb4, 0xc8, 0xd1, 0x55, 0xbb, 0x14, 0x5e,
+ 0x06, 0x2e, 0xc6, 0xed, 0xa2, 0x03, 0x2a, 0xf0, 0x7d, 0xfd, 0x13, 0x50, 0x0d, 0x29, 0xf7, 0xc3,
+ 0x80, 0x13, 0x6c, 0xd4, 0x55, 0x4f, 0x36, 0xe5, 0x53, 0x92, 0x81, 0xb1, 0x80, 0x35, 0x75, 0x82,
+ 0x0c, 0x69, 0xa1, 0x19, 0xab, 0xb2, 0x93, 0x17, 0x1c, 0x27, 0xe6, 0x20, 0x74, 0x4c, 0x8f, 0xf9,
+ 0xdc, 0xd0, 0x67, 0xd9, 0x21, 0x45, 0x7d, 0xfe, 0xf5, 0xfe, 0x11, 0xf3, 0xb9, 0xcc, 0xce, 0xcf,
+ 0x03, 0x59, 0x76, 0x05, 0x34, 0x9f, 0x5d, 0x31, 0xbc, 0x0c, 0xc8, 0xec, 0x0a, 0x0e, 0x68, 0xca,
+ 0x87, 0x8e, 0x5c, 0xea, 0xdf, 0x6b, 0xa0, 0x46, 0x43, 0xd7, 0xb4, 0x19, 0xa5, 0x44, 0x5d, 0x83,
+ 0x81, 0xb1, 0xae, 0x4e, 0xf7, 0x7c, 0x22, 0x60, 0x1d, 0x59, 0xa7, 0x87, 0xa1, 0xbb, 0x3b, 0x23,
+ 0x65, 0xc7, 0xd1, 0x02, 0x12, 0x0b, 0xf8, 0x76, 0xf2, 0x4a, 0x17, 0xe0, 0xe9, 0x19, 0x2f, 0xc6,
+ 0xed, 0x9b, 0x2a, 0xa8, 0xa4, 0xd1, 0x3b, 0xb8, 0x7c, 0xd5, 0xa8, 0x8c, 0x5f, 0x35, 0x2a, 0x97,
+ 0x93, 0x86, 0x36, 0x9e, 0x34, 0xb4, 0x9f, 0xae, 0x1b, 0x95, 0x97, 0xd7, 0x0d, 0x6d, 0x7c, 0xdd,
+ 0xa8, 0xfc, 0x79, 0xdd, 0xa8, 0x3c, 0x7b, 0xf7, 0x3f, 0xdc, 0xb9, 0x49, 0xe3, 0xf6, 0x17, 0xd5,
+ 0xdd, 0xfb, 0xc1, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x75, 0x19, 0xf5, 0x92, 0x9d, 0x09, 0x00,
+ 0x00,