Browse Source

fix race conditions

tags/v0.1.0
Jeremy Latt 10 years ago
parent
commit
6ea3c8f4d1
3 changed files with 31 additions and 7 deletions
  1. 1
    0
      README.md
  2. 15
    3
      irc/client.go
  3. 15
    4
      irc/socket.go

+ 1
- 0
README.md View File

@@ -17,6 +17,7 @@ I wanted to learn Go.
17 17
 - [RFC 2811: IRC Channel Management](http://tools.ietf.org/html/rfc2811)
18 18
 - [RFC 2812: IRC Client Protocol](http://tools.ietf.org/html/rfc2812)
19 19
 - [RFC 2813: IRC Server Protocol](http://tools.ietf.org/html/rfc2813)
20
+- [IRC/2 Numeric List](https://www.alien.net.au/irc/irc2numerics.html)
20 21
 
21 22
 ## Running the Server
22 23
 

+ 15
- 3
irc/client.go View File

@@ -4,6 +4,7 @@ import (
4 4
 	"fmt"
5 5
 	"log"
6 6
 	"net"
7
+	"sync"
7 8
 	"time"
8 9
 )
9 10
 
@@ -26,6 +27,7 @@ type Client struct {
26 27
 	replies     chan Reply
27 28
 	server      *Server
28 29
 	socket      *Socket
30
+	mutex       *sync.Mutex
29 31
 	authorized  bool
30 32
 	username    string
31 33
 }
@@ -40,6 +42,7 @@ func NewClient(server *Server, conn net.Conn) *Client {
40 42
 		replies:  make(chan Reply),
41 43
 		server:   server,
42 44
 		socket:   NewSocket(conn),
45
+		mutex:    &sync.Mutex{},
43 46
 	}
44 47
 	client.loginTimer = time.AfterFunc(LOGIN_TIMEOUT, client.Destroy)
45 48
 
@@ -50,7 +53,7 @@ func NewClient(server *Server, conn net.Conn) *Client {
50 53
 }
51 54
 
52 55
 func (client *Client) Touch() {
53
-	if client.destroyed {
56
+	if client.IsDestroyed() {
54 57
 		return
55 58
 	}
56 59
 
@@ -86,7 +89,7 @@ func (client *Client) ConnectionTimeout() {
86 89
 }
87 90
 
88 91
 func (client *Client) ConnectionClosed() {
89
-	if client.destroyed {
92
+	if client.IsDestroyed() {
90 93
 		return
91 94
 	}
92 95
 
@@ -133,8 +136,14 @@ func (client *Client) writeReplies() {
133 136
 	}
134 137
 }
135 138
 
139
+func (client *Client) IsDestroyed() bool {
140
+	client.mutex.Lock()
141
+	defer client.mutex.Unlock()
142
+	return client.destroyed
143
+}
144
+
136 145
 func (client *Client) Destroy() {
137
-	if client.destroyed {
146
+	if client.IsDestroyed() {
138 147
 		return
139 148
 	}
140 149
 
@@ -142,6 +151,7 @@ func (client *Client) Destroy() {
142 151
 		log.Printf("%s destroying", client)
143 152
 	}
144 153
 
154
+	client.mutex.Lock()
145 155
 	client.destroyed = true
146 156
 
147 157
 	if client.replies != nil {
@@ -164,6 +174,8 @@ func (client *Client) Destroy() {
164 174
 
165 175
 	client.server.clients.Remove(client)
166 176
 
177
+	client.mutex.Unlock()
178
+
167 179
 	if DEBUG_CLIENT {
168 180
 		log.Printf("%s destroyed", client)
169 181
 	}

+ 15
- 4
irc/socket.go View File

@@ -6,15 +6,17 @@ import (
6 6
 	"log"
7 7
 	"net"
8 8
 	"strings"
9
+	"sync"
9 10
 )
10 11
 
11 12
 type Socket struct {
12 13
 	closed  bool
13 14
 	conn    net.Conn
15
+	mutex   *sync.Mutex
14 16
 	reader  *bufio.Reader
15
-	writer  *bufio.Writer
16
-	send    chan string
17 17
 	receive chan string
18
+	send    chan string
19
+	writer  *bufio.Writer
18 20
 }
19 21
 
20 22
 func NewSocket(conn net.Conn) *Socket {
@@ -23,6 +25,7 @@ func NewSocket(conn net.Conn) *Socket {
23 25
 		reader:  bufio.NewReader(conn),
24 26
 		receive: make(chan string),
25 27
 		send:    make(chan string),
28
+		mutex:   &sync.Mutex{},
26 29
 		writer:  bufio.NewWriter(conn),
27 30
 	}
28 31
 
@@ -36,8 +39,14 @@ func (socket *Socket) String() string {
36 39
 	return socket.conn.RemoteAddr().String()
37 40
 }
38 41
 
42
+func (socket *Socket) IsClosed() bool {
43
+	socket.mutex.Lock()
44
+	defer socket.mutex.Unlock()
45
+	return socket.closed
46
+}
47
+
39 48
 func (socket *Socket) Close() {
40
-	if socket.closed {
49
+	if socket.IsClosed() {
41 50
 		return
42 51
 	}
43 52
 
@@ -45,10 +54,12 @@ func (socket *Socket) Close() {
45 54
 		log.Printf("%s closed", socket)
46 55
 	}
47 56
 
57
+	socket.mutex.Lock()
48 58
 	socket.closed = true
49 59
 	socket.conn.Close()
50 60
 	close(socket.send)
51 61
 	close(socket.receive)
62
+	socket.mutex.Unlock()
52 63
 }
53 64
 
54 65
 func (socket *Socket) Read() <-chan string {
@@ -57,7 +68,7 @@ func (socket *Socket) Read() <-chan string {
57 68
 
58 69
 func (socket *Socket) Write(lines []string) error {
59 70
 	for _, line := range lines {
60
-		if socket.closed {
71
+		if socket.IsClosed() {
61 72
 			return io.EOF
62 73
 		}
63 74
 		socket.send <- line

Loading…
Cancel
Save