From fec5644b9feb92ee9b74e51f35b8c0285162faa8 Mon Sep 17 00:00:00 2001 From: Kleissner Date: Mon, 1 Mar 2021 03:41:26 +0100 Subject: [PATCH] Connections: Introduce Redundant type to lower ping overhead. --- Commands.go | 42 ++++++++++++++++++++++++++++-------------- Connection.go | 26 ++++++++++++++++++++++---- 2 files changed, 50 insertions(+), 18 deletions(-) diff --git a/Commands.go b/Commands.go index 69d2977..c7fd45e 100644 --- a/Commands.go +++ b/Commands.go @@ -88,7 +88,7 @@ func (peer *PeerInfo) cmdChat(msg *packet2) { const pingTime = 10 // connectionInvalidate is the threshold in seconds to invalidate formerly active connections that no longer receive incoming packets. -const connectionInvalidate = 20 +const connectionInvalidate = 22 // connectionRemove is the threshold in seconds to remove inactive connections in case there is at least one active connection known. const connectionRemove = 2 * 60 @@ -97,24 +97,29 @@ const connectionRemove = 2 * 60 func autoPingAll() { for { time.Sleep(time.Second) - thresholdInvalidate := time.Now().Add(-connectionInvalidate * time.Second) - thresholdPingOut := time.Now().Add(-pingTime * time.Second) + thresholdInvalidate1 := time.Now().Add(-connectionInvalidate * time.Second) + thresholdInvalidate2 := time.Now().Add(-connectionInvalidate * time.Second * 4) + thresholdPingOut1 := time.Now().Add(-pingTime * time.Second) + thresholdPingOut2 := time.Now().Add(-pingTime * time.Second * 4) for _, peer := range PeerlistGet() { // first handle active connections for _, connection := range peer.GetConnections(true) { - // Check if no incoming packet for the last X seconds. Regularly sent pings should result in incoming packets. - if connection.LastPacketIn.Before(thresholdInvalidate) { + thresholdPing := thresholdPingOut1 + thresholdInv := thresholdInvalidate1 + + if connection.Status == ConnectionRedundant { + thresholdPing = thresholdPingOut2 + thresholdInv = thresholdInvalidate2 + } + + if connection.LastPacketIn.Before(thresholdInv) { peer.invalidateActiveConnection(connection) continue } - // Send ping if none was sent recently and no incoming packet was received recently. - if connection.LastPacketIn.Before(thresholdPingOut) && connection.LastPingOut.Before(thresholdPingOut) { - if err := peer.sendConnection(&PacketRaw{Command: CommandPing}, connection); IsNetworkErrorFatal(err) { - peer.invalidateActiveConnection(connection) - } - connection.LastPingOut = time.Now() + if connection.LastPacketIn.Before(thresholdPing) && connection.LastPingOut.Before(thresholdPing) { + peer.sendPing(connection) continue } } @@ -128,15 +133,24 @@ func autoPingAll() { } // if no ping was sent recently, send one now - if connection.LastPingOut.Before(thresholdPingOut) { - peer.sendConnection(&PacketRaw{Command: CommandPing}, connection) - connection.LastPingOut = time.Now() + if connection.LastPingOut.Before(thresholdPingOut1) { + peer.sendPing(connection) } } } } } +// sendPing sends a ping to the target peer +func (peer *PeerInfo) sendPing(connection *Connection) { + err := peer.sendConnection(&PacketRaw{Command: CommandPing}, connection) + connection.LastPingOut = time.Now() + + if (connection.Status == ConnectionActive || connection.Status == ConnectionRedundant) && IsNetworkErrorFatal(err) { + peer.invalidateActiveConnection(connection) + } +} + // SendChatAll sends a text message to all peers func SendChatAll(text string) { for _, peer := range PeerlistGet() { diff --git a/Connection.go b/Connection.go index e17e4b3..1d02f9c 100644 --- a/Connection.go +++ b/Connection.go @@ -24,7 +24,7 @@ type Connection struct { LastPacketOut time.Time // Last time an outgoing packet was attempted to send. LastPingOut time.Time // Last ping out. Expires time.Time // Inactive connections only: Expiry date. If it does not become active by that date, it will be considered expired and removed. - Status int // 0 = Active established connection, 1 = Inactive, 2 = Removed + Status int // 0 = Active established connection, 1 = Inactive, 2 = Removed, 3 = Redundant } // Connection status @@ -32,6 +32,7 @@ const ( ConnectionActive = iota ConnectionInactive ConnectionRemoved + ConnectionRedundant // Same as active. Incoming packets are accepted. Outgoing use only for redundancy. Reduces ping overhead. ) // Equal checks if the connection was established other the same network adapter using the same IP address. Port is intentionally not checked. @@ -64,7 +65,8 @@ func (peer *PeerInfo) registerConnection(incoming *Connection) (result *Connecti connection.Address.Port = incoming.Address.Port } - peer.connectionLatest = connection + connection.Status = ConnectionActive + peer.setConnectionLatest(connection) return connection } } @@ -78,8 +80,8 @@ func (peer *PeerInfo) registerConnection(incoming *Connection) (result *Connecti // elevate by adding to active and mark as latest active connection.Status = ConnectionActive - peer.connectionLatest = connection peer.connectionActive = append(peer.connectionActive, connection) + peer.setConnectionLatest(connection) // remove from inactive inactiveNew := peer.connectionInactive[:n] @@ -94,11 +96,27 @@ func (peer *PeerInfo) registerConnection(incoming *Connection) (result *Connecti // otherwise it is a new connection! peer.connectionActive = append(peer.connectionActive, incoming) - peer.connectionLatest = incoming + peer.setConnectionLatest(incoming) return incoming } +// setConnectionLatest updates the latest valid connection to use for sending. All other connections will be changed to redundant, which reduces ping overhead. +func (peer *PeerInfo) setConnectionLatest(latest *Connection) { + if peer.connectionLatest == latest { + return + } + + peer.connectionLatest = latest + + for _, connection := range peer.connectionActive { + if connection == latest { + continue + } + connection.Status = ConnectionRedundant + } +} + // invalidateActiveConnection invalidates an active connection func (peer *PeerInfo) invalidateActiveConnection(input *Connection) { peer.Lock()