]> Sergey Matveev's repositories - godlighty.git/blob - cmd/godlighty/main.go
Configuration spewing
[godlighty.git] / cmd / godlighty / main.go
1 /*
2 godlighty -- highly-customizable HTTP, HTTP/2, HTTPS server
3 Copyright (C) 2021 Sergey Matveev <stargrave@stargrave.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, version 3 of the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 package main
19
20 import (
21         "context"
22         "crypto/tls"
23         "flag"
24         "log"
25         "net"
26         "net/http"
27         "os"
28         "os/signal"
29         "strconv"
30         "strings"
31         "syscall"
32         "time"
33
34         "github.com/davecgh/go-spew/spew"
35         "golang.org/x/net/netutil"
36
37         "go.stargrave.org/godlighty"
38         _ "go.stargrave.org/godlighty/rc/cfg"
39 )
40
41 const MaxConns = 128
42
43 var GracefulTime = 10 * time.Second
44
45 func main() {
46         bind := flag.String("bind", "[::]:80", "Address to bind and listen on")
47         doTLS := flag.Bool("tls", false, "Enable TLS")
48         doSetUID := flag.Int("setuid", 0, "Set that UID after binding the socket")
49         doSetGID := flag.Int("setgid", 0, "Set that GID after binding the socket")
50         doSetGIDs := flag.String("setgids", "", "Comma-separated GIDs to set")
51         log.SetFlags(log.Lshortfile)
52         log.SetOutput(os.Stdout)
53         flag.Parse()
54         if *doTLS {
55                 godlighty.LoadCertificates()
56         }
57         shutdown := make(chan os.Signal)
58         signal.Notify(shutdown, syscall.SIGTERM, syscall.SIGINT, syscall.SIGHUP)
59         exitErr := make(chan error)
60         l, err := net.Listen("tcp", *bind)
61         if err != nil {
62                 log.Fatalln(err)
63         }
64
65         if *doSetGID != 0 {
66                 if err := syscall.Setregid(*doSetGID, *doSetGID); err != nil {
67                         log.Fatal(err)
68                 }
69         }
70         if *doSetGIDs == "" {
71                 if *doSetGID != 0 {
72                         if err := syscall.Setgroups([]int{*doSetGID}); err != nil {
73                                 log.Fatal(err)
74                         }
75                 }
76         } else {
77                 gids := []int{}
78                 for _, g := range strings.Split(*doSetGIDs, ",") {
79                         gid, err := strconv.Atoi(g)
80                         if err != nil {
81                                 log.Fatalln(err)
82                         }
83                         gids = append(gids, gid)
84                 }
85                 if err := syscall.Setgroups(gids); err != nil {
86                         log.Fatal(err)
87                 }
88         }
89         if *doSetUID != 0 {
90                 if err := syscall.Setreuid(*doSetUID, *doSetUID); err != nil {
91                         log.Fatal(err)
92                 }
93         }
94
95         info := make(chan os.Signal)
96         signal.Notify(info, syscall.SIGINFO)
97         go func() {
98                 for {
99                         <-info
100                         spew.Fdump(os.Stdout, godlighty.Hosts)
101                 }
102         }()
103
104         srv := http.Server{Handler: godlighty.MainHandler}
105         go func() {
106                 <-shutdown
107                 log.Println("shutting down")
108                 ctx, cancel := context.WithTimeout(context.TODO(), GracefulTime)
109                 exitErr <- srv.Shutdown(ctx)
110                 cancel()
111         }()
112         var ll net.Listener
113         if *doTLS {
114                 tlsCfg := godlighty.NewTLSConfig()
115                 ll = tls.NewListener(netutil.LimitListener(l, MaxConns), tlsCfg)
116         } else {
117                 ll = netutil.LimitListener(l, MaxConns)
118         }
119         log.Println(
120                 godlighty.Version,
121                 "bind:", *bind,
122                 "tls:", *doTLS,
123                 "hosts:", len(godlighty.Hosts),
124         )
125         if err = srv.Serve(ll); err != http.ErrServerClosed {
126                 log.Fatalln(err)
127         }
128         if err := <-exitErr; err != nil {
129                 log.Fatal(err)
130         }
131 }