mirror of
https://github.com/ergochat/ergo.git
synced 2024-12-22 18:52:41 +01:00
solve quit/connection close race
This commit is contained in:
parent
2bc1b952a0
commit
9e471b5b5d
@ -19,6 +19,7 @@ type Client struct {
|
||||
ctime time.Time
|
||||
flags map[UserMode]bool
|
||||
friends map[*Client]uint
|
||||
hasQuit bool
|
||||
hops uint
|
||||
hostname string
|
||||
idleTimer *time.Timer
|
||||
@ -46,12 +47,16 @@ func NewClient(server *Server, conn net.Conn) *Client {
|
||||
socket: NewSocket(conn),
|
||||
}
|
||||
|
||||
client.loginTimer = time.AfterFunc(LOGIN_TIMEOUT, client.connectionClosed)
|
||||
client.loginTimer = time.AfterFunc(LOGIN_TIMEOUT, client.connectionTimeout)
|
||||
go client.readCommands()
|
||||
|
||||
return client
|
||||
}
|
||||
|
||||
//
|
||||
// socket read gorountine
|
||||
//
|
||||
|
||||
func (client *Client) readCommands() {
|
||||
for line := range client.socket.Read() {
|
||||
msg, err := ParseCommand(line)
|
||||
@ -68,12 +73,46 @@ func (client *Client) readCommands() {
|
||||
client.server.commands <- msg
|
||||
}
|
||||
|
||||
client.server.toDestroy <- client
|
||||
client.connectionClosed()
|
||||
}
|
||||
|
||||
func (client *Client) connectionClosed() {
|
||||
msg := &QuitCommand{
|
||||
message: "connection closed",
|
||||
}
|
||||
msg.SetClient(client)
|
||||
client.server.commands <- msg
|
||||
}
|
||||
|
||||
//
|
||||
// idle timer goroutine
|
||||
//
|
||||
|
||||
func (client *Client) connectionIdle() {
|
||||
client.server.idle <- client
|
||||
}
|
||||
|
||||
//
|
||||
// quit timer goroutine
|
||||
//
|
||||
|
||||
func (client *Client) connectionTimeout() {
|
||||
msg := &QuitCommand{
|
||||
message: "connection timeout",
|
||||
}
|
||||
msg.SetClient(client)
|
||||
client.server.commands <- msg
|
||||
}
|
||||
|
||||
//
|
||||
// server goroutine
|
||||
//
|
||||
|
||||
func (client *Client) Active() {
|
||||
client.atime = time.Now()
|
||||
}
|
||||
|
||||
func (client *Client) Touch() {
|
||||
client.atime = time.Now()
|
||||
|
||||
if client.quitTimer != nil {
|
||||
client.quitTimer.Stop()
|
||||
}
|
||||
@ -95,24 +134,11 @@ func (client *Client) Idle() {
|
||||
}
|
||||
}
|
||||
|
||||
func (client *Client) connectionIdle() {
|
||||
client.server.idle <- client
|
||||
}
|
||||
|
||||
func (client *Client) connectionTimeout() {
|
||||
msg := &QuitCommand{
|
||||
message: "connection timeout",
|
||||
}
|
||||
msg.SetClient(client)
|
||||
client.server.commands <- msg
|
||||
}
|
||||
|
||||
func (client *Client) connectionClosed() {
|
||||
msg := &QuitCommand{
|
||||
message: "connection closed",
|
||||
}
|
||||
msg.SetClient(client)
|
||||
client.server.commands <- msg
|
||||
func (client *Client) Register() {
|
||||
client.phase = Normal
|
||||
client.loginTimer.Stop()
|
||||
client.AddFriend(client)
|
||||
client.Touch()
|
||||
}
|
||||
|
||||
func (client *Client) Destroy() {
|
||||
@ -225,6 +251,13 @@ func (client *Client) ChangeNickname(nickname string) {
|
||||
}
|
||||
|
||||
func (client *Client) Quit(message string) {
|
||||
if client.hasQuit {
|
||||
return
|
||||
}
|
||||
client.hasQuit = true
|
||||
client.Reply(RplError(client.server, client.Nick()))
|
||||
client.Destroy()
|
||||
|
||||
if len(client.friends) > 0 {
|
||||
reply := RplQuit(client, message)
|
||||
for friend := range client.friends {
|
||||
@ -234,7 +267,4 @@ func (client *Client) Quit(message string) {
|
||||
friend.Reply(reply)
|
||||
}
|
||||
}
|
||||
|
||||
client.Reply(RplError(client.server, client))
|
||||
client.socket.Close()
|
||||
}
|
||||
|
@ -238,8 +238,8 @@ func RplQuit(client *Client, message string) Reply {
|
||||
return NewStringReply(client, QUIT, ":%s", message)
|
||||
}
|
||||
|
||||
func RplError(server *Server, target Identifier) Reply {
|
||||
return NewStringReply(server, ERROR, target.Nick())
|
||||
func RplError(server *Server, message string) Reply {
|
||||
return NewStringReply(server, ERROR, message)
|
||||
}
|
||||
|
||||
func RplInviteMsg(channel *Channel, inviter *Client) Reply {
|
||||
|
@ -24,7 +24,6 @@ type Server struct {
|
||||
name string
|
||||
operators map[string]string
|
||||
password string
|
||||
toDestroy chan *Client
|
||||
}
|
||||
|
||||
func NewServer(config *Config) *Server {
|
||||
@ -39,7 +38,6 @@ func NewServer(config *Config) *Server {
|
||||
name: config.Name,
|
||||
operators: make(map[string]string),
|
||||
password: config.Password,
|
||||
toDestroy: make(chan *Client),
|
||||
}
|
||||
|
||||
for _, opConf := range config.Operators {
|
||||
@ -59,9 +57,6 @@ func (server *Server) ReceiveCommands() {
|
||||
case conn := <-server.conns:
|
||||
NewClient(server, conn)
|
||||
|
||||
case client := <-server.toDestroy:
|
||||
client.Destroy()
|
||||
|
||||
case client := <-server.idle:
|
||||
client.Idle()
|
||||
|
||||
@ -75,7 +70,7 @@ func (server *Server) ReceiveCommands() {
|
||||
case Authorization:
|
||||
authCmd, ok := cmd.(AuthServerCommand)
|
||||
if !ok {
|
||||
client.socket.Close()
|
||||
client.Quit("unexpected command")
|
||||
continue
|
||||
}
|
||||
authCmd.HandleAuthServer(server)
|
||||
@ -83,7 +78,7 @@ func (server *Server) ReceiveCommands() {
|
||||
case Registration:
|
||||
regCmd, ok := cmd.(RegServerCommand)
|
||||
if !ok {
|
||||
client.socket.Close()
|
||||
client.Quit("unexpected command")
|
||||
continue
|
||||
}
|
||||
regCmd.HandleRegServer(server)
|
||||
@ -94,7 +89,15 @@ func (server *Server) ReceiveCommands() {
|
||||
client.Reply(ErrUnknownCommand(server, cmd.Code()))
|
||||
continue
|
||||
}
|
||||
client.Touch()
|
||||
switch srvCmd.(type) {
|
||||
case *PingCommand, *PongCommand:
|
||||
client.Touch()
|
||||
case *QuitCommand:
|
||||
// no-op
|
||||
default:
|
||||
client.Active()
|
||||
client.Touch()
|
||||
}
|
||||
srvCmd.HandleServer(server)
|
||||
}
|
||||
}
|
||||
@ -184,10 +187,7 @@ func (s *Server) GenerateGuestNick() string {
|
||||
|
||||
func (s *Server) tryRegister(c *Client) {
|
||||
if c.HasNick() && c.HasUsername() {
|
||||
c.phase = Normal
|
||||
c.loginTimer.Stop()
|
||||
c.AddFriend(c)
|
||||
|
||||
c.Register()
|
||||
c.Reply(RplWelcome(s, c))
|
||||
c.Reply(RplYourHost(s))
|
||||
c.Reply(RplCreated(s))
|
||||
@ -270,6 +270,10 @@ func (m *PassCommand) HandleAuthServer(s *Server) {
|
||||
client.phase = Registration
|
||||
}
|
||||
|
||||
func (msg *QuitCommand) HandleAuthServer(server *Server) {
|
||||
msg.Client().Quit(msg.message)
|
||||
}
|
||||
|
||||
//
|
||||
// registration commands
|
||||
//
|
||||
@ -319,6 +323,10 @@ func (msg *UserCommand) HandleRegServer2(server *Server) {
|
||||
server.tryRegister(client)
|
||||
}
|
||||
|
||||
func (msg *QuitCommand) HandleRegServer(server *Server) {
|
||||
msg.Client().Quit(msg.message)
|
||||
}
|
||||
|
||||
//
|
||||
// normal commands
|
||||
//
|
||||
|
Loading…
Reference in New Issue
Block a user