-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathsmtprelay.go
159 lines (137 loc) · 4.03 KB
/
smtprelay.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package main
import (
"flag"
"fmt"
"os"
"os/signal"
"runtime"
"smtprelay/smtpd"
"syscall"
"time"
)
var (
conf *Conf
flags Flags
EXIT chan int
)
const (
MAINCONFIGFILENAME = "config.json"
LOGCONFIGFILENAME = "logconfig.xml"
)
type Flags struct {
MainConfigFilePath string
LogConfigFilePath string
}
func ReloadConfig(filename string) {
log.Info("Reloading config file")
newConf := new(Conf)
if err := newConf.Load(flags.MainConfigFilePath); err != nil {
log.Critical("can't reload config, old settings will be used:", err.Error())
}
conf = newConf
runtime.GOMAXPROCS(conf.NumCPU)
}
func main() {
EXIT = make(chan int)
flags = GetFlags()
InitLogger(flags.LogConfigFilePath)
log.Info("SYSTEM: Starting..")
conf = new(Conf)
if err := conf.Load(flags.MainConfigFilePath); err != nil {
log.Critical("can't load config,shut down:", err.Error())
panic(err.Error())
}
runtime.GOMAXPROCS(conf.NumCPU)
if err := InitQueues(); err != nil {
log.Critical("can't init MQ", err.Error())
panic(err.Error())
}
log.Info("SYSTEM: MQ initialized")
go StartStatisticServer()
go StartSender()
if conf.DKIMEnabled {
log.Info("SYSTEM: DKIM enabled, loading keys..")
err := DKIMLoadKeyRepository()
if err != nil {
log.Critical("Can't load DKIM repo:%s", err.Error())
panic(err.Error())
}
} else {
log.Info("DKIM disabled")
}
if conf.RelayModeEnabled {
log.Info("SYSTEM: Relay mode enabled! All messages will be redirected to %s", conf.RelayServer)
}
log.Info("SYSTEM: Incoming connections limit - %d", conf.MaxIncomingConnections)
log.Info("SYSTEM: Outcoming connections limit - %d", conf.MaxOutcomingConnections)
go StartSignalListener()
go StartSMTPServer()
go StartTCPServer()
<-EXIT
}
func handlerPanicProcessor(handler func(peer smtpd.Peer, env smtpd.Envelope) error) func(peer smtpd.Peer, env smtpd.Envelope) error {
return func(peer smtpd.Peer, env smtpd.Envelope) (err error) {
defer func() {
if r := recover(); r != nil {
log.Critical("PANIC, message DROPPED: %s", r)
err = ErrMessageErrorUnknown
}
}()
return handler(peer, env)
}
}
func GetFlags() (flags Flags) {
var workDir = flag.String("workdir", "/usr/local/etc/smtprelay", "Enter path to workdir. Default:/usr/local/etc/smtprelay")
flag.Parse()
flags.MainConfigFilePath = *workDir + string(os.PathSeparator) + MAINCONFIGFILENAME
flags.LogConfigFilePath = *workDir + string(os.PathSeparator) + LOGCONFIGFILENAME
if _, err := os.Stat(flags.MainConfigFilePath); os.IsNotExist(err) {
fmt.Fprintf(os.Stderr, "File %s not found.Please specify correct workdir\n", flags.MainConfigFilePath)
os.Exit(1)
}
if _, err := os.Stat(flags.LogConfigFilePath); os.IsNotExist(err) {
fmt.Fprintf(os.Stderr, "File %s not found.Please specify correct workdir\n", flags.LogConfigFilePath)
os.Exit(1)
}
return flags
}
func StartSignalListener() {
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGUSR1, syscall.SIGUSR2, syscall.SIGINT, syscall.SIGKILL, syscall.SIGTERM)
for {
var signal = <-c
log.Info("SYSTEM: SIGNAL %s RECEIVED", signal.String())
switch signal {
case syscall.SIGUSR1:
ReloadConfig(flags.MainConfigFilePath)
case syscall.SIGUSR2:
FlushQueues()
case syscall.SIGINT:
GracefullyStop()
case syscall.SIGKILL:
GracefullyStop()
case syscall.SIGTERM:
GracefullyStop()
case syscall.SIGHUP:
GracefullyStop()
}
}
}
func GracefullyStop() {
StopSMTPServer()
StopTCPListener()
log.Info("SYSTEM: Waiting for processing existing outcoming SMTP connections and queued messages (%d in all queues)", GetMailQueueLength()+GetErrorQueueLength())
for GetMailQueueLength()+GetErrorQueueLength() > 0 {
FlushErrors()
time.Sleep(1 * time.Second)
log.Info("SYSTEM: Messages left in queues - %d (mails - %d;errors - %d)", GetMailQueueLength()+GetErrorQueueLength(), GetMailQueueLength(), GetErrorQueueLength())
}
time.Sleep(200 * time.Millisecond)
log.Info("SYSTEM: Smtprelay stopped")
time.Sleep(200 * time.Millisecond)
EXIT <- 1
}
func FlushQueues() {
log.Info("SYSTEM: Start flushing queues")
FlushErrors()
}