mirror of
https://github.com/octoleo/syncthing.git
synced 2024-12-22 10:58:57 +00:00
wip
This commit is contained in:
parent
962fedc378
commit
795cbff55d
@ -68,7 +68,6 @@ var (
|
|||||||
const (
|
const (
|
||||||
perDeviceWarningIntv = 15 * time.Minute
|
perDeviceWarningIntv = 15 * time.Minute
|
||||||
tlsHandshakeTimeout = 10 * time.Second
|
tlsHandshakeTimeout = 10 * time.Second
|
||||||
minConnectionReplaceAge = 10 * time.Second
|
|
||||||
minConnectionLoopSleep = 5 * time.Second
|
minConnectionLoopSleep = 5 * time.Second
|
||||||
stdConnectionLoopSleep = time.Minute
|
stdConnectionLoopSleep = time.Minute
|
||||||
worstDialerPriority = math.MaxInt32
|
worstDialerPriority = math.MaxInt32
|
||||||
@ -318,17 +317,17 @@ func (s *service) connectionCheckEarly(remoteID protocol.DeviceID, c internalCon
|
|||||||
return errNetworkNotAllowed
|
return errNetworkNotAllowed
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lower priority is better, just like nice etc.
|
if existing := s.connectionsForDevice(cfg.DeviceID); existing > 0 {
|
||||||
if ct, ok := s.model.Connection(remoteID); ok {
|
// Check if the new connection is better than an existing one. Lower
|
||||||
if ct.Priority() > c.priority || time.Since(ct.Statistics().StartedAt) > minConnectionReplaceAge {
|
// priority is better, just like `nice` etc.
|
||||||
l.Debugf("Switching connections %s (existing: %s new: %s)", remoteID, ct, c)
|
if ct, ok := s.model.Connection(remoteID); ok {
|
||||||
} else if cfg.MultipleConnections <= s.connectionsForDevice(cfg.DeviceID) {
|
if ct.Priority() > c.priority {
|
||||||
// We should not already be connected to the other party. TODO: This
|
l.Debugf("Switching connections %s (existing: %s new: %s)", remoteID, ct, c)
|
||||||
// could use some better handling. If the old connection is dead but
|
return nil
|
||||||
// hasn't timed out yet we may want to drop *that* connection and keep
|
}
|
||||||
// this one. But in case we are two devices connecting to each other
|
}
|
||||||
// in parallel we don't want to do that or we end up with no
|
if existing >= cfg.MultipleConnections {
|
||||||
// connections still established...
|
// We're not allowed to accept any more connections to this device.
|
||||||
return errDeviceAlreadyConnected
|
return errDeviceAlreadyConnected
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,21 +93,28 @@ func (t connType) Transport() string {
|
|||||||
|
|
||||||
func newInternalConn(tc tlsConn, connType connType, isLocal bool, priority int) internalConn {
|
func newInternalConn(tc tlsConn, connType connType, isLocal bool, priority int) internalConn {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
buf := binary.BigEndian.AppendUint64(nil, uint64(now.UnixNano()))
|
|
||||||
hash := sha256.Sum224([]byte(fmt.Sprintf("%v-%v-%v", tc.LocalAddr(), connType.Transport(), tc.RemoteAddr())))
|
|
||||||
buf = append(buf, hash[:]...)
|
|
||||||
connectionID := base32.HexEncoding.WithPadding(base32.NoPadding).EncodeToString(buf)
|
|
||||||
|
|
||||||
return internalConn{
|
return internalConn{
|
||||||
tlsConn: tc,
|
tlsConn: tc,
|
||||||
connType: connType,
|
connType: connType,
|
||||||
isLocal: isLocal,
|
isLocal: isLocal,
|
||||||
priority: priority,
|
priority: priority,
|
||||||
establishedAt: now.Truncate(time.Second),
|
establishedAt: now.Truncate(time.Second),
|
||||||
connectionID: connectionID,
|
connectionID: newConnectionID(tc, connType, now),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// newConnection generates a connection ID. The connection ID is designed to
|
||||||
|
// be 1) unique for each connection (even those reusing the same socket
|
||||||
|
// address on both sides), 2) sortable so that the connection with the
|
||||||
|
// lowest ID will be the primary one. This also coincides with being the
|
||||||
|
// oldest connection.
|
||||||
|
func newConnectionID(tc tlsConn, connType connType, now time.Time) string {
|
||||||
|
buf := binary.BigEndian.AppendUint64(nil, uint64(now.UnixNano()))
|
||||||
|
hash := sha256.Sum224([]byte(fmt.Sprintf("%v-%v-%v", tc.LocalAddr(), connType.Transport(), tc.RemoteAddr())))
|
||||||
|
buf = append(buf, hash[:]...)
|
||||||
|
return base32.HexEncoding.WithPadding(base32.NoPadding).EncodeToString(buf)
|
||||||
|
}
|
||||||
|
|
||||||
func (c internalConn) Close() error {
|
func (c internalConn) Close() error {
|
||||||
// *tls.Conn.Close() does more than it says on the tin. Specifically, it
|
// *tls.Conn.Close() does more than it says on the tin. Specifically, it
|
||||||
// sends a TLS alert message, which might block forever if the
|
// sends a TLS alert message, which might block forever if the
|
||||||
|
@ -163,6 +163,7 @@ type model struct {
|
|||||||
pmut sync.RWMutex
|
pmut sync.RWMutex
|
||||||
conns map[string]protocol.Connection // connection ID -> connection
|
conns map[string]protocol.Connection // connection ID -> connection
|
||||||
deviceConns map[protocol.DeviceID][]string // device -> connection IDs (invariant: if the key exists, the value is len >= 1, with the primary connection at the start of the slice)
|
deviceConns map[protocol.DeviceID][]string // device -> connection IDs (invariant: if the key exists, the value is len >= 1, with the primary connection at the start of the slice)
|
||||||
|
promotedConn map[protocol.DeviceID]string // device -> last promoted connection ID
|
||||||
connRequestLimiters map[protocol.DeviceID]*util.Semaphore
|
connRequestLimiters map[protocol.DeviceID]*util.Semaphore
|
||||||
closed map[string]chan struct{} // connection ID -> closed channel
|
closed map[string]chan struct{} // connection ID -> closed channel
|
||||||
helloMessages map[protocol.DeviceID]protocol.Hello
|
helloMessages map[protocol.DeviceID]protocol.Hello
|
||||||
@ -248,6 +249,7 @@ func NewModel(cfg config.Wrapper, id protocol.DeviceID, clientName, clientVersio
|
|||||||
pmut: sync.NewRWMutex(),
|
pmut: sync.NewRWMutex(),
|
||||||
conns: make(map[string]protocol.Connection),
|
conns: make(map[string]protocol.Connection),
|
||||||
deviceConns: make(map[protocol.DeviceID][]string),
|
deviceConns: make(map[protocol.DeviceID][]string),
|
||||||
|
promotedConn: make(map[protocol.DeviceID]string),
|
||||||
connRequestLimiters: make(map[protocol.DeviceID]*util.Semaphore),
|
connRequestLimiters: make(map[protocol.DeviceID]*util.Semaphore),
|
||||||
closed: make(map[string]chan struct{}),
|
closed: make(map[string]chan struct{}),
|
||||||
helloMessages: make(map[protocol.DeviceID]protocol.Hello),
|
helloMessages: make(map[protocol.DeviceID]protocol.Hello),
|
||||||
@ -1912,6 +1914,7 @@ func (m *model) Closed(conn protocol.Connection, err error) {
|
|||||||
if len(remainingConns) == 0 {
|
if len(remainingConns) == 0 {
|
||||||
// All device connections closed
|
// All device connections closed
|
||||||
delete(m.deviceConns, deviceID)
|
delete(m.deviceConns, deviceID)
|
||||||
|
delete(m.promotedConn, deviceID)
|
||||||
delete(m.connRequestLimiters, deviceID)
|
delete(m.connRequestLimiters, deviceID)
|
||||||
delete(m.helloMessages, deviceID)
|
delete(m.helloMessages, deviceID)
|
||||||
delete(m.remoteFolderStates, deviceID)
|
delete(m.remoteFolderStates, deviceID)
|
||||||
@ -2433,10 +2436,33 @@ func (m *model) promoteConnections() {
|
|||||||
defer m.pmut.Unlock()
|
defer m.pmut.Unlock()
|
||||||
|
|
||||||
for deviceID, connIDs := range m.deviceConns {
|
for deviceID, connIDs := range m.deviceConns {
|
||||||
|
// Figure out the best current connection priority for this device.
|
||||||
|
bestPriority := m.conns[connIDs[0]].Priority()
|
||||||
|
for _, connID := range connIDs[1:] {
|
||||||
|
priority := m.conns[connID].Priority()
|
||||||
|
if priority < bestPriority {
|
||||||
|
bestPriority = priority
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close connections with a worse connection priority than best.
|
||||||
|
closing := make(map[string]bool)
|
||||||
|
for _, connID := range connIDs {
|
||||||
|
if m.conns[connID].Priority() > bestPriority {
|
||||||
|
l.Infoln("Closing connection", connID, "to", deviceID.Short(), "because it has a worse connection priority than the best connection")
|
||||||
|
go m.conns[connID].Close(errReplacingConnection)
|
||||||
|
closing[connID] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cm, passwords := m.generateClusterConfigFRLocked(deviceID)
|
cm, passwords := m.generateClusterConfigFRLocked(deviceID)
|
||||||
if idxh, ok := m.indexHandlers[deviceID]; !ok || idxh.conn.ConnectionID() != connIDs[0] {
|
if !closing[connIDs[0]] && m.promotedConn[deviceID] != connIDs[0] {
|
||||||
// Primary device lacks an index handler. We should promote the
|
// The last promoted connection is not the current primary; we
|
||||||
// primary connection to be the index handling one.
|
// should promote the primary connection to be the index
|
||||||
|
// handling one. We do this by sending a ClusterConfig on it,
|
||||||
|
// which will cause the other side to start sending us index
|
||||||
|
// messages there. (On our side, we manage index handlers based
|
||||||
|
// on where we get ClusterConfigs from the peer.)
|
||||||
l.Infoln("Promoting connection", connIDs[0], "to", deviceID.Short())
|
l.Infoln("Promoting connection", connIDs[0], "to", deviceID.Short())
|
||||||
conn := m.conns[connIDs[0]]
|
conn := m.conns[connIDs[0]]
|
||||||
if conn.Statistics().StartedAt.IsZero() {
|
if conn.Statistics().StartedAt.IsZero() {
|
||||||
@ -2444,11 +2470,15 @@ func (m *model) promoteConnections() {
|
|||||||
conn.Start()
|
conn.Start()
|
||||||
}
|
}
|
||||||
conn.ClusterConfig(cm)
|
conn.ClusterConfig(cm)
|
||||||
|
m.promotedConn[deviceID] = connIDs[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure any new connections also get started, and a
|
// Make sure any other new connections also get started, and a
|
||||||
// secondary-marked ClusterConfig.
|
// secondary-marked ClusterConfig.
|
||||||
for _, connID := range connIDs[1:] {
|
for _, connID := range connIDs[1:] {
|
||||||
|
if closing[connID] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
conn := m.conns[connID]
|
conn := m.conns[connID]
|
||||||
if conn.Statistics().StartedAt.IsZero() {
|
if conn.Statistics().StartedAt.IsZero() {
|
||||||
conn.SetFolderPasswords(passwords)
|
conn.SetFolderPasswords(passwords)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<configuration version="37">
|
<configuration version="37">
|
||||||
<folder id="default" label="" path="s1?files=10000&sizeavg=25000000" type="sendreceive" rescanIntervalS="3600" fsWatcherEnabled="false" fsWatcherDelayS="10" ignorePerms="false" autoNormalize="true">
|
<folder id="default" label="" path="s1" type="sendreceive" rescanIntervalS="3600" fsWatcherEnabled="false" fsWatcherDelayS="10" ignorePerms="false" autoNormalize="true">
|
||||||
<filesystemType>fake</filesystemType>
|
<filesystemType>fake</filesystemType>
|
||||||
<device id="I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU" introducedBy="">
|
<device id="I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU" introducedBy="">
|
||||||
<encryptionPassword></encryptionPassword>
|
<encryptionPassword></encryptionPassword>
|
||||||
@ -123,9 +123,9 @@
|
|||||||
<connectionLimitEnough>0</connectionLimitEnough>
|
<connectionLimitEnough>0</connectionLimitEnough>
|
||||||
<connectionLimitMax>0</connectionLimitMax>
|
<connectionLimitMax>0</connectionLimitMax>
|
||||||
<insecureAllowOldTLSVersions>false</insecureAllowOldTLSVersions>
|
<insecureAllowOldTLSVersions>false</insecureAllowOldTLSVersions>
|
||||||
<connectionPriorityTcpLan>20</connectionPriorityTcpLan>
|
<connectionPriorityTcpLan>10</connectionPriorityTcpLan>
|
||||||
<connectionPriorityQuicLan>20</connectionPriorityQuicLan>
|
<connectionPriorityQuicLan>20</connectionPriorityQuicLan>
|
||||||
<connectionPriorityTcpWan>40</connectionPriorityTcpWan>
|
<connectionPriorityTcpWan>30</connectionPriorityTcpWan>
|
||||||
<connectionPriorityQuicWan>40</connectionPriorityQuicWan>
|
<connectionPriorityQuicWan>40</connectionPriorityQuicWan>
|
||||||
<connectionPriorityRelay>50</connectionPriorityRelay>
|
<connectionPriorityRelay>50</connectionPriorityRelay>
|
||||||
<connectionPriorityUpgradeThreshold>0</connectionPriorityUpgradeThreshold>
|
<connectionPriorityUpgradeThreshold>0</connectionPriorityUpgradeThreshold>
|
||||||
|
@ -44,8 +44,7 @@
|
|||||||
</xattrFilter>
|
</xattrFilter>
|
||||||
</folder>
|
</folder>
|
||||||
<device id="I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU" name="s1" compression="metadata" introducer="false" skipIntroductionRemovals="false" introducedBy="">
|
<device id="I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU" name="s1" compression="metadata" introducer="false" skipIntroductionRemovals="false" introducedBy="">
|
||||||
<address>tcp://127.0.0.1:22001</address>
|
<address>dynamic</address>
|
||||||
<address>quic://127.0.0.1:22001</address>
|
|
||||||
<paused>false</paused>
|
<paused>false</paused>
|
||||||
<autoAcceptFolders>false</autoAcceptFolders>
|
<autoAcceptFolders>false</autoAcceptFolders>
|
||||||
<maxSendKbps>0</maxSendKbps>
|
<maxSendKbps>0</maxSendKbps>
|
||||||
@ -121,9 +120,9 @@
|
|||||||
<connectionLimitEnough>0</connectionLimitEnough>
|
<connectionLimitEnough>0</connectionLimitEnough>
|
||||||
<connectionLimitMax>0</connectionLimitMax>
|
<connectionLimitMax>0</connectionLimitMax>
|
||||||
<insecureAllowOldTLSVersions>false</insecureAllowOldTLSVersions>
|
<insecureAllowOldTLSVersions>false</insecureAllowOldTLSVersions>
|
||||||
<connectionPriorityTcpLan>20</connectionPriorityTcpLan>
|
<connectionPriorityTcpLan>10</connectionPriorityTcpLan>
|
||||||
<connectionPriorityQuicLan>20</connectionPriorityQuicLan>
|
<connectionPriorityQuicLan>20</connectionPriorityQuicLan>
|
||||||
<connectionPriorityTcpWan>40</connectionPriorityTcpWan>
|
<connectionPriorityTcpWan>30</connectionPriorityTcpWan>
|
||||||
<connectionPriorityQuicWan>40</connectionPriorityQuicWan>
|
<connectionPriorityQuicWan>40</connectionPriorityQuicWan>
|
||||||
<connectionPriorityRelay>50</connectionPriorityRelay>
|
<connectionPriorityRelay>50</connectionPriorityRelay>
|
||||||
<connectionPriorityUpgradeThreshold>0</connectionPriorityUpgradeThreshold>
|
<connectionPriorityUpgradeThreshold>0</connectionPriorityUpgradeThreshold>
|
||||||
|
Loading…
Reference in New Issue
Block a user