diff --git a/main.go b/main.go index 88b4c80..1012fc9 100644 --- a/main.go +++ b/main.go @@ -50,10 +50,7 @@ func main() { continue } - // Spin up an IRC server for the new user. - // The upstream connection doesn't get launched until we hear a nick - // from the irc client - + // Spin up a worker for the new user. server := NewServer(*serverName, libnmdc.HubAddress(*dcAddress), conn) go server.RunWorker() } diff --git a/server.go b/server.go index 4ecd93c..e42143e 100644 --- a/server.go +++ b/server.go @@ -33,7 +33,6 @@ type Server struct { motd string clientConn net.Conn - clientNick string clientRegistered bool upstreamLauncher libnmdc.HubConnectionOptions @@ -59,29 +58,20 @@ func NewServer(name string, upstream libnmdc.HubAddress, conn net.Conn) *Server func (s *Server) RunWorker() { - // Send the connection handshake + // Send the connection handshake. + // Can't connect to the upstream server yet, until we've recieved a nick. s.sendClientGlobalMessage(s.motd) - // Can't connect to the upstream server yet, until we've recieved a nick. - for { + if s.clientConn == nil { + break // abandon thread + } + buf := make([]byte, CLIENT_READ_BUFFSIZE) - s.clientConn.SetReadDeadline(time.Now().Add(time.Second * CLIENT_READ_TIMEOUT_SEC)) ln, err := s.clientConn.Read(buf) if err != nil { if err == io.EOF { - s.DisconnectClient() // if not already done - - // Cleanup upstream - if s.clientConn != nil && s.clientRegistered { - s.upstreamCloser <- struct{}{} - } - - // Clean up ourselves - s.clientRegistered = false - - // Abandon thread - return + break // abandon thread } continue } @@ -108,6 +98,17 @@ func (s *Server) RunWorker() { } } + // Cleanup + s.DisconnectClient() // if not already done + + // Cleanup upstream + if s.clientConn != nil && s.clientRegistered { + s.upstreamCloser <- struct{}{} + } + + // Clean up ourselves + s.clientRegistered = false + } func (s *Server) upstreamWorker() { @@ -138,10 +139,10 @@ func (s *Server) upstreamWorker() { s.sendChannelTopic(hubEvent.Nick) case libnmdc.EVENT_PRIVATE: - s.reply(rplMsg, s.clientNick, hubEvent.Nick, hubEvent.Message) + s.reply(rplMsg, s.upstreamLauncher.Self.Nick, hubEvent.Nick, hubEvent.Message) case libnmdc.EVENT_PUBLIC: - s.reply(rplMsg, s.clientNick, BLESSED_CHANNEL, hubEvent.Message) + s.reply(rplMsg, s.upstreamLauncher.Self.Nick, BLESSED_CHANNEL, hubEvent.Message) case libnmdc.EVENT_SYSTEM_MESSAGE_FROM_CONN, libnmdc.EVENT_SYSTEM_MESSAGE_FROM_HUB: s.sendClientGlobalMessage(hubEvent.Message) @@ -195,7 +196,7 @@ func (s *Server) handleCommand(command string, args []string) { return } - if s.clientNick == "" { + if s.upstreamLauncher.Self.Nick == "" { s.reply(rplKill, "Your nickname is already being used", "") s.DisconnectClient() return @@ -209,7 +210,7 @@ func (s *Server) handleCommand(command string, args []string) { go s.upstreamWorker() // Tell the user that they themselves joined the chat channel - s.reply(rplJoin, s.clientNick, BLESSED_CHANNEL) + s.reply(rplJoin, s.upstreamLauncher.Self.Nick, BLESSED_CHANNEL) default: s.handleRegisteredCommand(command, args) @@ -339,7 +340,9 @@ func (s *Server) handleRegisteredCommand(command string, args []string) { } func (s *Server) DisconnectClient() { - s.clientConn.Close() + if s.clientConn != nil { + s.clientConn.Close() + } s.clientConn = nil // Readloop will stop, which kills the upstream connection too @@ -372,71 +375,71 @@ func (s *Server) reply(code replyCode, args ...string) { switch code { case rplWelcome: - s.writeClient(fmt.Sprintf(":%s 001 %s :Welcome to %s", s.name, s.clientNick, s.name)) + s.writeClient(fmt.Sprintf(":%s 001 %s :Welcome to %s", s.name, s.upstreamLauncher.Self.Nick, s.name)) case rplJoin: s.writeClient(fmt.Sprintf(":%s JOIN %s", args[0], args[1])) case rplPart: s.writeClient(fmt.Sprintf(":%s PART %s %s", args[0], args[1], args[2])) case rplTopic: - s.writeClient(fmt.Sprintf(":%s 332 %s %s :%s", s.name, s.clientNick, args[0], args[1])) + s.writeClient(fmt.Sprintf(":%s 332 %s %s :%s", s.name, s.upstreamLauncher.Self.Nick, args[0], args[1])) case rplNoTopic: - s.writeClient(fmt.Sprintf(":%s 331 %s %s :No topic is set", s.name, s.clientNick, args[0])) + s.writeClient(fmt.Sprintf(":%s 331 %s %s :No topic is set", s.name, s.upstreamLauncher.Self.Nick, args[0])) case rplNames: - s.writeClient(fmt.Sprintf(":%s 353 %s = %s :%s", s.name, s.clientNick, args[0], args[1])) + s.writeClient(fmt.Sprintf(":%s 353 %s = %s :%s", s.name, s.upstreamLauncher.Self.Nick, args[0], args[1])) case rplEndOfNames: - s.writeClient(fmt.Sprintf(":%s 366 %s %s :End of NAMES list", s.name, s.clientNick, args[0])) + s.writeClient(fmt.Sprintf(":%s 366 %s %s :End of NAMES list", s.name, s.upstreamLauncher.Self.Nick, args[0])) case rplNickChange: s.writeClient(fmt.Sprintf(":%s NICK %s", args[0], args[1])) case rplKill: - s.writeClient(fmt.Sprintf(":%s KILL %s A %s", args[0], s.clientNick, args[1])) + s.writeClient(fmt.Sprintf(":%s KILL %s A %s", args[0], s.upstreamLauncher.Self.Nick, args[1])) case rplMsg: for _, itm := range strings.Split(args[2], "\n") { s.writeClient(fmt.Sprintf(":%s PRIVMSG %s %s", args[0], args[1], itm)) } case rplList: - s.writeClient(fmt.Sprintf(":%s 322 %s %s", s.name, s.clientNick, args[0])) + s.writeClient(fmt.Sprintf(":%s 322 %s %s", s.name, s.upstreamLauncher.Self.Nick, args[0])) case rplListEnd: - s.writeClient(fmt.Sprintf(":%s 323 %s", s.name, s.clientNick)) + s.writeClient(fmt.Sprintf(":%s 323 %s", s.name, s.upstreamLauncher.Self.Nick)) case rplOper: - s.writeClient(fmt.Sprintf(":%s 381 %s :You are now an operator", s.name, s.clientNick)) + s.writeClient(fmt.Sprintf(":%s 381 %s :You are now an operator", s.name, s.upstreamLauncher.Self.Nick)) case rplChannelModeIs: - s.writeClient(fmt.Sprintf(":%s 324 %s %s %s %s", s.name, s.clientNick, args[0], args[1], args[2])) + s.writeClient(fmt.Sprintf(":%s 324 %s %s %s %s", s.name, s.upstreamLauncher.Self.Nick, args[0], args[1], args[2])) case rplKick: s.writeClient(fmt.Sprintf(":%s KICK %s %s %s", args[0], args[1], args[2], args[3])) case rplInfo: - s.writeClient(fmt.Sprintf(":%s 371 %s :%s", s.name, s.clientNick, args[0])) + s.writeClient(fmt.Sprintf(":%s 371 %s :%s", s.name, s.upstreamLauncher.Self.Nick, args[0])) case rplVersion: - s.writeClient(fmt.Sprintf(":%s 351 %s %s", s.name, s.clientNick, args[0])) + s.writeClient(fmt.Sprintf(":%s 351 %s %s", s.name, s.upstreamLauncher.Self.Nick, args[0])) case rplMOTDStart: - s.writeClient(fmt.Sprintf(":%s 375 %s :- Message of the day - ", s.name, s.clientNick)) + s.writeClient(fmt.Sprintf(":%s 375 %s :- Message of the day - ", s.name, s.upstreamLauncher.Self.Nick)) case rplMOTD: - s.writeClient(fmt.Sprintf(":%s 372 %s :- %s", s.name, s.clientNick, args[0])) + s.writeClient(fmt.Sprintf(":%s 372 %s :- %s", s.name, s.upstreamLauncher.Self.Nick, args[0])) case rplEndOfMOTD: - s.writeClient(fmt.Sprintf(":%s 376 %s :End of MOTD Command", s.name, s.clientNick)) + s.writeClient(fmt.Sprintf(":%s 376 %s :End of MOTD Command", s.name, s.upstreamLauncher.Self.Nick)) case rplPong: - s.writeClient(fmt.Sprintf(":%s PONG %s %s", s.name, s.clientNick, s.name)) + s.writeClient(fmt.Sprintf(":%s PONG %s %s", s.name, s.upstreamLauncher.Self.Nick, s.name)) case errMoreArgs: - s.writeClient(fmt.Sprintf(":%s 461 %s :Not enough params", s.name, s.clientNick)) + s.writeClient(fmt.Sprintf(":%s 461 %s :Not enough params", s.name, s.upstreamLauncher.Self.Nick)) case errNoNick: - s.writeClient(fmt.Sprintf(":%s 431 %s :No nickname given", s.name, s.clientNick)) + s.writeClient(fmt.Sprintf(":%s 431 %s :No nickname given", s.name, s.upstreamLauncher.Self.Nick)) case errInvalidNick: - s.writeClient(fmt.Sprintf(":%s 432 %s %s :Erronenous nickname", s.name, s.clientNick, args[0])) + s.writeClient(fmt.Sprintf(":%s 432 %s %s :Erronenous nickname", s.name, s.upstreamLauncher.Self.Nick, args[0])) case errNickInUse: - s.writeClient(fmt.Sprintf(":%s 433 %s %s :Nick already in use", s.name, s.clientNick, args[0])) + s.writeClient(fmt.Sprintf(":%s 433 %s %s :Nick already in use", s.name, s.upstreamLauncher.Self.Nick, args[0])) case errAlreadyReg: s.writeClient(fmt.Sprintf(":%s 462 :You need a valid nick first", s.name)) case errNoSuchNick: - s.writeClient(fmt.Sprintf(":%s 401 %s %s :No such nick/channel", s.name, s.clientNick, args[0])) + s.writeClient(fmt.Sprintf(":%s 401 %s %s :No such nick/channel", s.name, s.upstreamLauncher.Self.Nick, args[0])) case errUnknownCommand: - s.writeClient(fmt.Sprintf(":%s 421 %s %s :Unknown command", s.name, s.clientNick, args[0])) + s.writeClient(fmt.Sprintf(":%s 421 %s %s :Unknown command", s.name, s.upstreamLauncher.Self.Nick, args[0])) case errNotReg: s.writeClient(fmt.Sprintf(":%s 451 :You have not registered", s.name)) case errPassword: - s.writeClient(fmt.Sprintf(":%s 464 %s :Error, password incorrect", s.name, s.clientNick)) + s.writeClient(fmt.Sprintf(":%s 464 %s :Error, password incorrect", s.name, s.upstreamLauncher.Self.Nick)) case errNoPriv: - s.writeClient(fmt.Sprintf(":%s 481 %s :Permission denied", s.name, s.clientNick)) + s.writeClient(fmt.Sprintf(":%s 481 %s :Permission denied", s.name, s.upstreamLauncher.Self.Nick)) case errCannotSend: - s.writeClient(fmt.Sprintf(":%s 404 %s %s :Cannot send to channel", s.name, s.clientNick, args[0])) + s.writeClient(fmt.Sprintf(":%s 404 %s %s :Cannot send to channel", s.name, s.upstreamLauncher.Self.Nick, args[0])) } }