diff --git a/router/connection.go b/router/connection.go index f1ae3a04..961dd9cf 100644 --- a/router/connection.go +++ b/router/connection.go @@ -45,6 +45,7 @@ type LocalConnection struct { effectivePMTU int SessionKey *[32]byte establishedTimeout *time.Timer + heartbeatTimeout *time.Timer heartbeatFrame *ForwardedFrame heartbeat *time.Ticker fragTest *time.Ticker @@ -301,10 +302,12 @@ func (conn *LocalConnection) queryLoop(queryChan <-chan *ConnectionInteraction) case CSendProtocolMsg: err = conn.handleSendProtocolMsg(query.payload.(ProtocolMsg)) } - case <-conn.establishedTimeout.C: + case <-timerChan(conn.establishedTimeout): if !conn.established { err = fmt.Errorf("failed to establish UDP connectivity") } + case <-timerChan(conn.heartbeatTimeout): + err = fmt.Errorf("timed out waiting for UDP heartbeat") case <-tickerChan(conn.heartbeat): conn.Forward(true, conn.heartbeatFrame, nil) case <-tickerChan(conn.fragTest): @@ -329,6 +332,9 @@ func (conn *LocalConnection) handleReceivedHeartbeat(remoteUDPAddr *net.UDPAddr) conn.remoteUDPAddr = remoteUDPAddr conn.receivedHeartbeat = true conn.Unlock() + if conn.established { + conn.heartbeatTimeout.Reset(HeartbeatTimeout) + } if !old { if err := conn.handleSendSimpleProtocolMsg(ProtocolConnectionEstablished); err != nil { return err @@ -362,6 +368,7 @@ func (conn *LocalConnection) handleSetEstablished() error { dstPeer: conn.remote, frame: PMTUDiscovery}, nil) + conn.heartbeatTimeout = time.NewTimer(HeartbeatTimeout) conn.heartbeat = time.NewTicker(SlowHeartbeat) conn.fragTest = time.NewTicker(FragTestInterval) // avoid initial waits for timers to fire @@ -391,10 +398,8 @@ func (conn *LocalConnection) handleShutdown() { conn.Router.Ourself.DeleteConnection(conn) } - if conn.establishedTimeout != nil { - conn.establishedTimeout.Stop() - } - + stopTimer(conn.establishedTimeout) + stopTimer(conn.heartbeatTimeout) stopTicker(conn.heartbeat) stopTicker(conn.fragTest) @@ -498,3 +503,16 @@ func stopTicker(ticker *time.Ticker) { ticker.Stop() } } + +func timerChan(timer *time.Timer) <-chan time.Time { + if timer != nil { + return timer.C + } + return nil +} + +func stopTimer(timer *time.Timer) { + if timer != nil { + timer.Stop() + } +} diff --git a/router/consts.go b/router/consts.go index 11075638..da38e8ba 100644 --- a/router/consts.go +++ b/router/consts.go @@ -6,24 +6,26 @@ import ( ) const ( - EthernetOverhead = 14 - UDPOverhead = 28 // 20 bytes for IPv4, 8 bytes for UDP - Port = 6783 - HttpPort = Port + 1 - DefaultPMTU = 65535 - MaxUDPPacketSize = 65536 - ChannelSize = 16 - UDPNonceSendAt = 8192 - FragTestSize = 60001 - PMTUDiscoverySize = 60000 - FastHeartbeat = 500 * time.Millisecond - SlowHeartbeat = 10 * time.Second - FragTestInterval = 5 * time.Minute - EstablishedTimeout = 30 * time.Second - ReadTimeout = 1 * time.Minute - PMTUVerifyAttempts = 8 - PMTUVerifyTimeout = 10 * time.Millisecond // gets doubled with every attempt - MaxDuration = time.Duration(math.MaxInt64) + EthernetOverhead = 14 + UDPOverhead = 28 // 20 bytes for IPv4, 8 bytes for UDP + Port = 6783 + HttpPort = Port + 1 + DefaultPMTU = 65535 + MaxUDPPacketSize = 65536 + ChannelSize = 16 + UDPNonceSendAt = 8192 + FragTestSize = 60001 + PMTUDiscoverySize = 60000 + FastHeartbeat = 500 * time.Millisecond + SlowHeartbeat = 10 * time.Second + FragTestInterval = 5 * time.Minute + EstablishedTimeout = 30 * time.Second + ReadTimeout = 1 * time.Minute + PMTUVerifyAttempts = 8 + PMTUVerifyTimeout = 10 * time.Millisecond // gets doubled with every attempt + MaxDuration = time.Duration(math.MaxInt64) + MaxMissedHeartbeats = 3 + HeartbeatTimeout = MaxMissedHeartbeats * SlowHeartbeat ) var (