From 6ea3c8f4d1fcdcd81542b49319b9990de7ef9a16 Mon Sep 17 00:00:00 2001 From: Jeremy Latt Date: Thu, 13 Feb 2014 23:16:07 -0800 Subject: [PATCH] fix race conditions --- README.md | 1 + irc/client.go | 18 +++++++++++++++--- irc/socket.go | 19 +++++++++++++++---- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index f7e46dc0..e09d06dd 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ I wanted to learn Go. - [RFC 2811: IRC Channel Management](http://tools.ietf.org/html/rfc2811) - [RFC 2812: IRC Client Protocol](http://tools.ietf.org/html/rfc2812) - [RFC 2813: IRC Server Protocol](http://tools.ietf.org/html/rfc2813) +- [IRC/2 Numeric List](https://www.alien.net.au/irc/irc2numerics.html) ## Running the Server diff --git a/irc/client.go b/irc/client.go index 325f5a85..cf44a1f4 100644 --- a/irc/client.go +++ b/irc/client.go @@ -4,6 +4,7 @@ import ( "fmt" "log" "net" + "sync" "time" ) @@ -26,6 +27,7 @@ type Client struct { replies chan Reply server *Server socket *Socket + mutex *sync.Mutex authorized bool username string } @@ -40,6 +42,7 @@ func NewClient(server *Server, conn net.Conn) *Client { replies: make(chan Reply), server: server, socket: NewSocket(conn), + mutex: &sync.Mutex{}, } client.loginTimer = time.AfterFunc(LOGIN_TIMEOUT, client.Destroy) @@ -50,7 +53,7 @@ func NewClient(server *Server, conn net.Conn) *Client { } func (client *Client) Touch() { - if client.destroyed { + if client.IsDestroyed() { return } @@ -86,7 +89,7 @@ func (client *Client) ConnectionTimeout() { } func (client *Client) ConnectionClosed() { - if client.destroyed { + if client.IsDestroyed() { return } @@ -133,8 +136,14 @@ func (client *Client) writeReplies() { } } +func (client *Client) IsDestroyed() bool { + client.mutex.Lock() + defer client.mutex.Unlock() + return client.destroyed +} + func (client *Client) Destroy() { - if client.destroyed { + if client.IsDestroyed() { return } @@ -142,6 +151,7 @@ func (client *Client) Destroy() { log.Printf("%s destroying", client) } + client.mutex.Lock() client.destroyed = true if client.replies != nil { @@ -164,6 +174,8 @@ func (client *Client) Destroy() { client.server.clients.Remove(client) + client.mutex.Unlock() + if DEBUG_CLIENT { log.Printf("%s destroyed", client) } diff --git a/irc/socket.go b/irc/socket.go index f635ec50..c77d2d2c 100644 --- a/irc/socket.go +++ b/irc/socket.go @@ -6,15 +6,17 @@ import ( "log" "net" "strings" + "sync" ) type Socket struct { closed bool conn net.Conn + mutex *sync.Mutex reader *bufio.Reader - writer *bufio.Writer - send chan string receive chan string + send chan string + writer *bufio.Writer } func NewSocket(conn net.Conn) *Socket { @@ -23,6 +25,7 @@ func NewSocket(conn net.Conn) *Socket { reader: bufio.NewReader(conn), receive: make(chan string), send: make(chan string), + mutex: &sync.Mutex{}, writer: bufio.NewWriter(conn), } @@ -36,8 +39,14 @@ func (socket *Socket) String() string { return socket.conn.RemoteAddr().String() } +func (socket *Socket) IsClosed() bool { + socket.mutex.Lock() + defer socket.mutex.Unlock() + return socket.closed +} + func (socket *Socket) Close() { - if socket.closed { + if socket.IsClosed() { return } @@ -45,10 +54,12 @@ func (socket *Socket) Close() { log.Printf("%s closed", socket) } + socket.mutex.Lock() socket.closed = true socket.conn.Close() close(socket.send) close(socket.receive) + socket.mutex.Unlock() } func (socket *Socket) Read() <-chan string { @@ -57,7 +68,7 @@ func (socket *Socket) Read() <-chan string { func (socket *Socket) Write(lines []string) error { for _, line := range lines { - if socket.closed { + if socket.IsClosed() { return io.EOF } socket.send <- line