Files
weave/router/status.go
T
Matthias Radestock 520c7286c4 backoff retries for late-failing connections
If a connection gets through all the handshake and subsequent checks -
i.e. it ends up getting added to the LocalPeer's connection list - but
gets terminated within one minute (of the start of the successful
connection attempt), then we apply the existing backoff logic to
schedule a retry, instead of retrying immediately.

In order to do this we retain the 'Target' data structure for such
connections, marking it as 'connected' instead of deleting it (as we
did previously).

Fixes #953.
2015-10-01 20:05:12 +01:00

214 lines
4.8 KiB
Go

package router
import (
"time"
)
type Status struct {
Protocol string
ProtocolMinVersion int
ProtocolMaxVersion int
Encryption bool
PeerDiscovery bool
Name string
NickName string
Port int
Interface string
CaptureStats map[string]int
MACs []MACStatus
Peers []PeerStatus
UnicastRoutes []UnicastRouteStatus
BroadcastRoutes []BroadcastRouteStatus
Connections []LocalConnectionStatus
Targets []string
}
type MACStatus struct {
Mac string
Name string
NickName string
LastSeen time.Time
}
type PeerStatus struct {
Name string
NickName string
UID PeerUID
Version uint64
Connections []ConnectionStatus
}
type ConnectionStatus struct {
Name string
NickName string
Address string
Outbound bool
Established bool
}
type UnicastRouteStatus struct {
Dest, Via string
}
type BroadcastRouteStatus struct {
Source string
Via []string
}
type LocalConnectionStatus struct {
Address string
Outbound bool
State string
Info string
}
func NewStatus(router *Router) *Status {
return &Status{
Protocol,
ProtocolMinVersion,
ProtocolMaxVersion,
router.UsingPassword(),
router.PeerDiscovery,
router.Ourself.Name.String(),
router.Ourself.NickName,
router.Port,
router.Bridge.String(),
router.Bridge.Stats(),
NewMACStatusSlice(router.Macs),
NewPeerStatusSlice(router.Peers),
NewUnicastRouteStatusSlice(router.Routes),
NewBroadcastRouteStatusSlice(router.Routes),
NewLocalConnectionStatusSlice(router.ConnectionMaker),
NewTargetSlice(router.ConnectionMaker)}
}
func NewMACStatusSlice(cache *MacCache) []MACStatus {
cache.RLock()
defer cache.RUnlock()
var slice []MACStatus
for key, entry := range cache.table {
slice = append(slice, MACStatus{
intmac(key).String(),
entry.peer.Name.String(),
entry.peer.NickName,
entry.lastSeen})
}
return slice
}
func NewPeerStatusSlice(peers *Peers) []PeerStatus {
var slice []PeerStatus
peers.ForEach(func(peer *Peer) {
var connections []ConnectionStatus
if peer == peers.ourself.Peer {
for conn := range peers.ourself.Connections() {
connections = append(connections, newConnectionStatus(conn))
}
} else {
// Modifying peer.connections requires a write lock on
// Peers, and since we are holding a read lock (due to the
// ForEach), access without locking the peer is safe.
for _, conn := range peer.connections {
connections = append(connections, newConnectionStatus(conn))
}
}
slice = append(slice, PeerStatus{
peer.Name.String(),
peer.NickName,
peer.UID,
peer.Version,
connections})
})
return slice
}
func newConnectionStatus(c Connection) ConnectionStatus {
return ConnectionStatus{
c.Remote().Name.String(),
c.Remote().NickName,
c.RemoteTCPAddr(),
c.Outbound(),
c.Established()}
}
func NewUnicastRouteStatusSlice(routes *Routes) []UnicastRouteStatus {
routes.RLock()
defer routes.RUnlock()
var slice []UnicastRouteStatus
for dest, via := range routes.unicast {
slice = append(slice, UnicastRouteStatus{dest.String(), via.String()})
}
return slice
}
func NewBroadcastRouteStatusSlice(routes *Routes) []BroadcastRouteStatus {
routes.RLock()
defer routes.RUnlock()
var slice []BroadcastRouteStatus
for source, via := range routes.broadcast {
var hops []string
for _, hop := range via {
hops = append(hops, hop.String())
}
slice = append(slice, BroadcastRouteStatus{source.String(), hops})
}
return slice
}
func NewLocalConnectionStatusSlice(cm *ConnectionMaker) []LocalConnectionStatus {
resultChan := make(chan []LocalConnectionStatus, 0)
cm.actionChan <- func() bool {
var slice []LocalConnectionStatus
for conn := range cm.connections {
state := "pending"
if conn.Established() {
state = "established"
}
slice = append(slice, LocalConnectionStatus{conn.RemoteTCPAddr(), conn.Outbound(), state, conn.Remote().String()})
}
for address, target := range cm.targets {
var state, info string
switch {
case target.connected:
continue
case target.lastError == nil:
state = "connecting"
info = ""
case target.attempting:
state = "retrying"
info = target.lastError.Error()
default:
state = "failed"
retry := "never"
if !target.tryAfter.IsZero() {
retry = target.tryAfter.String()
}
info = target.lastError.Error() + ", retry: " + retry
}
slice = append(slice, LocalConnectionStatus{address, true, state, info})
}
resultChan <- slice
return false
}
return <-resultChan
}
func NewTargetSlice(cm *ConnectionMaker) []string {
resultChan := make(chan []string, 0)
cm.actionChan <- func() bool {
var slice []string
for peer := range cm.directPeers {
slice = append(slice, peer)
}
resultChan <- slice
return false
}
return <-resultChan
}