func (s *IRCd) manageServers() { defer s.running.Done() sid2conn := make(map[string]*conn.Conn) upstream := "" _ = upstream var open bool = true var msg *parser.Message for open { // Check if we are connected to our upstream // TODO(kevlar): upstream select { //// Incoming and outgoing messages to and from servers // Messages directly from connections case msg = <-s.fromServer: var conn *conn.Conn var ok bool if conn, ok = sid2conn[msg.SenderID]; !ok { log.Debug.Printf("{%s} >> [DROPPING] %s\n", msg.SenderID, msg) continue } log.Debug.Printf("{%s} >> %s\n", msg.SenderID, msg) if msg.Command == parser.CMD_ERROR { if conn != nil { log.Debug.Printf("{%s} ** Connection terminated remotely", msg.SenderID) sid2conn[msg.SenderID] = nil, false conn.UnsubscribeClose(s.serverClosing) conn.Close() if server.IsLocal(msg.SenderID) { DispatchServer(&parser.Message{ SenderID: msg.SenderID, Command: parser.CMD_SQUIT, Args: []string{ msg.SenderID, "Unexpected ERROR on connection", }, }, s) } } continue } DispatchServer(msg, s) // Messages from hooks case msg, open = <-s.ToServer: // Count the number of messages sent sentcount := 0 for _, dest := range msg.DestIDs { log.Debug.Printf("{%v} << %s\n", dest, msg) if conn, ok := sid2conn[dest]; ok { conn.WriteMessage(msg) sentcount++ } else { log.Warn.Printf("Unknown SID %s", dest) } } if sentcount == 0 { log.Warn.Printf("Dropped outgoing server message: %s", msg) } //// Connection management // Connecting servers case conn := <-s.newServer: sid := conn.ID() sid2conn[sid] = conn server.Get(sid, true) log.Debug.Printf("{%s} ** Registered connection", sid) conn.Subscribe(s.fromServer) conn.SubscribeClose(s.serverClosing) // Disconnecting servers case closeid := <-s.serverClosing: log.Debug.Printf("{%s} ** Connection closed", closeid) sid2conn[closeid] = nil, false if server.IsLocal(closeid) { DispatchServer(&parser.Message{ SenderID: closeid, Command: parser.CMD_SQUIT, Args: []string{ closeid, "Connection close", }, }, s) } } } }
// Handle the NICK, USER, SERVER, and PASS messages func ConnReg(hook string, msg *parser.Message, ircd *IRCd) { var err os.Error var u *user.User var s *server.Server switch len(msg.SenderID) { case 3: s = server.Get(msg.SenderID, true) case 9: u = user.Get(msg.SenderID) } switch msg.Command { case parser.CMD_NICK: // NICK <nick> if u != nil { nick := msg.Args[0] err = u.SetNick(nick) } case parser.CMD_USER: // USER <user> . . :<real name> if u != nil { username, realname := msg.Args[0], msg.Args[3] err = u.SetUser(username, realname) } case parser.CMD_PASS: if s != nil { if len(msg.Args) != 4 { return } // PASS <password> TS <ver> <pfx> err = s.SetPass(msg.Args[0], msg.Args[2], msg.Args[3]) } case parser.CMD_CAPAB: if s != nil { err = s.SetCapab(msg.Args[0]) } case parser.CMD_SERVER: if s != nil { err = s.SetServer(msg.Args[0], msg.Args[1]) } default: log.Warn.Printf("Unknown command %q", msg) } if u != nil { if err != nil { switch err := err.(type) { case *parser.Numeric: msg := err.Message() msg.DestIDs = append(msg.DestIDs, u.ID()) ircd.ToClient <- msg return default: msg := &parser.Message{ Command: parser.CMD_ERROR, Args: []string{err.String()}, DestIDs: []string{u.ID()}, } ircd.ToClient <- msg return } } nickname, username, realname, _ := u.Info() if nickname != "*" && username != "" { // Notify servers for sid := range server.Iter() { ircd.ToServer <- &parser.Message{ Prefix: Config.SID, Command: parser.CMD_UID, Args: []string{ nickname, "1", u.TS(), "+i", username, "some.host", "127.0.0.1", u.ID(), realname, }, DestIDs: []string{sid}, } } // Process signon sendSignon(u, ircd) return } } if s != nil { if err != nil { switch err := err.(type) { case *parser.Numeric: msg := err.Message() msg.DestIDs = append(msg.DestIDs, s.ID()) ircd.ToServer <- msg return default: msg := &parser.Message{ Command: parser.CMD_ERROR, Args: []string{err.String()}, DestIDs: []string{s.ID()}, } ircd.ToServer <- msg return } } sid, serv, pass, capab := s.Info() if sid != "" && serv != "" && pass != "" && len(capab) > 0 { // Notify servers for sid := range server.Iter() { ircd.ToServer <- &parser.Message{ Prefix: Config.SID, Command: parser.CMD_SID, Args: []string{ serv, "2", sid, "some server", }, DestIDs: []string{sid}, } } sendServerSignon(s, ircd) Burst(s, ircd) } } }