server.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. package guerrilla
  2. import (
  3. "crypto/rand"
  4. "crypto/tls"
  5. "fmt"
  6. "io"
  7. "net"
  8. "strings"
  9. "sync"
  10. "sync/atomic"
  11. "time"
  12. "crypto/x509"
  13. "github.com/flashmob/go-guerrilla/backends"
  14. "github.com/flashmob/go-guerrilla/log"
  15. "github.com/flashmob/go-guerrilla/mail"
  16. "github.com/flashmob/go-guerrilla/response"
  17. "io/ioutil"
  18. )
  19. const (
  20. CommandVerbMaxLength = 16
  21. CommandLineMaxLength = 1024
  22. // Number of allowed unrecognized commands before we terminate the connection
  23. MaxUnrecognizedCommands = 5
  24. // The maximum total length of a reverse-path or forward-path is 256
  25. RFC2821LimitPath = 256
  26. // The maximum total length of a user name or other local-part is 64
  27. RFC2832LimitLocalPart = 64
  28. //The maximum total length of a domain name or number is 255
  29. RFC2821LimitDomain = 255
  30. // The minimum total number of recipients that must be buffered is 100
  31. RFC2821LimitRecipients = 100
  32. )
  33. const (
  34. // server has just been created
  35. ServerStateNew = iota
  36. // Server has just been stopped
  37. ServerStateStopped
  38. // Server has been started and is running
  39. ServerStateRunning
  40. // Server could not start due to an error
  41. ServerStateStartError
  42. )
  43. // Server listens for SMTP clients on the port specified in its config
  44. type server struct {
  45. configStore atomic.Value // stores guerrilla.ServerConfig
  46. tlsConfigStore atomic.Value
  47. timeout atomic.Value // stores time.Duration
  48. listenInterface string
  49. clientPool *Pool
  50. wg sync.WaitGroup // for waiting to shutdown
  51. listener net.Listener
  52. closedListener chan (bool)
  53. hosts allowedHosts // stores map[string]bool for faster lookup
  54. state int
  55. // If log changed after a config reload, newLogStore stores the value here until it's safe to change it
  56. logStore atomic.Value
  57. mainlogStore atomic.Value
  58. backendStore atomic.Value
  59. envelopePool *mail.Pool
  60. }
  61. type allowedHosts struct {
  62. table map[string]bool // host lookup table
  63. sync.Mutex // guard access to the map
  64. }
  65. // Creates and returns a new ready-to-run Server from a configuration
  66. func newServer(sc *ServerConfig, b backends.Backend, l log.Logger) (*server, error) {
  67. server := &server{
  68. clientPool: NewPool(sc.MaxClients),
  69. closedListener: make(chan (bool), 1),
  70. listenInterface: sc.ListenInterface,
  71. state: ServerStateNew,
  72. envelopePool: mail.NewPool(sc.MaxClients),
  73. }
  74. server.logStore.Store(l)
  75. server.backendStore.Store(b)
  76. logFile := sc.LogFile
  77. if logFile == "" {
  78. // none set, use the same log file as mainlog
  79. logFile = server.mainlog().GetLogDest()
  80. }
  81. // set level to same level as mainlog level
  82. mainlog, logOpenError := log.GetLogger(logFile, server.mainlog().GetLevel())
  83. server.mainlogStore.Store(mainlog)
  84. if logOpenError != nil {
  85. server.log().WithError(logOpenError).Errorf("Failed creating a logger for server [%s]", sc.ListenInterface)
  86. }
  87. server.setConfig(sc)
  88. server.setTimeout(sc.Timeout)
  89. if err := server.configureSSL(); err != nil {
  90. return server, err
  91. }
  92. return server, nil
  93. }
  94. func (s *server) configureSSL() error {
  95. sConfig := s.configStore.Load().(ServerConfig)
  96. if sConfig.TLS.AlwaysOn || sConfig.TLS.StartTLSOn {
  97. cert, err := tls.LoadX509KeyPair(sConfig.TLS.PublicKeyFile, sConfig.TLS.PrivateKeyFile)
  98. if err != nil {
  99. return fmt.Errorf("error while loading the certificate: %s", err)
  100. }
  101. tlsConfig := &tls.Config{
  102. Certificates: []tls.Certificate{cert},
  103. ClientAuth: tls.VerifyClientCertIfGiven,
  104. ServerName: sConfig.Hostname,
  105. }
  106. if len(sConfig.TLS.Protocols) > 0 {
  107. if min, ok := TLSProtocols[sConfig.TLS.Protocols[0]]; ok {
  108. tlsConfig.MinVersion = min
  109. }
  110. }
  111. if len(sConfig.TLS.Protocols) > 1 {
  112. if max, ok := TLSProtocols[sConfig.TLS.Protocols[1]]; ok {
  113. tlsConfig.MaxVersion = max
  114. }
  115. }
  116. if len(sConfig.TLS.Ciphers) > 0 {
  117. for _, val := range sConfig.TLS.Ciphers {
  118. if c, ok := TLSCiphers[val]; ok {
  119. tlsConfig.CipherSuites = append(tlsConfig.CipherSuites, c)
  120. }
  121. }
  122. }
  123. if len(sConfig.TLS.Curves) > 0 {
  124. for _, val := range sConfig.TLS.Curves {
  125. if c, ok := TLSCurves[val]; ok {
  126. tlsConfig.CurvePreferences = append(tlsConfig.CurvePreferences, c)
  127. }
  128. }
  129. }
  130. if len(sConfig.TLS.RootCAs) > 0 {
  131. caCert, err := ioutil.ReadFile(sConfig.TLS.RootCAs)
  132. if err != nil {
  133. s.log().WithError(err).Errorf("failed opening TLSRootCAs file [%s]", sConfig.TLS.RootCAs)
  134. } else {
  135. caCertPool := x509.NewCertPool()
  136. caCertPool.AppendCertsFromPEM(caCert)
  137. tlsConfig.RootCAs = caCertPool
  138. }
  139. }
  140. if len(sConfig.TLS.ClientAuthType) > 0 {
  141. if ca, ok := TLSClientAuthTypes[sConfig.TLS.ClientAuthType]; ok {
  142. tlsConfig.ClientAuth = ca
  143. }
  144. }
  145. tlsConfig.PreferServerCipherSuites = sConfig.TLS.PreferServerCipherSuites
  146. tlsConfig.Rand = rand.Reader
  147. s.tlsConfigStore.Store(tlsConfig)
  148. }
  149. return nil
  150. }
  151. // setBackend sets the backend to use for processing email envelopes
  152. func (s *server) setBackend(b backends.Backend) {
  153. s.backendStore.Store(b)
  154. }
  155. // backend gets the backend used to process email envelopes
  156. func (s *server) backend() backends.Backend {
  157. if b, ok := s.backendStore.Load().(backends.Backend); ok {
  158. return b
  159. }
  160. return nil
  161. }
  162. // Set the timeout for the server and all clients
  163. func (server *server) setTimeout(seconds int) {
  164. duration := time.Duration(int64(seconds))
  165. server.clientPool.SetTimeout(duration)
  166. server.timeout.Store(duration)
  167. }
  168. // goroutine safe config store
  169. func (server *server) setConfig(sc *ServerConfig) {
  170. server.configStore.Store(*sc)
  171. }
  172. // goroutine safe
  173. func (server *server) isEnabled() bool {
  174. sc := server.configStore.Load().(ServerConfig)
  175. return sc.IsEnabled
  176. }
  177. // Set the allowed hosts for the server
  178. func (server *server) setAllowedHosts(allowedHosts []string) {
  179. server.hosts.Lock()
  180. defer server.hosts.Unlock()
  181. server.hosts.table = make(map[string]bool, len(allowedHosts))
  182. for _, h := range allowedHosts {
  183. server.hosts.table[strings.ToLower(h)] = true
  184. }
  185. }
  186. // Begin accepting SMTP clients. Will block unless there is an error or server.Shutdown() is called
  187. func (server *server) Start(startWG *sync.WaitGroup) error {
  188. var clientID uint64
  189. clientID = 0
  190. listener, err := net.Listen("tcp", server.listenInterface)
  191. server.listener = listener
  192. if err != nil {
  193. startWG.Done() // don't wait for me
  194. server.state = ServerStateStartError
  195. return fmt.Errorf("[%s] Cannot listen on port: %s ", server.listenInterface, err.Error())
  196. }
  197. server.log().Infof("Listening on TCP %s", server.listenInterface)
  198. server.state = ServerStateRunning
  199. startWG.Done() // start successful, don't wait for me
  200. for {
  201. server.log().Debugf("[%s] Waiting for a new client. Next Client ID: %d", server.listenInterface, clientID+1)
  202. conn, err := listener.Accept()
  203. clientID++
  204. if err != nil {
  205. if e, ok := err.(net.Error); ok && !e.Temporary() {
  206. server.log().Infof("Server [%s] has stopped accepting new clients", server.listenInterface)
  207. // the listener has been closed, wait for clients to exit
  208. server.log().Infof("shutting down pool [%s]", server.listenInterface)
  209. server.clientPool.ShutdownState()
  210. server.clientPool.ShutdownWait()
  211. server.state = ServerStateStopped
  212. server.closedListener <- true
  213. return nil
  214. }
  215. server.mainlog().WithError(err).Info("Temporary error accepting client")
  216. continue
  217. }
  218. go func(p Poolable, borrow_err error) {
  219. c := p.(*client)
  220. if borrow_err == nil {
  221. server.handleClient(c)
  222. server.envelopePool.Return(c.Envelope)
  223. server.clientPool.Return(c)
  224. } else {
  225. server.log().WithError(borrow_err).Info("couldn't borrow a new client")
  226. // we could not get a client, so close the connection.
  227. conn.Close()
  228. }
  229. // intentionally placed Borrow in args so that it's called in the
  230. // same main goroutine.
  231. }(server.clientPool.Borrow(conn, clientID, server.log(), server.envelopePool))
  232. }
  233. }
  234. func (server *server) Shutdown() {
  235. if server.listener != nil {
  236. // This will cause Start function to return, by causing an error on listener.Accept
  237. server.listener.Close()
  238. // wait for the listener to listener.Accept
  239. <-server.closedListener
  240. // At this point Start will exit and close down the pool
  241. } else {
  242. server.clientPool.ShutdownState()
  243. // listener already closed, wait for clients to exit
  244. server.clientPool.ShutdownWait()
  245. server.state = ServerStateStopped
  246. }
  247. }
  248. func (server *server) GetActiveClientsCount() int {
  249. return server.clientPool.GetActiveClientsCount()
  250. }
  251. // Verifies that the host is a valid recipient.
  252. // host checking turned off if there is a single entry and it's a dot.
  253. func (server *server) allowsHost(host string) bool {
  254. server.hosts.Lock()
  255. defer server.hosts.Unlock()
  256. if len(server.hosts.table) == 1 {
  257. if _, ok := server.hosts.table["."]; ok {
  258. return true
  259. }
  260. }
  261. if _, ok := server.hosts.table[strings.ToLower(host)]; ok {
  262. return true
  263. }
  264. return false
  265. }
  266. // Reads from the client until a terminating sequence is encountered,
  267. // or until a timeout occurs.
  268. func (server *server) readCommand(client *client, maxSize int64) (string, error) {
  269. var input, reply string
  270. var err error
  271. // In command state, stop reading at line breaks
  272. suffix := "\r\n"
  273. for {
  274. client.setTimeout(server.timeout.Load().(time.Duration))
  275. reply, err = client.bufin.ReadString('\n')
  276. input = input + reply
  277. if err != nil {
  278. break
  279. }
  280. if strings.HasSuffix(input, suffix) {
  281. // discard the suffix and stop reading
  282. input = input[0 : len(input)-len(suffix)]
  283. break
  284. }
  285. }
  286. return input, err
  287. }
  288. // flushResponse a response to the client. Flushes the client.bufout buffer to the connection
  289. func (server *server) flushResponse(client *client) error {
  290. client.setTimeout(server.timeout.Load().(time.Duration))
  291. return client.bufout.Flush()
  292. }
  293. func (server *server) isShuttingDown() bool {
  294. return server.clientPool.IsShuttingDown()
  295. }
  296. // Handles an entire client SMTP exchange
  297. func (server *server) handleClient(client *client) {
  298. defer func() {
  299. server.log().WithFields(map[string]interface{}{
  300. "event": "disconnect",
  301. "id": client.ID,
  302. }).Info("Disconnect client")
  303. client.closeConn()
  304. }()
  305. sc := server.configStore.Load().(ServerConfig)
  306. server.log().WithFields(map[string]interface{}{
  307. "event": "connect",
  308. "id": client.ID,
  309. }).Infof("Handle client [%s]", client.RemoteIP)
  310. // Initial greeting
  311. greeting := fmt.Sprintf("220 %s SMTP Guerrilla(%s) #%d (%d) %s",
  312. sc.Hostname, Version, client.ID,
  313. server.clientPool.GetActiveClientsCount(), time.Now().Format(time.RFC3339))
  314. helo := fmt.Sprintf("250 %s Hello", sc.Hostname)
  315. // ehlo is a multi-line reply and need additional \r\n at the end
  316. ehlo := fmt.Sprintf("250-%s Hello\r\n", sc.Hostname)
  317. // Extended feature advertisements
  318. messageSize := fmt.Sprintf("250-SIZE %d\r\n", sc.MaxSize)
  319. pipelining := "250-PIPELINING\r\n"
  320. advertiseTLS := "250-STARTTLS\r\n"
  321. advertiseEnhancedStatusCodes := "250-ENHANCEDSTATUSCODES\r\n"
  322. // The last line doesn't need \r\n since string will be printed as a new line.
  323. // Also, Last line has no dash -
  324. help := "250 HELP"
  325. if sc.TLS.AlwaysOn {
  326. tlsConfig, ok := server.tlsConfigStore.Load().(*tls.Config)
  327. if !ok {
  328. server.mainlog().Error("Failed to load *tls.Config")
  329. } else if err := client.upgradeToTLS(tlsConfig); err == nil {
  330. advertiseTLS = ""
  331. } else {
  332. server.log().WithError(err).Warnf("[%s] Failed TLS handshake", client.RemoteIP)
  333. // server requires TLS, but can't handshake
  334. client.kill()
  335. }
  336. }
  337. if !sc.TLS.StartTLSOn {
  338. // STARTTLS turned off, don't advertise it
  339. advertiseTLS = ""
  340. }
  341. for client.isAlive() {
  342. switch client.state {
  343. case ClientGreeting:
  344. client.sendResponse(greeting)
  345. client.state = ClientCmd
  346. case ClientCmd:
  347. client.bufin.setLimit(CommandLineMaxLength)
  348. input, err := server.readCommand(client, sc.MaxSize)
  349. server.log().Debugf("Client sent: %s", input)
  350. if err == io.EOF {
  351. server.log().WithError(err).Warnf("Client closed the connection: %s", client.RemoteIP)
  352. return
  353. } else if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
  354. server.log().WithError(err).Warnf("Timeout: %s", client.RemoteIP)
  355. return
  356. } else if err == LineLimitExceeded {
  357. client.sendResponse(response.Canned.FailLineTooLong)
  358. client.kill()
  359. break
  360. } else if err != nil {
  361. server.log().WithError(err).Warnf("Read error: %s", client.RemoteIP)
  362. client.kill()
  363. break
  364. }
  365. if server.isShuttingDown() {
  366. client.state = ClientShutdown
  367. continue
  368. }
  369. input = strings.Trim(input, " \r\n")
  370. cmdLen := len(input)
  371. if cmdLen > CommandVerbMaxLength {
  372. cmdLen = CommandVerbMaxLength
  373. }
  374. cmd := strings.ToUpper(input[:cmdLen])
  375. switch {
  376. case strings.Index(cmd, "HELO") == 0:
  377. client.Helo = strings.Trim(input[4:], " ")
  378. client.resetTransaction()
  379. client.sendResponse(helo)
  380. case strings.Index(cmd, "EHLO") == 0:
  381. client.Helo = strings.Trim(input[4:], " ")
  382. client.resetTransaction()
  383. client.sendResponse(ehlo,
  384. messageSize,
  385. pipelining,
  386. advertiseTLS,
  387. advertiseEnhancedStatusCodes,
  388. help)
  389. case strings.Index(cmd, "HELP") == 0:
  390. quote := response.GetQuote()
  391. client.sendResponse("214-OK\r\n" + quote)
  392. case sc.XClientOn && strings.Index(cmd, "XCLIENT ") == 0:
  393. if toks := strings.Split(input[8:], " "); len(toks) > 0 {
  394. for i := range toks {
  395. if vals := strings.Split(toks[i], "="); len(vals) == 2 {
  396. if vals[1] == "[UNAVAILABLE]" {
  397. // skip
  398. continue
  399. }
  400. if vals[0] == "ADDR" {
  401. client.RemoteIP = vals[1]
  402. }
  403. if vals[0] == "HELO" {
  404. client.Helo = vals[1]
  405. }
  406. }
  407. }
  408. }
  409. client.sendResponse(response.Canned.SuccessMailCmd)
  410. case strings.Index(cmd, "MAIL FROM:") == 0:
  411. if client.isInTransaction() {
  412. client.sendResponse(response.Canned.FailNestedMailCmd)
  413. break
  414. }
  415. addr := input[10:]
  416. if !(strings.Index(addr, "<>") == 0) &&
  417. !(strings.Index(addr, " <>") == 0) {
  418. // Not Bounce, extract mail.
  419. if from, err := extractEmail(addr); err != nil {
  420. client.sendResponse(err)
  421. break
  422. } else {
  423. client.MailFrom = from
  424. server.log().WithFields(map[string]interface{}{
  425. "event": "mailfrom",
  426. "helo": client.Helo,
  427. "domain": from.Host,
  428. "address": getRemoteAddr(client.conn),
  429. "id": client.ID,
  430. }).Info("Mail from")
  431. }
  432. } else {
  433. // bounce has empty from address
  434. client.MailFrom = mail.Address{}
  435. }
  436. client.sendResponse(response.Canned.SuccessMailCmd)
  437. case strings.Index(cmd, "RCPT TO:") == 0:
  438. if len(client.RcptTo) > RFC2821LimitRecipients {
  439. client.sendResponse(response.Canned.ErrorTooManyRecipients)
  440. break
  441. }
  442. to, err := extractEmail(input[8:])
  443. if err != nil {
  444. client.sendResponse(err.Error())
  445. } else {
  446. if !server.allowsHost(to.Host) {
  447. client.sendResponse(response.Canned.ErrorRelayDenied, to.Host)
  448. } else {
  449. client.PushRcpt(to)
  450. rcptError := server.backend().ValidateRcpt(client.Envelope)
  451. if rcptError != nil {
  452. client.PopRcpt()
  453. client.sendResponse(response.Canned.FailRcptCmd + " " + rcptError.Error())
  454. } else {
  455. client.sendResponse(response.Canned.SuccessRcptCmd)
  456. }
  457. }
  458. }
  459. case strings.Index(cmd, "RSET") == 0:
  460. client.resetTransaction()
  461. client.sendResponse(response.Canned.SuccessResetCmd)
  462. case strings.Index(cmd, "VRFY") == 0:
  463. client.sendResponse(response.Canned.SuccessVerifyCmd)
  464. case strings.Index(cmd, "NOOP") == 0:
  465. client.sendResponse(response.Canned.SuccessNoopCmd)
  466. case strings.Index(cmd, "QUIT") == 0:
  467. client.sendResponse(response.Canned.SuccessQuitCmd)
  468. client.kill()
  469. case strings.Index(cmd, "DATA") == 0:
  470. if len(client.RcptTo) == 0 {
  471. client.sendResponse(response.Canned.FailNoRecipientsDataCmd)
  472. break
  473. }
  474. client.sendResponse(response.Canned.SuccessDataCmd)
  475. client.state = ClientData
  476. case sc.TLS.StartTLSOn && strings.Index(cmd, "STARTTLS") == 0:
  477. client.sendResponse(response.Canned.SuccessStartTLSCmd)
  478. client.state = ClientStartTLS
  479. default:
  480. client.errors++
  481. if client.errors >= MaxUnrecognizedCommands {
  482. client.sendResponse(response.Canned.FailMaxUnrecognizedCmd)
  483. client.kill()
  484. } else {
  485. client.sendResponse(response.Canned.FailUnrecognizedCmd)
  486. }
  487. }
  488. case ClientData:
  489. // intentionally placed the limit 1MB above so that reading does not return with an error
  490. // if the client goes a little over. Anything above will err
  491. client.bufin.setLimit(int64(sc.MaxSize) + 1024000) // This a hard limit.
  492. n, err := client.Data.ReadFrom(client.smtpReader.DotReader())
  493. if n > sc.MaxSize {
  494. err = fmt.Errorf("Maximum DATA size exceeded (%d)", sc.MaxSize)
  495. }
  496. if err != nil {
  497. if err == LineLimitExceeded {
  498. client.sendResponse(response.Canned.FailReadLimitExceededDataCmd, LineLimitExceeded.Error())
  499. client.kill()
  500. } else if err == MessageSizeExceeded {
  501. client.sendResponse(response.Canned.FailMessageSizeExceeded, MessageSizeExceeded.Error())
  502. client.kill()
  503. } else {
  504. client.sendResponse(response.Canned.FailReadErrorDataCmd, err.Error())
  505. client.kill()
  506. }
  507. server.log().WithError(err).Warn("Error reading data")
  508. client.resetTransaction()
  509. break
  510. }
  511. res := server.backend().Process(client.Envelope)
  512. if res.Code() < 300 {
  513. client.messagesSent++
  514. server.log().WithFields(map[string]interface{}{
  515. "helo": client.Helo,
  516. "remoteAddress": getRemoteAddr(client.conn),
  517. "success": true,
  518. }).Info("Received message")
  519. }
  520. client.sendResponse(res.String())
  521. client.state = ClientCmd
  522. if server.isShuttingDown() {
  523. client.state = ClientShutdown
  524. }
  525. client.resetTransaction()
  526. case ClientStartTLS:
  527. if !client.TLS && sc.TLS.StartTLSOn {
  528. tlsConfig, ok := server.tlsConfigStore.Load().(*tls.Config)
  529. if !ok {
  530. server.mainlog().Error("Failed to load *tls.Config")
  531. } else if err := client.upgradeToTLS(tlsConfig); err == nil {
  532. advertiseTLS = ""
  533. client.resetTransaction()
  534. } else {
  535. server.log().WithError(err).Warnf("[%s] Failed TLS handshake", client.RemoteIP)
  536. // Don't disconnect, let the client decide if it wants to continue
  537. }
  538. }
  539. // change to command state
  540. client.state = ClientCmd
  541. case ClientShutdown:
  542. // shutdown state
  543. client.sendResponse(response.Canned.ErrorShutdown)
  544. client.kill()
  545. }
  546. if client.bufout.Buffered() > 0 {
  547. if server.log().IsDebug() {
  548. server.log().Debugf("Writing response to client: \n%s", client.response.String())
  549. }
  550. err := server.flushResponse(client)
  551. if err != nil {
  552. server.log().WithError(err).Debug("Error writing response")
  553. return
  554. }
  555. }
  556. }
  557. }
  558. func (s *server) log() log.Logger {
  559. if l, ok := s.logStore.Load().(log.Logger); ok {
  560. return l
  561. }
  562. l, err := log.GetLogger(log.OutputStderr.String(), log.InfoLevel.String())
  563. if err == nil {
  564. s.logStore.Store(l)
  565. }
  566. return l
  567. }
  568. func (s *server) mainlog() log.Logger {
  569. if l, ok := s.mainlogStore.Load().(log.Logger); ok {
  570. return l
  571. }
  572. l, err := log.GetLogger(log.OutputStderr.String(), log.InfoLevel.String())
  573. if err == nil {
  574. s.mainlogStore.Store(l)
  575. }
  576. return l
  577. }