Procházet zdrojové kódy

Fix various locks around joining, kicking and quitting

tags/v0.6.0
Daniel Oaks před 7 roky
rodič
revize
c39bebc696
2 změnil soubory, kde provedl 42 přidání a 18 odebrání
  1. 38
    15
      irc/channel.go
  2. 4
    3
      irc/server.go

+ 38
- 15
irc/channel.go Zobrazit soubor

@@ -68,11 +68,23 @@ func NewChannel(s *Server, name string, addDefaultModes bool) *Channel {
68 68
 func (channel *Channel) IsEmpty() bool {
69 69
 	channel.membersMutex.RLock()
70 70
 	defer channel.membersMutex.RUnlock()
71
+
72
+	return channel.isEmptyNoMutex()
73
+}
74
+
75
+func (channel *Channel) isEmptyNoMutex() bool {
71 76
 	return len(channel.members) == 0
72 77
 }
73 78
 
74 79
 func (channel *Channel) Names(client *Client) {
75
-	currentNicks := channel.Nicks(client)
80
+	channel.membersMutex.RLock()
81
+	defer channel.membersMutex.RUnlock()
82
+
83
+	channel.namesNoMutex(client)
84
+}
85
+
86
+func (channel *Channel) namesNoMutex(client *Client) {
87
+	currentNicks := channel.nicksNoMutex(client)
76 88
 	// assemble and send replies
77 89
 	maxNamLen := 480 - len(client.server.name) - len(client.nick)
78 90
 	var buffer string
@@ -101,6 +113,12 @@ func (channel *Channel) ClientIsAtLeast(client *Client, permission ChannelMode)
101 113
 	channel.membersMutex.RLock()
102 114
 	defer channel.membersMutex.RUnlock()
103 115
 
116
+	return channel.clientIsAtLeastNoMutex(client, permission)
117
+}
118
+
119
+func (channel *Channel) clientIsAtLeastNoMutex(client *Client, permission ChannelMode) bool {
120
+	// requires RLock()
121
+
104 122
 	// get voice, since it's not a part of ChannelPrivModes
105 123
 	if channel.members.HasMode(client, permission) {
106 124
 		return true
@@ -141,10 +159,7 @@ func (modes ChannelModeSet) Prefixes(isMultiPrefix bool) string {
141 159
 	return prefixes
142 160
 }
143 161
 
144
-func (channel *Channel) Nicks(target *Client) []string {
145
-	channel.membersMutex.RLock()
146
-	defer channel.membersMutex.RUnlock()
147
-
162
+func (channel *Channel) nicksNoMutex(target *Client) []string {
148 163
 	isMultiPrefix := (target != nil) && target.capabilities[MultiPrefix]
149 164
 	isUserhostInNames := (target != nil) && target.capabilities[UserhostInNames]
150 165
 	nicks := make([]string, len(channel.members))
@@ -218,12 +233,11 @@ func (channel *Channel) CheckKey(key string) bool {
218 233
 
219 234
 func (channel *Channel) Join(client *Client, key string) {
220 235
 	channel.membersMutex.Lock()
221
-	defer channel.membersMutex.Unlock()
222
-
223 236
 	if channel.members.Has(client) {
224 237
 		// already joined, no message?
225 238
 		return
226 239
 	}
240
+	channel.membersMutex.Unlock()
227 241
 
228 242
 	if channel.IsFull() {
229 243
 		client.Send(nil, client.server.name, ERR_CHANNELISFULL, channel.name, "Cannot join channel (+l)")
@@ -241,6 +255,8 @@ func (channel *Channel) Join(client *Client, key string) {
241 255
 		return
242 256
 	}
243 257
 
258
+	channel.membersMutex.Lock()
259
+	defer channel.membersMutex.Unlock()
244 260
 	if channel.lists[BanMask].Match(client.nickMaskCasefolded) &&
245 261
 		!isInvited &&
246 262
 		!channel.lists[ExceptMask].Match(client.nickMaskCasefolded) {
@@ -270,8 +286,8 @@ func (channel *Channel) Join(client *Client, key string) {
270 286
 	} else {
271 287
 		client.Send(nil, client.nickMaskString, "JOIN", channel.name)
272 288
 	}
273
-	channel.GetTopic(client)
274
-	channel.Names(client)
289
+	channel.getTopicNoMutex(client) // we already have Lock
290
+	channel.namesNoMutex(client)
275 291
 }
276 292
 
277 293
 func (channel *Channel) Part(client *Client, message string) {
@@ -293,6 +309,10 @@ func (channel *Channel) GetTopic(client *Client) {
293 309
 	channel.membersMutex.RLock()
294 310
 	defer channel.membersMutex.RUnlock()
295 311
 
312
+	channel.getTopicNoMutex(client)
313
+}
314
+
315
+func (channel *Channel) getTopicNoMutex(client *Client) {
296 316
 	if !channel.members.Has(client) {
297 317
 		client.Send(nil, client.server.name, ERR_NOTONCHANNEL, client.nick, channel.name, "You're not on that channel")
298 318
 		return
@@ -507,23 +527,26 @@ func (channel *Channel) Quit(client *Client) {
507 527
 	channel.membersMutex.Lock()
508 528
 	defer channel.membersMutex.Unlock()
509 529
 
530
+	channel.quitNoMutex(client)
531
+}
532
+
533
+func (channel *Channel) quitNoMutex(client *Client) {
510 534
 	channel.members.Remove(client)
511 535
 	client.channels.Remove(channel)
512 536
 
513
-	if channel.IsEmpty() {
537
+	if channel.isEmptyNoMutex() {
514 538
 		channel.server.channels.Remove(channel)
515 539
 	}
516 540
 }
517 541
 
518
-func (channel *Channel) Kick(client *Client, target *Client, comment string) {
519
-	channel.membersMutex.Lock()
520
-	defer channel.membersMutex.Unlock()
542
+func (channel *Channel) kickNoMutex(client *Client, target *Client, comment string) {
543
+	// needs a Lock()
521 544
 
522 545
 	if !(client.flags[Operator] || channel.members.Has(client)) {
523 546
 		client.Send(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, "You're not on that channel")
524 547
 		return
525 548
 	}
526
-	if !channel.ClientIsAtLeast(client, ChannelOperator) {
549
+	if !channel.clientIsAtLeastNoMutex(client, ChannelOperator) {
527 550
 		client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, "Cannot send to channel")
528 551
 		return
529 552
 	}
@@ -539,7 +562,7 @@ func (channel *Channel) Kick(client *Client, target *Client, comment string) {
539 562
 	for member := range channel.members {
540 563
 		member.Send(nil, client.nickMaskString, "KICK", channel.name, target.nick, comment)
541 564
 	}
542
-	channel.Quit(target)
565
+	channel.quitNoMutex(target)
543 566
 }
544 567
 
545 568
 func (channel *Channel) Invite(invitee *Client, inviter *Client) {

+ 4
- 3
irc/server.go Zobrazit soubor

@@ -1381,8 +1381,7 @@ func kickHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
1381 1381
 		// make sure client has privs to kick the given user
1382 1382
 		//TODO(dan): split this into a separate function that checks if users have privs
1383 1383
 		// over other users, useful for things like -aoh as well
1384
-		channel.membersMutex.RLock()
1385
-		defer channel.membersMutex.RUnlock()
1384
+		channel.membersMutex.Lock()
1386 1385
 
1387 1386
 		var hasPrivs bool
1388 1387
 		for _, mode := range ChannelPrivModes {
@@ -1404,10 +1403,12 @@ func kickHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
1404 1403
 			if comment == "" {
1405 1404
 				comment = nickname
1406 1405
 			}
1407
-			channel.Kick(client, target, comment)
1406
+			channel.kickNoMutex(client, target, comment)
1408 1407
 		} else {
1409 1408
 			client.Send(nil, client.server.name, ERR_CHANOPRIVSNEEDED, chname, "You're not a channel operator")
1410 1409
 		}
1410
+
1411
+		channel.membersMutex.Unlock()
1411 1412
 	}
1412 1413
 	return false
1413 1414
 }

Načítá se…
Zrušit
Uložit