...

Source file src/github.com/sassoftware/relic/server/daemon/daemon.go

Documentation: github.com/sassoftware/relic/server/daemon

     1  //
     2  // Copyright (c) SAS Institute Inc.
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //     http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    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  	// prevent Serve() from returning until the shutdown completes
   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