1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package daemon
18
19 import (
20 "context"
21 "crypto/tls"
22 "errors"
23 "fmt"
24 "io"
25 "net"
26 "net/http"
27 "os"
28 "sync"
29
30 "github.com/sassoftware/relic/config"
31 "github.com/sassoftware/relic/internal/activation"
32 "github.com/sassoftware/relic/lib/certloader"
33 "github.com/sassoftware/relic/lib/x509tools"
34 "github.com/sassoftware/relic/server"
35 "golang.org/x/net/http2"
36 )
37
38 type Daemon struct {
39 server *server.Server
40 httpServer *http.Server
41 listeners []net.Listener
42 wg sync.WaitGroup
43 }
44
45 func makeTLSConfig(config *config.Config) (*tls.Config, error) {
46 cert, err := certloader.LoadX509KeyPair(config.Server.CertFile, config.Server.KeyFile)
47 if err != nil {
48 return nil, err
49 }
50 var keyLog io.Writer
51 if klf := os.Getenv("SSLKEYLOGFILE"); klf != "" {
52 fmt.Fprintln(os.Stderr, "WARNING: SSLKEYLOGFILE is set! TLS master secrets will be logged.")
53 keyLog, err = os.OpenFile(klf, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
54 if err != nil {
55 return nil, err
56 }
57 }
58
59 tconf := &tls.Config{
60 Certificates: []tls.Certificate{cert.TLS()},
61 PreferServerCipherSuites: true,
62 SessionTicketsDisabled: true,
63 ClientAuth: tls.RequestClientCert,
64 MinVersion: tls.VersionTLS12,
65 KeyLogWriter: keyLog,
66 }
67 x509tools.SetKeyLogFile(tconf)
68 return tconf, nil
69 }
70
71 func getListener(laddr string, tconf *tls.Config) (net.Listener, error) {
72 listener, err := activation.GetListener(0, "tcp", laddr)
73 if err == nil {
74 if listener.Addr().Network() != "tcp" {
75 return nil, errors.New("inherited a listener but it isn't tcp")
76 }
77 listener = tls.NewListener(listener, tconf)
78 }
79 return listener, err
80 }
81
82 func New(config *config.Config, test bool) (*Daemon, error) {
83 srv, err := server.New(config)
84 if err != nil {
85 return nil, err
86 }
87 tconf, err := makeTLSConfig(config)
88 if err != nil {
89 return nil, err
90 }
91 httpServer := &http.Server{
92 Handler: srv,
93 ErrorLog: srv.ErrorLog,
94 TLSConfig: tconf,
95 }
96 if err := http2.ConfigureServer(httpServer, nil); err != nil {
97 return nil, err
98 }
99 if test {
100 srv.Close()
101 return nil, nil
102 }
103
104 listener, err := getListener(config.Server.Listen, tconf)
105 if err != nil {
106 return nil, err
107 }
108 listeners := []net.Listener{listener}
109 if config.Server.ListenHTTP != "" {
110 httpListener, err := activation.GetListener(1, "tcp", config.Server.ListenHTTP)
111 if err != nil {
112 return nil, err
113 }
114 listeners = append(listeners, httpListener)
115 }
116 return &Daemon{
117 server: srv,
118 httpServer: httpServer,
119 listeners: listeners,
120 }, nil
121 }
122
123 func (d *Daemon) SetOutput(w io.Writer) {
124 d.server.ErrorLog.SetFlags(0)
125 d.server.ErrorLog.SetPrefix("")
126 d.server.ErrorLog.SetOutput(w)
127 }
128
129 func (d *Daemon) ReopenLogger() error {
130 return d.server.ReopenLogger()
131 }
132
133 func (d *Daemon) Serve() error {
134 activation.DaemonReady()
135 errch := make(chan error, len(d.listeners))
136 for _, listener := range d.listeners {
137 d.wg.Add(1)
138 go func(listener net.Listener) {
139 errch <- d.httpServer.Serve(listener)
140 d.wg.Done()
141 }(listener)
142 }
143 d.wg.Wait()
144 for _ = range d.listeners {
145 if err := <-errch; err != nil {
146 return err
147 }
148 }
149 return nil
150 }
151
152 func (d *Daemon) Close() error {
153
154 d.wg.Add(1)
155 err := d.httpServer.Shutdown(context.Background())
156 d.server.Close()
157 d.wg.Done()
158 return err
159 }
160
View as plain text