You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

server.go 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762
  1. package irc
  2. import (
  3. "bufio"
  4. "database/sql"
  5. "fmt"
  6. "log"
  7. "net"
  8. "net/http"
  9. "os"
  10. "os/signal"
  11. "strings"
  12. "syscall"
  13. "time"
  14. )
  15. type ServerCommand interface {
  16. Command
  17. HandleServer(*Server)
  18. }
  19. type RegServerCommand interface {
  20. Command
  21. HandleRegServer(*Server)
  22. }
  23. type Server struct {
  24. channels ChannelNameMap
  25. clients *ClientLookupSet
  26. commands chan Command
  27. ctime time.Time
  28. db *sql.DB
  29. idle chan *Client
  30. motdFile string
  31. name Name
  32. newConns chan net.Conn
  33. operators map[Name][]byte
  34. password []byte
  35. signals chan os.Signal
  36. whoWas *WhoWasList
  37. theaters map[Name][]byte
  38. }
  39. var (
  40. SERVER_SIGNALS = []os.Signal{syscall.SIGINT, syscall.SIGHUP,
  41. syscall.SIGTERM, syscall.SIGQUIT}
  42. )
  43. func NewServer(config *Config) *Server {
  44. server := &Server{
  45. channels: make(ChannelNameMap),
  46. clients: NewClientLookupSet(),
  47. commands: make(chan Command),
  48. ctime: time.Now(),
  49. db: OpenDB(config.Server.Database),
  50. idle: make(chan *Client),
  51. motdFile: config.Server.MOTD,
  52. name: NewName(config.Server.Name),
  53. newConns: make(chan net.Conn),
  54. operators: config.Operators(),
  55. signals: make(chan os.Signal, len(SERVER_SIGNALS)),
  56. whoWas: NewWhoWasList(100),
  57. theaters: config.Theaters(),
  58. }
  59. if config.Server.Password != "" {
  60. server.password = config.Server.PasswordBytes()
  61. }
  62. server.loadChannels()
  63. for _, addr := range config.Server.Listen {
  64. server.listen(addr)
  65. }
  66. if config.Server.Wslisten != "" {
  67. server.wslisten(config.Server.Wslisten)
  68. }
  69. signal.Notify(server.signals, SERVER_SIGNALS...)
  70. return server
  71. }
  72. func loadChannelList(channel *Channel, list string, maskMode ChannelMode) {
  73. if list == "" {
  74. return
  75. }
  76. channel.lists[maskMode].AddAll(NewNames(strings.Split(list, " ")))
  77. }
  78. func (server *Server) loadChannels() {
  79. rows, err := server.db.Query(`
  80. SELECT name, flags, key, topic, user_limit, ban_list, except_list,
  81. invite_list
  82. FROM channel`)
  83. if err != nil {
  84. log.Fatal("error loading channels: ", err)
  85. }
  86. for rows.Next() {
  87. var name, flags, key, topic string
  88. var userLimit uint64
  89. var banList, exceptList, inviteList string
  90. err = rows.Scan(&name, &flags, &key, &topic, &userLimit, &banList,
  91. &exceptList, &inviteList)
  92. if err != nil {
  93. log.Println("Server.loadChannels:", err)
  94. continue
  95. }
  96. channel := NewChannel(server, NewName(name))
  97. for _, flag := range flags {
  98. channel.flags[ChannelMode(flag)] = true
  99. }
  100. channel.key = NewText(key)
  101. channel.topic = NewText(topic)
  102. channel.userLimit = userLimit
  103. loadChannelList(channel, banList, BanMask)
  104. loadChannelList(channel, exceptList, ExceptMask)
  105. loadChannelList(channel, inviteList, InviteMask)
  106. }
  107. }
  108. func (server *Server) processCommand(cmd Command) {
  109. client := cmd.Client()
  110. if !client.registered {
  111. regCmd, ok := cmd.(RegServerCommand)
  112. if !ok {
  113. client.Quit("unexpected command")
  114. return
  115. }
  116. regCmd.HandleRegServer(server)
  117. return
  118. }
  119. srvCmd, ok := cmd.(ServerCommand)
  120. if !ok {
  121. client.ErrUnknownCommand(cmd.Code())
  122. return
  123. }
  124. switch srvCmd.(type) {
  125. case *PingCommand, *PongCommand:
  126. client.Touch()
  127. case *QuitCommand:
  128. // no-op
  129. default:
  130. client.Active()
  131. client.Touch()
  132. }
  133. srvCmd.HandleServer(server)
  134. }
  135. func (server *Server) Shutdown() {
  136. server.db.Close()
  137. for _, client := range server.clients.byNick {
  138. client.Reply(RplNotice(server, client, "shutting down"))
  139. }
  140. }
  141. func (server *Server) Run() {
  142. done := false
  143. for !done {
  144. select {
  145. case <-server.signals:
  146. server.Shutdown()
  147. done = true
  148. case conn := <-server.newConns:
  149. NewClient(server, conn)
  150. case cmd := <-server.commands:
  151. server.processCommand(cmd)
  152. case client := <-server.idle:
  153. client.Idle()
  154. }
  155. }
  156. }
  157. //
  158. // listen goroutine
  159. //
  160. func (s *Server) listen(addr string) {
  161. listener, err := net.Listen("tcp", addr)
  162. if err != nil {
  163. log.Fatal(s, "listen error: ", err)
  164. }
  165. Log.info.Printf("%s listening on %s", s, addr)
  166. go func() {
  167. for {
  168. conn, err := listener.Accept()
  169. if err != nil {
  170. Log.error.Printf("%s accept error: %s", s, err)
  171. continue
  172. }
  173. Log.debug.Printf("%s accept: %s", s, conn.RemoteAddr())
  174. s.newConns <- conn
  175. }
  176. }()
  177. }
  178. //
  179. // websocket listen goroutine
  180. //
  181. func (s *Server) wslisten(addr string) {
  182. http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  183. if r.Method != "GET" {
  184. Log.error.Printf("%s method not allowed", s)
  185. return
  186. }
  187. ws, err := upgrader.Upgrade(w, r, nil)
  188. if err != nil {
  189. Log.error.Printf("%s websocket upgrade error: %s", s, err)
  190. return
  191. }
  192. wsc := WSContainer{
  193. conn: ws,
  194. }
  195. s.newConns <- wsc
  196. })
  197. go func() {
  198. Log.info.Printf("%s listening on %s", s, addr)
  199. err := http.ListenAndServe(addr, nil)
  200. if err != nil {
  201. Log.error.Printf("%s listenAndServe error: %s", s, err)
  202. }
  203. }()
  204. }
  205. //
  206. // server functionality
  207. //
  208. func (s *Server) tryRegister(c *Client) {
  209. if c.registered || !c.HasNick() || !c.HasUsername() ||
  210. (c.capState == CapNegotiating) {
  211. return
  212. }
  213. c.Register()
  214. c.RplWelcome()
  215. c.RplYourHost()
  216. c.RplCreated()
  217. c.RplMyInfo()
  218. s.MOTD(c)
  219. }
  220. func (server *Server) MOTD(client *Client) {
  221. if server.motdFile == "" {
  222. client.ErrNoMOTD()
  223. return
  224. }
  225. file, err := os.Open(server.motdFile)
  226. if err != nil {
  227. client.ErrNoMOTD()
  228. return
  229. }
  230. defer file.Close()
  231. client.RplMOTDStart()
  232. reader := bufio.NewReader(file)
  233. for {
  234. line, err := reader.ReadString('\n')
  235. if err != nil {
  236. break
  237. }
  238. line = strings.TrimRight(line, "\r\n")
  239. if len(line) > 80 {
  240. for len(line) > 80 {
  241. client.RplMOTD(line[0:80])
  242. line = line[80:]
  243. }
  244. if len(line) > 0 {
  245. client.RplMOTD(line)
  246. }
  247. } else {
  248. client.RplMOTD(line)
  249. }
  250. }
  251. client.RplMOTDEnd()
  252. }
  253. func (s *Server) Id() Name {
  254. return s.name
  255. }
  256. func (s *Server) String() string {
  257. return s.name.String()
  258. }
  259. func (s *Server) Nick() Name {
  260. return s.Id()
  261. }
  262. func (server *Server) Reply(target *Client, message string) {
  263. target.Reply(RplPrivMsg(server, target, NewText(message)))
  264. }
  265. func (server *Server) Replyf(target *Client, format string, args ...interface{}) {
  266. server.Reply(target, fmt.Sprintf(format, args...))
  267. }
  268. //
  269. // registration commands
  270. //
  271. func (msg *PassCommand) HandleRegServer(server *Server) {
  272. client := msg.Client()
  273. if msg.err != nil {
  274. client.ErrPasswdMismatch()
  275. client.Quit("bad password")
  276. return
  277. }
  278. client.authorized = true
  279. }
  280. func (msg *ProxyCommand) HandleRegServer(server *Server) {
  281. msg.Client().hostname = msg.hostname
  282. }
  283. func (msg *RFC1459UserCommand) HandleRegServer(server *Server) {
  284. client := msg.Client()
  285. if !client.authorized {
  286. client.ErrPasswdMismatch()
  287. client.Quit("bad password")
  288. return
  289. }
  290. msg.setUserInfo(server)
  291. }
  292. func (msg *RFC2812UserCommand) HandleRegServer(server *Server) {
  293. client := msg.Client()
  294. if !client.authorized {
  295. client.ErrPasswdMismatch()
  296. client.Quit("bad password")
  297. return
  298. }
  299. flags := msg.Flags()
  300. if len(flags) > 0 {
  301. for _, mode := range flags {
  302. client.flags[mode] = true
  303. }
  304. client.RplUModeIs(client)
  305. }
  306. msg.setUserInfo(server)
  307. }
  308. func (msg *UserCommand) setUserInfo(server *Server) {
  309. client := msg.Client()
  310. if client.capState == CapNegotiating {
  311. client.capState = CapNegotiated
  312. }
  313. server.clients.Remove(client)
  314. client.username, client.realname = msg.username, msg.realname
  315. server.clients.Add(client)
  316. server.tryRegister(client)
  317. }
  318. func (msg *QuitCommand) HandleRegServer(server *Server) {
  319. msg.Client().Quit(msg.message)
  320. }
  321. //
  322. // normal commands
  323. //
  324. func (m *PassCommand) HandleServer(s *Server) {
  325. m.Client().ErrAlreadyRegistered()
  326. }
  327. func (m *PingCommand) HandleServer(s *Server) {
  328. client := m.Client()
  329. client.Reply(RplPong(client, m.server.Text()))
  330. }
  331. func (m *PongCommand) HandleServer(s *Server) {
  332. // no-op
  333. }
  334. func (m *UserCommand) HandleServer(s *Server) {
  335. m.Client().ErrAlreadyRegistered()
  336. }
  337. func (msg *QuitCommand) HandleServer(server *Server) {
  338. msg.Client().Quit(msg.message)
  339. }
  340. func (m *JoinCommand) HandleServer(s *Server) {
  341. client := m.Client()
  342. if m.zero {
  343. for channel := range client.channels {
  344. channel.Part(client, client.Nick().Text())
  345. }
  346. return
  347. }
  348. for name, key := range m.channels {
  349. if !name.IsChannel() {
  350. client.ErrNoSuchChannel(name)
  351. continue
  352. }
  353. channel := s.channels.Get(name)
  354. if channel == nil {
  355. channel = NewChannel(s, name)
  356. }
  357. channel.Join(client, key)
  358. }
  359. }
  360. func (m *PartCommand) HandleServer(server *Server) {
  361. client := m.Client()
  362. for _, chname := range m.channels {
  363. channel := server.channels.Get(chname)
  364. if channel == nil {
  365. m.Client().ErrNoSuchChannel(chname)
  366. continue
  367. }
  368. channel.Part(client, m.Message())
  369. }
  370. }
  371. func (msg *TopicCommand) HandleServer(server *Server) {
  372. client := msg.Client()
  373. channel := server.channels.Get(msg.channel)
  374. if channel == nil {
  375. client.ErrNoSuchChannel(msg.channel)
  376. return
  377. }
  378. if msg.setTopic {
  379. channel.SetTopic(client, msg.topic)
  380. } else {
  381. channel.GetTopic(client)
  382. }
  383. }
  384. func (msg *PrivMsgCommand) HandleServer(server *Server) {
  385. client := msg.Client()
  386. if msg.target.IsChannel() {
  387. channel := server.channels.Get(msg.target)
  388. if channel == nil {
  389. client.ErrNoSuchChannel(msg.target)
  390. return
  391. }
  392. channel.PrivMsg(client, msg.message)
  393. return
  394. }
  395. target := server.clients.Get(msg.target)
  396. if target == nil {
  397. client.ErrNoSuchNick(msg.target)
  398. return
  399. }
  400. target.Reply(RplPrivMsg(client, target, msg.message))
  401. if target.flags[Away] {
  402. client.RplAway(target)
  403. }
  404. }
  405. func (client *Client) WhoisChannelsNames() []string {
  406. chstrs := make([]string, len(client.channels))
  407. index := 0
  408. for channel := range client.channels {
  409. switch {
  410. case channel.members[client][ChannelOperator]:
  411. chstrs[index] = "@" + channel.name.String()
  412. case channel.members[client][Voice]:
  413. chstrs[index] = "+" + channel.name.String()
  414. default:
  415. chstrs[index] = channel.name.String()
  416. }
  417. index += 1
  418. }
  419. return chstrs
  420. }
  421. func (m *WhoisCommand) HandleServer(server *Server) {
  422. client := m.Client()
  423. // TODO implement target query
  424. for _, mask := range m.masks {
  425. matches := server.clients.FindAll(mask)
  426. if len(matches) == 0 {
  427. client.ErrNoSuchNick(mask)
  428. continue
  429. }
  430. for mclient := range matches {
  431. client.RplWhois(mclient)
  432. }
  433. }
  434. }
  435. func whoChannel(client *Client, channel *Channel, friends ClientSet) {
  436. for member := range channel.members {
  437. if !client.flags[Invisible] || friends[client] {
  438. client.RplWhoReply(channel, member)
  439. }
  440. }
  441. }
  442. func (msg *WhoCommand) HandleServer(server *Server) {
  443. client := msg.Client()
  444. friends := client.Friends()
  445. mask := msg.mask
  446. if mask == "" {
  447. for _, channel := range server.channels {
  448. whoChannel(client, channel, friends)
  449. }
  450. } else if mask.IsChannel() {
  451. // TODO implement wildcard matching
  452. channel := server.channels.Get(mask)
  453. if channel != nil {
  454. whoChannel(client, channel, friends)
  455. }
  456. } else {
  457. for mclient := range server.clients.FindAll(mask) {
  458. client.RplWhoReply(nil, mclient)
  459. }
  460. }
  461. client.RplEndOfWho(mask)
  462. }
  463. func (msg *OperCommand) HandleServer(server *Server) {
  464. client := msg.Client()
  465. if (msg.hash == nil) || (msg.err != nil) {
  466. client.ErrPasswdMismatch()
  467. return
  468. }
  469. client.flags[Operator] = true
  470. client.RplYoureOper()
  471. client.Reply(RplModeChanges(client, client, ModeChanges{&ModeChange{
  472. mode: Operator,
  473. op: Add,
  474. }}))
  475. }
  476. func (msg *AwayCommand) HandleServer(server *Server) {
  477. client := msg.Client()
  478. if len(msg.text) > 0 {
  479. client.flags[Away] = true
  480. } else {
  481. delete(client.flags, Away)
  482. }
  483. client.awayMessage = msg.text
  484. var op ModeOp
  485. if client.flags[Away] {
  486. op = Add
  487. client.RplNowAway()
  488. } else {
  489. op = Remove
  490. client.RplUnAway()
  491. }
  492. client.Reply(RplModeChanges(client, client, ModeChanges{&ModeChange{
  493. mode: Away,
  494. op: op,
  495. }}))
  496. }
  497. func (msg *IsOnCommand) HandleServer(server *Server) {
  498. client := msg.Client()
  499. ison := make([]string, 0)
  500. for _, nick := range msg.nicks {
  501. if iclient := server.clients.Get(nick); iclient != nil {
  502. ison = append(ison, iclient.Nick().String())
  503. }
  504. }
  505. client.RplIsOn(ison)
  506. }
  507. func (msg *MOTDCommand) HandleServer(server *Server) {
  508. server.MOTD(msg.Client())
  509. }
  510. func (msg *NoticeCommand) HandleServer(server *Server) {
  511. client := msg.Client()
  512. if msg.target.IsChannel() {
  513. channel := server.channels.Get(msg.target)
  514. if channel == nil {
  515. client.ErrNoSuchChannel(msg.target)
  516. return
  517. }
  518. channel.Notice(client, msg.message)
  519. return
  520. }
  521. target := server.clients.Get(msg.target)
  522. if target == nil {
  523. client.ErrNoSuchNick(msg.target)
  524. return
  525. }
  526. target.Reply(RplNotice(client, target, msg.message))
  527. }
  528. func (msg *KickCommand) HandleServer(server *Server) {
  529. client := msg.Client()
  530. for chname, nickname := range msg.kicks {
  531. channel := server.channels.Get(chname)
  532. if channel == nil {
  533. client.ErrNoSuchChannel(chname)
  534. continue
  535. }
  536. target := server.clients.Get(nickname)
  537. if target == nil {
  538. client.ErrNoSuchNick(nickname)
  539. continue
  540. }
  541. channel.Kick(client, target, msg.Comment())
  542. }
  543. }
  544. func (msg *ListCommand) HandleServer(server *Server) {
  545. client := msg.Client()
  546. // TODO target server
  547. if msg.target != "" {
  548. client.ErrNoSuchServer(msg.target)
  549. return
  550. }
  551. if len(msg.channels) == 0 {
  552. for _, channel := range server.channels {
  553. if !client.flags[Operator] && channel.flags[Private] {
  554. continue
  555. }
  556. client.RplList(channel)
  557. }
  558. } else {
  559. for _, chname := range msg.channels {
  560. channel := server.channels.Get(chname)
  561. if channel == nil || (!client.flags[Operator] && channel.flags[Private]) {
  562. client.ErrNoSuchChannel(chname)
  563. continue
  564. }
  565. client.RplList(channel)
  566. }
  567. }
  568. client.RplListEnd(server)
  569. }
  570. func (msg *NamesCommand) HandleServer(server *Server) {
  571. client := msg.Client()
  572. if len(server.channels) == 0 {
  573. for _, channel := range server.channels {
  574. channel.Names(client)
  575. }
  576. return
  577. }
  578. for _, chname := range msg.channels {
  579. channel := server.channels.Get(chname)
  580. if channel == nil {
  581. client.ErrNoSuchChannel(chname)
  582. continue
  583. }
  584. channel.Names(client)
  585. }
  586. }
  587. func (msg *VersionCommand) HandleServer(server *Server) {
  588. client := msg.Client()
  589. if (msg.target != "") && (msg.target != server.name) {
  590. client.ErrNoSuchServer(msg.target)
  591. return
  592. }
  593. client.RplVersion()
  594. }
  595. func (msg *InviteCommand) HandleServer(server *Server) {
  596. client := msg.Client()
  597. target := server.clients.Get(msg.nickname)
  598. if target == nil {
  599. client.ErrNoSuchNick(msg.nickname)
  600. return
  601. }
  602. channel := server.channels.Get(msg.channel)
  603. if channel == nil {
  604. client.RplInviting(target, msg.channel)
  605. target.Reply(RplInviteMsg(client, target, msg.channel))
  606. return
  607. }
  608. channel.Invite(target, client)
  609. }
  610. func (msg *TimeCommand) HandleServer(server *Server) {
  611. client := msg.Client()
  612. if (msg.target != "") && (msg.target != server.name) {
  613. client.ErrNoSuchServer(msg.target)
  614. return
  615. }
  616. client.RplTime()
  617. }
  618. func (msg *KillCommand) HandleServer(server *Server) {
  619. client := msg.Client()
  620. if !client.flags[Operator] {
  621. client.ErrNoPrivileges()
  622. return
  623. }
  624. target := server.clients.Get(msg.nickname)
  625. if target == nil {
  626. client.ErrNoSuchNick(msg.nickname)
  627. return
  628. }
  629. quitMsg := fmt.Sprintf("KILLed by %s: %s", client.Nick(), msg.comment)
  630. target.Quit(NewText(quitMsg))
  631. }
  632. func (msg *WhoWasCommand) HandleServer(server *Server) {
  633. client := msg.Client()
  634. for _, nickname := range msg.nicknames {
  635. results := server.whoWas.Find(nickname, msg.count)
  636. if len(results) == 0 {
  637. client.ErrWasNoSuchNick(nickname)
  638. } else {
  639. for _, whoWas := range results {
  640. client.RplWhoWasUser(whoWas)
  641. }
  642. }
  643. client.RplEndOfWhoWas(nickname)
  644. }
  645. }