server.go 19 KB

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