瀏覽代碼

Merge pull request #441 from slingamn/tor_timeout

work around a Tor bug
tags/v1.1.0-rc1
Daniel Oaks 5 年之前
父節點
當前提交
acd9eeeb15
No account linked to committer's email address
共有 1 個文件被更改,包括 28 次插入19 次删除
  1. 28
    19
      irc/idletimer.go

+ 28
- 19
irc/idletimer.go 查看文件

15
 const (
15
 const (
16
 	// RegisterTimeout is how long clients have to register before we disconnect them
16
 	// RegisterTimeout is how long clients have to register before we disconnect them
17
 	RegisterTimeout = time.Minute
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
 // client idleness state machine
31
 // client idleness state machine
39
 
44
 
40
 	// immutable after construction
45
 	// immutable after construction
41
 	registerTimeout time.Duration
46
 	registerTimeout time.Duration
42
-	quitTimeout     time.Duration
43
 	client          *Client
47
 	client          *Client
44
 
48
 
45
 	// mutable
49
 	// mutable
46
 	idleTimeout time.Duration
50
 	idleTimeout time.Duration
51
+	quitTimeout time.Duration
47
 	state       TimerState
52
 	state       TimerState
48
 	timer       *time.Timer
53
 	timer       *time.Timer
49
 }
54
 }
52
 func NewIdleTimer(client *Client) *IdleTimer {
57
 func NewIdleTimer(client *Client) *IdleTimer {
53
 	it := IdleTimer{
58
 	it := IdleTimer{
54
 		registerTimeout: RegisterTimeout,
59
 		registerTimeout: RegisterTimeout,
55
-		idleTimeout:     IdleTimeout,
56
-		quitTimeout:     QuitTimeout,
57
 		client:          client,
60
 		client:          client,
58
 	}
61
 	}
62
+	it.idleTimeout, it.quitTimeout = it.recomputeDurations()
59
 	return &it
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
 	// if they have the resume cap, wait longer before pinging them out
69
 	// if they have the resume cap, wait longer before pinging them out
67
 	// to give them a chance to resume their connection
70
 	// to give them a chance to resume their connection
68
 	if it.client.capabilities.Has(caps.Resume) {
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
 // Start starts counting idle time; if there is no activity from the client,
84
 // Start starts counting idle time; if there is no activity from the client,
84
 }
91
 }
85
 
92
 
86
 func (it *IdleTimer) Touch() {
93
 func (it *IdleTimer) Touch() {
87
-	it.updateIdleDuration()
94
+	idleTimeout, quitTimeout := it.recomputeDurations()
88
 
95
 
89
 	it.Lock()
96
 	it.Lock()
90
 	defer it.Unlock()
97
 	defer it.Unlock()
98
+	it.idleTimeout, it.quitTimeout = idleTimeout, quitTimeout
91
 	// a touch transitions TimerUnregistered or TimerIdle into TimerActive
99
 	// a touch transitions TimerUnregistered or TimerIdle into TimerActive
92
 	if it.state != TimerDead {
100
 	if it.state != TimerDead {
93
 		it.state = TimerActive
101
 		it.state = TimerActive
96
 }
104
 }
97
 
105
 
98
 func (it *IdleTimer) processTimeout() {
106
 func (it *IdleTimer) processTimeout() {
99
-	it.updateIdleDuration()
107
+	idleTimeout, quitTimeout := it.recomputeDurations()
100
 
108
 
101
 	var previousState TimerState
109
 	var previousState TimerState
102
 	func() {
110
 	func() {
103
 		it.Lock()
111
 		it.Lock()
104
 		defer it.Unlock()
112
 		defer it.Unlock()
113
+		it.idleTimeout, it.quitTimeout = idleTimeout, quitTimeout
105
 		previousState = it.state
114
 		previousState = it.state
106
 		// TimerActive transitions to TimerIdle, all others to TimerDead
115
 		// TimerActive transitions to TimerIdle, all others to TimerDead
107
 		if it.state == TimerActive {
116
 		if it.state == TimerActive {

Loading…
取消
儲存