]> Sergey Matveev's repositories - godlighty.git/blob - cmd/godlighty/main.go
6c7114511e455f2134eca5f797ea0716ef73fcd0
[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         "golang.org/x/net/netutil"
35
36         "go.stargrave.org/godlighty"
37         _ "go.stargrave.org/godlighty/rc/cfg"
38 )
39
40 const MaxConns = 128
41
42 var GracefulTime = 10 * time.Second
43
44 func main() {
45         bind := flag.String("bind", "[::]:80", "Address to bind and listen on")
46         doTLS := flag.Bool("tls", false, "Enable TLS")
47         doSetUID := flag.Int("setuid", 0, "Set that UID after binding the socket")
48         doSetGID := flag.Int("setgid", 0, "Set that GID after binding the socket")
49         doSetGIDs := flag.String("setgids", "", "Comma-separated GIDs to set")
50         log.SetFlags(log.Lshortfile)
51         log.SetOutput(os.Stdout)
52         flag.Parse()
53         if *doTLS {
54                 godlighty.LoadCertificates()
55         }
56         shutdown := make(chan os.Signal)
57         signal.Notify(shutdown, syscall.SIGTERM, syscall.SIGINT, syscall.SIGHUP)
58         exitErr := make(chan error)
59         l, err := net.Listen("tcp", *bind)
60         if err != nil {
61                 log.Fatalln(err)
62         }
63
64         if *doSetGID != 0 {
65                 if err := syscall.Setregid(*doSetGID, *doSetGID); err != nil {
66                         log.Fatal(err)
67                 }
68         }
69         if *doSetGIDs == "" {
70                 if *doSetGID != 0 {
71                         if err := syscall.Setgroups([]int{*doSetGID}); err != nil {
72                                 log.Fatal(err)
73                         }
74                 }
75         } else {
76                 gids := []int{}
77                 for _, g := range strings.Split(*doSetGIDs, ",") {
78                         gid, err := strconv.Atoi(g)
79                         if err != nil {
80                                 log.Fatalln(err)
81                         }
82                         gids = append(gids, gid)
83                 }
84                 if err := syscall.Setgroups(gids); err != nil {
85                         log.Fatal(err)
86                 }
87         }
88         if *doSetUID != 0 {
89                 if err := syscall.Setreuid(*doSetUID, *doSetUID); err != nil {
90                         log.Fatal(err)
91                 }
92         }
93
94         srv := http.Server{Handler: godlighty.MainHandler}
95         go func() {
96                 <-shutdown
97                 log.Println("shutting down")
98                 ctx, cancel := context.WithTimeout(context.TODO(), GracefulTime)
99                 exitErr <- srv.Shutdown(ctx)
100                 cancel()
101         }()
102         var ll net.Listener
103         if *doTLS {
104                 tlsCfg := godlighty.NewTLSConfig()
105                 ll = tls.NewListener(netutil.LimitListener(l, MaxConns), tlsCfg)
106         } else {
107                 ll = netutil.LimitListener(l, MaxConns)
108         }
109         log.Println(
110                 godlighty.Version,
111                 "bind:", *bind,
112                 "tls:", *doTLS,
113                 "hosts:", len(godlighty.Hosts),
114         )
115         if err = srv.Serve(ll); err != http.ErrServerClosed {
116                 log.Fatalln(err)
117         }
118         if err := <-exitErr; err != nil {
119                 log.Fatal(err)
120         }
121 }