Explorar el Código

remove indirections in Fakelag and NickTimer

tags/v1.1.0-rc1
Shivaram Lingamneni hace 5 años
padre
commit
2e88f82e41
Se han modificado 6 ficheros con 79 adiciones y 76 borrados
  1. 6
    20
      irc/client.go
  2. 13
    21
      irc/fakelag.go
  3. 9
    2
      irc/fakelag_test.go
  4. 0
    4
      irc/getters.go
  5. 44
    29
      irc/idletimer.go
  6. 7
    0
      irc/server.go

+ 6
- 20
irc/client.go Ver fichero

@@ -57,7 +57,7 @@ type Client struct {
57 57
 	channels           ChannelSet
58 58
 	ctime              time.Time
59 59
 	exitedSnomaskSent  bool
60
-	fakelag            *Fakelag
60
+	fakelag            Fakelag
61 61
 	flags              *modes.ModeSet
62 62
 	hasQuit            bool
63 63
 	hops               int
@@ -75,7 +75,7 @@ type Client struct {
75 75
 	nickCasefolded     string
76 76
 	nickMaskCasefolded string
77 77
 	nickMaskString     string // cache for nickmask string since it's used with lots of replies
78
-	nickTimer          *NickTimer
78
+	nickTimer          NickTimer
79 79
 	oper               *Oper
80 80
 	preregNick         string
81 81
 	proxiedIP          net.IP // actual remote IP if using the PROXY protocol
@@ -217,23 +217,9 @@ func (client *Client) isAuthorized(config *Config) bool {
217 217
 }
218 218
 
219 219
 func (client *Client) resetFakelag() {
220
-	fakelag := func() *Fakelag {
221
-		if client.HasRoleCapabs("nofakelag") {
222
-			return nil
223
-		}
224
-
225
-		flc := client.server.FakelagConfig()
226
-
227
-		if !flc.Enabled {
228
-			return nil
229
-		}
230
-
231
-		return NewFakelag(flc.Window, flc.BurstLimit, flc.MessagesPerWindow, flc.Cooldown)
232
-	}()
233
-
234
-	client.stateMutex.Lock()
235
-	defer client.stateMutex.Unlock()
236
-	client.fakelag = fakelag
220
+	var flc FakelagConfig = client.server.Config().Fakelag
221
+	flc.Enabled = flc.Enabled && !client.HasRoleCapabs("nofakelag")
222
+	client.fakelag.Initialize(flc)
237 223
 }
238 224
 
239 225
 // IP returns the IP address of this client.
@@ -309,7 +295,7 @@ func (client *Client) run() {
309 295
 	client.idletimer = NewIdleTimer(client)
310 296
 	client.idletimer.Start()
311 297
 
312
-	client.nickTimer = NewNickTimer(client)
298
+	client.nickTimer.Initialize(client)
313 299
 
314 300
 	client.resetFakelag()
315 301
 

+ 13
- 21
irc/fakelag.go Ver fichero

@@ -24,33 +24,25 @@ const (
24 24
 // this is intentionally not threadsafe, because it should only be touched
25 25
 // from the loop that accepts the client's input and runs commands
26 26
 type Fakelag struct {
27
-	window                    time.Duration
28
-	burstLimit                uint
29
-	throttleMessagesPerWindow uint
30
-	cooldown                  time.Duration
31
-	nowFunc                   func() time.Time
32
-	sleepFunc                 func(time.Duration)
27
+	config    FakelagConfig
28
+	nowFunc   func() time.Time
29
+	sleepFunc func(time.Duration)
33 30
 
34 31
 	state      FakelagState
35 32
 	burstCount uint // number of messages sent in the current burst
36 33
 	lastTouch  time.Time
37 34
 }
38 35
 
39
-func NewFakelag(window time.Duration, burstLimit uint, throttleMessagesPerWindow uint, cooldown time.Duration) *Fakelag {
40
-	return &Fakelag{
41
-		window:                    window,
42
-		burstLimit:                burstLimit,
43
-		throttleMessagesPerWindow: throttleMessagesPerWindow,
44
-		cooldown:                  cooldown,
45
-		nowFunc:                   time.Now,
46
-		sleepFunc:                 time.Sleep,
47
-		state:                     FakelagBursting,
48
-	}
36
+func (fl *Fakelag) Initialize(config FakelagConfig) {
37
+	fl.config = config
38
+	fl.nowFunc = time.Now
39
+	fl.sleepFunc = time.Sleep
40
+	fl.state = FakelagBursting
49 41
 }
50 42
 
51 43
 // register a new command, sleep if necessary to delay it
52 44
 func (fl *Fakelag) Touch() {
53
-	if fl == nil {
45
+	if !fl.config.Enabled {
54 46
 		return
55 47
 	}
56 48
 
@@ -61,12 +53,12 @@ func (fl *Fakelag) Touch() {
61 53
 
62 54
 	if fl.state == FakelagBursting {
63 55
 		// determine if the previous burst is over
64
-		if elapsed > fl.cooldown {
56
+		if elapsed > fl.config.Cooldown {
65 57
 			fl.burstCount = 0
66 58
 		}
67 59
 
68 60
 		fl.burstCount++
69
-		if fl.burstCount > fl.burstLimit {
61
+		if fl.burstCount > fl.config.BurstLimit {
70 62
 			// reset burst window for next time
71 63
 			fl.burstCount = 0
72 64
 			// transition to throttling
@@ -78,13 +70,13 @@ func (fl *Fakelag) Touch() {
78 70
 	}
79 71
 
80 72
 	if fl.state == FakelagThrottled {
81
-		if elapsed > fl.cooldown {
73
+		if elapsed > fl.config.Cooldown {
82 74
 			// let them burst again
83 75
 			fl.state = FakelagBursting
84 76
 			return
85 77
 		}
86 78
 		// space them out by at least window/messagesperwindow
87
-		sleepDuration := time.Duration((int64(fl.window) / int64(fl.throttleMessagesPerWindow)) - int64(elapsed))
79
+		sleepDuration := time.Duration((int64(fl.config.Window) / int64(fl.config.MessagesPerWindow)) - int64(elapsed))
88 80
 		if sleepDuration > 0 {
89 81
 			fl.sleepFunc(sleepDuration)
90 82
 			// the touch time should take into account the time we slept

+ 9
- 2
irc/fakelag_test.go Ver fichero

@@ -40,13 +40,20 @@ func (mt *mockTime) lastSleep() (slept bool, duration time.Duration) {
40 40
 }
41 41
 
42 42
 func newFakelagForTesting(window time.Duration, burstLimit uint, throttleMessagesPerWindow uint, cooldown time.Duration) (*Fakelag, *mockTime) {
43
-	fl := NewFakelag(window, burstLimit, throttleMessagesPerWindow, cooldown)
43
+	fl := Fakelag{}
44
+	fl.config = FakelagConfig{
45
+		Enabled:           true,
46
+		Window:            window,
47
+		BurstLimit:        burstLimit,
48
+		MessagesPerWindow: throttleMessagesPerWindow,
49
+		Cooldown:          cooldown,
50
+	}
44 51
 	mt := new(mockTime)
45 52
 	mt.now, _ = time.Parse("Mon Jan 2 15:04:05 -0700 MST 2006", "Mon Jan 2 15:04:05 -0700 MST 2006")
46 53
 	mt.lastCheckedSleep = -1
47 54
 	fl.nowFunc = mt.Now
48 55
 	fl.sleepFunc = mt.Sleep
49
-	return fl, mt
56
+	return &fl, mt
50 57
 }
51 58
 
52 59
 func TestFakelag(t *testing.T) {

+ 0
- 4
irc/getters.go Ver fichero

@@ -46,10 +46,6 @@ func (server *Server) AccountConfig() *AccountConfig {
46 46
 	return &server.Config().Accounts
47 47
 }
48 48
 
49
-func (server *Server) FakelagConfig() *FakelagConfig {
50
-	return &server.Config().Fakelag
51
-}
52
-
53 49
 func (server *Server) GetOperator(name string) (oper *Oper) {
54 50
 	name, err := CasefoldName(name)
55 51
 	if err != nil {

+ 44
- 29
irc/idletimer.go Ver fichero

@@ -6,6 +6,7 @@ package irc
6 6
 import (
7 7
 	"fmt"
8 8
 	"sync"
9
+	"sync/atomic"
9 10
 	"time"
10 11
 
11 12
 	"github.com/goshuirc/irc-go/ircfmt"
@@ -180,33 +181,50 @@ type NickTimer struct {
180 181
 	sync.Mutex // tier 1
181 182
 
182 183
 	// immutable after construction
183
-	timeout time.Duration
184
-	client  *Client
184
+	client *Client
185 185
 
186 186
 	// mutable
187
-	stopped        bool
188 187
 	nick           string
189 188
 	accountForNick string
190 189
 	account        string
190
+	timeout        time.Duration
191 191
 	timer          *time.Timer
192
+	enabled        uint32
192 193
 }
193 194
 
194
-// NewNickTimer sets up a new nick timer (returning nil if timeout enforcement is not enabled)
195
-func NewNickTimer(client *Client) *NickTimer {
196
-	config := client.server.AccountConfig().NickReservation
197
-	if !(config.Enabled && (config.Method == NickReservationWithTimeout || config.AllowCustomEnforcement)) {
198
-		return nil
195
+// Initialize sets up a NickTimer, based on server config settings.
196
+func (nt *NickTimer) Initialize(client *Client) {
197
+	if nt.client == nil {
198
+		nt.client = client // placate the race detector
199 199
 	}
200 200
 
201
-	return &NickTimer{
202
-		client:  client,
203
-		timeout: config.RenameTimeout,
201
+	config := &client.server.Config().Accounts.NickReservation
202
+	enabled := config.Enabled && (config.Method == NickReservationWithTimeout || config.AllowCustomEnforcement)
203
+
204
+	nt.Lock()
205
+	defer nt.Unlock()
206
+	nt.timeout = config.RenameTimeout
207
+	if enabled {
208
+		atomic.StoreUint32(&nt.enabled, 1)
209
+	} else {
210
+		nt.stopInternal()
204 211
 	}
205 212
 }
206 213
 
214
+func (nt *NickTimer) Enabled() bool {
215
+	return atomic.LoadUint32(&nt.enabled) == 1
216
+}
217
+
218
+func (nt *NickTimer) Timeout() (timeout time.Duration) {
219
+	nt.Lock()
220
+	timeout = nt.timeout
221
+	nt.Unlock()
222
+	return
223
+}
224
+
207 225
 // Touch records a nick change and updates the timer as necessary
208 226
 func (nt *NickTimer) Touch() {
209
-	if nt == nil {
227
+	if !nt.Enabled() {
210 228
 		return
211 229
 	}
212 230
 
@@ -215,16 +233,12 @@ func (nt *NickTimer) Touch() {
215 233
 	accountForNick, method := nt.client.server.accounts.EnforcementStatus(cfnick, skeleton)
216 234
 	enforceTimeout := method == NickReservationWithTimeout
217 235
 
218
-	var shouldWarn bool
236
+	var shouldWarn, shouldRename bool
219 237
 
220 238
 	func() {
221 239
 		nt.Lock()
222 240
 		defer nt.Unlock()
223 241
 
224
-		if nt.stopped {
225
-			return
226
-		}
227
-
228 242
 		// the timer will not reset as long as the squatter is targeting the same account
229 243
 		accountChanged := accountForNick != nt.accountForNick
230 244
 		// change state
@@ -237,38 +251,39 @@ func (nt *NickTimer) Touch() {
237 251
 			nt.timer.Stop()
238 252
 			nt.timer = nil
239 253
 		}
240
-		if enforceTimeout && delinquent && accountChanged {
254
+		if enforceTimeout && delinquent && (accountChanged || nt.timer == nil) {
241 255
 			nt.timer = time.AfterFunc(nt.timeout, nt.processTimeout)
242 256
 			shouldWarn = true
257
+		} else if method == NickReservationStrict && delinquent {
258
+			shouldRename = true // this can happen if reservation was enabled by rehash
243 259
 		}
244 260
 	}()
245 261
 
246 262
 	if shouldWarn {
247
-		nt.sendWarning()
263
+		nt.client.Send(nil, "NickServ", "NOTICE", nt.client.Nick(), fmt.Sprintf(ircfmt.Unescape(nt.client.t(nsTimeoutNotice)), nt.Timeout()))
264
+	} else if shouldRename {
265
+		nt.client.Notice(nt.client.t("Nickname is reserved by a different account"))
266
+		nt.client.server.RandomlyRename(nt.client)
248 267
 	}
249 268
 }
250 269
 
251 270
 // Stop stops counting time and cleans up the timer
252 271
 func (nt *NickTimer) Stop() {
253
-	if nt == nil {
254
-		return
255
-	}
256
-
257 272
 	nt.Lock()
258 273
 	defer nt.Unlock()
274
+	nt.stopInternal()
275
+}
276
+
277
+func (nt *NickTimer) stopInternal() {
259 278
 	if nt.timer != nil {
260 279
 		nt.timer.Stop()
261 280
 		nt.timer = nil
262 281
 	}
263
-	nt.stopped = true
264
-}
265
-
266
-func (nt *NickTimer) sendWarning() {
267
-	nt.client.Send(nil, "NickServ", "NOTICE", nt.client.Nick(), fmt.Sprintf(ircfmt.Unescape(nt.client.t(nsTimeoutNotice)), nt.timeout))
282
+	atomic.StoreUint32(&nt.enabled, 0)
268 283
 }
269 284
 
270 285
 func (nt *NickTimer) processTimeout() {
271 286
 	baseMsg := "Nick is reserved and authentication timeout expired: %v"
272
-	nt.client.Notice(fmt.Sprintf(nt.client.t(baseMsg), nt.timeout))
287
+	nt.client.Notice(fmt.Sprintf(nt.client.t(baseMsg), nt.Timeout()))
273 288
 	nt.client.server.RandomlyRename(nt.client)
274 289
 }

+ 7
- 0
irc/server.go Ver fichero

@@ -826,6 +826,13 @@ func (server *Server) applyConfig(config *Config, initial bool) (err error) {
826 826
 			if sendRawOutputNotice {
827 827
 				sClient.Notice(sClient.t("This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect."))
828 828
 			}
829
+
830
+			if !oldConfig.Accounts.NickReservation.Enabled && config.Accounts.NickReservation.Enabled {
831
+				sClient.nickTimer.Initialize(sClient)
832
+				sClient.nickTimer.Touch()
833
+			} else if oldConfig.Accounts.NickReservation.Enabled && !config.Accounts.NickReservation.Enabled {
834
+				sClient.nickTimer.Stop()
835
+			}
829 836
 		}
830 837
 	}
831 838
 

Loading…
Cancelar
Guardar