mirror of
https://github.com/ergochat/ergo.git
synced 2024-12-22 18:52:41 +01:00
Merge pull request #441 from slingamn/tor_timeout
work around a Tor bug
This commit is contained in:
commit
acd9eeeb15
@ -15,12 +15,17 @@ import (
|
|||||||
const (
|
const (
|
||||||
// RegisterTimeout is how long clients have to register before we disconnect them
|
// RegisterTimeout is how long clients have to register before we disconnect them
|
||||||
RegisterTimeout = time.Minute
|
RegisterTimeout = time.Minute
|
||||||
// IdleTimeout is how long without traffic before a registered client is considered idle.
|
// DefaultIdleTimeout is how long without traffic before we send the client a PING
|
||||||
IdleTimeout = time.Minute + time.Second*30
|
DefaultIdleTimeout = time.Minute + 30*time.Second
|
||||||
// IdleTimeoutWithResumeCap is how long without traffic before a registered client is considered idle, when they have the resume capability.
|
// For Tor clients, we send a PING at least every 30 seconds, as a workaround for this bug
|
||||||
IdleTimeoutWithResumeCap = time.Minute*2 + time.Second*30
|
// (single-onion circuits will close unless the client sends data once every 60 seconds):
|
||||||
// QuitTimeout is how long without traffic before an idle client is disconnected
|
// https://bugs.torproject.org/29665
|
||||||
QuitTimeout = time.Minute
|
TorIdleTimeout = time.Second * 30
|
||||||
|
// This is how long a client gets without sending any message, including the PONG to our
|
||||||
|
// PING, before we disconnect them:
|
||||||
|
DefaultTotalTimeout = 2*time.Minute + 30*time.Second
|
||||||
|
// Resumeable clients (clients who have negotiated caps.Resume) get longer:
|
||||||
|
ResumeableTotalTimeout = 3*time.Minute + 30*time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
// client idleness state machine
|
// client idleness state machine
|
||||||
@ -39,11 +44,11 @@ type IdleTimer struct {
|
|||||||
|
|
||||||
// immutable after construction
|
// immutable after construction
|
||||||
registerTimeout time.Duration
|
registerTimeout time.Duration
|
||||||
quitTimeout time.Duration
|
|
||||||
client *Client
|
client *Client
|
||||||
|
|
||||||
// mutable
|
// mutable
|
||||||
idleTimeout time.Duration
|
idleTimeout time.Duration
|
||||||
|
quitTimeout time.Duration
|
||||||
state TimerState
|
state TimerState
|
||||||
timer *time.Timer
|
timer *time.Timer
|
||||||
}
|
}
|
||||||
@ -52,26 +57,28 @@ type IdleTimer struct {
|
|||||||
func NewIdleTimer(client *Client) *IdleTimer {
|
func NewIdleTimer(client *Client) *IdleTimer {
|
||||||
it := IdleTimer{
|
it := IdleTimer{
|
||||||
registerTimeout: RegisterTimeout,
|
registerTimeout: RegisterTimeout,
|
||||||
idleTimeout: IdleTimeout,
|
|
||||||
quitTimeout: QuitTimeout,
|
|
||||||
client: client,
|
client: client,
|
||||||
}
|
}
|
||||||
|
it.idleTimeout, it.quitTimeout = it.recomputeDurations()
|
||||||
return &it
|
return &it
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateIdleDuration updates the idle duration, given the client's caps.
|
// recomputeDurations recomputes the idle and quit durations, given the client's caps.
|
||||||
func (it *IdleTimer) updateIdleDuration() {
|
func (it *IdleTimer) recomputeDurations() (idleTimeout, quitTimeout time.Duration) {
|
||||||
newIdleTime := IdleTimeout
|
totalTimeout := DefaultTotalTimeout
|
||||||
|
|
||||||
// if they have the resume cap, wait longer before pinging them out
|
// if they have the resume cap, wait longer before pinging them out
|
||||||
// to give them a chance to resume their connection
|
// to give them a chance to resume their connection
|
||||||
if it.client.capabilities.Has(caps.Resume) {
|
if it.client.capabilities.Has(caps.Resume) {
|
||||||
newIdleTime = IdleTimeoutWithResumeCap
|
totalTimeout = ResumeableTotalTimeout
|
||||||
}
|
}
|
||||||
|
|
||||||
it.Lock()
|
idleTimeout = DefaultIdleTimeout
|
||||||
defer it.Unlock()
|
if it.client.isTor {
|
||||||
it.idleTimeout = newIdleTime
|
idleTimeout = TorIdleTimeout
|
||||||
|
}
|
||||||
|
|
||||||
|
quitTimeout = totalTimeout - idleTimeout
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start starts counting idle time; if there is no activity from the client,
|
// Start starts counting idle time; if there is no activity from the client,
|
||||||
@ -84,10 +91,11 @@ func (it *IdleTimer) Start() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (it *IdleTimer) Touch() {
|
func (it *IdleTimer) Touch() {
|
||||||
it.updateIdleDuration()
|
idleTimeout, quitTimeout := it.recomputeDurations()
|
||||||
|
|
||||||
it.Lock()
|
it.Lock()
|
||||||
defer it.Unlock()
|
defer it.Unlock()
|
||||||
|
it.idleTimeout, it.quitTimeout = idleTimeout, quitTimeout
|
||||||
// a touch transitions TimerUnregistered or TimerIdle into TimerActive
|
// a touch transitions TimerUnregistered or TimerIdle into TimerActive
|
||||||
if it.state != TimerDead {
|
if it.state != TimerDead {
|
||||||
it.state = TimerActive
|
it.state = TimerActive
|
||||||
@ -96,12 +104,13 @@ func (it *IdleTimer) Touch() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (it *IdleTimer) processTimeout() {
|
func (it *IdleTimer) processTimeout() {
|
||||||
it.updateIdleDuration()
|
idleTimeout, quitTimeout := it.recomputeDurations()
|
||||||
|
|
||||||
var previousState TimerState
|
var previousState TimerState
|
||||||
func() {
|
func() {
|
||||||
it.Lock()
|
it.Lock()
|
||||||
defer it.Unlock()
|
defer it.Unlock()
|
||||||
|
it.idleTimeout, it.quitTimeout = idleTimeout, quitTimeout
|
||||||
previousState = it.state
|
previousState = it.state
|
||||||
// TimerActive transitions to TimerIdle, all others to TimerDead
|
// TimerActive transitions to TimerIdle, all others to TimerDead
|
||||||
if it.state == TimerActive {
|
if it.state == TimerActive {
|
||||||
|
Loading…
Reference in New Issue
Block a user