From 990937d451208b0299246c46dd29adf7a35f97ee Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Tue, 19 Aug 2014 18:11:56 +0400 Subject: [PATCH] Remove signal processor for password reloading and use pointers to strings Simplify code and server maintaining by removing password file caching and refreshing it with HUP signal. Also use pointers to strings, already presented after flag-module work. --- client.go | 6 ++-- client_test.go | 6 ++-- daemon.go | 81 +++++++++++++++++++++++--------------------------- daemon_test.go | 11 ++++--- goircd.go | 22 ++------------ room.go | 10 +++---- room_test.go | 12 ++++---- 7 files changed, 66 insertions(+), 82 deletions(-) diff --git a/client.go b/client.go index 4f48daf..3637d49 100644 --- a/client.go +++ b/client.go @@ -31,7 +31,7 @@ const ( ) type Client struct { - hostname string + hostname *string conn net.Conn registered bool nickname string @@ -49,7 +49,7 @@ func (client Client) String() string { return client.nickname + "!" + client.username + "@" + client.conn.RemoteAddr().String() } -func NewClient(hostname string, conn net.Conn) *Client { +func NewClient(hostname *string, conn net.Conn) *Client { return &Client{hostname: hostname, conn: conn, nickname: "*", password: ""} } @@ -89,7 +89,7 @@ func (client *Client) Msg(text string) { // Send message from server. It has ": servername" prefix. func (client *Client) Reply(text string) { - client.Msg(":" + client.hostname + " " + text) + client.Msg(":" + *client.hostname + " " + text) } // Send server message, concatenating all provided text parts and diff --git a/client_test.go b/client_test.go index f9e3887..5369bbe 100644 --- a/client_test.go +++ b/client_test.go @@ -96,7 +96,8 @@ func (conn TestingConn) SetWriteDeadline(t time.Time) error { func TestNewClient(t *testing.T) { conn := NewTestingConn() sink := make(chan ClientEvent) - client := NewClient("foohost", conn) + host := "foohost" + client := NewClient(&host, conn) go client.Processor(sink) event := <-sink @@ -123,7 +124,8 @@ func TestNewClient(t *testing.T) { // Test replies formatting func TestClientReplies(t *testing.T) { conn := NewTestingConn() - client := NewClient("foohost", conn) + host := "foohost" + client := NewClient(&host, conn) client.nickname = "мойник" client.Reply("hello") diff --git a/daemon.go b/daemon.go index 2bf696c..9b0d77f 100644 --- a/daemon.go +++ b/daemon.go @@ -25,7 +25,6 @@ import ( "regexp" "sort" "strings" - "sync" "time" ) @@ -39,13 +38,12 @@ var ( RENickname = regexp.MustCompile("^[a-zA-Z0-9-]{1,9}$") ) -var passwordsRefreshLock sync.Mutex - type Daemon struct { Verbose bool version string - hostname string - motd string + hostname *string + motd *string + passwords *string clients map[*Client]bool clientAliveness map[*Client]*ClientAlivenessState rooms map[string]*Room @@ -53,11 +51,10 @@ type Daemon struct { lastAlivenessCheck time.Time logSink chan<- LogEvent stateSink chan<- StateEvent - passwords map[string]string } -func NewDaemon(version, hostname, motd string, logSink chan<- LogEvent, stateSink chan<- StateEvent) *Daemon { - daemon := Daemon{version: version, hostname: hostname, motd: motd} +func NewDaemon(version string, hostname, motd, passwords *string, logSink chan<- LogEvent, stateSink chan<- StateEvent) *Daemon { + daemon := Daemon{version: version, hostname: hostname, motd: motd, passwords: passwords} daemon.clients = make(map[*Client]bool) daemon.clientAliveness = make(map[*Client]*ClientAlivenessState) daemon.rooms = make(map[string]*Room) @@ -78,19 +75,19 @@ func (daemon *Daemon) SendLusers(client *Client) { } func (daemon *Daemon) SendMotd(client *Client) { - if len(daemon.motd) == 0 { + if daemon.motd == nil || *daemon.motd == "" { client.ReplyNicknamed("422", "MOTD File is missing") return } - motd, err := ioutil.ReadFile(daemon.motd) + motd, err := ioutil.ReadFile(*daemon.motd) if err != nil { - log.Printf("Can not read motd file %s: %v", daemon.motd, err) + log.Printf("Can not read motd file %s: %v", *daemon.motd, err) client.ReplyNicknamed("422", "Error reading MOTD File") return } - client.ReplyNicknamed("375", "- "+daemon.hostname+" Message of the day -") + client.ReplyNicknamed("375", "- "+*daemon.hostname+" Message of the day -") for _, s := range strings.Split(strings.Trim(string(motd), "\n"), "\n") { client.ReplyNicknamed("372", "- "+string(s)) } @@ -113,7 +110,7 @@ func (daemon *Daemon) SendWhois(client *Client, nicknames []string) { h = "Unknown" } client.ReplyNicknamed("311", c.nickname, c.username, h, "*", c.realname) - client.ReplyNicknamed("312", c.nickname, daemon.hostname, daemon.hostname) + client.ReplyNicknamed("312", c.nickname, *daemon.hostname, *daemon.hostname) subscriptions := []string{} for _, room := range daemon.rooms { for subscriber := range room.members { @@ -196,19 +193,34 @@ func (daemon *Daemon) ClientRegister(client *Client, command string, cols []stri client.realname = strings.TrimLeft(args[3], ":") } if client.nickname != "*" && client.username != "" { - passwordsRefreshLock.Lock() - if daemon.passwords != nil && (client.password == "" || daemon.passwords[client.nickname] != client.password) { - passwordsRefreshLock.Unlock() - client.ReplyParts("462", "You may not register") - client.conn.Close() - return + if daemon.passwords != nil && *daemon.passwords != "" { + if client.password == "" { + client.ReplyParts("462", "You may not register") + client.conn.Close() + return + } + contents, err := ioutil.ReadFile(*daemon.passwords) + if err != nil { + log.Fatalf("Can no read passwords file %s: %s", *daemon.passwords, err) + return + } + for _, entry := range strings.Split(string(contents), "\n") { + if entry == "" { + continue + } + if lp := strings.Split(entry, ":"); lp[0] == client.nickname && lp[1] != client.password { + client.ReplyParts("462", "You may not register") + client.conn.Close() + return + } + } } - passwordsRefreshLock.Unlock() + client.registered = true client.ReplyNicknamed("001", "Hi, welcome to IRC") - client.ReplyNicknamed("002", "Your host is "+daemon.hostname+", running goircd "+daemon.version) + client.ReplyNicknamed("002", "Your host is "+*daemon.hostname+", running goircd "+daemon.version) client.ReplyNicknamed("003", "This server was created sometime") - client.ReplyNicknamed("004", daemon.hostname+" goircd o o") + client.ReplyNicknamed("004", *daemon.hostname+" goircd o o") daemon.SendLusers(client) daemon.SendMotd(client) log.Println(client, "logged in") @@ -295,7 +307,7 @@ func (daemon *Daemon) Processor(events <-chan ClientEvent) { } if !aliveness.pingSent && aliveness.timestamp.Add(PingThreshold).Before(now) { if c.registered { - c.Msg("PING :" + daemon.hostname) + c.Msg("PING :" + *daemon.hostname) aliveness.pingSent = true } else { log.Println(c, "ping timeout") @@ -391,7 +403,7 @@ func (daemon *Daemon) Processor(events <-chan ClientEvent) { client.ReplyNicknamed("409", "No origin specified") continue } - client.Reply(fmt.Sprintf("PONG %s :%s", daemon.hostname, cols[1])) + client.Reply(fmt.Sprintf("PONG %s :%s", *daemon.hostname, cols[1])) case "PONG": continue case "NOTICE", "PRIVMSG": @@ -466,7 +478,7 @@ func (daemon *Daemon) Processor(events <-chan ClientEvent) { } else { debug = "" } - client.ReplyNicknamed("351", fmt.Sprintf("%s.%s %s :", daemon.version, debug, daemon.hostname)) + client.ReplyNicknamed("351", fmt.Sprintf("%s.%s %s :", daemon.version, debug, *daemon.hostname)) default: client.ReplyNicknamed("421", command, "Unknown command") } @@ -477,22 +489,3 @@ func (daemon *Daemon) Processor(events <-chan ClientEvent) { } } } - -func (daemon *Daemon) PasswordsRefresh() { - contents, err := ioutil.ReadFile(*passwords) - if err != nil { - log.Fatalf("Can no read passwords file %s: %s", *passwords, err) - return - } - processed := make(map[string]string) - for _, entry := range strings.Split(string(contents), "\n") { - loginAndPassword := strings.Split(entry, ":") - if len(loginAndPassword) == 2 { - processed[loginAndPassword[0]] = loginAndPassword[1] - } - } - log.Printf("Read %d passwords", len(processed)) - passwordsRefreshLock.Lock() - daemon.passwords = processed - passwordsRefreshLock.Unlock() -} diff --git a/daemon_test.go b/daemon_test.go index d049e42..ac9bc4c 100644 --- a/daemon_test.go +++ b/daemon_test.go @@ -25,11 +25,12 @@ import ( ) func TestRegistrationWorkflow(t *testing.T) { - daemon := NewDaemon("ver1", "foohost", "", nil, nil) + host := "foohost" + daemon := NewDaemon("ver1", &host, nil, nil, nil, nil) events := make(chan ClientEvent) go daemon.Processor(events) conn := NewTestingConn() - client := NewClient("foohost", conn) + client := NewClient(&host, conn) go client.Processor(events) conn.inbound <- "UNEXISTENT CMD" // should recieve nothing on this @@ -119,8 +120,10 @@ func TestMotd(t *testing.T) { fd.WriteString("catched\n") conn := NewTestingConn() - client := NewClient("foohost", conn) - daemon := NewDaemon("ver1", "foohost", fd.Name(), nil, nil) + host := "foohost" + client := NewClient(&host, conn) + motdName := fd.Name() + daemon := NewDaemon("ver1", &host, &motdName, nil, nil, nil) daemon.SendMotd(client) if r := <-conn.outbound; !strings.HasPrefix(r, ":foohost 375") { diff --git a/goircd.go b/goircd.go index b0f5e07..13efe2c 100644 --- a/goircd.go +++ b/goircd.go @@ -23,12 +23,9 @@ import ( "io/ioutil" "log" "net" - "os" - "os/signal" "path" "path/filepath" "strings" - "syscall" ) var ( @@ -53,7 +50,7 @@ func listenerLoop(sock net.Listener, events chan<- ClientEvent) { log.Println("Error during accepting connection", err) continue } - client := NewClient(*hostname, conn) + client := NewClient(hostname, conn) go client.Processor(events) } } @@ -79,9 +76,9 @@ func Run() { } stateSink := make(chan StateEvent) - daemon := NewDaemon(version, *hostname, *motd, logSink, stateSink) + daemon := NewDaemon(version, hostname, motd, passwords, logSink, stateSink) daemon.Verbose = *verbose - log.Println("goircd "+daemon.version+" is starting") + log.Println("goircd " + daemon.version + " is starting") if *statedir == "" { // Dummy statekeeper go func() { @@ -115,19 +112,6 @@ func Run() { log.Println(*statedir, "statekeeper initialized") } - if *passwords != "" { - daemon.PasswordsRefresh() - hups := make(chan os.Signal) - signal.Notify(hups, syscall.SIGHUP) - go func() { - for { - <-hups - daemon.PasswordsRefresh() - } - }() - } - - if *bind != "" { listener, err := net.Listen("tcp", *bind) if err != nil { diff --git a/room.go b/room.go index ccfdb07..ff57231 100644 --- a/room.go +++ b/room.go @@ -41,16 +41,16 @@ type Room struct { topic string key string members map[*Client]bool - hostname string + hostname *string logSink chan<- LogEvent stateSink chan<- StateEvent } -func (r Room) String() string { - return r.name +func (room Room) String() string { + return room.name } -func NewRoom(hostname, name string, logSink chan<- LogEvent, stateSink chan<- StateEvent) *Room { +func NewRoom(hostname *string, name string, logSink chan<- LogEvent, stateSink chan<- StateEvent) *Room { room := Room{name: name} room.members = make(map[*Client]bool) room.topic = "" @@ -128,7 +128,7 @@ func (room *Room) Processor(events <-chan ClientEvent) { room.StateSave() case EventWho: for m := range room.members { - client.ReplyNicknamed("352", room.name, m.username, m.conn.RemoteAddr().String(), room.hostname, m.nickname, "H", "0 "+m.realname) + client.ReplyNicknamed("352", room.name, m.username, m.conn.RemoteAddr().String(), *room.hostname, m.nickname, "H", "0 "+m.realname) } client.ReplyNicknamed("315", room.name, "End of /WHO list") case EventMode: diff --git a/room_test.go b/room_test.go index 6bd1cb0..3de4195 100644 --- a/room_test.go +++ b/room_test.go @@ -26,14 +26,15 @@ func notEnoughParams(t *testing.T, c *TestingConn) { func TestTwoUsers(t *testing.T) { logSink := make(chan LogEvent, 8) stateSink := make(chan StateEvent, 8) - daemon := NewDaemon("ver1", "foohost", "", logSink, stateSink) + host := "foohost" + daemon := NewDaemon("ver1", &host, nil, nil, logSink, stateSink) events := make(chan ClientEvent) go daemon.Processor(events) conn1 := NewTestingConn() conn2 := NewTestingConn() - client1 := NewClient("foohost", conn1) - client2 := NewClient("foohost", conn2) + client1 := NewClient(&host, conn1) + client2 := NewClient(&host, conn2) go client1.Processor(events) go client2.Processor(events) @@ -100,11 +101,12 @@ func TestTwoUsers(t *testing.T) { func TestJoin(t *testing.T) { logSink := make(chan LogEvent, 8) stateSink := make(chan StateEvent, 8) - daemon := NewDaemon("ver1", "foohost", "", logSink, stateSink) + host := "foohost" + daemon := NewDaemon("ver1", &host, nil, nil, logSink, stateSink) events := make(chan ClientEvent) go daemon.Processor(events) conn := NewTestingConn() - client := NewClient("foohost", conn) + client := NewClient(&host, conn) go client.Processor(events) conn.inbound <- "NICK nick2\r\nUSER foo2 bar2 baz2 :Long name2\r\n"