protocol: Add "Hello" message at connection start, also for unauthed peers
This commit is contained in:
@@ -87,10 +87,10 @@ type Model struct {
|
||||
folderStatRefs map[string]*stats.FolderStatisticsReference // folder -> statsRef
|
||||
fmut sync.RWMutex // protects the above
|
||||
|
||||
conn map[protocol.DeviceID]Connection
|
||||
deviceVer map[protocol.DeviceID]string
|
||||
devicePaused map[protocol.DeviceID]bool
|
||||
pmut sync.RWMutex // protects the above
|
||||
conn map[protocol.DeviceID]Connection
|
||||
helloMessages map[protocol.DeviceID]protocol.HelloMessage
|
||||
devicePaused map[protocol.DeviceID]bool
|
||||
pmut sync.RWMutex // protects the above
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -128,7 +128,7 @@ func NewModel(cfg *config.Wrapper, id protocol.DeviceID, deviceName, clientName,
|
||||
folderRunnerTokens: make(map[string][]suture.ServiceToken),
|
||||
folderStatRefs: make(map[string]*stats.FolderStatisticsReference),
|
||||
conn: make(map[protocol.DeviceID]Connection),
|
||||
deviceVer: make(map[protocol.DeviceID]string),
|
||||
helloMessages: make(map[protocol.DeviceID]protocol.HelloMessage),
|
||||
devicePaused: make(map[protocol.DeviceID]bool),
|
||||
|
||||
fmut: sync.NewRWMutex(),
|
||||
@@ -315,8 +315,13 @@ func (m *Model) ConnectionStats() map[string]interface{} {
|
||||
devs := m.cfg.Devices()
|
||||
conns := make(map[string]ConnectionInfo, len(devs))
|
||||
for device := range devs {
|
||||
hello := m.helloMessages[device]
|
||||
versionString := hello.ClientVersion
|
||||
if hello.ClientName != "syncthing" {
|
||||
versionString = hello.ClientName + " " + hello.ClientVersion
|
||||
}
|
||||
ci := ConnectionInfo{
|
||||
ClientVersion: m.deviceVer[device],
|
||||
ClientVersion: versionString,
|
||||
Paused: m.devicePaused[device],
|
||||
}
|
||||
if conn, ok := m.conn[device]; ok {
|
||||
@@ -606,30 +611,6 @@ func (m *Model) folderSharedWithUnlocked(folder string, deviceID protocol.Device
|
||||
}
|
||||
|
||||
func (m *Model) ClusterConfig(deviceID protocol.DeviceID, cm protocol.ClusterConfigMessage) {
|
||||
m.pmut.Lock()
|
||||
if cm.ClientName == "syncthing" {
|
||||
m.deviceVer[deviceID] = cm.ClientVersion
|
||||
} else {
|
||||
m.deviceVer[deviceID] = cm.ClientName + " " + cm.ClientVersion
|
||||
}
|
||||
|
||||
event := map[string]string{
|
||||
"id": deviceID.String(),
|
||||
"deviceName": cm.DeviceName,
|
||||
"clientName": cm.ClientName,
|
||||
"clientVersion": cm.ClientVersion,
|
||||
}
|
||||
|
||||
if conn, ok := m.conn[deviceID]; ok {
|
||||
event["type"] = conn.Type.String()
|
||||
addr := conn.RemoteAddr()
|
||||
if addr != nil {
|
||||
event["addr"] = addr.String()
|
||||
}
|
||||
}
|
||||
|
||||
m.pmut.Unlock()
|
||||
|
||||
// Check the peer device's announced folders against our own. Emits events
|
||||
// for folders that we don't expect (unknown or not shared).
|
||||
|
||||
@@ -661,19 +642,8 @@ nextFolder:
|
||||
}
|
||||
m.fmut.Unlock()
|
||||
|
||||
events.Default.Log(events.DeviceConnected, event)
|
||||
|
||||
l.Infof(`Device %s client is "%s %s" named "%s"`, deviceID, cm.ClientName, cm.ClientVersion, cm.DeviceName)
|
||||
|
||||
var changed bool
|
||||
|
||||
device, ok := m.cfg.Devices()[deviceID]
|
||||
if ok && device.Name == "" {
|
||||
device.Name = cm.DeviceName
|
||||
m.cfg.SetDevice(device)
|
||||
changed = true
|
||||
}
|
||||
|
||||
if m.cfg.Devices()[deviceID].Introducer {
|
||||
// This device is an introducer. Go through the announced lists of folders
|
||||
// and devices and add what we are missing.
|
||||
@@ -773,7 +743,7 @@ func (m *Model) Close(device protocol.DeviceID, err error) {
|
||||
closeRawConn(conn)
|
||||
}
|
||||
delete(m.conn, device)
|
||||
delete(m.deviceVer, device)
|
||||
delete(m.helloMessages, device)
|
||||
m.pmut.Unlock()
|
||||
}
|
||||
|
||||
@@ -978,10 +948,41 @@ func (m *Model) SetIgnores(folder string, content []string) error {
|
||||
return m.ScanFolder(folder)
|
||||
}
|
||||
|
||||
// OnHello is called when an device connects to us.
|
||||
// This allows us to extract some information from the Hello message
|
||||
// and add it to a list of known devices ahead of any checks.
|
||||
func (m *Model) OnHello(remoteID protocol.DeviceID, addr net.Addr, hello protocol.HelloMessage) {
|
||||
for deviceID := range m.cfg.Devices() {
|
||||
if deviceID == remoteID {
|
||||
// Existing device, we will get the hello message in AddConnection
|
||||
// hence do not persist any state here, as the connection might
|
||||
// get killed before AddConnection
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !m.cfg.IgnoredDevice(remoteID) {
|
||||
events.Default.Log(events.DeviceRejected, map[string]string{
|
||||
"name": hello.DeviceName,
|
||||
"device": remoteID.String(),
|
||||
"address": addr.String(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// GetHello is called when we are about to connect to some remote device.
|
||||
func (m *Model) GetHello(protocol.DeviceID) protocol.HelloMessage {
|
||||
return protocol.HelloMessage{
|
||||
DeviceName: m.deviceName,
|
||||
ClientName: m.clientName,
|
||||
ClientVersion: m.clientVersion,
|
||||
}
|
||||
}
|
||||
|
||||
// AddConnection adds a new peer connection to the model. An initial index will
|
||||
// be sent to the connected peer, thereafter index updates whenever the local
|
||||
// folder changes.
|
||||
func (m *Model) AddConnection(conn Connection) {
|
||||
func (m *Model) AddConnection(conn Connection, hello protocol.HelloMessage) {
|
||||
deviceID := conn.ID()
|
||||
|
||||
m.pmut.Lock()
|
||||
@@ -990,6 +991,32 @@ func (m *Model) AddConnection(conn Connection) {
|
||||
}
|
||||
m.conn[deviceID] = conn
|
||||
|
||||
m.helloMessages[deviceID] = hello
|
||||
|
||||
event := map[string]string{
|
||||
"id": deviceID.String(),
|
||||
"deviceName": hello.DeviceName,
|
||||
"clientName": hello.ClientName,
|
||||
"clientVersion": hello.ClientVersion,
|
||||
"type": conn.Type.String(),
|
||||
}
|
||||
|
||||
addr := conn.RemoteAddr()
|
||||
if addr != nil {
|
||||
event["addr"] = addr.String()
|
||||
}
|
||||
|
||||
events.Default.Log(events.DeviceConnected, event)
|
||||
|
||||
l.Infof(`Device %s client is "%s %s" named "%s"`, deviceID, hello.ClientName, hello.ClientVersion, hello.DeviceName)
|
||||
|
||||
device, ok := m.cfg.Devices()[deviceID]
|
||||
if ok && device.Name == "" {
|
||||
device.Name = hello.DeviceName
|
||||
m.cfg.SetDevice(device)
|
||||
m.cfg.Save()
|
||||
}
|
||||
|
||||
conn.Start()
|
||||
|
||||
cm := m.generateClusterConfig(deviceID)
|
||||
@@ -1510,11 +1537,7 @@ func (m *Model) numHashers(folder string) int {
|
||||
// generateClusterConfig returns a ClusterConfigMessage that is correct for
|
||||
// the given peer device
|
||||
func (m *Model) generateClusterConfig(device protocol.DeviceID) protocol.ClusterConfigMessage {
|
||||
message := protocol.ClusterConfigMessage{
|
||||
DeviceName: m.deviceName,
|
||||
ClientName: m.clientName,
|
||||
ClientVersion: m.clientVersion,
|
||||
}
|
||||
var message protocol.ClusterConfigMessage
|
||||
|
||||
m.fmut.RLock()
|
||||
for _, folder := range m.deviceFolders[device] {
|
||||
|
||||
@@ -279,7 +279,7 @@ func BenchmarkRequest(b *testing.B) {
|
||||
&net.TCPConn{},
|
||||
fc,
|
||||
ConnectionTypeDirectAccept,
|
||||
})
|
||||
}, protocol.HelloMessage{})
|
||||
m.Index(device1, "default", files, 0, nil)
|
||||
|
||||
b.ResetTimer()
|
||||
@@ -295,11 +295,10 @@ func BenchmarkRequest(b *testing.B) {
|
||||
}
|
||||
|
||||
func TestDeviceRename(t *testing.T) {
|
||||
ccm := protocol.ClusterConfigMessage{
|
||||
hello := protocol.HelloMessage{
|
||||
ClientName: "syncthing",
|
||||
ClientVersion: "v0.9.4",
|
||||
}
|
||||
|
||||
defer os.Remove("tmpconfig.xml")
|
||||
|
||||
rawCfg := config.New(device1)
|
||||
@@ -313,35 +312,39 @@ func TestDeviceRename(t *testing.T) {
|
||||
db := db.OpenMemory()
|
||||
m := NewModel(cfg, protocol.LocalDeviceID, "device", "syncthing", "dev", db, nil)
|
||||
|
||||
fc := FakeConnection{
|
||||
id: device1,
|
||||
requestData: []byte("some data to return"),
|
||||
if cfg.Devices()[device1].Name != "" {
|
||||
t.Errorf("Device already has a name")
|
||||
}
|
||||
|
||||
m.AddConnection(Connection{
|
||||
conn := Connection{
|
||||
&net.TCPConn{},
|
||||
fc,
|
||||
FakeConnection{
|
||||
id: device1,
|
||||
requestData: []byte("some data to return"),
|
||||
},
|
||||
ConnectionTypeDirectAccept,
|
||||
})
|
||||
}
|
||||
|
||||
m.AddConnection(conn, hello)
|
||||
|
||||
m.ServeBackground()
|
||||
|
||||
if cfg.Devices()[device1].Name != "" {
|
||||
t.Errorf("Device already has a name")
|
||||
}
|
||||
|
||||
m.ClusterConfig(device1, ccm)
|
||||
if cfg.Devices()[device1].Name != "" {
|
||||
t.Errorf("Device already has a name")
|
||||
}
|
||||
m.Close(device1, protocol.ErrTimeout)
|
||||
hello.DeviceName = "tester"
|
||||
m.AddConnection(conn, hello)
|
||||
|
||||
ccm.DeviceName = "tester"
|
||||
m.ClusterConfig(device1, ccm)
|
||||
if cfg.Devices()[device1].Name != "tester" {
|
||||
t.Errorf("Device did not get a name")
|
||||
}
|
||||
|
||||
ccm.DeviceName = "tester2"
|
||||
m.ClusterConfig(device1, ccm)
|
||||
m.Close(device1, protocol.ErrTimeout)
|
||||
hello.DeviceName = "tester2"
|
||||
m.AddConnection(conn, hello)
|
||||
|
||||
if cfg.Devices()[device1].Name != "tester" {
|
||||
t.Errorf("Device name got overwritten")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user