diff --git a/cmd/jounce/main.go b/cmd/jounce/main.go index 509bd52..9f3c37a 100644 --- a/cmd/jounce/main.go +++ b/cmd/jounce/main.go @@ -15,20 +15,18 @@ func main() { log.Fatalf("failed to start listener: %v", err) } + srv := jounce.NewServer() // TODO: load from config/DB - s := jounce.Server{ - Hostname: "localhost", - Logger: log.New(log.Writer(), "", log.LstdFlags), - Upstreams: []jounce.Upstream{{ - Addr: "chat.freenode.net:6697", - Nick: "jounce", - Username: "jounce", - Realname: "jounce", - Channels: []string{"#jounce"}, - }}, - } + srv.Hostname = "localhost" + srv.Upstreams = []jounce.Upstream{{ + Addr: "chat.freenode.net:6697", + Nick: "jounce", + Username: "jounce", + Realname: "jounce", + Channels: []string{"#jounce"}, + }} log.Printf("Server listening on %v", addr) - go s.Run() - log.Fatal(s.Serve(ln)) + go srv.Run() + log.Fatal(srv.Serve(ln)) } diff --git a/downstream.go b/downstream.go index ef18829..6926742 100644 --- a/downstream.go +++ b/downstream.go @@ -46,6 +46,7 @@ type downstreamConn struct { messages chan<- *irc.Message registered bool + user *user closed bool nick string username string @@ -166,40 +167,50 @@ func (c *downstreamConn) handleMessageUnregistered(msg *irc.Message) error { } func (c *downstreamConn) register() error { + c.srv.lock.Lock() + u, ok := c.srv.users[c.username] + c.srv.lock.Unlock() + + if !ok { + c.messages <- &irc.Message{ + Prefix: c.srv.prefix(), + Command: irc.ERR_PASSWDMISMATCH, + Params: []string{"*", "Invalid username or password"}, + } + return nil + } + c.registered = true + c.user = u c.messages <- &irc.Message{ Prefix: c.srv.prefix(), Command: irc.RPL_WELCOME, Params: []string{c.nick, "Welcome to jounce, " + c.nick}, } - c.messages <- &irc.Message{ Prefix: c.srv.prefix(), Command: irc.RPL_YOURHOST, Params: []string{c.nick, "Your host is " + c.srv.Hostname}, } - c.messages <- &irc.Message{ Prefix: c.srv.prefix(), Command: irc.RPL_CREATED, Params: []string{c.nick, "This server was created "}, // TODO } - c.messages <- &irc.Message{ Prefix: c.srv.prefix(), Command: irc.RPL_MYINFO, Params: []string{c.nick, c.srv.Hostname, "jounce", "aiwroO", "OovaimnqpsrtklbeI"}, } - c.messages <- &irc.Message{ Prefix: c.srv.prefix(), Command: irc.ERR_NOMOTD, Params: []string{c.nick, "No MOTD"}, } - c.srv.lock.Lock() - for _, uc := range c.srv.upstreamConns { + u.lock.Lock() + for _, uc := range u.upstreamConns { // TODO: fix races accessing upstream connection data if !uc.registered { continue @@ -210,7 +221,7 @@ func (c *downstreamConn) register() error { } } } - c.srv.lock.Unlock() + u.lock.Unlock() return nil } diff --git a/server.go b/server.go index dc0a193..f89177e 100644 --- a/server.go +++ b/server.go @@ -2,6 +2,7 @@ package jounce import ( "fmt" + "log" "net" "sync" @@ -30,6 +31,14 @@ func (l *prefixLogger) Printf(format string, v ...interface{}) { l.logger.Printf("%v"+format, v...) } +type user struct { + username string + srv *Server + + lock sync.Mutex + upstreamConns []*upstreamConn +} + type Upstream struct { Addr string Nick string @@ -44,8 +53,15 @@ type Server struct { Upstreams []Upstream // TODO: per-user lock sync.Mutex + users map[string]*user downstreamConns []*downstreamConn - upstreamConns []*upstreamConn +} + +func NewServer() *Server { + return &Server{ + Logger: log.New(log.Writer(), "", log.LstdFlags), + users: make(map[string]*user), + } } func (s *Server) prefix() *irc.Prefix { @@ -53,32 +69,39 @@ func (s *Server) prefix() *irc.Prefix { } func (s *Server) Run() { + // TODO: multi-user + u := &user{username: "jounce", srv: s} + + s.lock.Lock() + s.users[u.username] = u + s.lock.Unlock() + for i := range s.Upstreams { upstream := &s.Upstreams[i] // TODO: retry connecting go func() { - conn, err := connectToUpstream(s, upstream) + conn, err := connectToUpstream(u, upstream) if err != nil { s.Logger.Printf("failed to connect to upstream server %q: %v", upstream.Addr, err) return } - s.lock.Lock() - s.upstreamConns = append(s.upstreamConns, conn) - s.lock.Unlock() + u.lock.Lock() + u.upstreamConns = append(u.upstreamConns, conn) + u.lock.Unlock() if err := conn.readMessages(); err != nil { conn.logger.Printf("failed to handle messages: %v", err) } - s.lock.Lock() - for i, c := range s.upstreamConns { + u.lock.Lock() + for i, c := range u.upstreamConns { if c == conn { - s.upstreamConns = append(s.upstreamConns[:i], s.upstreamConns[i+1:]...) + u.upstreamConns = append(u.upstreamConns[:i], u.upstreamConns[i+1:]...) break } } - s.lock.Unlock() + u.lock.Unlock() }() } } diff --git a/upstream.go b/upstream.go index 5394c2e..b5200c0 100644 --- a/upstream.go +++ b/upstream.go @@ -29,6 +29,7 @@ type upstreamConn struct { net net.Conn irc *irc.Conn srv *Server + user *user messages chan<- *irc.Message serverName string @@ -42,8 +43,8 @@ type upstreamConn struct { channels map[string]*upstreamChannel } -func connectToUpstream(s *Server, upstream *Upstream) (*upstreamConn, error) { - logger := &prefixLogger{s.Logger, fmt.Sprintf("upstream %q: ", upstream.Addr)} +func connectToUpstream(u *user, upstream *Upstream) (*upstreamConn, error) { + logger := &prefixLogger{u.srv.Logger, fmt.Sprintf("upstream %q: ", upstream.Addr)} logger.Printf("connecting to server") netConn, err := tls.Dial("tcp", upstream.Addr, nil) @@ -57,7 +58,8 @@ func connectToUpstream(s *Server, upstream *Upstream) (*upstreamConn, error) { logger: logger, net: netConn, irc: irc.NewConn(netConn), - srv: s, + srv: u.srv, + user: u, messages: msgs, channels: make(map[string]*upstreamChannel), }