8 "github.com/mjl-/mox/dmarcdb"
9 "github.com/mjl-/mox/dns"
10 "github.com/mjl-/mox/http"
11 "github.com/mjl-/mox/imapserver"
12 "github.com/mjl-/mox/mlog"
13 "github.com/mjl-/mox/mox-"
14 "github.com/mjl-/mox/mtastsdb"
15 "github.com/mjl-/mox/queue"
16 "github.com/mjl-/mox/smtpserver"
17 "github.com/mjl-/mox/store"
18 "github.com/mjl-/mox/tlsrptdb"
19 "github.com/mjl-/mox/tlsrptsend"
22func shutdown(log mlog.Log) {
23 // We indicate we are shutting down. Causes new connections and new SMTP commands
24 // to be rejected. Should stop active connections pretty quickly.
27 // Now we are going to wait for all connections to be gone, up to a timeout.
28 done := mox.Connections.Done()
29 second := time.Tick(time.Second)
32 log.Print("connections shutdown, waiting until 1 second passed")
35 case <-time.Tick(3 * time.Second):
36 // We now cancel all pending operations, and set an immediate deadline on sockets.
37 // Should get us a clean shutdown relatively quickly.
39 mox.Connections.Shutdown()
41 second := time.Tick(time.Second)
44 log.Print("no more connections, shutdown is clean, waiting until 1 second passed")
45 <-second // Still wait for second, giving processes like imports a chance to clean up.
47 log.Print("shutting down with pending sockets")
50 err := os.Remove(mox.DataDirPath("ctl"))
51 log.Check(err, "removing ctl unix domain socket during shutdown")
54// start initializes all packages, starts all listeners and the switchboard
55// goroutine, then returns.
56func start(mtastsdbRefresher, sendDMARCReports, sendTLSReports, skipForkExec bool) error {
62 // If we were just launched as root, fork and exec as unprivileged user, handing
63 // over the bound sockets to the new process. We'll get to this same code path
64 // again, skipping this if block, continuing below with the actual serving.
66 mox.ForkExecUnprivileged()
67 panic("cannot happen")
69 mox.CleanupPassedFiles()
73 if err := mtastsdb.Init(mtastsdbRefresher); err != nil {
74 return fmt.Errorf("mtasts init: %s", err)
77 if err := tlsrptdb.Init(); err != nil {
78 return fmt.Errorf("tlsrpt init: %s", err)
81 done := make(chan struct{}) // Goroutines for messages and webhooks, and cleaners.
82 if err := queue.Start(dns.StrictResolver{Pkg: "queue"}, done); err != nil {
83 return fmt.Errorf("queue start: %s", err)
86 // dmarcdb starts after queue because it may start sending reports through the queue.
87 if err := dmarcdb.Init(); err != nil {
88 return fmt.Errorf("dmarc init: %s", err)
91 dmarcdb.Start(dns.StrictResolver{Pkg: "dmarcdb"})
95 tlsrptsend.Start(dns.StrictResolver{Pkg: "tlsrptsend"})
98 store.StartAuthCache()
105 <-make(chan struct{})