|
@@ -15,12 +15,17 @@ import (
|
15
|
15
|
const (
|
16
|
16
|
// RegisterTimeout is how long clients have to register before we disconnect them
|
17
|
17
|
RegisterTimeout = time.Minute
|
18
|
|
- // IdleTimeout is how long without traffic before a registered client is considered idle.
|
19
|
|
- IdleTimeout = time.Minute + time.Second*30
|
20
|
|
- // IdleTimeoutWithResumeCap is how long without traffic before a registered client is considered idle, when they have the resume capability.
|
21
|
|
- IdleTimeoutWithResumeCap = time.Minute*2 + time.Second*30
|
22
|
|
- // QuitTimeout is how long without traffic before an idle client is disconnected
|
23
|
|
- QuitTimeout = time.Minute
|
|
18
|
+ // DefaultIdleTimeout is how long without traffic before we send the client a PING
|
|
19
|
+ DefaultIdleTimeout = time.Minute + 30*time.Second
|
|
20
|
+ // For Tor clients, we send a PING at least every 30 seconds, as a workaround for this bug
|
|
21
|
+ // (single-onion circuits will close unless the client sends data once every 60 seconds):
|
|
22
|
+ // https://bugs.torproject.org/29665
|
|
23
|
+ TorIdleTimeout = time.Second * 30
|
|
24
|
+ // This is how long a client gets without sending any message, including the PONG to our
|
|
25
|
+ // PING, before we disconnect them:
|
|
26
|
+ DefaultTotalTimeout = 2*time.Minute + 30*time.Second
|
|
27
|
+ // Resumeable clients (clients who have negotiated caps.Resume) get longer:
|
|
28
|
+ ResumeableTotalTimeout = 3*time.Minute + 30*time.Second
|
24
|
29
|
)
|
25
|
30
|
|
26
|
31
|
// client idleness state machine
|
|
@@ -39,11 +44,11 @@ type IdleTimer struct {
|
39
|
44
|
|
40
|
45
|
// immutable after construction
|
41
|
46
|
registerTimeout time.Duration
|
42
|
|
- quitTimeout time.Duration
|
43
|
47
|
client *Client
|
44
|
48
|
|
45
|
49
|
// mutable
|
46
|
50
|
idleTimeout time.Duration
|
|
51
|
+ quitTimeout time.Duration
|
47
|
52
|
state TimerState
|
48
|
53
|
timer *time.Timer
|
49
|
54
|
}
|
|
@@ -52,26 +57,28 @@ type IdleTimer struct {
|
52
|
57
|
func NewIdleTimer(client *Client) *IdleTimer {
|
53
|
58
|
it := IdleTimer{
|
54
|
59
|
registerTimeout: RegisterTimeout,
|
55
|
|
- idleTimeout: IdleTimeout,
|
56
|
|
- quitTimeout: QuitTimeout,
|
57
|
60
|
client: client,
|
58
|
61
|
}
|
|
62
|
+ it.idleTimeout, it.quitTimeout = it.recomputeDurations()
|
59
|
63
|
return &it
|
60
|
64
|
}
|
61
|
65
|
|
62
|
|
-// updateIdleDuration updates the idle duration, given the client's caps.
|
63
|
|
-func (it *IdleTimer) updateIdleDuration() {
|
64
|
|
- newIdleTime := IdleTimeout
|
65
|
|
-
|
|
66
|
+// recomputeDurations recomputes the idle and quit durations, given the client's caps.
|
|
67
|
+func (it *IdleTimer) recomputeDurations() (idleTimeout, quitTimeout time.Duration) {
|
|
68
|
+ totalTimeout := DefaultTotalTimeout
|
66
|
69
|
// if they have the resume cap, wait longer before pinging them out
|
67
|
70
|
// to give them a chance to resume their connection
|
68
|
71
|
if it.client.capabilities.Has(caps.Resume) {
|
69
|
|
- newIdleTime = IdleTimeoutWithResumeCap
|
|
72
|
+ totalTimeout = ResumeableTotalTimeout
|
70
|
73
|
}
|
71
|
74
|
|
72
|
|
- it.Lock()
|
73
|
|
- defer it.Unlock()
|
74
|
|
- it.idleTimeout = newIdleTime
|
|
75
|
+ idleTimeout = DefaultIdleTimeout
|
|
76
|
+ if it.client.isTor {
|
|
77
|
+ idleTimeout = TorIdleTimeout
|
|
78
|
+ }
|
|
79
|
+
|
|
80
|
+ quitTimeout = totalTimeout - idleTimeout
|
|
81
|
+ return
|
75
|
82
|
}
|
76
|
83
|
|
77
|
84
|
// Start starts counting idle time; if there is no activity from the client,
|
|
@@ -84,10 +91,11 @@ func (it *IdleTimer) Start() {
|
84
|
91
|
}
|
85
|
92
|
|
86
|
93
|
func (it *IdleTimer) Touch() {
|
87
|
|
- it.updateIdleDuration()
|
|
94
|
+ idleTimeout, quitTimeout := it.recomputeDurations()
|
88
|
95
|
|
89
|
96
|
it.Lock()
|
90
|
97
|
defer it.Unlock()
|
|
98
|
+ it.idleTimeout, it.quitTimeout = idleTimeout, quitTimeout
|
91
|
99
|
// a touch transitions TimerUnregistered or TimerIdle into TimerActive
|
92
|
100
|
if it.state != TimerDead {
|
93
|
101
|
it.state = TimerActive
|
|
@@ -96,12 +104,13 @@ func (it *IdleTimer) Touch() {
|
96
|
104
|
}
|
97
|
105
|
|
98
|
106
|
func (it *IdleTimer) processTimeout() {
|
99
|
|
- it.updateIdleDuration()
|
|
107
|
+ idleTimeout, quitTimeout := it.recomputeDurations()
|
100
|
108
|
|
101
|
109
|
var previousState TimerState
|
102
|
110
|
func() {
|
103
|
111
|
it.Lock()
|
104
|
112
|
defer it.Unlock()
|
|
113
|
+ it.idleTimeout, it.quitTimeout = idleTimeout, quitTimeout
|
105
|
114
|
previousState = it.state
|
106
|
115
|
// TimerActive transitions to TimerIdle, all others to TimerDead
|
107
|
116
|
if it.state == TimerActive {
|