Browse Source

Fix various locks around joining, kicking and quitting

tags/v0.6.0
Daniel Oaks 7 years ago
parent
commit
c39bebc696
2 changed files with 42 additions and 18 deletions
  1. 38
    15
      irc/channel.go
  2. 4
    3
      irc/server.go

+ 38
- 15
irc/channel.go View File

68
 func (channel *Channel) IsEmpty() bool {
68
 func (channel *Channel) IsEmpty() bool {
69
 	channel.membersMutex.RLock()
69
 	channel.membersMutex.RLock()
70
 	defer channel.membersMutex.RUnlock()
70
 	defer channel.membersMutex.RUnlock()
71
+
72
+	return channel.isEmptyNoMutex()
73
+}
74
+
75
+func (channel *Channel) isEmptyNoMutex() bool {
71
 	return len(channel.members) == 0
76
 	return len(channel.members) == 0
72
 }
77
 }
73
 
78
 
74
 func (channel *Channel) Names(client *Client) {
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
 	// assemble and send replies
88
 	// assemble and send replies
77
 	maxNamLen := 480 - len(client.server.name) - len(client.nick)
89
 	maxNamLen := 480 - len(client.server.name) - len(client.nick)
78
 	var buffer string
90
 	var buffer string
101
 	channel.membersMutex.RLock()
113
 	channel.membersMutex.RLock()
102
 	defer channel.membersMutex.RUnlock()
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
 	// get voice, since it's not a part of ChannelPrivModes
122
 	// get voice, since it's not a part of ChannelPrivModes
105
 	if channel.members.HasMode(client, permission) {
123
 	if channel.members.HasMode(client, permission) {
106
 		return true
124
 		return true
141
 	return prefixes
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
 	isMultiPrefix := (target != nil) && target.capabilities[MultiPrefix]
163
 	isMultiPrefix := (target != nil) && target.capabilities[MultiPrefix]
149
 	isUserhostInNames := (target != nil) && target.capabilities[UserhostInNames]
164
 	isUserhostInNames := (target != nil) && target.capabilities[UserhostInNames]
150
 	nicks := make([]string, len(channel.members))
165
 	nicks := make([]string, len(channel.members))
218
 
233
 
219
 func (channel *Channel) Join(client *Client, key string) {
234
 func (channel *Channel) Join(client *Client, key string) {
220
 	channel.membersMutex.Lock()
235
 	channel.membersMutex.Lock()
221
-	defer channel.membersMutex.Unlock()
222
-
223
 	if channel.members.Has(client) {
236
 	if channel.members.Has(client) {
224
 		// already joined, no message?
237
 		// already joined, no message?
225
 		return
238
 		return
226
 	}
239
 	}
240
+	channel.membersMutex.Unlock()
227
 
241
 
228
 	if channel.IsFull() {
242
 	if channel.IsFull() {
229
 		client.Send(nil, client.server.name, ERR_CHANNELISFULL, channel.name, "Cannot join channel (+l)")
243
 		client.Send(nil, client.server.name, ERR_CHANNELISFULL, channel.name, "Cannot join channel (+l)")
241
 		return
255
 		return
242
 	}
256
 	}
243
 
257
 
258
+	channel.membersMutex.Lock()
259
+	defer channel.membersMutex.Unlock()
244
 	if channel.lists[BanMask].Match(client.nickMaskCasefolded) &&
260
 	if channel.lists[BanMask].Match(client.nickMaskCasefolded) &&
245
 		!isInvited &&
261
 		!isInvited &&
246
 		!channel.lists[ExceptMask].Match(client.nickMaskCasefolded) {
262
 		!channel.lists[ExceptMask].Match(client.nickMaskCasefolded) {
270
 	} else {
286
 	} else {
271
 		client.Send(nil, client.nickMaskString, "JOIN", channel.name)
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
 func (channel *Channel) Part(client *Client, message string) {
293
 func (channel *Channel) Part(client *Client, message string) {
293
 	channel.membersMutex.RLock()
309
 	channel.membersMutex.RLock()
294
 	defer channel.membersMutex.RUnlock()
310
 	defer channel.membersMutex.RUnlock()
295
 
311
 
312
+	channel.getTopicNoMutex(client)
313
+}
314
+
315
+func (channel *Channel) getTopicNoMutex(client *Client) {
296
 	if !channel.members.Has(client) {
316
 	if !channel.members.Has(client) {
297
 		client.Send(nil, client.server.name, ERR_NOTONCHANNEL, client.nick, channel.name, "You're not on that channel")
317
 		client.Send(nil, client.server.name, ERR_NOTONCHANNEL, client.nick, channel.name, "You're not on that channel")
298
 		return
318
 		return
507
 	channel.membersMutex.Lock()
527
 	channel.membersMutex.Lock()
508
 	defer channel.membersMutex.Unlock()
528
 	defer channel.membersMutex.Unlock()
509
 
529
 
530
+	channel.quitNoMutex(client)
531
+}
532
+
533
+func (channel *Channel) quitNoMutex(client *Client) {
510
 	channel.members.Remove(client)
534
 	channel.members.Remove(client)
511
 	client.channels.Remove(channel)
535
 	client.channels.Remove(channel)
512
 
536
 
513
-	if channel.IsEmpty() {
537
+	if channel.isEmptyNoMutex() {
514
 		channel.server.channels.Remove(channel)
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
 	if !(client.flags[Operator] || channel.members.Has(client)) {
545
 	if !(client.flags[Operator] || channel.members.Has(client)) {
523
 		client.Send(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, "You're not on that channel")
546
 		client.Send(nil, client.server.name, ERR_NOTONCHANNEL, channel.name, "You're not on that channel")
524
 		return
547
 		return
525
 	}
548
 	}
526
-	if !channel.ClientIsAtLeast(client, ChannelOperator) {
549
+	if !channel.clientIsAtLeastNoMutex(client, ChannelOperator) {
527
 		client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, "Cannot send to channel")
550
 		client.Send(nil, client.server.name, ERR_CANNOTSENDTOCHAN, channel.name, "Cannot send to channel")
528
 		return
551
 		return
529
 	}
552
 	}
539
 	for member := range channel.members {
562
 	for member := range channel.members {
540
 		member.Send(nil, client.nickMaskString, "KICK", channel.name, target.nick, comment)
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
 func (channel *Channel) Invite(invitee *Client, inviter *Client) {
568
 func (channel *Channel) Invite(invitee *Client, inviter *Client) {

+ 4
- 3
irc/server.go View File

1381
 		// make sure client has privs to kick the given user
1381
 		// make sure client has privs to kick the given user
1382
 		//TODO(dan): split this into a separate function that checks if users have privs
1382
 		//TODO(dan): split this into a separate function that checks if users have privs
1383
 		// over other users, useful for things like -aoh as well
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
 		var hasPrivs bool
1386
 		var hasPrivs bool
1388
 		for _, mode := range ChannelPrivModes {
1387
 		for _, mode := range ChannelPrivModes {
1404
 			if comment == "" {
1403
 			if comment == "" {
1405
 				comment = nickname
1404
 				comment = nickname
1406
 			}
1405
 			}
1407
-			channel.Kick(client, target, comment)
1406
+			channel.kickNoMutex(client, target, comment)
1408
 		} else {
1407
 		} else {
1409
 			client.Send(nil, client.server.name, ERR_CHANOPRIVSNEEDED, chname, "You're not a channel operator")
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
 	return false
1413
 	return false
1413
 }
1414
 }

Loading…
Cancel
Save