Explorar el Código

Squash a bunch of possible races

tags/v0.8.0
Daniel Oaks hace 7 años
padre
commit
c911ff2bcd
Se han modificado 3 ficheros con 78 adiciones y 27 borrados
  1. 21
    7
      irc/client.go
  2. 42
    20
      irc/socket.go
  3. 15
    0
      irc/whowas.go

+ 21
- 7
irc/client.go Ver fichero

@@ -13,6 +13,7 @@ import (
13 13
 	"runtime/debug"
14 14
 	"strconv"
15 15
 	"strings"
16
+	"sync"
16 17
 	"time"
17 18
 
18 19
 	"github.com/DanielOaks/girc-go/ircmsg"
@@ -43,23 +44,24 @@ type Client struct {
43 44
 	channels           ChannelSet
44 45
 	class              *OperClass
45 46
 	ctime              time.Time
47
+	destroyMutex       sync.Mutex
46 48
 	flags              map[Mode]bool
47
-	isDestroyed        bool
48
-	isQuitting         bool
49 49
 	hasQuit            bool
50 50
 	hops               int
51 51
 	hostname           string
52
-	rawHostname        string
53
-	vhost              string
54 52
 	idleTimer          *time.Timer
53
+	isDestroyed        bool
54
+	isQuitting         bool
55 55
 	monitoring         map[string]bool
56 56
 	nick               string
57 57
 	nickCasefolded     string
58
-	nickMaskString     string // cache for nickmask string since it's used with lots of replies
59 58
 	nickMaskCasefolded string
59
+	nickMaskString     string // cache for nickmask string since it's used with lots of replies
60 60
 	operName           string
61
-	quitTimer          *time.Timer
62 61
 	quitMessageSent    bool
62
+	quitMutex          sync.Mutex
63
+	quitTimer          *time.Timer
64
+	rawHostname        string
63 65
 	realname           string
64 66
 	registered         bool
65 67
 	saslInProgress     bool
@@ -67,7 +69,9 @@ type Client struct {
67 69
 	saslValue          string
68 70
 	server             *Server
69 71
 	socket             *Socket
72
+	timerMutex         sync.Mutex
70 73
 	username           string
74
+	vhost              string
71 75
 	whoisLine          string
72 76
 }
73 77
 
@@ -229,6 +233,9 @@ func (client *Client) Active() {
229 233
 
230 234
 // Touch marks the client as alive.
231 235
 func (client *Client) Touch() {
236
+	client.timerMutex.Lock()
237
+	defer client.timerMutex.Unlock()
238
+
232 239
 	if client.quitTimer != nil {
233 240
 		client.quitTimer.Stop()
234 241
 	}
@@ -242,6 +249,9 @@ func (client *Client) Touch() {
242 249
 
243 250
 // Idle resets the timeout handlers and sends the client a PING.
244 251
 func (client *Client) Idle() {
252
+	client.timerMutex.Lock()
253
+	defer client.timerMutex.Unlock()
254
+
245 255
 	client.Send(nil, "", "PING", client.nick)
246 256
 
247 257
 	if client.quitTimer == nil {
@@ -435,6 +445,8 @@ func (client *Client) ChangeNickname(nickname string) error {
435 445
 
436 446
 // Quit sends the given quit message to the client (but does not destroy them).
437 447
 func (client *Client) Quit(message string) {
448
+	client.quitMutex.Lock()
449
+	defer client.quitMutex.Unlock()
438 450
 	if !client.quitMessageSent {
439 451
 		quitMsg := ircmsg.MakeMessage(nil, client.nickMaskString, "QUIT", message)
440 452
 		quitLine, _ := quitMsg.Line()
@@ -442,13 +454,15 @@ func (client *Client) Quit(message string) {
442 454
 		errorMsg := ircmsg.MakeMessage(nil, "", "ERROR", message)
443 455
 		errorLine, _ := errorMsg.Line()
444 456
 
445
-		client.socket.FinalData = quitLine + errorLine
457
+		client.socket.SetFinalData(quitLine + errorLine)
446 458
 		client.quitMessageSent = true
447 459
 	}
448 460
 }
449 461
 
450 462
 // destroy gets rid of a client, removes them from server lists etc.
451 463
 func (client *Client) destroy() {
464
+	client.destroyMutex.Lock()
465
+	defer client.destroyMutex.Unlock()
452 466
 	if client.isDestroyed {
453 467
 		return
454 468
 	}

+ 42
- 20
irc/socket.go Ver fichero

@@ -10,7 +10,6 @@ import (
10 10
 	"crypto/tls"
11 11
 	"encoding/hex"
12 12
 	"errors"
13
-	"fmt"
14 13
 	"io"
15 14
 	"net"
16 15
 	"strings"
@@ -26,12 +25,16 @@ var (
26 25
 
27 26
 // Socket represents an IRC socket.
28 27
 type Socket struct {
29
-	Closed bool
30 28
 	conn   net.Conn
31 29
 	reader *bufio.Reader
32 30
 
33 31
 	MaxSendQBytes uint64
34
-	FinalData     string // what to send when we die
32
+
33
+	closed      bool
34
+	closedMutex sync.Mutex
35
+
36
+	finalData      string // what to send when we die
37
+	finalDataMutex sync.Mutex
35 38
 
36 39
 	lineToSendExists chan bool
37 40
 	linesToSend      []string
@@ -50,10 +53,12 @@ func NewSocket(conn net.Conn, maxSendQBytes uint64) Socket {
50 53
 
51 54
 // Close stops a Socket from being able to send/receive any more data.
52 55
 func (socket *Socket) Close() {
53
-	if socket.Closed {
56
+	socket.closedMutex.Lock()
57
+	defer socket.closedMutex.Unlock()
58
+	if socket.closed {
54 59
 		return
55 60
 	}
56
-	socket.Closed = true
61
+	socket.closed = true
57 62
 
58 63
 	// force close loop to happen if it hasn't already
59 64
 	go socket.timedFillLineToSendExists(200 * time.Millisecond)
@@ -88,7 +93,7 @@ func (socket *Socket) CertFP() (string, error) {
88 93
 
89 94
 // Read returns a single IRC line from a Socket.
90 95
 func (socket *Socket) Read() (string, error) {
91
-	if socket.Closed {
96
+	if socket.IsClosed() {
92 97
 		return "", io.EOF
93 98
 	}
94 99
 
@@ -113,7 +118,7 @@ func (socket *Socket) Read() (string, error) {
113 118
 
114 119
 // Write sends the given string out of Socket.
115 120
 func (socket *Socket) Write(data string) error {
116
-	if socket.Closed {
121
+	if socket.IsClosed() {
117 122
 		return io.EOF
118 123
 	}
119 124
 
@@ -121,9 +126,7 @@ func (socket *Socket) Write(data string) error {
121 126
 	socket.linesToSend = append(socket.linesToSend, data)
122 127
 	socket.linesToSendMutex.Unlock()
123 128
 
124
-	if !socket.Closed {
125
-		go socket.timedFillLineToSendExists(15 * time.Second)
126
-	}
129
+	go socket.timedFillLineToSendExists(15 * time.Second)
127 130
 
128 131
 	return nil
129 132
 }
@@ -138,9 +141,22 @@ func (socket *Socket) timedFillLineToSendExists(duration time.Duration) {
138 141
 	}
139 142
 }
140 143
 
144
+// SetFinalData sets the final data to send when the SocketWriter closes.
145
+func (socket *Socket) SetFinalData(data string) {
146
+	socket.finalDataMutex.Lock()
147
+	socket.finalData = data
148
+	socket.finalDataMutex.Unlock()
149
+}
150
+
151
+// IsClosed returns whether the socket is closed.
152
+func (socket *Socket) IsClosed() bool {
153
+	socket.closedMutex.Lock()
154
+	defer socket.closedMutex.Unlock()
155
+	return socket.closed
156
+}
157
+
141 158
 // RunSocketWriter starts writing messages to the outgoing socket.
142 159
 func (socket *Socket) RunSocketWriter() {
143
-	var errOut bool
144 160
 	for {
145 161
 		// wait for new lines
146 162
 		select {
@@ -148,7 +164,7 @@ func (socket *Socket) RunSocketWriter() {
148 164
 			socket.linesToSendMutex.Lock()
149 165
 
150 166
 			// check if we're closed
151
-			if socket.Closed {
167
+			if socket.IsClosed() {
152 168
 				socket.linesToSendMutex.Unlock()
153 169
 				break
154 170
 			}
@@ -169,7 +185,7 @@ func (socket *Socket) RunSocketWriter() {
169 185
 				}
170 186
 			}
171 187
 			if socket.MaxSendQBytes < sendQBytes {
172
-				socket.FinalData = "\r\nERROR :SendQ Exceeded\r\n"
188
+				socket.SetFinalData("\r\nERROR :SendQ Exceeded\r\n")
173 189
 				socket.linesToSendMutex.Unlock()
174 190
 				break
175 191
 			}
@@ -184,24 +200,30 @@ func (socket *Socket) RunSocketWriter() {
184 200
 			if 0 < len(data) {
185 201
 				_, err := socket.conn.Write([]byte(data))
186 202
 				if err != nil {
187
-					errOut = true
188
-					fmt.Println(err.Error())
189 203
 					break
190 204
 				}
191 205
 			}
192 206
 		}
193
-		if errOut || socket.Closed {
207
+		if socket.IsClosed() {
194 208
 			// error out or we've been closed
195 209
 			break
196 210
 		}
197 211
 	}
198
-	if !socket.Closed {
199
-		socket.Closed = true
212
+	// force closure of socket
213
+	socket.closedMutex.Lock()
214
+	if !socket.closed {
215
+		socket.closed = true
200 216
 	}
217
+	socket.closedMutex.Unlock()
218
+
201 219
 	// write error lines
202
-	if 0 < len(socket.FinalData) {
203
-		socket.conn.Write([]byte(socket.FinalData))
220
+	socket.finalDataMutex.Lock()
221
+	if 0 < len(socket.finalData) {
222
+		socket.conn.Write([]byte(socket.finalData))
204 223
 	}
224
+	socket.finalDataMutex.Unlock()
225
+
226
+	// close the connection
205 227
 	socket.conn.Close()
206 228
 
207 229
 	// empty the lineToSendExists channel

+ 15
- 0
irc/whowas.go Ver fichero

@@ -4,10 +4,16 @@
4 4
 
5 5
 package irc
6 6
 
7
+import (
8
+	"sync"
9
+)
10
+
7 11
 type WhoWasList struct {
8 12
 	buffer []*WhoWas
9 13
 	start  int
10 14
 	end    int
15
+
16
+	accessMutex sync.RWMutex
11 17
 }
12 18
 
13 19
 type WhoWas struct {
@@ -25,6 +31,9 @@ func NewWhoWasList(size uint) *WhoWasList {
25 31
 }
26 32
 
27 33
 func (list *WhoWasList) Append(client *Client) {
34
+	list.accessMutex.Lock()
35
+	defer list.accessMutex.Unlock()
36
+
28 37
 	list.buffer[list.end] = &WhoWas{
29 38
 		nicknameCasefolded: client.nickCasefolded,
30 39
 		nickname:           client.nick,
@@ -39,6 +48,9 @@ func (list *WhoWasList) Append(client *Client) {
39 48
 }
40 49
 
41 50
 func (list *WhoWasList) Find(nickname string, limit int64) []*WhoWas {
51
+	list.accessMutex.RLock()
52
+	defer list.accessMutex.RUnlock()
53
+
42 54
 	results := make([]*WhoWas, 0)
43 55
 
44 56
 	casefoldedNickname, err := CasefoldName(nickname)
@@ -59,6 +71,9 @@ func (list *WhoWasList) Find(nickname string, limit int64) []*WhoWas {
59 71
 }
60 72
 
61 73
 func (list *WhoWasList) prev(index int) int {
74
+	list.accessMutex.RLock()
75
+	defer list.accessMutex.RUnlock()
76
+
62 77
 	index--
63 78
 	if index < 0 {
64 79
 		index += len(list.buffer)

Loading…
Cancelar
Guardar