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.
This commit is contained in:
parent
85e6538f2f
commit
990937d451
@ -31,7 +31,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
hostname string
|
hostname *string
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
registered bool
|
registered bool
|
||||||
nickname string
|
nickname string
|
||||||
@ -49,7 +49,7 @@ func (client Client) String() string {
|
|||||||
return client.nickname + "!" + client.username + "@" + client.conn.RemoteAddr().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: ""}
|
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.
|
// Send message from server. It has ": servername" prefix.
|
||||||
func (client *Client) Reply(text string) {
|
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
|
// Send server message, concatenating all provided text parts and
|
||||||
|
@ -96,7 +96,8 @@ func (conn TestingConn) SetWriteDeadline(t time.Time) error {
|
|||||||
func TestNewClient(t *testing.T) {
|
func TestNewClient(t *testing.T) {
|
||||||
conn := NewTestingConn()
|
conn := NewTestingConn()
|
||||||
sink := make(chan ClientEvent)
|
sink := make(chan ClientEvent)
|
||||||
client := NewClient("foohost", conn)
|
host := "foohost"
|
||||||
|
client := NewClient(&host, conn)
|
||||||
go client.Processor(sink)
|
go client.Processor(sink)
|
||||||
|
|
||||||
event := <-sink
|
event := <-sink
|
||||||
@ -123,7 +124,8 @@ func TestNewClient(t *testing.T) {
|
|||||||
// Test replies formatting
|
// Test replies formatting
|
||||||
func TestClientReplies(t *testing.T) {
|
func TestClientReplies(t *testing.T) {
|
||||||
conn := NewTestingConn()
|
conn := NewTestingConn()
|
||||||
client := NewClient("foohost", conn)
|
host := "foohost"
|
||||||
|
client := NewClient(&host, conn)
|
||||||
client.nickname = "мойник"
|
client.nickname = "мойник"
|
||||||
|
|
||||||
client.Reply("hello")
|
client.Reply("hello")
|
||||||
|
81
daemon.go
81
daemon.go
@ -25,7 +25,6 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -39,13 +38,12 @@ var (
|
|||||||
RENickname = regexp.MustCompile("^[a-zA-Z0-9-]{1,9}$")
|
RENickname = regexp.MustCompile("^[a-zA-Z0-9-]{1,9}$")
|
||||||
)
|
)
|
||||||
|
|
||||||
var passwordsRefreshLock sync.Mutex
|
|
||||||
|
|
||||||
type Daemon struct {
|
type Daemon struct {
|
||||||
Verbose bool
|
Verbose bool
|
||||||
version string
|
version string
|
||||||
hostname string
|
hostname *string
|
||||||
motd string
|
motd *string
|
||||||
|
passwords *string
|
||||||
clients map[*Client]bool
|
clients map[*Client]bool
|
||||||
clientAliveness map[*Client]*ClientAlivenessState
|
clientAliveness map[*Client]*ClientAlivenessState
|
||||||
rooms map[string]*Room
|
rooms map[string]*Room
|
||||||
@ -53,11 +51,10 @@ type Daemon struct {
|
|||||||
lastAlivenessCheck time.Time
|
lastAlivenessCheck time.Time
|
||||||
logSink chan<- LogEvent
|
logSink chan<- LogEvent
|
||||||
stateSink chan<- StateEvent
|
stateSink chan<- StateEvent
|
||||||
passwords map[string]string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDaemon(version, hostname, motd string, logSink chan<- LogEvent, stateSink chan<- StateEvent) *Daemon {
|
func NewDaemon(version string, hostname, motd, passwords *string, logSink chan<- LogEvent, stateSink chan<- StateEvent) *Daemon {
|
||||||
daemon := Daemon{version: version, hostname: hostname, motd: motd}
|
daemon := Daemon{version: version, hostname: hostname, motd: motd, passwords: passwords}
|
||||||
daemon.clients = make(map[*Client]bool)
|
daemon.clients = make(map[*Client]bool)
|
||||||
daemon.clientAliveness = make(map[*Client]*ClientAlivenessState)
|
daemon.clientAliveness = make(map[*Client]*ClientAlivenessState)
|
||||||
daemon.rooms = make(map[string]*Room)
|
daemon.rooms = make(map[string]*Room)
|
||||||
@ -78,19 +75,19 @@ func (daemon *Daemon) SendLusers(client *Client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) SendMotd(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")
|
client.ReplyNicknamed("422", "MOTD File is missing")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
motd, err := ioutil.ReadFile(daemon.motd)
|
motd, err := ioutil.ReadFile(*daemon.motd)
|
||||||
if err != nil {
|
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")
|
client.ReplyNicknamed("422", "Error reading MOTD File")
|
||||||
return
|
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") {
|
for _, s := range strings.Split(strings.Trim(string(motd), "\n"), "\n") {
|
||||||
client.ReplyNicknamed("372", "- "+string(s))
|
client.ReplyNicknamed("372", "- "+string(s))
|
||||||
}
|
}
|
||||||
@ -113,7 +110,7 @@ func (daemon *Daemon) SendWhois(client *Client, nicknames []string) {
|
|||||||
h = "Unknown"
|
h = "Unknown"
|
||||||
}
|
}
|
||||||
client.ReplyNicknamed("311", c.nickname, c.username, h, "*", c.realname)
|
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{}
|
subscriptions := []string{}
|
||||||
for _, room := range daemon.rooms {
|
for _, room := range daemon.rooms {
|
||||||
for subscriber := range room.members {
|
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], ":")
|
client.realname = strings.TrimLeft(args[3], ":")
|
||||||
}
|
}
|
||||||
if client.nickname != "*" && client.username != "" {
|
if client.nickname != "*" && client.username != "" {
|
||||||
passwordsRefreshLock.Lock()
|
if daemon.passwords != nil && *daemon.passwords != "" {
|
||||||
if daemon.passwords != nil && (client.password == "" || daemon.passwords[client.nickname] != client.password) {
|
if client.password == "" {
|
||||||
passwordsRefreshLock.Unlock()
|
client.ReplyParts("462", "You may not register")
|
||||||
client.ReplyParts("462", "You may not register")
|
client.conn.Close()
|
||||||
client.conn.Close()
|
return
|
||||||
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.registered = true
|
||||||
client.ReplyNicknamed("001", "Hi, welcome to IRC")
|
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("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.SendLusers(client)
|
||||||
daemon.SendMotd(client)
|
daemon.SendMotd(client)
|
||||||
log.Println(client, "logged in")
|
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 !aliveness.pingSent && aliveness.timestamp.Add(PingThreshold).Before(now) {
|
||||||
if c.registered {
|
if c.registered {
|
||||||
c.Msg("PING :" + daemon.hostname)
|
c.Msg("PING :" + *daemon.hostname)
|
||||||
aliveness.pingSent = true
|
aliveness.pingSent = true
|
||||||
} else {
|
} else {
|
||||||
log.Println(c, "ping timeout")
|
log.Println(c, "ping timeout")
|
||||||
@ -391,7 +403,7 @@ func (daemon *Daemon) Processor(events <-chan ClientEvent) {
|
|||||||
client.ReplyNicknamed("409", "No origin specified")
|
client.ReplyNicknamed("409", "No origin specified")
|
||||||
continue
|
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":
|
case "PONG":
|
||||||
continue
|
continue
|
||||||
case "NOTICE", "PRIVMSG":
|
case "NOTICE", "PRIVMSG":
|
||||||
@ -466,7 +478,7 @@ func (daemon *Daemon) Processor(events <-chan ClientEvent) {
|
|||||||
} else {
|
} else {
|
||||||
debug = ""
|
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:
|
default:
|
||||||
client.ReplyNicknamed("421", command, "Unknown command")
|
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()
|
|
||||||
}
|
|
||||||
|
@ -25,11 +25,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestRegistrationWorkflow(t *testing.T) {
|
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)
|
events := make(chan ClientEvent)
|
||||||
go daemon.Processor(events)
|
go daemon.Processor(events)
|
||||||
conn := NewTestingConn()
|
conn := NewTestingConn()
|
||||||
client := NewClient("foohost", conn)
|
client := NewClient(&host, conn)
|
||||||
go client.Processor(events)
|
go client.Processor(events)
|
||||||
|
|
||||||
conn.inbound <- "UNEXISTENT CMD" // should recieve nothing on this
|
conn.inbound <- "UNEXISTENT CMD" // should recieve nothing on this
|
||||||
@ -119,8 +120,10 @@ func TestMotd(t *testing.T) {
|
|||||||
fd.WriteString("catched\n")
|
fd.WriteString("catched\n")
|
||||||
|
|
||||||
conn := NewTestingConn()
|
conn := NewTestingConn()
|
||||||
client := NewClient("foohost", conn)
|
host := "foohost"
|
||||||
daemon := NewDaemon("ver1", "foohost", fd.Name(), nil, nil)
|
client := NewClient(&host, conn)
|
||||||
|
motdName := fd.Name()
|
||||||
|
daemon := NewDaemon("ver1", &host, &motdName, nil, nil, nil)
|
||||||
|
|
||||||
daemon.SendMotd(client)
|
daemon.SendMotd(client)
|
||||||
if r := <-conn.outbound; !strings.HasPrefix(r, ":foohost 375") {
|
if r := <-conn.outbound; !strings.HasPrefix(r, ":foohost 375") {
|
||||||
|
22
goircd.go
22
goircd.go
@ -23,12 +23,9 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
|
||||||
"os/signal"
|
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -53,7 +50,7 @@ func listenerLoop(sock net.Listener, events chan<- ClientEvent) {
|
|||||||
log.Println("Error during accepting connection", err)
|
log.Println("Error during accepting connection", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
client := NewClient(*hostname, conn)
|
client := NewClient(hostname, conn)
|
||||||
go client.Processor(events)
|
go client.Processor(events)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,9 +76,9 @@ func Run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
stateSink := make(chan StateEvent)
|
stateSink := make(chan StateEvent)
|
||||||
daemon := NewDaemon(version, *hostname, *motd, logSink, stateSink)
|
daemon := NewDaemon(version, hostname, motd, passwords, logSink, stateSink)
|
||||||
daemon.Verbose = *verbose
|
daemon.Verbose = *verbose
|
||||||
log.Println("goircd "+daemon.version+" is starting")
|
log.Println("goircd " + daemon.version + " is starting")
|
||||||
if *statedir == "" {
|
if *statedir == "" {
|
||||||
// Dummy statekeeper
|
// Dummy statekeeper
|
||||||
go func() {
|
go func() {
|
||||||
@ -115,19 +112,6 @@ func Run() {
|
|||||||
log.Println(*statedir, "statekeeper initialized")
|
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 != "" {
|
if *bind != "" {
|
||||||
listener, err := net.Listen("tcp", *bind)
|
listener, err := net.Listen("tcp", *bind)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
10
room.go
10
room.go
@ -41,16 +41,16 @@ type Room struct {
|
|||||||
topic string
|
topic string
|
||||||
key string
|
key string
|
||||||
members map[*Client]bool
|
members map[*Client]bool
|
||||||
hostname string
|
hostname *string
|
||||||
logSink chan<- LogEvent
|
logSink chan<- LogEvent
|
||||||
stateSink chan<- StateEvent
|
stateSink chan<- StateEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r Room) String() string {
|
func (room Room) String() string {
|
||||||
return r.name
|
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 := Room{name: name}
|
||||||
room.members = make(map[*Client]bool)
|
room.members = make(map[*Client]bool)
|
||||||
room.topic = ""
|
room.topic = ""
|
||||||
@ -128,7 +128,7 @@ func (room *Room) Processor(events <-chan ClientEvent) {
|
|||||||
room.StateSave()
|
room.StateSave()
|
||||||
case EventWho:
|
case EventWho:
|
||||||
for m := range room.members {
|
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")
|
client.ReplyNicknamed("315", room.name, "End of /WHO list")
|
||||||
case EventMode:
|
case EventMode:
|
||||||
|
12
room_test.go
12
room_test.go
@ -26,14 +26,15 @@ func notEnoughParams(t *testing.T, c *TestingConn) {
|
|||||||
func TestTwoUsers(t *testing.T) {
|
func TestTwoUsers(t *testing.T) {
|
||||||
logSink := make(chan LogEvent, 8)
|
logSink := make(chan LogEvent, 8)
|
||||||
stateSink := make(chan StateEvent, 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)
|
events := make(chan ClientEvent)
|
||||||
go daemon.Processor(events)
|
go daemon.Processor(events)
|
||||||
|
|
||||||
conn1 := NewTestingConn()
|
conn1 := NewTestingConn()
|
||||||
conn2 := NewTestingConn()
|
conn2 := NewTestingConn()
|
||||||
client1 := NewClient("foohost", conn1)
|
client1 := NewClient(&host, conn1)
|
||||||
client2 := NewClient("foohost", conn2)
|
client2 := NewClient(&host, conn2)
|
||||||
go client1.Processor(events)
|
go client1.Processor(events)
|
||||||
go client2.Processor(events)
|
go client2.Processor(events)
|
||||||
|
|
||||||
@ -100,11 +101,12 @@ func TestTwoUsers(t *testing.T) {
|
|||||||
func TestJoin(t *testing.T) {
|
func TestJoin(t *testing.T) {
|
||||||
logSink := make(chan LogEvent, 8)
|
logSink := make(chan LogEvent, 8)
|
||||||
stateSink := make(chan StateEvent, 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)
|
events := make(chan ClientEvent)
|
||||||
go daemon.Processor(events)
|
go daemon.Processor(events)
|
||||||
conn := NewTestingConn()
|
conn := NewTestingConn()
|
||||||
client := NewClient("foohost", conn)
|
client := NewClient(&host, conn)
|
||||||
go client.Processor(events)
|
go client.Processor(events)
|
||||||
|
|
||||||
conn.inbound <- "NICK nick2\r\nUSER foo2 bar2 baz2 :Long name2\r\n"
|
conn.inbound <- "NICK nick2\r\nUSER foo2 bar2 baz2 :Long name2\r\n"
|
||||||
|
Loading…
Reference in New Issue
Block a user