From 4dff342b70669f17348d981e5c0be3c0724902f5 Mon Sep 17 00:00:00 2001 From: an Date: Tue, 22 Aug 2017 07:23:30 +0200 Subject: [PATCH] ... --- client.go | 46 ++++++++++++++++++++++++++++++++++++---------- handlers.go | 34 +++++++++++++++++++++++++++++++++- monitoring.go | 2 +- server.go | 28 ++++++++++++++++------------ service.go | 7 +++++-- 5 files changed, 91 insertions(+), 26 deletions(-) diff --git a/client.go b/client.go index cd023d9..7ee7af9 100644 --- a/client.go +++ b/client.go @@ -3,7 +3,7 @@ package ircd import ( - "bufio" + "bytes" "fmt" "io" "net" @@ -119,7 +119,7 @@ func (cl *RemoteClient) Destroy() { func (cl *RemoteClient) dispatcher() { for { - time.Sleep(1 * time.Millisecond) + time.Sleep(10 * time.Millisecond) if cl.isClosed { return } @@ -140,34 +140,56 @@ func (cl *RemoteClient) dispatcher() { } } -func (cl *RemoteClient) connReader() { - input := bufio.NewReader(cl.conn) +/*func (cl *RemoteClient) pinger() { for { + time.Sleep(30 * time.Second) + if cl.isClosed { + return + } + cl.writeLine("PING %s", cl.server.host) + } +}*/ + +func (cl *RemoteClient) connReader() { + for { + time.Sleep(10 * time.Millisecond) + buf := make([]byte, 4096) if cl.isClosed { xlog.Debug("connReader: exiting") return } - s, err := input.ReadString('\n') + cl.conn.SetReadDeadline(time.Now().Add(time.Second * 5)) + n, err := cl.conn.Read(buf) if err == io.EOF { xlog.Info("connReader: Connection closed by peer") cl.server.DelClient(cl) return } if err != nil { - xlog.Error("connReader: %s", err.Error()) - cl.server.DelClient(cl) - return + continue + } + raw := buf[:n] + raw = bytes.Replace(raw, []byte("\r\n"), []byte("\n"), -1) + raw = bytes.Replace(raw, []byte("\r"), []byte("\n"), -1) + lines := bytes.Split(raw, []byte("\n")) + for _, line := range lines { + if len(line) > 0 { + cl.handleCmd(string(line)) + } } - s = strings.Trim(s, "\r\n") - cl.handleCmd(s) } } func (cl *RemoteClient) connWriter() { for line := range cl.writeq { + time.Sleep(10 * time.Millisecond) + if cl.isClosed { + return + } written := 0 bytes := []byte(line + "\r\n") for written < len(line) { + cl.conn.SetWriteDeadline(time.Now().Add(time.Second * 5)) n, err := cl.conn.Write(bytes[written:]) if err == io.EOF { xlog.Info("connWriter: Connection closed by peer") @@ -185,6 +207,10 @@ func (cl *RemoteClient) connWriter() { } func (cl *RemoteClient) writeMsg(msg *irc.Message) { + clid := strings.ToLower(msg.Pre) + if _, exists := cl.server.clients[clid]; exists { + msg.Pre = msg.Pre + "!" + msg.Pre + "@" + cl.server.clHosts[clid] + } cl.writeLine(msg.String()) } diff --git a/handlers.go b/handlers.go index f9a25b6..c20ac45 100644 --- a/handlers.go +++ b/handlers.go @@ -3,6 +3,7 @@ package ircd import ( + "fmt" "strings" "code.dnix.de/an/irc" @@ -25,8 +26,10 @@ var svCommandHooks = map[string]commandHook{ "TOPIC": {handleCmdTopic, 1, false, ""}, "KICK": {handleCmdKick, 2, false, ""}, "NAMES": {handleCmdNames, 1, false, ""}, + "WHO": {handleCmdWho, 1, false, ""}, "WHOIS": {handleCmdWhois, 0, false, ""}, "PING": {handleCmdPing, 1, false, ""}, + "PONG": {handleCmdPong, 0, false, ""}, "REHASH": {handleCmdRehash, 0, false, "ao"}, "KILL": {handleCmdKill, 0, false, "ao"}, /* @@ -235,14 +238,43 @@ func handleCmdNames(sv *Server, msg *irc.Message) { sv.channelNames(msg.Pre, chid) } +func handleCmdWho(sv *Server, msg *irc.Message) { + clid := strings.ToLower(msg.Args[0]) + if _, exists := sv.clients[clid]; exists { + // :irc.dnix.de 352 Anydin #northbrigade webuser369 -anon/guest irc.dnix.de webuser36968 H :0 webuser36968 + sv.sendReply(msg.Pre, RPL_WHOREPLY, + fmt.Sprintf("* %s %s %s %s %s%s", clid, sv.clHosts[clid], sv.host, clid, "H", ""), "0 "+msg.Args[0]) + } + sv.sendReply(msg.Pre, RPL_ENDOFWHO, clid, "End of /WHO list.") +} + func handleCmdWhois(sv *Server, msg *irc.Message) { - sv.sendReply(msg.Pre, RPL_WHOISUSER, "nick user host *", "real name") + clid := strings.ToLower(msg.Args[0]) + if _, exists := sv.clients[clid]; !exists { + sv.sendReply(msg.Pre, ERR_NOSUCHNICK, clid, "No such nick") + return + } + sv.sendReply(msg.Pre, RPL_WHOISUSER, fmt.Sprintf("%s %s %s *", clid, clid, sv.clHosts[clid]), msg.Args[0]) + m, isoper := sv.opers[clid] + if isoper { + if m == "a" { + sv.sendReply(msg.Pre, RPL_WHOISOPERATOR, clid, "is a server administrator") + } + if m == "o" { + sv.sendReply(msg.Pre, RPL_WHOISOPERATOR, clid, "is a server operator") + } + } + sv.sendReply(msg.Pre, RPL_ENDOFWHOIS, "", "End of /WHOIS list") + } func handleCmdPing(sv *Server, msg *irc.Message) { sv.sendReply(msg.Pre, "PONG", msg.Args[0], "") } +func handleCmdPong(sv *Server, msg *irc.Message) { +} + func handleCmdRehash(sv *Server, msg *irc.Message) { sv.loadConfig() sv.sendReply(msg.Pre, RPL_REHASHING, "", "Rehashing") diff --git a/monitoring.go b/monitoring.go index a32a506..fa6d40c 100644 --- a/monitoring.go +++ b/monitoring.go @@ -58,7 +58,7 @@ func monitoringRun(sv *Server) { func monitoringUpdater(sv *Server) { for { - time.Sleep(5 * time.Second) + time.Sleep(10 * time.Second) gaugeGoroutinesRunning.Set(float64(runtime.NumGoroutine())) gaugePacketsTransferred.Set(sv.packetsTransferred) gaugeConnectionsCurrent.Set(float64(len(sv.clients))) diff --git a/server.go b/server.go index b07ce04..b9842d1 100644 --- a/server.go +++ b/server.go @@ -46,6 +46,7 @@ type Server struct { clients map[string]Client clModes map[string]string + clHosts map[string]string services map[string]*Service @@ -59,7 +60,7 @@ type Server struct { packetsTransferred float64 connectionsCount float64 - authCallback func(name, pass string) bool + authCallback func(name, pass string) (string, bool) } func NewServer(configPath, software, version string) *Server { @@ -76,6 +77,7 @@ func NewServer(configPath, software, version string) *Server { sv.clients = make(map[string]Client) sv.clModes = make(map[string]string) + sv.clHosts = make(map[string]string) sv.services = make(map[string]*Service, 0) @@ -98,11 +100,11 @@ func NewServer(configPath, software, version string) *Server { nicks, _ := sv.config.GetString("control", "a") for _, nick := range strings.Split(nicks, ",") { - sv.opers[nick] = "a" + sv.opers[strings.ToLower(nick)] = "a" } nicks, _ = sv.config.GetString("control", "o") for _, nick := range strings.Split(nicks, ",") { - sv.opers[nick] = "o" + sv.opers[strings.ToLower(nick)] = "o" } sv.packetsTransferred = 0 @@ -111,7 +113,7 @@ func NewServer(configPath, software, version string) *Server { return sv } -func (sv *Server) SetAuthCallback(authCB func(name, pass string) bool) { +func (sv *Server) SetAuthCallback(authCB func(name, pass string) (string, bool)) { sv.authCallback = authCB } @@ -232,7 +234,7 @@ func (sv *Server) dispatcher() (err error) { case cl := <-sv.delq: sv.delClient(cl) default: - time.Sleep(100 * time.Microsecond) + time.Sleep(10 * time.Millisecond) } } return @@ -258,7 +260,15 @@ func (sv *Server) addClient(cl Client) { xlog.Info("Client registration failed: '%s' (client exists)", clid) return } - if !sv.authCallback(cl.Name(), cl.Password()) { + if host, success := sv.authCallback(cl.Name(), cl.Password()); success { + sv.clients[clid] = cl + sv.clHosts[clid] = host + sv.sendLogon(cl.Name()) + cl.Register(true) + sv.cluster.Subscribe(clid, sv.remoteq) + xlog.Info("Client registered: '%s'", clid) + xlog.Info("Server has %d client(s)", len(sv.clients)) + } else { cl.Receive(irc.M(sv.host, ERR_PASSWDMISMATCH, "", "Password incorrect")) go func() { time.Sleep(5 * time.Second) @@ -267,12 +277,6 @@ func (sv *Server) addClient(cl Client) { xlog.Info("Client registration failed: '%s' (wrong password)", clid) return } - sv.clients[clid] = cl - sv.sendLogon(cl.Name()) - cl.Register(true) - sv.cluster.Subscribe(clid, sv.remoteq) - xlog.Info("Client registered: '%s'", clid) - xlog.Info("Server has %d client(s)", len(sv.clients)) } func (sv *Server) delClient(cl Client) { diff --git a/service.go b/service.go index 7084ffc..1e8b596 100644 --- a/service.go +++ b/service.go @@ -23,6 +23,9 @@ func (svc *Service) Run() { go svc.dispatcher() } +func (svc *Service) Stop() { +} + func (svc *Service) Dispatch(msg *irc.Message) { svc.recvq <- msg } @@ -33,13 +36,13 @@ func (svc *Service) Handler(cmd string, fn func(*irc.Message)) { func (svc *Service) dispatcher() { for { + time.Sleep(10 * time.Millisecond) select { case msg := <-svc.recvq: - if fn, exists := sv.handlers[msg.Pre]; exists { + if fn, exists := svc.handlers[msg.Pre]; exists { fn(msg) } default: - time.Sleep(100 * time.Microsecond) } } return